summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/phonon
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@nokia.com>2009-03-23 10:18:55 +0100
committerSimon Hausmann <simon.hausmann@nokia.com>2009-03-23 10:18:55 +0100
commite5fcad302d86d316390c6b0f62759a067313e8a9 (patch)
treec2afbf6f1066b6ce261f14341cf6d310e5595bc1 /src/3rdparty/phonon
Long live Qt 4.5!
Diffstat (limited to 'src/3rdparty/phonon')
-rw-r--r--src/3rdparty/phonon/CMakeLists.txt272
-rw-r--r--src/3rdparty/phonon/COPYING.LIB510
-rw-r--r--src/3rdparty/phonon/ds9/CMakeLists.txt53
-rw-r--r--src/3rdparty/phonon/ds9/ConfigureChecks.cmake44
-rw-r--r--src/3rdparty/phonon/ds9/abstractvideorenderer.cpp118
-rw-r--r--src/3rdparty/phonon/ds9/abstractvideorenderer.h73
-rw-r--r--src/3rdparty/phonon/ds9/audiooutput.cpp111
-rw-r--r--src/3rdparty/phonon/ds9/audiooutput.h68
-rw-r--r--src/3rdparty/phonon/ds9/backend.cpp343
-rw-r--r--src/3rdparty/phonon/ds9/backend.h83
-rw-r--r--src/3rdparty/phonon/ds9/backendnode.cpp115
-rw-r--r--src/3rdparty/phonon/ds9/backendnode.h73
-rw-r--r--src/3rdparty/phonon/ds9/compointer.h114
-rw-r--r--src/3rdparty/phonon/ds9/ds9.desktop51
-rw-r--r--src/3rdparty/phonon/ds9/effect.cpp153
-rw-r--r--src/3rdparty/phonon/ds9/effect.h59
-rw-r--r--src/3rdparty/phonon/ds9/fakesource.cpp166
-rw-r--r--src/3rdparty/phonon/ds9/fakesource.h54
-rw-r--r--src/3rdparty/phonon/ds9/iodevicereader.cpp228
-rw-r--r--src/3rdparty/phonon/ds9/iodevicereader.h57
-rw-r--r--src/3rdparty/phonon/ds9/lgpl-2.1.txt504
-rw-r--r--src/3rdparty/phonon/ds9/lgpl-3.txt165
-rw-r--r--src/3rdparty/phonon/ds9/mediagraph.cpp1099
-rw-r--r--src/3rdparty/phonon/ds9/mediagraph.h148
-rw-r--r--src/3rdparty/phonon/ds9/mediaobject.cpp1208
-rw-r--r--src/3rdparty/phonon/ds9/mediaobject.h313
-rw-r--r--src/3rdparty/phonon/ds9/phononds9_namespace.h33
-rw-r--r--src/3rdparty/phonon/ds9/qasyncreader.cpp198
-rw-r--r--src/3rdparty/phonon/ds9/qasyncreader.h77
-rw-r--r--src/3rdparty/phonon/ds9/qaudiocdreader.cpp332
-rw-r--r--src/3rdparty/phonon/ds9/qaudiocdreader.h58
-rw-r--r--src/3rdparty/phonon/ds9/qbasefilter.cpp831
-rw-r--r--src/3rdparty/phonon/ds9/qbasefilter.h136
-rw-r--r--src/3rdparty/phonon/ds9/qmeminputpin.cpp357
-rw-r--r--src/3rdparty/phonon/ds9/qmeminputpin.h82
-rw-r--r--src/3rdparty/phonon/ds9/qpin.cpp653
-rw-r--r--src/3rdparty/phonon/ds9/qpin.h121
-rw-r--r--src/3rdparty/phonon/ds9/videorenderer_soft.cpp1011
-rw-r--r--src/3rdparty/phonon/ds9/videorenderer_soft.h68
-rw-r--r--src/3rdparty/phonon/ds9/videorenderer_vmr9.cpp333
-rw-r--r--src/3rdparty/phonon/ds9/videorenderer_vmr9.h56
-rw-r--r--src/3rdparty/phonon/ds9/videowidget.cpp397
-rw-r--r--src/3rdparty/phonon/ds9/videowidget.h96
-rw-r--r--src/3rdparty/phonon/ds9/volumeeffect.cpp296
-rw-r--r--src/3rdparty/phonon/ds9/volumeeffect.h71
-rw-r--r--src/3rdparty/phonon/gstreamer/CMakeLists.txt72
-rw-r--r--src/3rdparty/phonon/gstreamer/ConfigureChecks.cmake37
-rw-r--r--src/3rdparty/phonon/gstreamer/Messages.sh5
-rw-r--r--src/3rdparty/phonon/gstreamer/abstractrenderer.cpp56
-rw-r--r--src/3rdparty/phonon/gstreamer/abstractrenderer.h62
-rw-r--r--src/3rdparty/phonon/gstreamer/alsasink2.c1756
-rw-r--r--src/3rdparty/phonon/gstreamer/alsasink2.h87
-rw-r--r--src/3rdparty/phonon/gstreamer/artssink.cpp277
-rw-r--r--src/3rdparty/phonon/gstreamer/artssink.h91
-rw-r--r--src/3rdparty/phonon/gstreamer/audioeffect.cpp78
-rw-r--r--src/3rdparty/phonon/gstreamer/audioeffect.h55
-rw-r--r--src/3rdparty/phonon/gstreamer/audiooutput.cpp257
-rw-r--r--src/3rdparty/phonon/gstreamer/audiooutput.h82
-rw-r--r--src/3rdparty/phonon/gstreamer/backend.cpp455
-rw-r--r--src/3rdparty/phonon/gstreamer/backend.h101
-rw-r--r--src/3rdparty/phonon/gstreamer/common.h51
-rw-r--r--src/3rdparty/phonon/gstreamer/devicemanager.cpp357
-rw-r--r--src/3rdparty/phonon/gstreamer/devicemanager.h80
-rw-r--r--src/3rdparty/phonon/gstreamer/effect.cpp246
-rw-r--r--src/3rdparty/phonon/gstreamer/effect.h64
-rw-r--r--src/3rdparty/phonon/gstreamer/effectmanager.cpp105
-rw-r--r--src/3rdparty/phonon/gstreamer/effectmanager.h91
-rw-r--r--src/3rdparty/phonon/gstreamer/glrenderer.cpp339
-rw-r--r--src/3rdparty/phonon/gstreamer/glrenderer.h101
-rw-r--r--src/3rdparty/phonon/gstreamer/gsthelper.cpp170
-rw-r--r--src/3rdparty/phonon/gstreamer/gsthelper.h49
-rw-r--r--src/3rdparty/phonon/gstreamer/gstreamer.desktop51
-rw-r--r--src/3rdparty/phonon/gstreamer/lgpl-2.1.txt504
-rw-r--r--src/3rdparty/phonon/gstreamer/lgpl-3.txt165
-rw-r--r--src/3rdparty/phonon/gstreamer/medianode.cpp456
-rw-r--r--src/3rdparty/phonon/gstreamer/medianode.h128
-rw-r--r--src/3rdparty/phonon/gstreamer/medianodeevent.cpp38
-rw-r--r--src/3rdparty/phonon/gstreamer/medianodeevent.h70
-rw-r--r--src/3rdparty/phonon/gstreamer/mediaobject.cpp1479
-rw-r--r--src/3rdparty/phonon/gstreamer/mediaobject.h294
-rw-r--r--src/3rdparty/phonon/gstreamer/message.cpp75
-rw-r--r--src/3rdparty/phonon/gstreamer/message.h58
-rw-r--r--src/3rdparty/phonon/gstreamer/phononsrc.cpp257
-rw-r--r--src/3rdparty/phonon/gstreamer/phononsrc.h69
-rw-r--r--src/3rdparty/phonon/gstreamer/qwidgetvideosink.cpp221
-rw-r--r--src/3rdparty/phonon/gstreamer/qwidgetvideosink.h97
-rw-r--r--src/3rdparty/phonon/gstreamer/streamreader.cpp53
-rw-r--r--src/3rdparty/phonon/gstreamer/streamreader.h96
-rw-r--r--src/3rdparty/phonon/gstreamer/videowidget.cpp387
-rw-r--r--src/3rdparty/phonon/gstreamer/videowidget.h106
-rw-r--r--src/3rdparty/phonon/gstreamer/volumefadereffect.cpp162
-rw-r--r--src/3rdparty/phonon/gstreamer/volumefadereffect.h70
-rw-r--r--src/3rdparty/phonon/gstreamer/widgetrenderer.cpp150
-rw-r--r--src/3rdparty/phonon/gstreamer/widgetrenderer.h63
-rw-r--r--src/3rdparty/phonon/gstreamer/x11renderer.cpp194
-rw-r--r--src/3rdparty/phonon/gstreamer/x11renderer.h68
-rw-r--r--src/3rdparty/phonon/includes/CMakeLists.txt49
-rw-r--r--src/3rdparty/phonon/includes/Phonon/AbstractAudioOutput1
-rw-r--r--src/3rdparty/phonon/includes/Phonon/AbstractMediaStream1
-rw-r--r--src/3rdparty/phonon/includes/Phonon/AbstractVideoOutput1
-rw-r--r--src/3rdparty/phonon/includes/Phonon/AddonInterface1
-rw-r--r--src/3rdparty/phonon/includes/Phonon/AudioDevice1
-rw-r--r--src/3rdparty/phonon/includes/Phonon/AudioDeviceEnumerator1
-rw-r--r--src/3rdparty/phonon/includes/Phonon/AudioOutput1
-rw-r--r--src/3rdparty/phonon/includes/Phonon/AudioOutputDevice1
-rw-r--r--src/3rdparty/phonon/includes/Phonon/AudioOutputDeviceModel1
-rw-r--r--src/3rdparty/phonon/includes/Phonon/AudioOutputInterface1
-rw-r--r--src/3rdparty/phonon/includes/Phonon/BackendCapabilities1
-rw-r--r--src/3rdparty/phonon/includes/Phonon/BackendInterface1
-rw-r--r--src/3rdparty/phonon/includes/Phonon/Effect1
-rw-r--r--src/3rdparty/phonon/includes/Phonon/EffectDescription1
-rw-r--r--src/3rdparty/phonon/includes/Phonon/EffectDescriptionModel1
-rw-r--r--src/3rdparty/phonon/includes/Phonon/EffectInterface1
-rw-r--r--src/3rdparty/phonon/includes/Phonon/EffectParameter1
-rw-r--r--src/3rdparty/phonon/includes/Phonon/EffectWidget1
-rw-r--r--src/3rdparty/phonon/includes/Phonon/Experimental/AbstractVideoDataOutput1
-rw-r--r--src/3rdparty/phonon/includes/Phonon/Experimental/AudioDataOutput1
-rw-r--r--src/3rdparty/phonon/includes/Phonon/Experimental/SnapshotInterface1
-rw-r--r--src/3rdparty/phonon/includes/Phonon/Experimental/VideoDataOutput1
-rw-r--r--src/3rdparty/phonon/includes/Phonon/Experimental/VideoDataOutputInterface1
-rw-r--r--src/3rdparty/phonon/includes/Phonon/Experimental/VideoFrame1
-rw-r--r--src/3rdparty/phonon/includes/Phonon/Experimental/VideoFrame21
-rw-r--r--src/3rdparty/phonon/includes/Phonon/Experimental/Visualization1
-rw-r--r--src/3rdparty/phonon/includes/Phonon/Global1
-rw-r--r--src/3rdparty/phonon/includes/Phonon/MediaController1
-rw-r--r--src/3rdparty/phonon/includes/Phonon/MediaNode1
-rw-r--r--src/3rdparty/phonon/includes/Phonon/MediaObject1
-rw-r--r--src/3rdparty/phonon/includes/Phonon/MediaObjectInterface1
-rw-r--r--src/3rdparty/phonon/includes/Phonon/MediaSource1
-rw-r--r--src/3rdparty/phonon/includes/Phonon/ObjectDescription1
-rw-r--r--src/3rdparty/phonon/includes/Phonon/ObjectDescriptionModel1
-rw-r--r--src/3rdparty/phonon/includes/Phonon/Path1
-rw-r--r--src/3rdparty/phonon/includes/Phonon/PlatformPlugin1
-rw-r--r--src/3rdparty/phonon/includes/Phonon/SeekSlider1
-rw-r--r--src/3rdparty/phonon/includes/Phonon/StreamInterface1
-rw-r--r--src/3rdparty/phonon/includes/Phonon/VideoPlayer1
-rw-r--r--src/3rdparty/phonon/includes/Phonon/VideoWidget1
-rw-r--r--src/3rdparty/phonon/includes/Phonon/VideoWidgetInterface1
-rw-r--r--src/3rdparty/phonon/includes/Phonon/VolumeFaderEffect1
-rw-r--r--src/3rdparty/phonon/includes/Phonon/VolumeFaderInterface1
-rw-r--r--src/3rdparty/phonon/includes/Phonon/VolumeSlider1
-rw-r--r--src/3rdparty/phonon/phonon.pc.cmake11
-rw-r--r--src/3rdparty/phonon/phonon/.krazy2
-rw-r--r--src/3rdparty/phonon/phonon/BUGS9
-rw-r--r--src/3rdparty/phonon/phonon/CMakeLists.txt104
-rw-r--r--src/3rdparty/phonon/phonon/IDEAS70
-rw-r--r--src/3rdparty/phonon/phonon/Messages.sh6
-rw-r--r--src/3rdparty/phonon/phonon/TODO31
-rw-r--r--src/3rdparty/phonon/phonon/abstractaudiooutput.cpp50
-rw-r--r--src/3rdparty/phonon/phonon/abstractaudiooutput.h57
-rw-r--r--src/3rdparty/phonon/phonon/abstractaudiooutput_p.cpp44
-rw-r--r--src/3rdparty/phonon/phonon/abstractaudiooutput_p.h50
-rw-r--r--src/3rdparty/phonon/phonon/abstractmediastream.cpp198
-rw-r--r--src/3rdparty/phonon/phonon/abstractmediastream.h227
-rw-r--r--src/3rdparty/phonon/phonon/abstractmediastream_p.h83
-rw-r--r--src/3rdparty/phonon/phonon/abstractvideooutput.cpp41
-rw-r--r--src/3rdparty/phonon/phonon/abstractvideooutput.h74
-rw-r--r--src/3rdparty/phonon/phonon/abstractvideooutput_p.cpp41
-rw-r--r--src/3rdparty/phonon/phonon/abstractvideooutput_p.h48
-rw-r--r--src/3rdparty/phonon/phonon/addoninterface.h103
-rw-r--r--src/3rdparty/phonon/phonon/audiooutput.cpp418
-rw-r--r--src/3rdparty/phonon/phonon/audiooutput.h179
-rw-r--r--src/3rdparty/phonon/phonon/audiooutput_p.h95
-rw-r--r--src/3rdparty/phonon/phonon/audiooutputadaptor.cpp101
-rw-r--r--src/3rdparty/phonon/phonon/audiooutputadaptor_p.h109
-rw-r--r--src/3rdparty/phonon/phonon/audiooutputinterface.cpp40
-rw-r--r--src/3rdparty/phonon/phonon/audiooutputinterface.h151
-rw-r--r--src/3rdparty/phonon/phonon/backend.dox107
-rw-r--r--src/3rdparty/phonon/phonon/backendcapabilities.cpp121
-rw-r--r--src/3rdparty/phonon/phonon/backendcapabilities.h213
-rw-r--r--src/3rdparty/phonon/phonon/backendcapabilities_p.h50
-rw-r--r--src/3rdparty/phonon/phonon/backendinterface.h287
-rw-r--r--src/3rdparty/phonon/phonon/effect.cpp136
-rw-r--r--src/3rdparty/phonon/phonon/effect.h119
-rw-r--r--src/3rdparty/phonon/phonon/effect_p.h61
-rw-r--r--src/3rdparty/phonon/phonon/effectinterface.h68
-rw-r--r--src/3rdparty/phonon/phonon/effectparameter.cpp142
-rw-r--r--src/3rdparty/phonon/phonon/effectparameter.h237
-rw-r--r--src/3rdparty/phonon/phonon/effectparameter_p.h56
-rw-r--r--src/3rdparty/phonon/phonon/effectwidget.cpp254
-rw-r--r--src/3rdparty/phonon/phonon/effectwidget.h76
-rw-r--r--src/3rdparty/phonon/phonon/effectwidget_p.h64
-rwxr-xr-xsrc/3rdparty/phonon/phonon/extractmethodcalls.rb527
-rw-r--r--src/3rdparty/phonon/phonon/factory.cpp457
-rw-r--r--src/3rdparty/phonon/phonon/factory_p.h196
-rw-r--r--src/3rdparty/phonon/phonon/frontendinterface_p.h68
-rw-r--r--src/3rdparty/phonon/phonon/globalconfig.cpp243
-rw-r--r--src/3rdparty/phonon/phonon/globalconfig_p.h65
-rw-r--r--src/3rdparty/phonon/phonon/globalstatic_p.h293
-rw-r--r--src/3rdparty/phonon/phonon/iodevicestream.cpp100
-rw-r--r--src/3rdparty/phonon/phonon/iodevicestream_p.h58
-rw-r--r--src/3rdparty/phonon/phonon/mediacontroller.cpp239
-rw-r--r--src/3rdparty/phonon/phonon/mediacontroller.h188
-rw-r--r--src/3rdparty/phonon/phonon/medianode.cpp130
-rw-r--r--src/3rdparty/phonon/phonon/medianode.h69
-rw-r--r--src/3rdparty/phonon/phonon/medianode_p.h145
-rw-r--r--src/3rdparty/phonon/phonon/medianodedestructionhandler_p.h62
-rw-r--r--src/3rdparty/phonon/phonon/mediaobject.cpp572
-rw-r--r--src/3rdparty/phonon/phonon/mediaobject.dox71
-rw-r--r--src/3rdparty/phonon/phonon/mediaobject.h625
-rw-r--r--src/3rdparty/phonon/phonon/mediaobject_p.h113
-rw-r--r--src/3rdparty/phonon/phonon/mediaobjectinterface.h242
-rw-r--r--src/3rdparty/phonon/phonon/mediasource.cpp232
-rw-r--r--src/3rdparty/phonon/phonon/mediasource.h279
-rw-r--r--src/3rdparty/phonon/phonon/mediasource_p.h89
-rw-r--r--src/3rdparty/phonon/phonon/objectdescription.cpp140
-rw-r--r--src/3rdparty/phonon/phonon/objectdescription.h342
-rw-r--r--src/3rdparty/phonon/phonon/objectdescription_p.h64
-rw-r--r--src/3rdparty/phonon/phonon/objectdescriptionmodel.cpp392
-rw-r--r--src/3rdparty/phonon/phonon/objectdescriptionmodel.h380
-rw-r--r--src/3rdparty/phonon/phonon/objectdescriptionmodel_p.h65
-rw-r--r--src/3rdparty/phonon/phonon/org.kde.Phonon.AudioOutput.xml32
-rw-r--r--src/3rdparty/phonon/phonon/path.cpp472
-rw-r--r--src/3rdparty/phonon/phonon/path.h243
-rw-r--r--src/3rdparty/phonon/phonon/path_p.h79
-rw-r--r--src/3rdparty/phonon/phonon/phonon_export.h58
-rw-r--r--src/3rdparty/phonon/phonon/phonondefs.h144
-rw-r--r--src/3rdparty/phonon/phonon/phonondefs_p.h369
-rw-r--r--src/3rdparty/phonon/phonon/phononnamespace.cpp92
-rw-r--r--src/3rdparty/phonon/phonon/phononnamespace.h306
-rw-r--r--src/3rdparty/phonon/phonon/phononnamespace.h.in306
-rw-r--r--src/3rdparty/phonon/phonon/phononnamespace_p.h38
-rw-r--r--src/3rdparty/phonon/phonon/platform.cpp144
-rw-r--r--src/3rdparty/phonon/phonon/platform_p.h62
-rw-r--r--src/3rdparty/phonon/phonon/platformplugin.h118
-rwxr-xr-xsrc/3rdparty/phonon/phonon/preprocessandextract.sh39
-rw-r--r--src/3rdparty/phonon/phonon/qsettingsgroup_p.h91
-rw-r--r--src/3rdparty/phonon/phonon/seekslider.cpp263
-rw-r--r--src/3rdparty/phonon/phonon/seekslider.h157
-rw-r--r--src/3rdparty/phonon/phonon/seekslider_p.h101
-rw-r--r--src/3rdparty/phonon/phonon/stream-thoughts72
-rw-r--r--src/3rdparty/phonon/phonon/streaminterface.cpp114
-rw-r--r--src/3rdparty/phonon/phonon/streaminterface.h123
-rw-r--r--src/3rdparty/phonon/phonon/streaminterface_p.h59
-rw-r--r--src/3rdparty/phonon/phonon/videoplayer.cpp184
-rw-r--r--src/3rdparty/phonon/phonon/videoplayer.h207
-rw-r--r--src/3rdparty/phonon/phonon/videowidget.cpp183
-rw-r--r--src/3rdparty/phonon/phonon/videowidget.h219
-rw-r--r--src/3rdparty/phonon/phonon/videowidget_p.h84
-rw-r--r--src/3rdparty/phonon/phonon/videowidgetinterface.h65
-rw-r--r--src/3rdparty/phonon/phonon/volumefadereffect.cpp108
-rw-r--r--src/3rdparty/phonon/phonon/volumefadereffect.h178
-rw-r--r--src/3rdparty/phonon/phonon/volumefadereffect_p.h58
-rw-r--r--src/3rdparty/phonon/phonon/volumefaderinterface.h58
-rw-r--r--src/3rdparty/phonon/phonon/volumeslider.cpp262
-rw-r--r--src/3rdparty/phonon/phonon/volumeslider.h155
-rw-r--r--src/3rdparty/phonon/phonon/volumeslider_p.h101
-rw-r--r--src/3rdparty/phonon/qt7/CMakeLists.txt58
-rw-r--r--src/3rdparty/phonon/qt7/ConfigureChecks.cmake16
-rw-r--r--src/3rdparty/phonon/qt7/audioconnection.h84
-rw-r--r--src/3rdparty/phonon/qt7/audioconnection.mm152
-rw-r--r--src/3rdparty/phonon/qt7/audiodevice.h52
-rw-r--r--src/3rdparty/phonon/qt7/audiodevice.mm177
-rw-r--r--src/3rdparty/phonon/qt7/audioeffects.h80
-rw-r--r--src/3rdparty/phonon/qt7/audioeffects.mm254
-rw-r--r--src/3rdparty/phonon/qt7/audiograph.h86
-rw-r--r--src/3rdparty/phonon/qt7/audiograph.mm320
-rw-r--r--src/3rdparty/phonon/qt7/audiomixer.h91
-rw-r--r--src/3rdparty/phonon/qt7/audiomixer.mm181
-rw-r--r--src/3rdparty/phonon/qt7/audionode.h86
-rw-r--r--src/3rdparty/phonon/qt7/audionode.mm240
-rw-r--r--src/3rdparty/phonon/qt7/audiooutput.h88
-rw-r--r--src/3rdparty/phonon/qt7/audiooutput.mm168
-rw-r--r--src/3rdparty/phonon/qt7/audiopartoutput.h47
-rw-r--r--src/3rdparty/phonon/qt7/audiopartoutput.mm69
-rw-r--r--src/3rdparty/phonon/qt7/audiosplitter.h50
-rw-r--r--src/3rdparty/phonon/qt7/audiosplitter.mm52
-rw-r--r--src/3rdparty/phonon/qt7/backend.h61
-rw-r--r--src/3rdparty/phonon/qt7/backend.mm276
-rw-r--r--src/3rdparty/phonon/qt7/backendheader.h184
-rw-r--r--src/3rdparty/phonon/qt7/backendheader.mm127
-rw-r--r--src/3rdparty/phonon/qt7/backendinfo.h48
-rw-r--r--src/3rdparty/phonon/qt7/backendinfo.mm311
-rw-r--r--src/3rdparty/phonon/qt7/lgpl-2.1.txt504
-rw-r--r--src/3rdparty/phonon/qt7/lgpl-3.txt165
-rw-r--r--src/3rdparty/phonon/qt7/medianode.h85
-rw-r--r--src/3rdparty/phonon/qt7/medianode.mm261
-rw-r--r--src/3rdparty/phonon/qt7/medianodeevent.h71
-rw-r--r--src/3rdparty/phonon/qt7/medianodeevent.mm37
-rw-r--r--src/3rdparty/phonon/qt7/medianodevideopart.h42
-rw-r--r--src/3rdparty/phonon/qt7/medianodevideopart.mm37
-rw-r--r--src/3rdparty/phonon/qt7/mediaobject.h171
-rw-r--r--src/3rdparty/phonon/qt7/mediaobject.mm852
-rw-r--r--src/3rdparty/phonon/qt7/mediaobjectaudionode.h75
-rw-r--r--src/3rdparty/phonon/qt7/mediaobjectaudionode.mm207
-rw-r--r--src/3rdparty/phonon/qt7/quicktimeaudioplayer.h112
-rw-r--r--src/3rdparty/phonon/qt7/quicktimeaudioplayer.mm491
-rw-r--r--src/3rdparty/phonon/qt7/quicktimemetadata.h67
-rw-r--r--src/3rdparty/phonon/qt7/quicktimemetadata.mm185
-rw-r--r--src/3rdparty/phonon/qt7/quicktimestreamreader.h71
-rw-r--r--src/3rdparty/phonon/qt7/quicktimestreamreader.mm137
-rw-r--r--src/3rdparty/phonon/qt7/quicktimevideoplayer.h167
-rw-r--r--src/3rdparty/phonon/qt7/quicktimevideoplayer.mm955
-rw-r--r--src/3rdparty/phonon/qt7/videoeffect.h63
-rw-r--r--src/3rdparty/phonon/qt7/videoeffect.mm76
-rw-r--r--src/3rdparty/phonon/qt7/videoframe.h98
-rw-r--r--src/3rdparty/phonon/qt7/videoframe.mm378
-rw-r--r--src/3rdparty/phonon/qt7/videowidget.h71
-rw-r--r--src/3rdparty/phonon/qt7/videowidget.mm883
-rw-r--r--src/3rdparty/phonon/waveout/audiooutput.cpp78
-rw-r--r--src/3rdparty/phonon/waveout/audiooutput.h65
-rw-r--r--src/3rdparty/phonon/waveout/backend.cpp131
-rw-r--r--src/3rdparty/phonon/waveout/backend.h69
-rw-r--r--src/3rdparty/phonon/waveout/mediaobject.cpp686
-rw-r--r--src/3rdparty/phonon/waveout/mediaobject.h162
305 files changed, 48849 insertions, 0 deletions
diff --git a/src/3rdparty/phonon/CMakeLists.txt b/src/3rdparty/phonon/CMakeLists.txt
new file mode 100644
index 0000000000..c18c3e7e87
--- /dev/null
+++ b/src/3rdparty/phonon/CMakeLists.txt
@@ -0,0 +1,272 @@
+project(Phonon)
+
+cmake_minimum_required(VERSION 2.6.2 FATAL_ERROR)
+
+# CMP0002: we have multiple targets with the same name for the unit tests
+cmake_policy(SET CMP0002 OLD)
+
+# enable unit tests
+option(PHONON_BUILD_TESTS "Build the tests")
+option(PHONON_BUILD_EXAMPLES "Build the examples")
+
+if (PHONON_BUILD_TESTS)
+ enable_testing()
+endif (PHONON_BUILD_TESTS)
+
+set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
+
+include(PhononMacros)
+
+include(MacroLogFeature)
+include(MacroOptionalFindPackage)
+
+set(QT_MIN_VERSION 4.4.0)
+find_package(Qt4 REQUIRED)
+if (NOT QT_QTDBUS_FOUND)
+ message(STATUS "Warning: Phonon won't be compiled with DBus support.")
+endif(NOT QT_QTDBUS_FOUND)
+
+find_package(Automoc4 REQUIRED)
+include (CheckCXXCompilerFlag)
+include (MacroEnsureVersion)
+
+if (NOT AUTOMOC4_VERSION)
+ set(AUTOMOC4_VERSION "0.9.83")
+endif (NOT AUTOMOC4_VERSION)
+macro_ensure_version("0.9.86" "${AUTOMOC4_VERSION}" _automoc4_version_ok)
+if (NOT _automoc4_version_ok)
+ message(FATAL_ERROR "Your version of automoc4 is too old. You have ${AUTOMOC4_VERSION}, you need at least 0.9.86")
+endif (NOT _automoc4_version_ok)
+
+if (CMAKE_COMPILER_IS_GNUCXX)
+ set (KDE4_ENABLE_EXCEPTIONS -fexceptions)
+ # Select flags.
+ set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g")
+ set(CMAKE_CXX_FLAGS_RELEASE "-O2 -DNDEBUG -DQT_NO_DEBUG")
+ set(CMAKE_CXX_FLAGS_DEBUG "-g -O2 -fno-reorder-blocks -fno-schedule-insns -fno-inline")
+ set(CMAKE_CXX_FLAGS_DEBUGFULL "-g3 -fno-inline")
+ set(CMAKE_CXX_FLAGS_PROFILE "-g3 -fno-inline -ftest-coverage -fprofile-arcs")
+ set(CMAKE_C_FLAGS_RELWITHDEBINFO "-O2 -g")
+ set(CMAKE_C_FLAGS_RELEASE "-O2 -DNDEBUG -DQT_NO_DEBUG")
+ set(CMAKE_C_FLAGS_DEBUG "-g -O2 -fno-reorder-blocks -fno-schedule-insns -fno-inline")
+ set(CMAKE_C_FLAGS_DEBUGFULL "-g3 -fno-inline")
+ set(CMAKE_C_FLAGS_PROFILE "-g3 -fno-inline -ftest-coverage -fprofile-arcs")
+
+ if (CMAKE_SYSTEM_NAME MATCHES Linux)
+ set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-long-long -std=iso9899:1990 -Wundef -Wcast-align -Werror-implicit-function-declaration -Wchar-subscripts -Wall -W -Wpointer-arith -Wwrite-strings -Wformat-security -Wmissing-format-attribute -fno-common")
+ set ( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wnon-virtual-dtor -Wno-long-long -ansi -Wundef -Wcast-align -Wchar-subscripts -Wall -W -Wpointer-arith -Wformat-security -fno-exceptions -fno-check-new -fno-common")
+ add_definitions (-D_BSD_SOURCE)
+ endif (CMAKE_SYSTEM_NAME MATCHES Linux)
+
+ # gcc under Windows
+ if (MINGW)
+ set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--export-all-symbols -Wl,--disable-auto-import")
+ set (CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,--export-all-symbols -Wl,--disable-auto-import")
+
+ # we always link against the release version of QT with mingw
+ # (even for debug builds). So we need to define QT_NO_DEBUG
+ # or else QPluginLoader rejects plugins because it thinks
+ # they're built against the wrong QT.
+ add_definitions(-DQT_NO_DEBUG)
+ endif (MINGW)
+
+ check_cxx_compiler_flag(-fPIE HAVE_FPIE_SUPPORT)
+ if(KDE4_ENABLE_FPIE)
+ if(HAVE_FPIE_SUPPORT)
+ set (KDE4_CXX_FPIE_FLAGS "-fPIE")
+ set (KDE4_PIE_LDFLAGS "-pie")
+ else(HAVE_FPIE_SUPPORT)
+ message(STATUS "Your compiler doesn't support PIE flag")
+ endif(HAVE_FPIE_SUPPORT)
+ endif(KDE4_ENABLE_FPIE)
+
+ check_cxx_compiler_flag(-Woverloaded-virtual __KDE_HAVE_W_OVERLOADED_VIRTUAL)
+ if(__KDE_HAVE_W_OVERLOADED_VIRTUAL)
+ set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Woverloaded-virtual")
+ endif(__KDE_HAVE_W_OVERLOADED_VIRTUAL)
+
+ # visibility support
+ check_cxx_compiler_flag(-fvisibility=hidden __KDE_HAVE_GCC_VISIBILITY)
+ set( __KDE_HAVE_GCC_VISIBILITY ${__KDE_HAVE_GCC_VISIBILITY} CACHE BOOL "GCC support for hidden visibility")
+
+ # get the gcc version
+ exec_program(${CMAKE_C_COMPILER} ARGS --version OUTPUT_VARIABLE _gcc_version_info)
+
+ string (REGEX MATCH "[345]\\.[0-9]\\.[0-9]" _gcc_version "${_gcc_version_info}")
+ # gcc on mac just reports: "gcc (GCC) 3.3 20030304 ..." without the patch level, handle this here:
+ if (NOT _gcc_version)
+ string (REGEX REPLACE ".*\\(GCC\\).* ([34]\\.[0-9]) .*" "\\1.0" _gcc_version "${_gcc_version_info}")
+ endif (NOT _gcc_version)
+
+ macro_ensure_version("4.1.0" "${_gcc_version}" GCC_IS_NEWER_THAN_4_1)
+ macro_ensure_version("4.2.0" "${_gcc_version}" GCC_IS_NEWER_THAN_4_2)
+ macro_ensure_version("4.3.0" "${_gcc_version}" GCC_IS_NEWER_THAN_4_3)
+
+ # save a little by making local statics not threadsafe
+ # ### do not enable it for older compilers, see
+ # ### http://gcc.gnu.org/bugzilla/show_bug.cgi?id=31806
+ if (GCC_IS_NEWER_THAN_4_3)
+ set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-threadsafe-statics")
+ endif (GCC_IS_NEWER_THAN_4_3)
+
+ set(_GCC_COMPILED_WITH_BAD_ALLOCATOR FALSE)
+ if (GCC_IS_NEWER_THAN_4_1)
+ exec_program(${CMAKE_C_COMPILER} ARGS -v OUTPUT_VARIABLE _gcc_alloc_info)
+ string(REGEX MATCH "(--enable-libstdcxx-allocator=mt)" _GCC_COMPILED_WITH_BAD_ALLOCATOR "${_gcc_alloc_info}")
+ endif (GCC_IS_NEWER_THAN_4_1)
+
+ if (__KDE_HAVE_GCC_VISIBILITY AND GCC_IS_NEWER_THAN_4_1 AND NOT _GCC_COMPILED_WITH_BAD_ALLOCATOR)
+ set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden")
+ set (KDE4_C_FLAGS "-fvisibility=hidden")
+ # check that Qt defines Q_DECL_EXPORT as __attribute__ ((visibility("default")))
+ # if it doesn't and KDE compiles with hidden default visibiltiy plugins will break
+ set(_source "#include <QtCore/QtGlobal>\n int main()\n {\n #ifdef QT_VISIBILITY_AVAILABLE \n return 0;\n #else \n return 1; \n #endif \n }\n")
+ set(_source_file ${CMAKE_BINARY_DIR}/CMakeTmp/check_qt_visibility.cpp)
+ file(WRITE "${_source_file}" "${_source}")
+ set(_include_dirs "-DINCLUDE_DIRECTORIES:STRING=${QT_INCLUDES}")
+
+ try_run(_run_result _compile_result ${CMAKE_BINARY_DIR} ${_source_file} CMAKE_FLAGS "${_include_dirs}")
+
+ if(NOT _compile_result)
+ message(FATAL_ERROR "Could not compile simple test program:\n ${_source}")
+ endif(NOT _compile_result)
+ if(_run_result)
+ message(FATAL_ERROR "Qt compiled without support for -fvisibility=hidden. This will break plugins and linking of some applications. Please fix your Qt installation.")
+ endif(_run_result)
+
+ if (GCC_IS_NEWER_THAN_4_2)
+ set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility-inlines-hidden")
+ endif (GCC_IS_NEWER_THAN_4_2)
+ else (__KDE_HAVE_GCC_VISIBILITY AND GCC_IS_NEWER_THAN_4_1 AND NOT _GCC_COMPILED_WITH_BAD_ALLOCATOR)
+ set (__KDE_HAVE_GCC_VISIBILITY 0)
+ endif (__KDE_HAVE_GCC_VISIBILITY AND GCC_IS_NEWER_THAN_4_1 AND NOT _GCC_COMPILED_WITH_BAD_ALLOCATOR)
+
+endif (CMAKE_COMPILER_IS_GNUCXX)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+set(CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE ON)
+set(CMAKE_COLOR_MAKEFILE ON)
+
+set(PHONON_LIB_MAJOR_VERSION "4")
+set(PHONON_LIB_MINOR_VERSION "3")
+set(PHONON_LIB_PATCH_VERSION "1")
+set(PHONON_LIB_VERSION "${PHONON_LIB_MAJOR_VERSION}.3.1")
+set(PHONON_LIB_SOVERSION ${PHONON_LIB_MAJOR_VERSION})
+
+add_definitions(${QT_DEFINITIONS})
+remove_definitions(-DQT3_SUPPORT_WARNINGS -DQT3_SUPPORT)
+if(MSVC)
+ add_definitions( -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE -D_SCL_SECURE_NO_WARNINGS )
+endif(MSVC)
+
+# for including config.h and for includes like <kparts/foo.h>
+include_directories(${QT_INCLUDES} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/includes ${CMAKE_CURRENT_SOURCE_DIR}/phonon ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/phonon)
+
+macro(_SET_FANCY _var _value _comment)
+ if (KDESupport_SOURCE_DIR)
+ # when building inside kdesupport other subprojects write crap into our variables
+ set(${_var} "${_value}")
+ else (KDESupport_SOURCE_DIR)
+ if (NOT DEFINED ${_var})
+ set(${_var} "${_value}")
+ else (NOT DEFINED ${_var})
+ set(${_var} "${${_var}}" CACHE PATH "${_comment}")
+ endif (NOT DEFINED ${_var})
+ endif (KDESupport_SOURCE_DIR)
+endmacro(_SET_FANCY)
+
+set(LIB_SUFFIX "" CACHE STRING "Define suffix of directory name (32/64)" )
+
+_set_fancy(EXEC_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}" "Base directory for executables and libraries")
+_set_fancy(SHARE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}/share" "Base directory for files which go to share/")
+_set_fancy(BIN_INSTALL_DIR "${EXEC_INSTALL_PREFIX}/bin" "The install dir for executables (default ${EXEC_INSTALL_PREFIX}/bin)")
+_set_fancy(LIB_INSTALL_DIR "${EXEC_INSTALL_PREFIX}/lib${LIB_SUFFIX}" "The subdirectory relative to the install prefix where libraries will be installed (default is ${EXEC_INSTALL_PREFIX}/lib${LIB_SUFFIX})")
+_set_fancy(INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/include" "The subdirectory to the header prefix")
+_set_fancy(PLUGIN_INSTALL_DIR "${LIB_INSTALL_DIR}/kde4" "The subdirectory relative to the install prefix where plugins will be installed (default is ${LIB_INSTALL_DIR}/kde4)")
+_set_fancy(ICON_INSTALL_DIR "${SHARE_INSTALL_PREFIX}/icons" "The icon install dir (default ${SHARE_INSTALL_PREFIX}/share/icons/)")
+_set_fancy(SERVICES_INSTALL_DIR "${SHARE_INSTALL_PREFIX}/kde4/services" "The install dir for service (desktop, protocol, ...) files")
+_set_fancy(DBUS_INTERFACES_INSTALL_DIR "${SHARE_INSTALL_PREFIX}/dbus-1/interfaces" "The dbus interfaces install dir (default: ${SHARE_INSTALL_PREFIX}/dbus-1/interfaces)")
+_set_fancy(DBUS_SERVICES_INSTALL_DIR "${SHARE_INSTALL_PREFIX}/dbus-1/services" "The dbus services install dir (default: ${SHARE_INSTALL_PREFIX}/dbus-1/services)")
+
+set(INSTALL_TARGETS_DEFAULT_ARGS RUNTIME DESTINATION "${BIN_INSTALL_DIR}"
+ LIBRARY DESTINATION "${LIB_INSTALL_DIR}"
+ ARCHIVE DESTINATION "${LIB_INSTALL_DIR}" COMPONENT Devel )
+
+# on the Mac support an extra install directory for application bundles
+if(APPLE)
+ set(INSTALL_TARGETS_DEFAULT_ARGS ${INSTALL_TARGETS_DEFAULT_ARGS}
+ BUNDLE DESTINATION "${BUNDLE_INSTALL_DIR}" )
+endif(APPLE)
+
+if (CMAKE_SYSTEM_NAME MATCHES Linux)
+ if (CMAKE_COMPILER_IS_GNUCXX)
+ set ( CMAKE_SHARED_LINKER_FLAGS "-Wl,--fatal-warnings -Wl,--no-undefined -lc ${CMAKE_SHARED_LINKER_FLAGS}")
+ set ( CMAKE_MODULE_LINKER_FLAGS "-Wl,--fatal-warnings -Wl,--no-undefined -lc ${CMAKE_MODULE_LINKER_FLAGS}")
+
+ set ( CMAKE_SHARED_LINKER_FLAGS "-Wl,--enable-new-dtags ${CMAKE_SHARED_LINKER_FLAGS}")
+ set ( CMAKE_MODULE_LINKER_FLAGS "-Wl,--enable-new-dtags ${CMAKE_MODULE_LINKER_FLAGS}")
+ set ( CMAKE_EXE_LINKER_FLAGS "-Wl,--enable-new-dtags ${CMAKE_EXE_LINKER_FLAGS}")
+
+ # we profile...
+ if(CMAKE_BUILD_TYPE_TOLOWER MATCHES profile)
+ set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fprofile-arcs -ftest-coverage")
+ set (CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage")
+ endif(CMAKE_BUILD_TYPE_TOLOWER MATCHES profile)
+ endif (CMAKE_COMPILER_IS_GNUCXX)
+ if (CMAKE_C_COMPILER MATCHES "icc")
+ set ( CMAKE_SHARED_LINKER_FLAGS "-Wl,--fatal-warnings -Wl,--no-undefined -lc ${CMAKE_SHARED_LINKER_FLAGS}")
+ set ( CMAKE_MODULE_LINKER_FLAGS "-Wl,--fatal-warnings -Wl,--no-undefined -lc ${CMAKE_MODULE_LINKER_FLAGS}")
+ endif (CMAKE_C_COMPILER MATCHES "icc")
+endif (CMAKE_SYSTEM_NAME MATCHES Linux)
+
+set(PHONON_LIBS phonon ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY})
+if(QT_QTDBUS_FOUND)
+ list(APPEND PHONON_LIBS phonon ${QT_QTDBUS_LIBRARY})
+endif(QT_QTDBUS_FOUND)
+
+set(EXECUTABLE_OUTPUT_PATH ${Phonon_BINARY_DIR}/bin)
+if (WIN32)
+ set(LIBRARY_OUTPUT_PATH ${EXECUTABLE_OUTPUT_PATH})
+else (WIN32)
+ set(LIBRARY_OUTPUT_PATH ${Phonon_BINARY_DIR}/lib)
+endif (WIN32)
+
+if (CMAKE_COMPILER_IS_GNUCXX OR CMAKE_C_COMPILER MATCHES "icc")
+ set ( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wnon-virtual-dtor -Wno-long-long -ansi -Wundef -Wcast-align -Wchar-subscripts -Wall -W -Wpointer-arith -Wformat-security -fno-check-new -fno-common")
+endif (CMAKE_COMPILER_IS_GNUCXX OR CMAKE_C_COMPILER MATCHES "icc")
+
+# Set up RPATH handling, so the libs are found if they are installed to a non-standard location.
+# By default cmake builds the targets with full RPATH to everything in the build directory,
+# but then removes the RPATH when installing.
+# These two options below make it set the RPATH of the installed targets to all
+# RPATH directories outside the current CMAKE_BINARY_DIR and also the library
+# install directory. Alex
+set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
+set(CMAKE_INSTALL_RPATH "${LIB_INSTALL_DIR}" )
+
+if(APPLE)
+ set(CMAKE_INSTALL_NAME_DIR ${LIB_INSTALL_DIR})
+endif(APPLE)
+
+
+add_subdirectory(cmake)
+add_subdirectory(phonon)
+add_subdirectory(includes)
+if (Q_WS_MAC AND BUILD_PHONON_QT7)
+ add_subdirectory(qt7)
+endif (Q_WS_MAC AND BUILD_PHONON_QT7)
+if (Q_WS_WIN)
+ add_subdirectory(ds9)
+endif (Q_WS_WIN)
+
+if (Q_WS_X11)
+ add_subdirectory(gstreamer)
+ add_subdirectory(xine)
+endif (Q_WS_X11)
+
+if(NOT WIN32) # pkgconfig file
+ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/phonon.pc.cmake ${CMAKE_CURRENT_BINARY_DIR}/phonon.pc @ONLY)
+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/phonon.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig)
+endif(NOT WIN32)
+
+macro_display_feature_log()
diff --git a/src/3rdparty/phonon/COPYING.LIB b/src/3rdparty/phonon/COPYING.LIB
new file mode 100644
index 0000000000..2d2d780e60
--- /dev/null
+++ b/src/3rdparty/phonon/COPYING.LIB
@@ -0,0 +1,510 @@
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations
+below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it
+becomes a de-facto standard. To achieve this, non-free programs must
+be allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control
+compilation and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at least
+ three years, to give the same user the materials specified in
+ Subsection 6a, above, for a charge no more than the cost of
+ performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply, and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License
+may add an explicit geographical distribution limitation excluding those
+countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms
+of the ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library.
+It is safest to attach them to the start of each source file to most
+effectively convey the exclusion of warranty; and each file should
+have at least the "copyright" line and a pointer to where the full
+notice is found.
+
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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 library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or
+your school, if any, to sign a "copyright disclaimer" for the library,
+if necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James
+ Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/src/3rdparty/phonon/ds9/CMakeLists.txt b/src/3rdparty/phonon/ds9/CMakeLists.txt
new file mode 100644
index 0000000000..1bb6f6f79d
--- /dev/null
+++ b/src/3rdparty/phonon/ds9/CMakeLists.txt
@@ -0,0 +1,53 @@
+# Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+#
+# This library 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, either version 2 or 3 of the License.
+#
+# This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+project(phonon-ds9)
+include(ConfigureChecks.cmake)
+
+if (BUILD_PHONON_DS9)
+ find_package(OPENGL REQUIRED)
+
+ include_directories($ENV{DXDSDK_DIR}/include $ENV{DXSDK_DIR})
+ set(phonon_ds9_SRCS
+ abstractvideorenderer.cpp
+ audiooutput.cpp
+ backend.cpp
+ backendnode.cpp
+ effect.cpp
+ fakesource.cpp
+ iodevicereader.cpp
+ mediagraph.cpp
+ mediaobject.cpp
+ videowidget.cpp
+ videorenderer_vmr9.cpp
+ videorenderer_soft.cpp
+ volumeeffect.cpp
+ qbasefilter.cpp
+ qpin.cpp
+ qasyncreader.cpp
+ qaudiocdreader.cpp
+ qmeminputpin.cpp
+ )
+
+ add_definitions(-DPHONON_MAKE_QT_ONLY_BACKEND -DUNICODE)
+ automoc4_add_library(phonon_ds9 SHARED ${phonon_ds9_SRCS})
+ set_target_properties(phonon_ds9 PROPERTIES PREFIX "")
+ target_link_libraries(phonon_ds9
+ ${PHONON_LIBS} ${QT_QTOPENGL_LIBRARY} ${OPENGL_gl_LIBRARY}
+ dxguid strmiids dmoguids msdmo ole32 oleaut32 uuid gdi32)
+ install(TARGETS phonon_ds9
+ RUNTIME DESTINATION ${BIN_INSTALL_DIR}/phonon_backend
+ LIBRARY DESTINATION ${LIB_INSTALL_DIR}
+ ARCHIVE DESTINATION ${LIB_INSTALL_DIR})
+ install(FILES ds9.desktop DESTINATION ${SERVICES_INSTALL_DIR}/phononbackends)
+endif (BUILD_PHONON_DS9)
diff --git a/src/3rdparty/phonon/ds9/ConfigureChecks.cmake b/src/3rdparty/phonon/ds9/ConfigureChecks.cmake
new file mode 100644
index 0000000000..c13056f1bc
--- /dev/null
+++ b/src/3rdparty/phonon/ds9/ConfigureChecks.cmake
@@ -0,0 +1,44 @@
+# Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+#
+# This library 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, either version 2 or 3 of the License.
+#
+# This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+# We must find:
+# $DXSDK_DIR/include/d3d9.h
+# $DXDSK_DIR/$LIB/dxguid.lib
+# vmr9.h
+# dshow.h
+# strmiids.lib
+# dmoguids.lib
+# msdmo.lib
+include(CheckCXXSourceCompiles)
+
+macro_push_required_vars()
+
+set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES} ${CMAKE_INCLUDE_PATH} $ENV{DXSDK_DIR} $ENV{DXSDK_DIR}/include)
+set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} dxguid strmiids dmoguids msdmo)
+
+CHECK_CXX_SOURCE_COMPILES(
+"#include <d3d9.h>
+#include <dshow.h>
+#include <strmif.h>
+#include <vmr9.h>
+
+int main() { }" BUILD_PHONON_DS9)
+
+macro_pop_required_vars()
+
+if (BUILD_PHONON_DS9)
+ message(STATUS "Found DirectShow 9 support: $ENV{DXSDK_DIR}")
+else (BUILD_PHONON_DS9)
+ message(STATUS "DirectShow 9 support NOT found")
+endif (BUILD_PHONON_DS9)
diff --git a/src/3rdparty/phonon/ds9/abstractvideorenderer.cpp b/src/3rdparty/phonon/ds9/abstractvideorenderer.cpp
new file mode 100644
index 0000000000..e932e70962
--- /dev/null
+++ b/src/3rdparty/phonon/ds9/abstractvideorenderer.cpp
@@ -0,0 +1,118 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library 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, either version 2.1 or 3 of the License.
+
+This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "abstractvideorenderer.h"
+
+#include <QtGui/QApplication>
+#include <QtGui/QDesktopWidget>
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_PHONON_VIDEO
+
+namespace Phonon
+{
+ namespace DS9
+ {
+
+ AbstractVideoRenderer::AbstractVideoRenderer() :
+ m_dstX(0), m_dstY(0), m_dstWidth(0), m_dstHeight(0),
+ m_active(false)
+ {
+ }
+
+ AbstractVideoRenderer::~AbstractVideoRenderer()
+ {
+ }
+
+ Filter AbstractVideoRenderer::getFilter() const
+ {
+ return m_filter;
+ }
+
+ QSize AbstractVideoRenderer::sizeHint() const
+ {
+ QSize s = videoSize();
+ if (s.isNull()) {
+ s = QSize(640, 480).boundedTo( QApplication::desktop()->availableGeometry().size() );
+ }
+ return s;
+ }
+
+ void AbstractVideoRenderer::setActive(bool b)
+ {
+ m_active = b;
+ }
+
+ bool AbstractVideoRenderer::isActive() const
+ {
+ return m_active;
+ }
+
+ void AbstractVideoRenderer::internalNotifyResize(const QSize &size, const QSize &videoSize,
+ Phonon::VideoWidget::AspectRatio aspectRatio, Phonon::VideoWidget::ScaleMode scaleMode)
+ {
+ //update the video rects
+ qreal ratio = -1.;
+ const int videoWidth = videoSize.width(),
+ videoHeight = videoSize.height();
+
+ switch(aspectRatio)
+ {
+ case Phonon::VideoWidget::AspectRatioAuto:
+ {
+ //preserve the aspect ratio of the video
+ ratio = qreal(videoWidth) / qreal(videoHeight);
+ }
+ break;
+ case Phonon::VideoWidget::AspectRatio4_3:
+ ratio = qreal(4. / 3.);
+ break;
+ case Phonon::VideoWidget::AspectRatio16_9:
+ ratio = qreal(16. / 9.);
+ break;
+ case Phonon::VideoWidget::AspectRatioWidget:
+ default:
+ break;
+ }
+
+ const qreal realWidth = size.width(),
+ realHeight = size.height();
+
+ //reinitialization
+ m_dstWidth = size.width();
+ m_dstHeight = size.height();
+ m_dstX = m_dstY = 0;
+
+ if (ratio > 0) {
+ if (realWidth / realHeight > ratio && scaleMode == Phonon::VideoWidget::FitInView
+ || realWidth / realHeight < ratio && scaleMode == Phonon::VideoWidget::ScaleAndCrop) {
+ //the height is correct, let's change the width
+ m_dstWidth = qRound(realHeight * ratio);
+ m_dstX = qRound((realWidth - realHeight * ratio) / 2.);
+ } else {
+ m_dstHeight = qRound(realWidth / ratio);
+ m_dstY = qRound((realHeight - realWidth / ratio) / 2.);
+ }
+ }
+ }
+ }
+}
+
+#endif //QT_NO_PHONON_EFFECT
+
+QT_END_NAMESPACE
diff --git a/src/3rdparty/phonon/ds9/abstractvideorenderer.h b/src/3rdparty/phonon/ds9/abstractvideorenderer.h
new file mode 100644
index 0000000000..25c660fa06
--- /dev/null
+++ b/src/3rdparty/phonon/ds9/abstractvideorenderer.h
@@ -0,0 +1,73 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library 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, either version 2.1 or 3 of the License.
+
+This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef PHONON_ABSTRACTVIDEORENDERER_H
+#define PHONON_ABSTRACTVIDEORENDERER_H
+
+#include "backendnode.h"
+
+#include <phonon/videowidget.h>
+
+QT_BEGIN_NAMESPACE
+
+class QImage;
+
+#ifndef QT_NO_PHONON_VIDEO
+
+namespace Phonon
+{
+ namespace DS9
+ {
+ //this is the interface used by the videorenderer from the VideoWidget class
+ class AbstractVideoRenderer
+ {
+ public:
+ virtual ~AbstractVideoRenderer();
+
+ virtual void repaintCurrentFrame(QWidget *target, const QRect &rect) = 0;
+ virtual void notifyResize(const QSize&, Phonon::VideoWidget::AspectRatio, Phonon::VideoWidget::ScaleMode) = 0;
+ virtual void applyMixerSettings(qreal brightness, qreal contrast, qreal m_hue, qreal saturation) = 0;
+
+ void setActive(bool);
+ bool isActive() const;
+
+ virtual bool isNative() const = 0;
+ virtual QImage snapshot() const = 0;
+
+ Filter getFilter() const;
+ QSize sizeHint() const;
+
+ protected:
+ virtual QSize videoSize() const = 0;
+
+ AbstractVideoRenderer();
+ void internalNotifyResize(const QSize &size, const QSize &videoSize,
+ Phonon::VideoWidget::AspectRatio aspectRatio, Phonon::VideoWidget::ScaleMode scaleMode);
+
+
+ Filter m_filter;
+ int m_dstX, m_dstY, m_dstWidth, m_dstHeight;
+ bool m_active;
+ };
+ }
+}
+
+#endif //QT_NO_PHONON_VIDEO
+
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/3rdparty/phonon/ds9/audiooutput.cpp b/src/3rdparty/phonon/ds9/audiooutput.cpp
new file mode 100644
index 0000000000..fcc062cf48
--- /dev/null
+++ b/src/3rdparty/phonon/ds9/audiooutput.cpp
@@ -0,0 +1,111 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library 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, either version 2.1 or 3 of the License.
+
+This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "audiooutput.h"
+#include "mediaobject.h"
+
+#include <QtCore/qmath.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+ namespace DS9
+ {
+ AudioOutput::AudioOutput(Backend *back, QObject *parent)
+ : BackendNode(parent), m_currentIndex(0), m_crossfadeProgress(1.),
+ m_device(-1), m_backend(back), m_volume(0.)
+ {
+ }
+
+ AudioOutput::~AudioOutput()
+ {
+ }
+
+ int AudioOutput::outputDevice() const
+ {
+ return m_device;
+ }
+
+ static const qreal log10over20 = qreal(0.1151292546497022842); // ln(10) / 20
+
+ void AudioOutput::setVolume(qreal newVolume)
+ {
+ for(int i = 0; i < FILTER_COUNT; ++i) {
+ ComPointer<IBasicAudio> audio(m_filters[i], IID_IBasicAudio);
+ if (audio) {
+ const qreal currentVolume = newVolume * (m_currentIndex == i ? m_crossfadeProgress : 1-m_crossfadeProgress);
+ const qreal newDbVolume = (qMax(0., 1.-::log(::pow(currentVolume, -log10over20)))-1.) * 10000;
+ audio->put_Volume(qRound(newDbVolume));
+ }
+ }
+
+ if (m_volume != newVolume) {
+ m_volume = newVolume;
+ emit volumeChanged(newVolume);
+ }
+ }
+
+ void AudioOutput::setCrossFadingProgress(short currentIndex, qreal progress)
+ {
+ m_crossfadeProgress = progress;
+ m_currentIndex = currentIndex;
+ setVolume(m_volume);
+ }
+
+ bool AudioOutput::setOutputDevice(const AudioOutputDevice & newDevice)
+ {
+ //stub implementation
+ return setOutputDevice(newDevice.index());
+ }
+
+ qreal AudioOutput::volume() const
+ {
+ return m_volume;
+ }
+
+ bool AudioOutput::setOutputDevice(int newDevice)
+ {
+ if (newDevice == m_device) {
+ return true;
+ }
+
+ //free the previous one if it was already set
+ for(int i = 0; i < FILTER_COUNT; ++i) {
+ const Filter &oldFilter = m_filters[i];
+
+ Filter newFilter = m_backend->getAudioOutputFilter(newDevice);
+
+ if (m_mediaObject && oldFilter && newFilter) {
+ m_mediaObject->switchFilters(i, oldFilter, newFilter);
+ }
+
+ m_filters[i] = newFilter;
+
+
+ }
+
+ m_device = newDevice;
+ setVolume(m_volume);
+ return true;
+ }
+ }
+}
+
+QT_END_NAMESPACE
+
+#include "moc_audiooutput.cpp"
diff --git a/src/3rdparty/phonon/ds9/audiooutput.h b/src/3rdparty/phonon/ds9/audiooutput.h
new file mode 100644
index 0000000000..c3bfc8b753
--- /dev/null
+++ b/src/3rdparty/phonon/ds9/audiooutput.h
@@ -0,0 +1,68 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library 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, either version 2.1 or 3 of the License.
+
+This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef PHONON_AUDIOOUTPUT_H
+#define PHONON_AUDIOOUTPUT_H
+
+#include "backendnode.h"
+#include <phonon/audiooutputinterface.h>
+
+#include "backend.h"
+
+struct IBaseFilter;
+struct IBasicAudio;
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+ namespace DS9
+ {
+ class AudioOutput : public BackendNode, public Phonon::AudioOutputInterface
+ {
+ Q_OBJECT
+ Q_INTERFACES(Phonon::AudioOutputInterface)
+ public:
+ AudioOutput(Backend *back, QObject *parent);
+ ~AudioOutput();
+
+ // Attributes Getters:
+ qreal volume() const;
+ int outputDevice() const;
+ void setVolume(qreal newVolume);
+ bool setOutputDevice(int newDevice);
+ bool setOutputDevice(const AudioOutputDevice & newDevice);
+ void setCrossFadingProgress(short currentIndex, qreal progress);
+
+ Q_SIGNALS:
+ void volumeChanged(qreal newVolume);
+ void audioDeviceFailed();
+
+ private:
+ short m_currentIndex;
+ qreal m_crossfadeProgress;
+
+ int m_device;
+ Backend *m_backend;
+ qreal m_volume;
+ };
+ }
+}
+
+QT_END_NAMESPACE
+
+#endif // PHONON_AUDIOOUTPUT_H
diff --git a/src/3rdparty/phonon/ds9/backend.cpp b/src/3rdparty/phonon/ds9/backend.cpp
new file mode 100644
index 0000000000..245749aab1
--- /dev/null
+++ b/src/3rdparty/phonon/ds9/backend.cpp
@@ -0,0 +1,343 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library 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, either version 2.1 or 3 of the License.
+
+This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "backend.h"
+#include "backendnode.h"
+
+#include "audiooutput.h"
+#include "effect.h"
+#include "mediaobject.h"
+#include "videowidget.h"
+#include "volumeeffect.h"
+
+//windows specific (DirectX Media Object)
+#include <dmo.h>
+
+#include <QtCore/QSettings>
+#include <QtCore/QSet>
+#include <QtCore/QVariant>
+
+#include <QtCore/QtPlugin>
+
+QT_BEGIN_NAMESPACE
+
+Q_EXPORT_PLUGIN2(phonon_ds9, Phonon::DS9::Backend);
+
+namespace Phonon
+{
+ namespace DS9
+ {
+ bool Backend::AudioMoniker::operator==(const AudioMoniker &other)
+ {
+ return other->IsEqual(*this) == S_OK;
+ }
+
+
+ Backend::Backend(QObject *parent, const QVariantList &)
+ : QObject(parent)
+ {
+ ::CoInitialize(0);
+
+ //registering meta types
+ qRegisterMetaType<HRESULT>("HRESULT");
+ qRegisterMetaType<Graph>("Graph");
+ }
+
+ Backend::~Backend()
+ {
+ m_audioOutputs.clear();
+ m_audioEffects.clear();
+ ::CoUninitialize();
+ }
+
+ QObject *Backend::createObject(BackendInterface::Class c, QObject *parent, const QList<QVariant> &args)
+ {
+ switch (c)
+ {
+ case MediaObjectClass:
+ return new MediaObject(parent);
+ case AudioOutputClass:
+ return new AudioOutput(this, parent);
+#ifndef QT_NO_PHONON_EFFECT
+ case EffectClass:
+ return new Effect(m_audioEffects[ args[0].toInt() ], parent);
+#endif //QT_NO_PHONON_EFFECT
+#ifndef QT_NO_PHONON_VIDEO
+ case VideoWidgetClass:
+ return new VideoWidget(qobject_cast<QWidget *>(parent));
+#endif //QT_NO_PHONON_VIDEO
+#ifndef QT_NO_PHONON_VOLUMEFADEREFFECT
+ case VolumeFaderEffectClass:
+ return new VolumeEffect(parent);
+#endif //QT_NO_PHONON_VOLUMEFADEREFFECT
+ default:
+ return 0;
+ }
+ }
+
+ bool Backend::supportsVideo() const
+ {
+#ifndef QT_NO_PHONON_VIDEO
+ return true;
+#else
+ return false;
+#endif //QT_NO_PHONON_VIDEO
+ }
+
+ QStringList Backend::availableMimeTypes() const
+ {
+ QStringList ret;
+ {
+ QSettings settings(QLatin1String("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Multimedia\\mplayer2\\mime types"), QSettings::NativeFormat);
+ ret += settings.childGroups();
+ }
+ {
+ QSettings settings(QLatin1String("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Multimedia\\wmplayer\\mime types"), QSettings::NativeFormat);
+ ret += settings.childGroups();
+ }
+
+ ret.removeDuplicates();
+ ret.replaceInStrings("\\", "/");
+ qSort(ret);
+ return ret;
+ }
+
+ Filter Backend::getAudioOutputFilter(int index) const
+ {
+ Filter ret;
+ if (index >= 0 && index < m_audioOutputs.count()) {
+ m_audioOutputs.at(index)->BindToObject(0, 0, IID_IBaseFilter, reinterpret_cast<void**>(&ret));
+ } else {
+ //just return the default audio renderer (not directsound)
+ ret = Filter(CLSID_AudioRender, IID_IBaseFilter);
+ }
+ return ret;
+ }
+
+
+ QList<int> Backend::objectDescriptionIndexes(Phonon::ObjectDescriptionType type) const
+ {
+ QList<int> ret;
+
+ switch(type)
+ {
+ case Phonon::AudioOutputDeviceType:
+ {
+#ifdef Q_OS_WINCE
+ ret << 0; // only one audio device with index 0
+#else
+ ComPointer<ICreateDevEnum> devEnum(CLSID_SystemDeviceEnum, IID_ICreateDevEnum);
+ if (!devEnum) {
+ return ret; //it is impossible to enumerate the devices
+ }
+ ComPointer<IEnumMoniker> enumMon;
+ HRESULT hr = devEnum->CreateClassEnumerator(CLSID_AudioRendererCategory, enumMon.pparam(), 0);
+ if (FAILED(hr)) {
+ break;
+ }
+ AudioMoniker mon;
+
+ //let's reorder the devices so that directshound appears first
+ int nbds = 0; //number of directsound devices
+
+ while (S_OK == enumMon->Next(1, mon.pparam(), 0)) {
+ LPOLESTR str = 0;
+ mon->GetDisplayName(0,0,&str);
+ const QString name = QString::fromUtf16((unsigned short*)str);
+ ComPointer<IMalloc> alloc;
+ ::CoGetMalloc(1, alloc.pparam());
+ alloc->Free(str);
+
+ int insert_pos = 0;
+ if (!m_audioOutputs.contains(mon)) {
+ insert_pos = m_audioOutputs.count();
+ m_audioOutputs.append(mon);
+ } else {
+ insert_pos = m_audioOutputs.indexOf(mon);
+ }
+
+ if (name.contains(QLatin1String("DirectSound"))) {
+ ret.insert(nbds++, insert_pos);
+ } else {
+ ret.append(insert_pos);
+ }
+ }
+#endif
+ break;
+ }
+#ifndef QT_NO_PHONON_EFFECT
+ case Phonon::EffectType:
+ {
+ m_audioEffects.clear();
+ ComPointer<IEnumDMO> enumDMO;
+ HRESULT hr = ::DMOEnum(DMOCATEGORY_AUDIO_EFFECT, DMO_ENUMF_INCLUDE_KEYED, 0, 0, 0, 0, enumDMO.pparam());
+ if (SUCCEEDED(hr)) {
+ CLSID clsid;
+ while (S_OK == enumDMO->Next(1, &clsid, 0, 0)) {
+ ret += m_audioEffects.count();
+ m_audioEffects.append(clsid);
+ }
+ }
+ break;
+ }
+ break;
+#endif //QT_NO_PHONON_EFFECT
+ default:
+ break;
+ }
+ return ret;
+ }
+
+ QHash<QByteArray, QVariant> Backend::objectDescriptionProperties(Phonon::ObjectDescriptionType type, int index) const
+ {
+ QHash<QByteArray, QVariant> ret;
+ switch (type)
+ {
+ case Phonon::AudioOutputDeviceType:
+ {
+#ifdef Q_OS_WINCE
+ ret["name"] = QLatin1String("default audio device");
+#else
+ const AudioMoniker &mon = m_audioOutputs[index];
+ LPOLESTR str = 0;
+ HRESULT hr = mon->GetDisplayName(0,0, &str);
+ if (SUCCEEDED(hr)) {
+ QString name = QString::fromUtf16((unsigned short*)str);
+ ComPointer<IMalloc> alloc;
+ ::CoGetMalloc(1, alloc.pparam());
+ alloc->Free(str);
+ ret["name"] = name.mid(name.indexOf('\\') + 1);
+ }
+#endif
+ }
+ break;
+#ifndef QT_NO_PHONON_EFFECT
+ case Phonon::EffectType:
+ {
+ WCHAR name[80]; // 80 is clearly stated in the MSDN doc
+ HRESULT hr = ::DMOGetName(m_audioEffects[index], name);
+ if (SUCCEEDED(hr)) {
+ ret["name"] = QString::fromUtf16((unsigned short*)name);
+ }
+ }
+ break;
+#endif //QT_NO_PHONON_EFFECT
+ default:
+ break;
+ }
+ return ret;
+ }
+
+ bool Backend::endConnectionChange(QSet<QObject *> objects)
+ {
+ //end of a transaction
+ for(QSet<QObject *>::const_iterator it = objects.begin(); it != objects.end(); ++it) {
+ if (BackendNode *node = qobject_cast<BackendNode*>(*it)) {
+ MediaObject *mo = node->mediaObject();
+ if (mo) {
+ switch(mo->transactionState)
+ {
+ case Phonon::ErrorState:
+ case Phonon::StoppedState:
+ case Phonon::LoadingState:
+ //nothing to do
+ break;
+ case Phonon::PausedState:
+ mo->transactionState = Phonon::StoppedState;
+ mo->pause();
+ break;
+ default:
+ mo->transactionState = Phonon::StoppedState;
+ mo->play();
+ break;
+ }
+
+ if (mo->state() == Phonon::ErrorState)
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+
+ bool Backend::startConnectionChange(QSet<QObject *> objects)
+ {
+ //let's save the state of the graph (before we stop it)
+ for(QSet<QObject *>::const_iterator it = objects.begin(); it != objects.end(); ++it) {
+ if (BackendNode *node = qobject_cast<BackendNode*>(*it)) {
+ if (MediaObject *mo = node->mediaObject()) {
+ if (mo->state() != Phonon::StoppedState) {
+ mo->transactionState = mo->state();
+ mo->ensureStopped(); //we have to stop the graph..
+ if (mo->state() == Phonon::ErrorState)
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+ }
+
+ bool Backend::connectNodes(QObject *_source, QObject *_sink)
+ {
+ BackendNode *source = qobject_cast<BackendNode*>(_source);
+ if (!source) {
+ return false;
+ }
+ BackendNode *sink = qobject_cast<BackendNode*>(_sink);
+ if (!sink) {
+ return false;
+ }
+
+ //setting the graph if needed
+ if (source->mediaObject() == 0 && sink->mediaObject() == 0) {
+ //error: no graph selected
+ return false;
+ } else if (source->mediaObject() && source->mediaObject() != sink->mediaObject()) {
+ //this' graph becomes the common one
+ source->mediaObject()->grabNode(sink);
+ } else if (source->mediaObject() == 0) {
+ //sink's graph becomes the common one
+ sink->mediaObject()->grabNode(source);
+ }
+
+ return source->mediaObject()->connectNodes(source, sink);
+ }
+
+ bool Backend::disconnectNodes(QObject *_source, QObject *_sink)
+ {
+ BackendNode *source = qobject_cast<BackendNode*>(_source);
+ if (!source) {
+ return false;
+ }
+ BackendNode *sink = qobject_cast<BackendNode*>(_sink);
+ if (!sink) {
+ return false;
+ }
+
+ return source->mediaObject() == 0 ||
+ source->mediaObject()->disconnectNodes(source, sink);
+ }
+ }
+}
+
+QT_END_NAMESPACE
+
+#include "moc_backend.cpp"
diff --git a/src/3rdparty/phonon/ds9/backend.h b/src/3rdparty/phonon/ds9/backend.h
new file mode 100644
index 0000000000..ad638f23f7
--- /dev/null
+++ b/src/3rdparty/phonon/ds9/backend.h
@@ -0,0 +1,83 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library 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, either version 2.1 or 3 of the License.
+
+This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef PHONON_BACKEND_H
+#define PHONON_BACKEND_H
+
+#include "phononds9_namespace.h"
+#include <phonon/backendinterface.h>
+#include <phonon/phononnamespace.h>
+
+#include <QtCore/QList>
+
+#include "compointer.h"
+#include "backendnode.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+ namespace DS9
+ {
+ class AudioOutput;
+ class MediaObject;
+
+ typedef Phonon::ObjectDescriptionType ObjectDescriptionType;
+
+ class Backend : public QObject, public Phonon::BackendInterface
+ {
+ Q_OBJECT
+ Q_INTERFACES(Phonon::BackendInterface)
+ public:
+ Backend(QObject *parent = 0, const QVariantList & = QVariantList());
+ virtual ~Backend();
+
+ QObject *createObject(Phonon::BackendInterface::Class, QObject *parent, const QList<QVariant> &args);
+
+ bool supportsVideo() const;
+ QStringList availableMimeTypes() const;
+
+ QList<int> objectDescriptionIndexes(Phonon::ObjectDescriptionType type) const;
+ QHash<QByteArray, QVariant> objectDescriptionProperties(Phonon::ObjectDescriptionType type, int index) const;
+
+ bool connectNodes(QObject *, QObject *);
+ bool disconnectNodes(QObject *, QObject *);
+
+ //transaction management
+ bool startConnectionChange(QSet<QObject *>);
+ bool endConnectionChange(QSet<QObject *>);
+
+ Filter getAudioOutputFilter(int index) const;
+
+ Q_SIGNALS:
+ void objectDescriptionChanged(ObjectDescriptionType);
+
+ private:
+ class AudioMoniker : public ComPointer<IMoniker>
+ {
+ public:
+ bool operator==(const AudioMoniker &other);
+ };
+ mutable QVector<AudioMoniker> m_audioOutputs;
+ mutable QVector<CLSID> m_audioEffects;
+ };
+ }
+}
+
+QT_END_NAMESPACE
+
+#endif // PHONON_BACKEND_H
diff --git a/src/3rdparty/phonon/ds9/backendnode.cpp b/src/3rdparty/phonon/ds9/backendnode.cpp
new file mode 100644
index 0000000000..7e0b3cdd60
--- /dev/null
+++ b/src/3rdparty/phonon/ds9/backendnode.cpp
@@ -0,0 +1,115 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library 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, either version 2.1 or 3 of the License.
+
+This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "backendnode.h"
+#include "mediaobject.h"
+
+#include <ocidl.h> // ISpecifyPropertyPages
+#include <olectl.h> // OleCreatePropertyFrame
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+ namespace DS9
+ {
+ // Displays a property dialog for a filter (experimental but should be put into main
+ /*static void showPropertyDialog(const Filter &filter)
+ {
+ ComPointer<ISpecifyPropertyPages> prop(filter, IID_ISpecifyPropertyPages);
+ if (prop != 0) {
+ IUnknown *iunk[] = {filter};
+ // Show the page.
+ CAUUID caGUID;
+ prop->GetPages(&caGUID);
+ OleCreatePropertyFrame(
+ 0, // Parent window
+ 0, 0, // (Reserved)
+ 0, // Caption for the dialog box
+ 1, // Number of objects (just the filter)
+ iunk, // Array of object pointers.
+ caGUID.cElems, // Number of property pages
+ caGUID.pElems, // Array of property page CLSIDs
+ 0, // Locale identifier
+ 0, 0 // Reserved
+ );
+ }
+ }*/
+
+ //for now we have 2 graphs that do the same
+ BackendNode::BackendNode(QObject *parent) : QObject(parent), m_mediaObject(0)
+ {
+ }
+
+ BackendNode::~BackendNode()
+ {
+ }
+
+ void BackendNode::setMediaObject(MediaObject *mo)
+ {
+ if (m_mediaObject) {
+ disconnect(m_mediaObject, SIGNAL(destroyed()), this, SLOT(mediaObjectDestroyed()));
+ }
+ m_mediaObject = mo;
+ connect(mo, SIGNAL(destroyed()), SLOT(mediaObjectDestroyed()));
+ }
+
+ void BackendNode::mediaObjectDestroyed()
+ {
+ //remove the filter from its graph
+ FILTER_INFO info;
+ for(int i = 0; i < FILTER_COUNT; ++i) {
+ const Filter &filter = m_filters[i];
+ if (!filter)
+ continue;
+ filter->QueryFilterInfo(&info);
+ if (info.pGraph) {
+ HRESULT hr = info.pGraph->RemoveFilter(filter);
+ Q_ASSERT(SUCCEEDED(hr));
+ Q_UNUSED(hr);
+ info.pGraph->Release();
+ }
+ }
+ m_mediaObject = 0;
+ }
+
+ QList<InputPin> BackendNode::pins(const Filter &filter, PIN_DIRECTION wantedDirection)
+ {
+ QList<InputPin> ret;
+ if (filter) {
+ ComPointer<IEnumPins> enumPin;
+ HRESULT hr = filter->EnumPins(enumPin.pparam());
+ Q_UNUSED(hr);
+ Q_ASSERT( SUCCEEDED(hr));
+ InputPin pin;
+ while (enumPin->Next(1, pin.pparam(), 0) == S_OK) {
+ PIN_DIRECTION dir;
+ hr = pin->QueryDirection(&dir);
+ Q_ASSERT( SUCCEEDED(hr));
+ if (dir == wantedDirection) {
+ ret.append(pin);
+ }
+ }
+ }
+ return ret;
+ }
+ }
+}
+
+QT_END_NAMESPACE
+
+#include "moc_backendnode.cpp"
diff --git a/src/3rdparty/phonon/ds9/backendnode.h b/src/3rdparty/phonon/ds9/backendnode.h
new file mode 100644
index 0000000000..17bd3fbe37
--- /dev/null
+++ b/src/3rdparty/phonon/ds9/backendnode.h
@@ -0,0 +1,73 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library 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, either version 2.1 or 3 of the License.
+
+This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef PHONON_BACKENDNODE_H
+#define PHONON_BACKENDNODE_H
+
+#include "phononds9_namespace.h"
+
+#include <QtCore/QObject>
+#include <QtCore/QVector>
+
+#include "compointer.h"
+
+QT_BEGIN_NAMESPACE
+
+
+
+namespace Phonon
+{
+ namespace DS9
+ {
+ class MediaObject;
+ typedef ComPointer<IPin> InputPin;
+ typedef ComPointer<IPin> OutputPin;
+ typedef ComPointer<IBaseFilter> Filter;
+ typedef ComPointer<IGraphBuilder> Graph;
+
+ class BackendNode : public QObject
+ {
+ Q_OBJECT
+
+ public:
+ BackendNode(QObject *parent);
+ virtual ~BackendNode();
+
+ MediaObject *mediaObject() const {return m_mediaObject;}
+
+ static QList<InputPin> pins(const Filter &, PIN_DIRECTION);
+
+ Filter filter(int index) const { return m_filters[index]; }
+ //add a pointer to the base Media Object (giving access to the graph and error management)
+ void setMediaObject(MediaObject *mo);
+
+ //called by the connections to tell the node that it's been connection to anothe one through its 'inpin' input port
+ virtual void connected(BackendNode *, const InputPin& inpin) {}
+
+ private Q_SLOTS:
+ void mediaObjectDestroyed();
+
+ protected:
+ Filter m_filters[FILTER_COUNT];
+ MediaObject *m_mediaObject;
+ };
+ }
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/3rdparty/phonon/ds9/compointer.h b/src/3rdparty/phonon/ds9/compointer.h
new file mode 100644
index 0000000000..180febf820
--- /dev/null
+++ b/src/3rdparty/phonon/ds9/compointer.h
@@ -0,0 +1,114 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library 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, either version 2.1 or 3 of the License.
+
+This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef PHONON_COMPOINTER_H
+#define PHONON_COMPOINTER_H
+
+#include <windows.h>
+#include <dshow.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+ namespace DS9
+ {
+ template<class T> class ComPointer
+ {
+ public:
+ explicit ComPointer(T *t = 0) : m_t(t)
+ {
+ }
+
+ explicit ComPointer( const IID &clsid, const IID &iid) : m_t(0)
+ {
+ ::CoCreateInstance(clsid, 0, CLSCTX_INPROC_SERVER, iid,
+ reinterpret_cast<void**>(&m_t));
+ }
+
+ explicit ComPointer(IUnknown *_unk, const GUID &guid) : m_t(0)
+ {
+ if (_unk) {
+ _unk->QueryInterface(guid, reinterpret_cast<void**>(&m_t));
+ }
+ }
+
+ ComPointer(const ComPointer<T> &other) : m_t(other.m_t)
+ {
+ if (m_t) {
+ m_t->AddRef();
+ }
+ }
+
+ ComPointer<T> &operator=(const ComPointer<T> &other)
+ {
+ if (other.m_t) {
+ other.m_t->AddRef();
+ }
+ if (m_t) {
+ m_t->Release();
+ }
+ m_t = other.m_t;
+ return *this;
+ }
+
+ T *operator->() const
+ {
+ return m_t;
+ }
+
+ operator T*() const
+ {
+ return m_t;
+ }
+
+ //the following method first reinitialize their value to avoid mem leaks
+ T ** pparam()
+ {
+ if (m_t) {
+ m_t->Release();
+ m_t = 0;
+ }
+ return &m_t;
+ }
+
+ bool operator==(const ComPointer<T> &other) const
+ {
+ return m_t == other.m_t;
+ }
+
+ bool operator!=(const ComPointer<T> &other) const
+ {
+ return m_t != other.m_t;
+ }
+
+ ~ComPointer()
+ {
+ if (m_t) {
+ m_t->Release();
+ }
+ }
+
+ private:
+ T *m_t;
+ };
+ }
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/3rdparty/phonon/ds9/ds9.desktop b/src/3rdparty/phonon/ds9/ds9.desktop
new file mode 100644
index 0000000000..370011e912
--- /dev/null
+++ b/src/3rdparty/phonon/ds9/ds9.desktop
@@ -0,0 +1,51 @@
+[Desktop Entry]
+Type=Service
+X-KDE-ServiceTypes=PhononBackend
+MimeType=application/x-annodex;video/quicktime;video/x-quicktime;audio/x-m4a;application/x-quicktimeplayer;video/mkv;video/msvideo;video/x-msvideo;video/x-flic;audio/x-aiff;audio/aiff;audio/x-pn-aiff;audio/x-realaudio;audio/basic;audio/x-basic;audio/x-pn-au;audio/x-8svx;audio/8svx;audio/x-16sv;audio/168sv;image/x-ilbm;image/ilbm;video/x-anim;video/anim;image/png;image/x-png;video/mng;video/x-mng;audio/x-ogg;audio/x-speex+ogg;application/ogg;application/ogg;audio/vnd.rn-realaudio;audio/x-pn-realaudio-plugin;audio/x-real-audio;application/vnd.rn-realmedia;video/mpeg;video/x-mpeg;audio/x-wav;audio/wav;audio/x-pn-wav;audio/x-pn-windows-acm;audio/mpeg2;audio/x-mpeg2;audio/mpeg3;audio/x-mpeg3;audio/mpeg;audio/x-mpeg;x-mpegurl;audio/x-mpegurl;audio/mp3;audio/mpeg;
+X-KDE-Library=phonon_ds9
+X-KDE-PhononBackendInfo-InterfaceVersion=1
+X-KDE-PhononBackendInfo-Version=0.1
+X-KDE-PhononBackendInfo-Website=http://www.trolltech.com/
+InitialPreference=15
+
+Name=DirectShow9
+Name[pa]=ਡਾਇਰੈਕਸ਼ੋ9
+Name[sk]=DirectShow 9
+Name[sl]=DirectShow 9
+Name[sr]=Директшоу‑9
+Name[sr@latin]=DirectShow‑9
+Name[sv]=Directshow 9
+Name[x-test]=xxDirectShow9xx
+
+Comment=Phonon DirectShow9 backend
+Comment[bg]=Phonon DirectShow9
+Comment[ca]=Dorsal DirectShow9 del Phonon
+Comment[da]=DirectShow9-backend til Phonon
+Comment[de]=Phonon-Treiber für DirectShow9
+Comment[el]=Σύστημα υποστήριξης DirectShow9 του Phonon
+Comment[es]=Motor DirectShow9 para Phonon
+Comment[et]=Phononi DirectShow9 taustaprogramm
+Comment[fr]=Système de gestion DirectShow9 pour Phonon
+Comment[ga]=Inneall DirectShow9 le haghaidh Phonon
+Comment[gl]=Infraestrutura de DirectShow9 para Phonon
+Comment[it]=Motore DirectShow9 di Phonon
+Comment[ja]=Phonon DirectShow9 バックエンド
+Comment[ko]=Phonon DirectShow9 백엔드
+Comment[lv]=Phonon DirectShow9 aizmugure
+Comment[nds]=Phonon-Hülpprogrmm DirectShow9
+Comment[nl]=DirectShow9-backend (Phonon)
+Comment[nn]=Phonon-motor for DirectShow9
+Comment[pa]=ਫੋਨੋਨ ਡਾਇਰੈਕਟਸ਼ੋ9 ਬੈਕਐਂਡ
+Comment[pl]=Obsługa DirectShow9 przez Phonon
+Comment[pt]=Infra-estrutura do DirectShow9 para o Phonon
+Comment[pt_BR]=Infraestrutura Phonon DirectShow9
+Comment[sk]=Phonon DirectShow 9 podsystém
+Comment[sl]=Phononova Hrbtenica DirectShow 9
+Comment[sr]=Директшоу‑9 као позадина Фонона
+Comment[sr@latin]=DirectShow‑9 kao pozadina Phonona
+Comment[sv]=Phonon Directshow 9-gränssnitt
+Comment[tr]=Phonon DirectShow9 arka ucu
+Comment[uk]=Сервер DirectShow9 для Phonon
+Comment[x-test]=xxPhonon DirectShow9 backendxx
+Comment[zh_CN]=Phonon DirectShow9 后端
+Comment[zh_TW]=Phonon DirectShow9 後端介面
diff --git a/src/3rdparty/phonon/ds9/effect.cpp b/src/3rdparty/phonon/ds9/effect.cpp
new file mode 100644
index 0000000000..dc4ac3d603
--- /dev/null
+++ b/src/3rdparty/phonon/ds9/effect.cpp
@@ -0,0 +1,153 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library 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, either version 2.1 or 3 of the License.
+
+This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "effect.h"
+#include <phonon/effectparameter.h>
+
+#include <medparam.h>
+#include <dmo.h>
+#include <dmodshow.h>
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_PHONON_EFFECT
+
+namespace Phonon
+{
+ namespace DS9
+ {
+ Effect::Effect(CLSID effectClass, QObject *parent)
+ : BackendNode(parent)
+ {
+ //creation of the filter
+ for(int i = 0; i < FILTER_COUNT; ++i) {
+ Filter &filter = m_filters[i];
+ filter = Filter(CLSID_DMOWrapperFilter, IID_IBaseFilter);
+ Q_ASSERT(filter);
+ ComPointer<IDMOWrapperFilter> wrapper(filter, IID_IDMOWrapperFilter);
+ Q_ASSERT(wrapper);
+ wrapper->Init(effectClass, DMOCATEGORY_AUDIO_EFFECT);
+ }
+ }
+
+ Effect::Effect(QObject *parent) : BackendNode(parent)
+ {
+ //at this point the QVector of Filter should be filled
+ }
+
+ Effect::~Effect()
+ {
+ }
+
+ QList<Phonon::EffectParameter> Effect::parameters() const
+ {
+ QList<Phonon::EffectParameter> ret;
+ ComPointer<IMediaParamInfo> paramInfo(m_filters[0], IID_IMediaParamInfo);
+ if (!paramInfo) {
+ return ret;
+ }
+ DWORD paramCount = 0;
+ paramInfo->GetParamCount( &paramCount);
+
+ for(quint32 i = 0; i < paramCount; i++) {
+ MP_PARAMINFO info;
+ HRESULT hr = paramInfo->GetParamInfo(i, &info);
+ Q_ASSERT(SUCCEEDED(hr));
+ WCHAR *name = 0;
+ hr = paramInfo->GetParamText(i, &name);
+ Q_ASSERT(SUCCEEDED(hr));
+ QVariant def, min, max;
+
+ QVariantList values;
+
+ switch(info.mpType)
+ {
+ case MPT_ENUM:
+ {
+ WCHAR *current = name;
+ current += wcslen(current) + 1; //skip the name
+ current += wcslen(current) + 1; //skip the unit
+ for(; *current; current += wcslen(current) + 1) {
+ values.append( QString::fromUtf16((unsigned short*)current) );
+ }
+ }
+ //FALLTHROUGH
+ case MPT_INT:
+ def = int(info.mpdNeutralValue);
+ min = int(info.mpdMinValue);
+ max = int(info.mpdMaxValue);
+ break;
+ case MPT_FLOAT:
+ def = info.mpdNeutralValue;
+ min = info.mpdMinValue;
+ max = info.mpdMaxValue;
+ break;
+ case MPT_BOOL:
+ def = bool(info.mpdNeutralValue);
+ break;
+ case MPT_MAX:
+ //Reserved ms-help://MS.PSDKSVR2003R2.1033/directshow/htm/mp_typeenumeration.htm
+ break;
+ }
+
+ Phonon::EffectParameter::Hints hint = info.mopCaps == MP_CAPS_CURVE_INVSQUARE ?
+ Phonon::EffectParameter::LogarithmicHint : Phonon::EffectParameter::Hints(0);
+
+ const QString n = QString::fromUtf16((unsigned short*)name);
+ ret.append(Phonon::EffectParameter(i, n, hint, def, min, max, values));
+ ::CoTaskMemFree(name); //let's free the memory
+ }
+ return ret;
+ }
+
+ QVariant Effect::parameterValue(const Phonon::EffectParameter &p) const
+ {
+ QVariant ret;
+ ComPointer<IMediaParams> params(m_filters[0], IID_IMediaParams);
+ Q_ASSERT(params);
+ MP_DATA data;
+ HRESULT hr = params->GetParam(p.id(), &data);
+ if(SUCCEEDED(hr))
+ return data;
+ else
+ return QVariant();
+ }
+
+ void Effect::setParameterValue(const Phonon::EffectParameter &p, const QVariant &v)
+ {
+ if (v.isNull()) {
+ return;
+ }
+
+ for(int i=0; i < FILTER_COUNT ; ++i) {
+ const Filter &filter = m_filters[i];
+ ComPointer<IMediaParams> params(filter, IID_IMediaParams);
+ Q_ASSERT(params);
+
+ MP_DATA data = float(v.toDouble());
+ params->SetParam(p.id(), data);
+ }
+ }
+
+ }
+}
+
+#endif //QT_NO_PHONON_EFFECT
+
+QT_END_NAMESPACE
+
+#include "moc_effect.cpp"
diff --git a/src/3rdparty/phonon/ds9/effect.h b/src/3rdparty/phonon/ds9/effect.h
new file mode 100644
index 0000000000..50f3ea2d01
--- /dev/null
+++ b/src/3rdparty/phonon/ds9/effect.h
@@ -0,0 +1,59 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library 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, either version 2.1 or 3 of the License.
+
+This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef PHONON_AUDIOEFFECT_H
+#define PHONON_AUDIOEFFECT_H
+
+#include <QtCore/QObject>
+#include <phonon/effectinterface.h>
+#include "backendnode.h"
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_PHONON_EFFECT
+
+namespace Phonon
+{
+ namespace DS9
+ {
+ class EffectInterface;
+
+ class Effect : public BackendNode, public Phonon::EffectInterface
+ {
+ Q_OBJECT
+ Q_INTERFACES(Phonon::EffectInterface)
+ public:
+ Effect(CLSID effectClass, QObject *parent);
+ ~Effect();
+
+ QList<Phonon::EffectParameter> parameters() const;
+ QVariant parameterValue(const Phonon::EffectParameter &) const;
+ void setParameterValue(const Phonon::EffectParameter &, const QVariant &);
+
+
+ protected:
+ //this is the constructor called by the explicit subclasses of effect
+ Effect(QObject *parent);
+ };
+ }
+}
+
+#endif //QT_NO_PHONON_EFFECT
+
+QT_END_NAMESPACE
+
+#endif // PHONON_AUDIOEFFECT_H
diff --git a/src/3rdparty/phonon/ds9/fakesource.cpp b/src/3rdparty/phonon/ds9/fakesource.cpp
new file mode 100644
index 0000000000..9a61a2ed65
--- /dev/null
+++ b/src/3rdparty/phonon/ds9/fakesource.cpp
@@ -0,0 +1,166 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library 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, either version 2.1 or 3 of the License.
+
+This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "fakesource.h"
+#include "qpin.h"
+
+#include <dshow.h>
+#include <initguid.h>
+#include <dvdmedia.h> // VIDEOINFOHEADER2
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+ namespace DS9
+ {
+ static WAVEFORMATEX g_defaultWaveFormat = {WAVE_FORMAT_PCM, 2, 44100, 176400, 4, 16, 0};
+ static BITMAPINFOHEADER g_defautBitmapHeader = { sizeof(BITMAPINFOHEADER), 1, 1, 1, 0, 0, 0, 0, 0, 0, 0};
+ static VIDEOINFOHEADER2 g_defaultVideoInfo = { { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+ class FakePin : public QPin
+ {
+ public:
+ FakePin(FakeSource *source, const AM_MEDIA_TYPE &mt) :
+ QPin(source, PINDIR_OUTPUT, QVector<AM_MEDIA_TYPE>() << mt), m_source(source)
+ {
+ setAvailable(true);
+ }
+
+ ~FakePin()
+ {
+ }
+
+
+ STDMETHODIMP Disconnect()
+ {
+ HRESULT hr = QPin::Disconnect();
+ if (SUCCEEDED(hr)) {
+ setAvailable(true);
+ }
+ return hr;
+ }
+
+
+ STDMETHODIMP Connect(IPin *pin, const AM_MEDIA_TYPE *type)
+ {
+ HRESULT hr = QPin::Connect(pin, type);
+ if (SUCCEEDED(hr)) {
+ setAvailable(false);
+ }
+ return hr;
+ }
+
+ private:
+ void setAvailable(bool avail)
+ {
+ if (mediaTypes().first().majortype == MEDIATYPE_Audio) {
+ if (avail) {
+ m_source->addAvailableAudioPin(this);
+ } else {
+ m_source->removeAvailableAudioPin(this);
+ }
+ } else {
+ if (avail) {
+ m_source->addAvailableVideoPin(this);
+ } else {
+ m_source->removeAvailableVideoPin(this);
+ }
+ }
+ }
+
+ FakeSource *m_source;
+
+
+ };
+
+ FakeSource::FakeSource() : QBaseFilter(CLSID_NULL)
+ {
+ createFakeAudioPin();
+ createFakeVideoPin();
+ }
+
+ FakeSource::~FakeSource()
+ {
+ }
+
+ void FakeSource::addAvailableAudioPin(FakePin *pin)
+ {
+ availableAudioPins += pin;
+ }
+
+ void FakeSource::addAvailableVideoPin(FakePin *pin)
+ {
+ availableVideoPins += pin;
+ }
+
+ void FakeSource::removeAvailableAudioPin(FakePin *pin)
+ {
+ availableAudioPins -= pin;
+
+ if (availableAudioPins.isEmpty()) {
+ createFakeAudioPin();
+ }
+ }
+
+ void FakeSource::removeAvailableVideoPin(FakePin *pin)
+ {
+ availableVideoPins -= pin;
+
+ if (availableVideoPins.isEmpty()) {
+ createFakeVideoPin();
+ }
+ }
+
+ void FakeSource::createFakeAudioPin()
+ {
+ AM_MEDIA_TYPE mt;
+ qMemSet(&mt, 0, sizeof(AM_MEDIA_TYPE));
+ mt.majortype = MEDIATYPE_Audio;
+ mt.subtype = MEDIASUBTYPE_PCM;
+ mt.formattype = FORMAT_WaveFormatEx;
+ mt.lSampleSize = 2;
+
+ //fake the format (stereo 44.1 khz stereo 16 bits)
+ mt.cbFormat = sizeof(WAVEFORMATEX);
+ mt.pbFormat = reinterpret_cast<BYTE*>(&g_defaultWaveFormat);
+
+ new FakePin(this, mt);
+ }
+
+ void FakeSource::createFakeVideoPin()
+ {
+ AM_MEDIA_TYPE mt;
+ qMemSet(&mt, 0, sizeof(AM_MEDIA_TYPE));
+ mt.majortype = MEDIATYPE_Video;
+ mt.subtype = MEDIASUBTYPE_RGB32;
+ mt.formattype = FORMAT_VideoInfo2;
+ mt.bFixedSizeSamples = 1;
+
+ g_defaultVideoInfo.bmiHeader = g_defautBitmapHeader;
+
+ //fake the format
+ mt.cbFormat = sizeof(VIDEOINFOHEADER2);
+ mt.pbFormat = reinterpret_cast<BYTE*>(&g_defaultVideoInfo);
+
+ new FakePin(this, mt);
+ }
+
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/3rdparty/phonon/ds9/fakesource.h b/src/3rdparty/phonon/ds9/fakesource.h
new file mode 100644
index 0000000000..a32e0c2436
--- /dev/null
+++ b/src/3rdparty/phonon/ds9/fakesource.h
@@ -0,0 +1,54 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library 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, either version 2.1 or 3 of the License.
+
+This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef PHONON_FAKESOURCE_H
+#define PHONON_FAKESOURCE_H
+
+#include <QtCore/QSet>
+
+#include "qbasefilter.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+ namespace DS9
+ {
+ class FakePin;
+ class FakeSource : public QBaseFilter
+ {
+ public:
+ FakeSource();
+ ~FakeSource();
+
+ void addAvailableAudioPin(FakePin*);
+ void addAvailableVideoPin(FakePin*);
+ void removeAvailableAudioPin(FakePin*);
+ void removeAvailableVideoPin(FakePin*);
+ private:
+ void createFakeVideoPin();
+ void createFakeAudioPin();
+
+ QSet<FakePin*> availableAudioPins;
+ QSet<FakePin*> availableVideoPins;
+ };
+ }
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/3rdparty/phonon/ds9/iodevicereader.cpp b/src/3rdparty/phonon/ds9/iodevicereader.cpp
new file mode 100644
index 0000000000..ec10278494
--- /dev/null
+++ b/src/3rdparty/phonon/ds9/iodevicereader.cpp
@@ -0,0 +1,228 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library 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, either version 2.1 or 3 of the License.
+
+This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "iodevicereader.h"
+#include "qasyncreader.h"
+
+#include "mediagraph.h"
+
+#include <phonon/streaminterface.h>
+
+#include <dshow.h>
+#include <initguid.h>
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
+
+namespace Phonon
+{
+ namespace DS9
+ {
+ //these mediatypes define a stream, its type will be autodetected by DirectShow
+ static QVector<AM_MEDIA_TYPE> getMediaTypes()
+ {
+ AM_MEDIA_TYPE mt;
+ mt.majortype = MEDIATYPE_Stream;
+ mt.bFixedSizeSamples = TRUE;
+ mt.bTemporalCompression = FALSE;
+ mt.lSampleSize = 1;
+ mt.formattype = GUID_NULL;
+ mt.pUnk = 0;
+ mt.cbFormat = 0;
+ mt.pbFormat = 0;
+
+ QVector<AM_MEDIA_TYPE> ret;
+ //normal auto-detect stream
+ mt.subtype = MEDIASUBTYPE_NULL;
+ ret << mt;
+ //AVI stream
+ mt.subtype = MEDIASUBTYPE_Avi;
+ ret << mt;
+ //WAVE stream
+ mt.subtype = MEDIASUBTYPE_WAVE;
+ ret << mt;
+ return ret;
+ }
+
+ class StreamReader : public QAsyncReader, public Phonon::StreamInterface
+ {
+ public:
+ StreamReader(QBaseFilter *parent, const Phonon::MediaSource &source, const MediaGraph *mg) :
+ QAsyncReader(parent, getMediaTypes()),
+ m_seekable(false), m_pos(0), m_size(-1), m_mediaGraph(mg)
+ {
+ connectToSource(source);
+ }
+
+ //for Phonon::StreamInterface
+ void writeData(const QByteArray &data)
+ {
+ QWriteLocker locker(&m_lock);
+ m_pos += data.size();
+ m_buffer += data;
+ }
+
+ void endOfData()
+ {
+ }
+
+ void setStreamSize(qint64 newSize)
+ {
+ QWriteLocker locker(&m_lock);
+ m_size = newSize;
+ }
+
+ qint64 streamSize() const
+ {
+ QReadLocker locker(&m_lock);
+ return m_size;
+ }
+
+ void setStreamSeekable(bool s)
+ {
+ QWriteLocker locker(&m_lock);
+ m_seekable = s;
+ }
+
+ bool streamSeekable() const
+ {
+ QReadLocker locker(&m_lock);
+ return m_seekable;
+ }
+
+ void setCurrentPos(qint64 pos)
+ {
+ QWriteLocker locker(&m_lock);
+ m_pos = pos;
+ seekStream(pos);
+ m_buffer.clear();
+ }
+
+ qint64 currentPos() const
+ {
+ QReadLocker locker(&m_lock);
+ return m_pos;
+ }
+
+ int currentBufferSize() const
+ {
+ QReadLocker locker(&m_lock);
+ return m_buffer.size();
+ }
+
+ //virtual pure members
+
+ //implementation from IAsyncReader
+ STDMETHODIMP Length(LONGLONG *total, LONGLONG *available)
+ {
+ QReadLocker locker(&m_lock);
+ if (total) {
+ *total = m_size;
+ }
+
+ if (available) {
+ *available = m_size;
+ }
+
+ return S_OK;
+ }
+
+
+ HRESULT read(LONGLONG pos, LONG length, BYTE *buffer, LONG *actual)
+ {
+ QMutexLocker locker(&m_mutexRead);
+
+ if (m_mediaGraph->isStopping()) {
+ return VFW_E_WRONG_STATE;
+ }
+
+ if(streamSize() != 1 && pos + length > streamSize()) {
+ //it tries to read outside of the boundaries
+ return E_FAIL;
+ }
+
+ if (currentPos() - currentBufferSize() != pos) {
+ if (!streamSeekable()) {
+ return S_FALSE;
+ }
+ setCurrentPos(pos);
+ }
+
+ int oldSize = currentBufferSize();
+ while (currentBufferSize() < int(length)) {
+ needData();
+ if (m_mediaGraph->isStopping()) {
+ return VFW_E_WRONG_STATE;
+ }
+
+ if (oldSize == currentBufferSize()) {
+ break; //we didn't get any data
+ }
+ oldSize = currentBufferSize();
+ }
+
+ DWORD bytesRead = qMin(currentBufferSize(), int(length));
+ {
+ QWriteLocker locker(&m_lock);
+ qMemCopy(buffer, m_buffer.data(), bytesRead);
+ //truncate the buffer
+ m_buffer = m_buffer.mid(bytesRead);
+ }
+
+ if (actual) {
+ *actual = bytesRead; //initialization
+ }
+
+ return bytesRead == length ? S_OK : S_FALSE;
+ }
+
+ public:
+ //for Phonon::StreamInterface
+ QByteArray m_buffer;
+ bool m_seekable;
+ qint64 m_pos;
+ qint64 m_size;
+
+ QMutex m_mutexRead;
+ const MediaGraph *m_mediaGraph;
+ };
+
+ IODeviceReader::IODeviceReader(const Phonon::MediaSource &source, const MediaGraph *mg) :
+ QBaseFilter(CLSID_NULL)
+ {
+ //create the output pin
+ m_streamReader = new StreamReader(this, source, mg);
+ }
+
+ IODeviceReader::~IODeviceReader()
+ {
+ }
+
+ STDMETHODIMP IODeviceReader::Stop()
+ {
+ HRESULT hr = QBaseFilter::Stop();
+ m_streamReader->enoughData(); //this asks to cancel any blocked call to needData
+ return hr;
+ }
+
+ }
+}
+
+#endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
+
+QT_END_NAMESPACE
diff --git a/src/3rdparty/phonon/ds9/iodevicereader.h b/src/3rdparty/phonon/ds9/iodevicereader.h
new file mode 100644
index 0000000000..af4b2719c5
--- /dev/null
+++ b/src/3rdparty/phonon/ds9/iodevicereader.h
@@ -0,0 +1,57 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library 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, either version 2.1 or 3 of the License.
+
+This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef PHONON_IODEVICEREADER_H
+#define PHONON_IODEVICEREADER_H
+
+#include "qbasefilter.h"
+
+#include <phonon/mediasource.h>
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
+
+namespace Phonon
+{
+ class MediaSource;
+ namespace DS9
+ {
+ class MediaGraph;
+ class StreamReader;
+
+ //for the streams...
+ //the filter
+ class IODeviceReader : public QBaseFilter
+ {
+ public:
+ IODeviceReader(const MediaSource &source, const MediaGraph *);
+ ~IODeviceReader();
+ STDMETHODIMP Stop();
+
+ private:
+ StreamReader *m_streamReader;
+ };
+
+ }
+}
+
+#endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/3rdparty/phonon/ds9/lgpl-2.1.txt b/src/3rdparty/phonon/ds9/lgpl-2.1.txt
new file mode 100644
index 0000000000..5ab7695ab8
--- /dev/null
+++ b/src/3rdparty/phonon/ds9/lgpl-2.1.txt
@@ -0,0 +1,504 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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 library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/src/3rdparty/phonon/ds9/lgpl-3.txt b/src/3rdparty/phonon/ds9/lgpl-3.txt
new file mode 100644
index 0000000000..fc8a5de7ed
--- /dev/null
+++ b/src/3rdparty/phonon/ds9/lgpl-3.txt
@@ -0,0 +1,165 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+ This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+ 0. Additional Definitions.
+
+ As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+ "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+ An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+ A "Combined Work" is a work produced by combining or linking an
+Application with the Library. The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+ The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+ The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+ 1. Exception to Section 3 of the GNU GPL.
+
+ You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+ 2. Conveying Modified Versions.
+
+ If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+ a) under this License, provided that you make a good faith effort to
+ ensure that, in the event an Application does not supply the
+ function or data, the facility still operates, and performs
+ whatever part of its purpose remains meaningful, or
+
+ b) under the GNU GPL, with none of the additional permissions of
+ this License applicable to that copy.
+
+ 3. Object Code Incorporating Material from Library Header Files.
+
+ The object code form of an Application may incorporate material from
+a header file that is part of the Library. You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+ a) Give prominent notice with each copy of the object code that the
+ Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the object code with a copy of the GNU GPL and this license
+ document.
+
+ 4. Combined Works.
+
+ You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+ a) Give prominent notice with each copy of the Combined Work that
+ the Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
+ document.
+
+ c) For a Combined Work that displays copyright notices during
+ execution, include the copyright notice for the Library among
+ these notices, as well as a reference directing the user to the
+ copies of the GNU GPL and this license document.
+
+ d) Do one of the following:
+
+ 0) Convey the Minimal Corresponding Source under the terms of this
+ License, and the Corresponding Application Code in a form
+ suitable for, and under terms that permit, the user to
+ recombine or relink the Application with a modified version of
+ the Linked Version to produce a modified Combined Work, in the
+ manner specified by section 6 of the GNU GPL for conveying
+ Corresponding Source.
+
+ 1) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (a) uses at run time
+ a copy of the Library already present on the user's computer
+ system, and (b) will operate properly with a modified version
+ of the Library that is interface-compatible with the Linked
+ Version.
+
+ e) Provide Installation Information, but only if you would otherwise
+ be required to provide such information under section 6 of the
+ GNU GPL, and only to the extent that such information is
+ necessary to install and execute a modified version of the
+ Combined Work produced by recombining or relinking the
+ Application with a modified version of the Linked Version. (If
+ you use option 4d0, the Installation Information must accompany
+ the Minimal Corresponding Source and Corresponding Application
+ Code. If you use option 4d1, you must provide the Installation
+ Information in the manner specified by section 6 of the GNU GPL
+ for conveying Corresponding Source.)
+
+ 5. Combined Libraries.
+
+ You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+ a) Accompany the combined library with a copy of the same work based
+ on the Library, uncombined with any other library facilities,
+ conveyed under the terms of this License.
+
+ b) Give prominent notice with the combined library that part of it
+ is a work based on the Library, and explaining where to find the
+ accompanying uncombined form of the same work.
+
+ 6. Revised Versions of the GNU Lesser General Public License.
+
+ The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+ If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
diff --git a/src/3rdparty/phonon/ds9/mediagraph.cpp b/src/3rdparty/phonon/ds9/mediagraph.cpp
new file mode 100644
index 0000000000..31a0622ffe
--- /dev/null
+++ b/src/3rdparty/phonon/ds9/mediagraph.cpp
@@ -0,0 +1,1099 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library 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, either version 2.1 or 3 of the License.
+
+This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "fakesource.h"
+#include "iodevicereader.h"
+#include "qaudiocdreader.h"
+
+#include "mediagraph.h"
+#include "mediaobject.h"
+
+
+#include <QtCore/QUrl>
+#include <QtCore/QDebug>
+
+#include <qnetwork.h>
+
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+ namespace DS9
+ {
+ //description of a connection
+ struct GraphConnection
+ {
+ Filter output;
+ int outputOffset;
+ Filter input;
+ int inputOffset;
+ };
+
+ static QList<GraphConnection> getConnections(Filter source)
+ {
+ QList<GraphConnection> ret;
+ int outOffset = 0;
+ const QList<OutputPin> outputs = BackendNode::pins(source, PINDIR_OUTPUT);
+ for (int i = 0; i < outputs.count(); ++i) {
+ InputPin input;
+ if (outputs.at(i)->ConnectedTo(input.pparam()) == S_OK) {
+ PIN_INFO info;
+ input->QueryPinInfo(&info);
+ Filter current(info.pFilter);
+ if (current) {
+ //this is a valid connection
+ const int inOffset = BackendNode::pins(current, PINDIR_INPUT).indexOf(input);
+ const GraphConnection connection = {source, outOffset, current, inOffset};
+ ret += connection;
+ ret += getConnections(current); //get subsequent connections
+ }
+ }
+ outOffset++;
+ }
+ return ret;
+ }
+
+ static HRESULT saveToFile(Graph graph, const QString &filepath)
+ {
+ const WCHAR wszStreamName[] = L"ActiveMovieGraph";
+ HRESULT hr;
+ ComPointer<IStorage> storage;
+
+ // First, create a document file that will hold the GRF file
+ hr = StgCreateDocfile((OLECHAR*)filepath.utf16(),
+ STGM_CREATE | STGM_TRANSACTED | STGM_READWRITE |
+ STGM_SHARE_EXCLUSIVE,
+ 0, storage.pparam());
+
+ if (FAILED(hr)) {
+ return hr;
+ }
+
+ // Next, create a stream to store.
+ ComPointer<IStream> stream;
+ hr = storage->CreateStream(wszStreamName,
+ STGM_WRITE | STGM_CREATE | STGM_SHARE_EXCLUSIVE,
+ 0, 0, stream.pparam());
+
+ if (FAILED(hr)) {
+ return hr;
+ }
+
+ // The IpersistStream::Save method converts a stream into a persistent object.
+ ComPointer<IPersistStream> persist(graph, IID_IPersistStream);
+ hr = persist->Save(stream, TRUE);
+ if (SUCCEEDED(hr)) {
+ hr = storage->Commit(STGC_DEFAULT);
+ }
+
+ return hr;
+ }
+
+
+ MediaGraph::MediaGraph(MediaObject *mo, short index) :
+ m_graph(CLSID_FilterGraph, IID_IGraphBuilder),
+ m_fakeSource(new FakeSource()),
+ m_hasVideo(false), m_hasAudio(false), m_connectionsDirty(false),
+ m_isStopping(false), m_isSeekable(false), m_result(S_OK),
+ m_index(index), m_renderId(0), m_seekId(0),
+ m_currentTime(0), m_totalTime(0), m_mediaObject(mo)
+ {
+ m_mediaControl = ComPointer<IMediaControl>(m_graph, IID_IMediaControl);
+ Q_ASSERT(m_mediaControl);
+ m_mediaSeeking = ComPointer<IMediaSeeking>(m_graph, IID_IMediaSeeking);
+ Q_ASSERT(m_mediaSeeking);
+
+ HRESULT hr = m_graph->AddFilter(m_fakeSource, 0);
+ if (m_mediaObject->catchComError(hr)) {
+ return;
+ }
+ }
+
+ MediaGraph::~MediaGraph()
+ {
+ }
+
+ short MediaGraph::index() const
+ {
+ return m_index;
+ }
+
+ void MediaGraph::grabNode(BackendNode *node)
+ {
+ grabFilter(node->filter(m_index));
+ }
+
+ void MediaGraph::grabFilter(Filter filter)
+ {
+ if (filter) {
+ FILTER_INFO info;
+ filter->QueryFilterInfo(&info);
+ if (info.pGraph != m_graph) {
+ if (info.pGraph) {
+ m_mediaObject->catchComError(info.pGraph->RemoveFilter(filter));
+ }
+ m_mediaObject->catchComError(m_graph->AddFilter(filter, 0));
+ }
+ if (info.pGraph) {
+ info.pGraph->Release();
+ }
+ }
+ }
+
+ void MediaGraph::switchFilters(Filter oldFilter, Filter newFilter)
+ {
+ OAFilterState state = syncGetRealState();
+ if (state != State_Stopped) {
+ ensureStopped(); //to do the transaction
+ }
+
+
+ OutputPin connected;
+ {
+ InputPin pin = BackendNode::pins(oldFilter, PINDIR_INPUT).first();
+ pin->ConnectedTo(connected.pparam());
+ }
+
+ m_graph->RemoveFilter(oldFilter);
+ m_graph->AddFilter(newFilter, 0);
+
+ if (connected) {
+ InputPin pin = BackendNode::pins(newFilter, PINDIR_INPUT).first();
+ //let's reestablish the connections
+ m_graph->Connect(connected, pin);
+ }
+
+ switch(state)
+ {
+ case State_Running:
+ play();
+ break;
+ case State_Paused:
+ pause();
+ break;
+ default:
+ break;
+ }
+
+ }
+
+ OAFilterState MediaGraph::syncGetRealState() const
+ {
+ OAFilterState state;
+ m_mediaControl->GetState(INFINITE, &state);
+ return state;
+ }
+
+
+
+ void MediaGraph::ensureSourceDisconnected()
+ {
+ for (int i = 0; i < m_sinkConnections.count(); ++i) {
+ const Filter currentFilter = m_sinkConnections.at(i)->filter(m_index);
+ const QList<InputPin> inputs = BackendNode::pins(currentFilter, PINDIR_INPUT);
+ const QList<InputPin> outputs = BackendNode::pins(m_fakeSource, PINDIR_OUTPUT);
+
+ for (int i = 0; i < inputs.count(); ++i) {
+ for (int o = 0; o < outputs.count(); o++) {
+ tryDisconnect(outputs.at(o), inputs.at(i));
+ }
+
+ for (int d = 0; d < m_decoderPins.count(); ++d) {
+ tryDisconnect(m_decoderPins.at(d), inputs.at(i));
+ }
+ }
+ }
+ }
+
+ void MediaGraph::ensureSourceConnectedTo(bool force)
+ {
+ if (m_connectionsDirty == false && force == false) {
+ return;
+ }
+
+ m_connectionsDirty = false;
+ ensureSourceDisconnected();
+
+ //reconnect the pins
+ for (int i = 0; i < m_sinkConnections.count(); ++i) {
+ const Filter currentFilter = m_sinkConnections.at(i)->filter(m_index);
+ const QList<InputPin> inputs = BackendNode::pins(currentFilter, PINDIR_INPUT);
+ for(int i = 0; i < inputs.count(); ++i) {
+ //we ensure the filter belongs to the graph
+ grabFilter(currentFilter);
+
+ for (int d = 0; d < m_decoderPins.count(); ++d) {
+ //a decoder has only one output
+ if (tryConnect(m_decoderPins.at(d), inputs.at(i))) {
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ QList<Filter> MediaGraph::getAllFilters(Graph graph)
+ {
+ QList<Filter> ret;
+ ComPointer<IEnumFilters> enumFilters;
+ graph->EnumFilters(enumFilters.pparam());
+ Filter current;
+ while( enumFilters && enumFilters->Next(1, current.pparam(), 0) == S_OK) {
+ ret += current;
+ }
+ return ret;
+ }
+
+ QList<Filter> MediaGraph::getAllFilters() const
+ {
+ return getAllFilters(m_graph);
+ }
+
+
+ bool MediaGraph::isSeekable() const
+ {
+ return m_isSeekable;
+ }
+
+ qint64 MediaGraph::absoluteTotalTime() const
+ {
+ if (m_seekId) {
+ return m_totalTime;
+ } else {
+ qint64 ret = 0;
+ if (m_mediaSeeking) {
+ m_mediaSeeking->GetDuration(&ret);
+ ret /= 10000; //convert to milliseconds
+ }
+ return ret;
+ }
+ }
+
+ qint64 MediaGraph::absoluteCurrentTime() const
+ {
+ if (m_seekId) {
+ return m_currentTime;
+ } else {
+ qint64 ret = -1;
+ if (m_mediaSeeking) {
+ HRESULT hr = m_mediaSeeking->GetCurrentPosition(&ret);
+ if (FAILED(hr)) {
+ return ret;
+ }
+ ret /= 10000; //convert to milliseconds
+ }
+ return ret;
+ }
+ }
+
+ Phonon::MediaSource MediaGraph::mediaSource() const
+ {
+ return m_mediaSource;
+ }
+
+ void MediaGraph::play()
+ {
+ ensureSourceConnectedTo();
+ m_mediaObject->workerThread()->addStateChangeRequest(m_graph, State_Running, m_decoders);
+ }
+
+ void MediaGraph::pause()
+ {
+ ensureSourceConnectedTo();
+ m_mediaObject->workerThread()->addStateChangeRequest(m_graph, State_Paused, m_decoders);
+ }
+
+ HRESULT MediaGraph::renderResult() const
+ {
+ return m_result;
+ }
+
+ bool MediaGraph::isStopping() const
+ {
+ return m_isStopping;
+ }
+
+ Graph MediaGraph::graph() const
+ {
+ return m_graph;
+ }
+
+ void MediaGraph::stop()
+ {
+ if (!isLoading()) {
+ ensureStopped();
+ absoluteSeek(0); //resets the clock
+ } else {
+ m_mediaObject->workerThread()->abortCurrentRender(m_renderId);
+ m_renderId = 0; //cancels current loading
+ }
+ m_mediaObject->workerThread()->addStateChangeRequest(m_graph, State_Stopped);
+ }
+
+ void MediaGraph::ensureStopped()
+ {
+ m_isStopping = true;
+ //special case here because we want stopped to be synchronous
+ m_graph->Abort();
+ m_mediaControl->Stop();
+ OAFilterState dummy;
+ //this will wait until the change is effective
+ m_mediaControl->GetState(INFINITE, &dummy);
+ m_isStopping = false;
+ }
+
+ bool MediaGraph::isLoading() const
+ {
+ return m_renderId != 0;
+ }
+
+ void MediaGraph::absoluteSeek(qint64 time)
+ {
+ //this just sends a request
+ if (m_seekId == 0) {
+ m_currentTime = absoluteCurrentTime();
+ m_totalTime = absoluteTotalTime();
+ }
+ m_seekId = m_mediaObject->workerThread()->addSeekRequest(m_graph, time);
+ }
+
+ HRESULT MediaGraph::removeFilter(const Filter& filter)
+ {
+ FILTER_INFO info;
+ filter->QueryFilterInfo(&info);
+#ifdef GRAPH_DEBUG
+ qDebug() << "removeFilter" << QString::fromUtf16(info.achName);
+#endif
+ if (info.pGraph) {
+ info.pGraph->Release();
+ return m_graph->RemoveFilter(filter);
+ }
+
+ //already removed
+ return S_OK;
+ }
+
+ HRESULT MediaGraph::cleanup()
+ {
+ stop();
+
+ ensureSourceDisconnected();
+
+ QList<Filter> list = m_decoders;
+ if (m_demux) {
+ list << m_demux;
+ }
+ if (m_realSource) {
+ list << m_realSource;
+ }
+ list << m_decoders;
+
+ for (int i = 0; i < m_decoders.count(); ++i) {
+ list += getFilterChain(m_demux, m_decoders.at(i));
+ }
+
+ for (int i = 0; i < list.count(); ++i) {
+ removeFilter(list.at(i));
+ }
+
+ //Let's reinitialize the internal lists
+ m_decoderPins.clear();
+ m_decoders.clear();
+ m_demux = Filter();
+ m_realSource = Filter();
+ m_mediaSource = Phonon::MediaSource();
+
+ absoluteSeek(0); //resets the clock
+
+ return S_OK;
+ }
+
+
+ bool MediaGraph::disconnectNodes(BackendNode *source, BackendNode *sink)
+ {
+ const Filter sinkFilter = sink->filter(m_index);
+ const QList<InputPin> inputs = BackendNode::pins(sinkFilter, PINDIR_INPUT);
+
+ QList<OutputPin> outputs;
+ if (source == m_mediaObject) {
+ outputs = BackendNode::pins(m_fakeSource, PINDIR_OUTPUT);
+ outputs += m_decoderPins;
+ } else {
+ outputs = BackendNode::pins(source->filter(m_index), PINDIR_OUTPUT);
+ }
+
+
+ for (int i = 0; i < inputs.count(); ++i) {
+ for (int o = 0; o < outputs.count(); ++o) {
+ tryDisconnect(outputs.at(o), inputs.at(i));
+ }
+ }
+
+ if (m_sinkConnections.removeOne(sink)) {
+ m_connectionsDirty = true;
+ }
+ return true;
+ }
+
+ bool MediaGraph::tryDisconnect(const OutputPin &out, const InputPin &in)
+ {
+ bool ret = false;
+
+ OutputPin output;
+ if (SUCCEEDED(in->ConnectedTo(output.pparam()))) {
+
+ if (output == out) {
+ //we need a simple disconnection
+ ret = SUCCEEDED(out->Disconnect()) && SUCCEEDED(in->Disconnect());
+ } else {
+ InputPin in2;
+ if (SUCCEEDED(out->ConnectedTo(in2.pparam()))) {
+ PIN_INFO info;
+ in2->QueryPinInfo(&info);
+ Filter tee(info.pFilter);
+ CLSID clsid;
+ tee->GetClassID(&clsid);
+ if (clsid == CLSID_InfTee) {
+ //we have to remove all intermediate filters between the tee and the sink
+ PIN_INFO info;
+ in->QueryPinInfo(&info);
+ Filter sink(info.pFilter);
+ QList<Filter> list = getFilterChain(tee, sink);
+ out->QueryPinInfo(&info);
+ Filter source(info.pFilter);
+
+ if (list.isEmpty()) {
+ output->QueryPinInfo(&info);
+ if (Filter(info.pFilter) == tee) {
+ ret = SUCCEEDED(output->Disconnect()) && SUCCEEDED(in->Disconnect());
+ }
+ } else {
+ ret = true;
+ for (int i = 0; i < list.count(); ++i) {
+ ret = ret && SUCCEEDED(removeFilter(list.at(i)));
+ }
+ }
+
+ //Let's try to see if the Tee filter is still useful
+ if (ret) {
+ int connections = 0;
+ const QList<OutputPin> outputs = BackendNode::pins(tee, PINDIR_OUTPUT);
+ for(int i = 0; i < outputs.count(); ++i) {
+ InputPin p;
+ if ( SUCCEEDED(outputs.at(i)->ConnectedTo(p.pparam()))) {
+ connections++;
+ }
+ }
+ if (connections == 0) {
+ //this avoids a crash if the filter is destroyed
+ //by the subsequent call to removeFilter
+ output = OutputPin();
+ removeFilter(tee); //there is no more output for the tee, we remove it
+ }
+ }
+ }
+ }
+ }
+ }
+ return ret;
+ }
+
+ bool MediaGraph::tryConnect(const OutputPin &out, const InputPin &newIn)
+ {
+
+
+ ///The management of the creation of the Tees is done here (this is the only place where we call IPin::Connect
+ InputPin inPin;
+ if (SUCCEEDED(out->ConnectedTo(inPin.pparam()))) {
+
+ //the fake source has another mechanism for the connection
+ if (BackendNode::pins(m_fakeSource, PINDIR_OUTPUT).contains(out)) {
+ return false;
+ }
+
+ //the output pin is already connected
+ PIN_INFO info;
+ inPin->QueryPinInfo(&info);
+ Filter filter(info.pFilter); //this will ensure the interface is "Release"d
+ CLSID clsid;
+ filter->GetClassID(&clsid);
+ if (clsid == CLSID_InfTee) {
+ //there is already a Tee (namely 'filter') in use
+ const QList<OutputPin> outputs = BackendNode::pins(filter, PINDIR_OUTPUT);
+ for(int i = 0; i < outputs.count(); ++i) {
+ const OutputPin &pin = outputs.at(i);
+ if (VFW_E_NOT_CONNECTED == pin->ConnectedTo(inPin.pparam())) {
+ return SUCCEEDED(pin->Connect(newIn, 0));
+ }
+ }
+ //we shoud never go here
+ return false;
+ } else {
+ QAMMediaType type;
+ out->ConnectionMediaType(&type);
+
+ //first we disconnect the current connection (and we save the current media type)
+ if (!tryDisconnect(out, inPin)) {
+ return false;
+ }
+
+ //..then we try to connect the new node
+ if (SUCCEEDED(out->Connect(newIn, 0))) {
+
+ //we have to insert the Tee
+ if (!tryDisconnect(out, newIn)) {
+ return false;
+ }
+
+ Filter filter(CLSID_InfTee, IID_IBaseFilter);
+ if (!filter) {
+ //rollback
+ m_graph->Connect(out, inPin);
+ return false;
+ }
+
+ if (FAILED(m_graph->AddFilter(filter, 0))) {
+ return false;
+ }
+
+
+ InputPin teeIn = BackendNode::pins(filter, PINDIR_INPUT).first(); //a Tee has always one input
+ HRESULT hr = out->Connect(teeIn, &type);
+ if (FAILED(hr)) {
+ hr = m_graph->Connect(out, teeIn);
+ }
+ if (FAILED(hr)) {
+ m_graph->Connect(out, inPin);
+ return false;
+ }
+
+ OutputPin teeOut = BackendNode::pins(filter, PINDIR_OUTPUT).last(); //the last is always the one that's not connected
+
+ //we simply reconnect the pins as they
+ hr = m_graph->Connect(teeOut, inPin);
+ if (FAILED(hr)) {
+ m_graph->Connect(out, inPin);
+ return false;
+ }
+
+ teeOut = BackendNode::pins(filter, PINDIR_OUTPUT).last(); //the last is always the one that's not connected
+ if (FAILED(m_graph->Connect(teeOut, newIn))) {
+ m_graph->Connect(out, inPin);
+ return false;
+ }
+
+ return true;
+ } else {
+ //we simply reconnect the pins as they
+ m_graph->Connect(out, inPin);
+ return false;
+ }
+ }
+
+ } else {
+ return SUCCEEDED(m_graph->Connect(out, newIn));
+ }
+ }
+
+ bool MediaGraph::connectNodes(BackendNode *source, BackendNode *sink)
+ {
+ bool ret = false;
+ const QList<InputPin> inputs = BackendNode::pins(sink->filter(m_index), PINDIR_INPUT);
+ QList<OutputPin> outputs = BackendNode::pins(source == m_mediaObject ? m_fakeSource : source->filter(m_index), PINDIR_OUTPUT);
+
+ if (source == m_mediaObject) {
+ grabFilter(m_fakeSource);
+ }
+
+#ifdef GRAPH_DEBUG
+ qDebug() << Q_FUNC_INFO << source << sink << this;
+#endif
+
+ for (int o = 0; o < outputs.count(); o++) {
+ InputPin p;
+ for (int i = 0; i < inputs.count(); i++) {
+ const InputPin &inPin = inputs.at(i);
+ if (tryConnect(outputs.at(o), inPin)) {
+ //tell the sink node that it just got a new input
+ sink->connected(source, inPin);
+ ret = true;
+ if (source == m_mediaObject) {
+ m_connectionsDirty = true;
+ m_sinkConnections += sink;
+#ifdef GRAPH_DEBUG
+ qDebug() << "found a sink connection" << sink << m_sinkConnections.count();
+#endif
+ }
+ break;
+ }
+ }
+ }
+
+ return ret;
+ }
+
+
+ HRESULT MediaGraph::loadSource(const Phonon::MediaSource &source)
+ {
+ m_hasVideo = false;
+ m_hasAudio = false;
+ m_isSeekable = false;
+
+
+ //cleanup of the previous filters
+ m_result = cleanup();
+ if (FAILED(m_result)) {
+ return m_result;
+ }
+
+ m_mediaSource = source;
+
+ switch (source.type())
+ {
+ case Phonon::MediaSource::Disc:
+ if (source.discType() == Phonon::Dvd) {
+ m_result = E_NOTIMPL;
+ /*m_realSource = Filter(CLSID_DVDNavigator, IID_IBaseFilter);
+ if (m_realSource) {
+ return REGDB_E_CLASSNOTREG;
+ }
+
+ m_result = m_graph->AddFilter(m_realSource, L"DVD Navigator");*/
+
+
+ #ifndef QT_NO_PHONON_MEDIACONTROLLER
+ } else if (source.discType() == Phonon::Cd) {
+ m_realSource = Filter(new QAudioCDPlayer);
+ m_result = m_graph->AddFilter(m_realSource, 0);
+
+#endif //QT_NO_PHONON_MEDIACONTROLLER
+ } else {
+ m_result = E_NOTIMPL;
+ }
+ if (FAILED(m_result)) {
+ return m_result;
+ }
+ m_renderId = m_mediaObject->workerThread()->addFilterToRender(m_realSource);
+ return m_result;
+ case Phonon::MediaSource::Invalid:
+ return m_result;
+ case Phonon::MediaSource::Url:
+ case Phonon::MediaSource::LocalFile:
+ {
+ QString url;
+ if (source.type() == Phonon::MediaSource::LocalFile) {
+ url = source.fileName();
+ } else {
+ url = source.url().toString();
+ }
+ m_renderId = m_mediaObject->workerThread()->addUrlToRender(url);
+ }
+ break;
+#ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ case Phonon::MediaSource::Stream:
+ {
+ m_realSource = Filter(new IODeviceReader(source, this));
+ m_renderId = m_mediaObject->workerThread()->addFilterToRender(m_realSource);
+ }
+ break;
+#endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ default:
+ m_result = E_FAIL;
+ }
+
+ return m_result;
+ }
+
+ void MediaGraph::finishSeeking(quint16 workId, qint64 time)
+ {
+ if (m_seekId == workId) {
+ m_currentTime = time;
+ m_mediaObject->seekingFinished(this);
+ m_seekId = 0;
+ } else {
+ //it's a queue seek command
+ //we're still seeking
+ }
+ }
+
+ void MediaGraph::finishLoading(quint16 workId, HRESULT hr, Graph graph)
+ {
+ if (m_renderId == workId) {
+ m_renderId = 0;
+
+ //let's determine if the graph is seekable
+ {
+ ComPointer<IMediaSeeking> mediaSeeking(graph, IID_IMediaSeeking);
+ DWORD caps = AM_SEEKING_CanSeekAbsolute;
+ m_isSeekable = mediaSeeking && SUCCEEDED(mediaSeeking->CheckCapabilities(&caps));
+ }
+
+ m_result = reallyFinishLoading(hr, graph);
+ m_mediaObject->loadingFinished(this);
+ }
+ }
+
+
+ HRESULT MediaGraph::reallyFinishLoading(HRESULT hr, const Graph &graph)
+ {
+ if (FAILED(hr)) {
+ return hr;
+ }
+
+ const Graph oldGraph = m_graph;
+ m_graph = graph;
+
+ //we keep the source and all the way down to the decoders
+ QList<Filter> removedFilters;
+
+ const QList<Filter> allFilters = getAllFilters(graph);
+ for (int i = 0; i < allFilters.count(); ++i) {
+ const Filter &filter = allFilters.at(i);
+ if (isSourceFilter(filter)) {
+ m_realSource = filter; //save the source filter
+ if (!m_demux ) {
+ m_demux = filter; //in the WMV case, the demuxer is the source filter itself
+ }
+ } else if (isDemuxerFilter(filter)) {
+ m_demux = filter;
+ } else if (isDecoderFilter(filter)) {
+ m_decoders += filter;
+ m_decoderPins += BackendNode::pins(filter, PINDIR_OUTPUT).first();
+ } else {
+ removedFilters += filter;
+ }
+ }
+
+ for (int i = 0; i < m_decoders.count(); ++i) {
+ QList<Filter> chain = getFilterChain(m_demux, m_decoders.at(i));
+ for (int i = 0; i < chain.count(); ++i) {
+ //we keep those filters
+ removedFilters.removeOne(chain.at(i));
+ }
+ }
+
+ for (int i = 0; i < removedFilters.count(); ++i) {
+ graph->RemoveFilter(removedFilters.at(i));
+ }
+
+ m_mediaObject->workerThread()->replaceGraphForEventManagement(graph, oldGraph);
+
+ //let's transfer the nodes from the current graph to the new one
+ QList<GraphConnection> connections; //we store the connections that need to be restored
+
+ // First get all the sink nodes (nodes with no input connected)
+ for (int i = 0; i < m_sinkConnections.count(); ++i) {
+ Filter currentFilter = m_sinkConnections.at(i)->filter(m_index);
+ connections += getConnections(currentFilter);
+ grabFilter(currentFilter);
+ }
+
+ //we need to do something smart to detect if the streams are unencoded
+ if (m_demux) {
+ const QList<OutputPin> outputs = BackendNode::pins(m_demux, PINDIR_OUTPUT);
+ for (int i = 0; i < outputs.count(); ++i) {
+ const OutputPin &out = outputs.at(i);
+ InputPin pin;
+ if (out->ConnectedTo(pin.pparam()) == VFW_E_NOT_CONNECTED) {
+ m_decoderPins += out; //unconnected outputs can be decoded outputs
+ }
+ }
+ }
+
+ ensureSourceConnectedTo(true);
+
+ //let's reestablish the connections
+ for (int i = 0; i < connections.count(); ++i) {
+ const GraphConnection &connection = connections.at(i);
+ //check if we shoud transfer the sink node
+
+ grabFilter(connection.input);
+ grabFilter(connection.output);
+
+ const OutputPin output = BackendNode::pins(connection.output, PINDIR_OUTPUT).at(connection.outputOffset);
+ const InputPin input = BackendNode::pins(connection.input, PINDIR_INPUT).at(connection.inputOffset);
+ HRESULT hr = output->Connect(input, 0);
+ Q_UNUSED(hr);
+ Q_ASSERT( SUCCEEDED(hr));
+ }
+
+ //Finally, let's update the interfaces
+ m_mediaControl = ComPointer<IMediaControl>(graph, IID_IMediaControl);
+ m_mediaSeeking = ComPointer<IMediaSeeking>(graph, IID_IMediaSeeking);
+ return hr;
+ }
+
+ //utility functions
+ //retrieves the filters between source and sink
+ QList<Filter> MediaGraph::getFilterChain(const Filter &source, const Filter &sink)
+ {
+ QList<Filter> ret;
+ Filter current = sink;
+ while (current && BackendNode::pins(current, PINDIR_INPUT).count() == 1 && current != source) {
+ if (current != source)
+ ret += current;
+ InputPin pin = BackendNode::pins(current, PINDIR_INPUT).first();
+ current = Filter();
+ OutputPin output;
+ if (pin->ConnectedTo(output.pparam()) == S_OK) {
+ PIN_INFO info;
+ if (SUCCEEDED(output->QueryPinInfo(&info)) && info.pFilter) {
+ current = Filter(info.pFilter); //this will take care of releasing the interface pFilter
+ }
+ }
+ }
+ if (current != source) {
+ //the soruce and sink don't seem to be connected
+ ret.clear();
+ }
+ return ret;
+ }
+
+ bool MediaGraph::isDecoderFilter(const Filter &filter)
+ {
+ if (filter == 0) {
+ return false;
+ }
+#ifdef GRAPH_DEBUG
+ {
+ FILTER_INFO info;
+ filter->QueryFilterInfo(&info);
+ qDebug() << Q_FUNC_INFO << QString::fromUtf16(info.achName);
+ if (info.pGraph) {
+ info.pGraph->Release();
+ }
+ }
+#endif
+
+
+ QList<InputPin> inputs = BackendNode::pins(filter, PINDIR_INPUT);
+ QList<OutputPin> outputs = BackendNode::pins(filter, PINDIR_OUTPUT);
+
+ //TODO: find a better way to detect if a node is a decoder
+ if (inputs.count() == 0 || outputs.count() ==0) {
+ return false;
+ }
+
+ //the input pin must be encoded data
+ QAMMediaType type;
+ HRESULT hr = inputs.first()->ConnectionMediaType(&type);
+ if (FAILED(hr)) {
+ return false;
+ }
+
+
+ //...and the output must be decoded
+ QAMMediaType type2;
+ hr = outputs.first()->ConnectionMediaType(&type2);
+ if (FAILED(hr)) {
+ return false;
+ }
+
+ if (type2.majortype != MEDIATYPE_Video &&
+ type2.majortype != MEDIATYPE_Audio) {
+ return false;
+ }
+
+ if (type2.majortype == MEDIATYPE_Video) {
+ m_hasVideo = true;
+ } else {
+ m_hasAudio = true;
+ }
+
+#ifdef GRAPH_DEBUG
+ {
+ FILTER_INFO info;
+ filter->QueryFilterInfo(&info);
+ qDebug() << "found a decoder filter" << QString::fromUtf16(info.achName);
+ if (info.pGraph) {
+ info.pGraph->Release();
+ }
+ }
+#endif
+
+ return true;
+ }
+
+ bool MediaGraph::isSourceFilter(const Filter &filter) const
+ {
+#ifdef GRAPH_DEBUG
+ {
+ FILTER_INFO info;
+ filter->QueryFilterInfo(&info);
+ qDebug() << Q_FUNC_INFO << QString::fromUtf16(info.achName);
+ if (info.pGraph) {
+ info.pGraph->Release();
+ }
+ }
+#endif
+ //a source filter is one that has no input
+ return BackendNode::pins(filter, PINDIR_INPUT).isEmpty();
+ }
+
+ bool MediaGraph::isDemuxerFilter(const Filter &filter) const
+ {
+ QList<InputPin> inputs = BackendNode::pins(filter, PINDIR_INPUT);
+ QList<OutputPin> outputs = BackendNode::pins(filter, PINDIR_OUTPUT);
+
+#ifdef GRAPH_DEBUG
+ {
+ FILTER_INFO info;
+ filter->QueryFilterInfo(&info);
+ qDebug() << Q_FUNC_INFO << QString::fromUtf16(info.achName);
+ if (info.pGraph) {
+ info.pGraph->Release();
+ }
+ }
+#endif
+
+ if (inputs.count() != 1 || outputs.count() == 0) {
+ return false; //a demuxer has only one input
+ }
+
+ QAMMediaType type;
+ HRESULT hr = inputs.first()->ConnectionMediaType(&type);
+ if (FAILED(hr)) {
+ return false;
+ }
+
+ if (type.majortype != MEDIATYPE_Stream) {
+ return false;
+ }
+
+ for (int i = 0; i < outputs.count(); ++i) {
+ QAMMediaType type;
+ //for now we support only video and audio
+ hr = outputs.at(i)->ConnectionMediaType(&type);
+ if (SUCCEEDED(hr) &&
+ type.majortype != MEDIATYPE_Video && type.majortype != MEDIATYPE_Audio) {
+ return false;
+ }
+ }
+#ifdef GRAPH_DEBUG
+ {
+ FILTER_INFO info;
+ filter->QueryFilterInfo(&info);
+ qDebug() << "found a demuxer filter" << QString::fromUtf16(info.achName);
+ if (info.pGraph) {
+ info.pGraph->Release();
+ }
+ }
+#endif
+ return true;
+ }
+
+ QMultiMap<QString, QString> MediaGraph::metadata() const
+ {
+ QMultiMap<QString, QString> ret;
+ ComPointer<IAMMediaContent> mediaContent(m_demux, IID_IAMMediaContent);
+ if (mediaContent) {
+ //let's get the meta data
+ BSTR str;
+ HRESULT hr = mediaContent->get_AuthorName(&str);
+ if (SUCCEEDED(hr)) {
+ ret.insert(QLatin1String("ARTIST"), QString::fromUtf16((const unsigned short*)str));
+ SysFreeString(str);
+ }
+ hr = mediaContent->get_Title(&str);
+ if (SUCCEEDED(hr)) {
+ ret.insert(QLatin1String("TITLE"), QString::fromUtf16((const unsigned short*)str));
+ SysFreeString(str);
+ }
+ hr = mediaContent->get_Description(&str);
+ if (SUCCEEDED(hr)) {
+ ret.insert(QLatin1String("DESCRIPTION"), QString::fromUtf16((const unsigned short*)str));
+ SysFreeString(str);
+ }
+ hr = mediaContent->get_Copyright(&str);
+ if (SUCCEEDED(hr)) {
+ ret.insert(QLatin1String("COPYRIGHT"), QString::fromUtf16((const unsigned short*)str));
+ SysFreeString(str);
+ }
+ hr = mediaContent->get_MoreInfoText(&str);
+ if (SUCCEEDED(hr)) {
+ ret.insert(QLatin1String("MOREINFO"), QString::fromUtf16((const unsigned short*)str));
+ SysFreeString(str);
+ }
+ }
+ return ret;
+ }
+
+ Filter MediaGraph::realSource() const
+ {
+ return m_realSource;
+ }
+
+#ifndef QT_NO_PHONON_MEDIACONTROLLER
+ void MediaGraph::setStopPosition(qint64 time)
+ {
+ qint64 current = 0,
+ stop = 0;
+ m_mediaSeeking->GetPositions(&current, &stop);
+
+ const bool shouldSeek = current == stop;
+
+ if (time == -1) {
+ HRESULT hr = m_mediaSeeking->GetDuration(&time);
+ if (FAILED(hr)) {
+ return;
+ }
+ } else {
+ time *= 10000;
+ }
+
+ if (time == stop) {
+ //the stop position is already at the right place
+ return;
+ }
+
+ if (shouldSeek) {
+ m_mediaSeeking->SetPositions(&current, AM_SEEKING_AbsolutePositioning,
+ &time, AM_SEEKING_AbsolutePositioning);
+ } else {
+ m_mediaSeeking->SetPositions(0, AM_SEEKING_NoPositioning,
+ &time, AM_SEEKING_AbsolutePositioning);
+ }
+ }
+
+ qint64 MediaGraph::stopPosition() const
+ {
+ qint64 ret;
+ m_mediaSeeking->GetStopPosition(&ret);
+ return ret / 10000;
+
+ }
+
+ QList<qint64> MediaGraph::titles() const
+ {
+ //for now we only manage that for the audio cd
+ ComPointer<ITitleInterface> titleIFace(m_realSource, IID_ITitleInterface);
+ if (titleIFace) {
+ return titleIFace->titles();
+ } else {
+ // the default value: only one title that starts at position 0
+ return QList<qint64>() << 0;
+ }
+ }
+#endif //QT_NO_PHONON_MEDIACONTROLLER
+
+
+
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/3rdparty/phonon/ds9/mediagraph.h b/src/3rdparty/phonon/ds9/mediagraph.h
new file mode 100644
index 0000000000..13e7bcfc16
--- /dev/null
+++ b/src/3rdparty/phonon/ds9/mediagraph.h
@@ -0,0 +1,148 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library 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, either version 2.1 or 3 of the License.
+
+This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef PHONON_MEDIAGRAPH_H
+#define PHONON_MEDIAGRAPH_H
+
+#include "backendnode.h"
+#include <QtCore/QMultiMap>
+
+#include <phonon/mediasource.h>
+
+//#define GRAPH_DEBUG
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+ namespace DS9
+ {
+ class MediaObject;
+
+ //in the end we should probably have no more inheritance here: everything should be in the interface of the class
+ //could be nice to then remove all the "*this" in the code of this class
+ class MediaGraph : public QObject
+ {
+ public:
+ MediaGraph(MediaObject *mo, short index);
+ ~MediaGraph();
+ bool isSeekable() const;
+ qint64 absoluteTotalTime() const;
+ qint64 absoluteCurrentTime() const;
+ void play();
+ void stop();
+ void pause();
+ void absoluteSeek(qint64);
+
+ QMultiMap<QString, QString> metadata() const;
+
+ static QList<Filter> getAllFilters(Graph graph);
+ QList<Filter> getAllFilters() const;
+
+ HRESULT loadSource(const Phonon::MediaSource &);
+
+ bool hasVideo() const { return m_hasVideo; }
+ void grabNode(BackendNode *node);
+ void grabFilter(Filter filter);
+
+ //connections of the nodes
+ bool connectNodes(BackendNode *source, BackendNode *sink);
+ bool disconnectNodes(BackendNode *source, BackendNode *sink);
+
+ Phonon::MediaSource mediaSource() const;
+
+ //before loading a source, and after its playback this will be called
+ HRESULT cleanup();
+ void ensureStopped();
+
+ short index() const;
+
+ Filter realSource() const;
+
+
+#ifndef QT_NO_PHONON_MEDIACONTROLLER
+ QList<qint64> titles() const;
+ void setStopPosition(qint64 time);
+ qint64 stopPosition() const;
+#endif //QT_NO_PHONON_MEDIACONTROLLER
+
+ void switchFilters(Filter oldFilter, Filter newFilter);
+ OAFilterState syncGetRealState() const;
+
+ bool isLoading() const;
+ bool isStopping() const;
+ HRESULT renderResult() const;
+
+ Graph graph() const;
+
+ void finishLoading(quint16 workId, HRESULT hr, Graph);
+ void finishSeeking(quint16 workId, qint64 time);
+
+ private:
+ bool isSourceFilter(const Filter &filter) const;
+ bool isDemuxerFilter(const Filter &filter) const;
+ bool isDecoderFilter(const Filter &filter);
+ static QList<Filter> getFilterChain(const Filter &source, const Filter &sink);
+
+ HRESULT reallyFinishLoading(HRESULT, const Graph &graph);
+
+
+ //utility functions
+ void ensureSourceConnectedTo(bool force = false);
+ void ensureSourceDisconnected();
+ bool tryConnect(const OutputPin &, const InputPin &);
+ bool tryDisconnect(const OutputPin &, const InputPin &);
+ HRESULT removeFilter(const Filter& filter);
+
+ //after loading, removes the decoders that are not linked to a sink
+ HRESULT removeUselessDecoders();
+
+ //COM objects
+ Graph m_graph;
+ ComPointer<IMediaControl> m_mediaControl;
+ ComPointer<IMediaSeeking> m_mediaSeeking;
+ Filter m_fakeSource, m_realSource;
+ Filter m_demux;
+ QList<OutputPin> m_decoderPins;
+ QList<Filter> m_decoders;
+
+ bool m_hasVideo;
+ bool m_hasAudio;
+ bool m_connectionsDirty;
+ bool m_isStopping;
+ mutable bool m_isSeekable;
+ HRESULT m_result;
+ quint16 m_index;
+ quint16 m_renderId;
+ quint16 m_seekId;
+
+ //while seeking we need to store the current time
+ qint64 m_currentTime;
+ qint64 m_totalTime;
+
+ MediaObject *m_mediaObject;
+ Phonon::MediaSource m_mediaSource;
+ QList<BackendNode*> m_sinkConnections; //connections to the source
+
+ Q_DISABLE_COPY(MediaGraph);
+ };
+ }
+}
+
+QT_END_NAMESPACE
+
+#endif // PHONON_MEDIAGRAPH_H
diff --git a/src/3rdparty/phonon/ds9/mediaobject.cpp b/src/3rdparty/phonon/ds9/mediaobject.cpp
new file mode 100644
index 0000000000..93a19b05c7
--- /dev/null
+++ b/src/3rdparty/phonon/ds9/mediaobject.cpp
@@ -0,0 +1,1208 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library 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, either version 2.1 or 3 of the License.
+
+This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <QtCore/QVector>
+#include <QtCore/QTimerEvent>
+#include <QtCore/QTimer>
+#include <QtCore/QTime>
+#include <QtCore/QLibrary>
+
+#ifndef Q_CC_MSVC
+#include <dshow.h>
+#endif //Q_CC_MSVC
+#include <objbase.h>
+#include <initguid.h>
+#include <qnetwork.h>
+#include <evcode.h>
+
+#include "mediaobject.h"
+#include "videowidget.h"
+#include "audiooutput.h"
+
+
+#include <QtCore/QDebug>
+
+#define TIMER_INTERVAL 16 //... ms for the timer that polls the current state (we use the multimedia timer
+#define PRELOAD_TIME 2000 // 2 seconds to load a source
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+ namespace DS9
+ {
+ typedef BOOL (WINAPI* LPAMGETERRORTEXT)(HRESULT, WCHAR *, DWORD);
+
+ //first the definition of the WorkerThread class
+ WorkerThread::WorkerThread()
+ : QThread(), m_currentRenderId(0), m_finished(false), m_currentWorkId(1)
+ {
+ }
+
+ WorkerThread::~WorkerThread()
+ {
+ }
+
+ WorkerThread::Work WorkerThread::dequeueWork()
+ {
+ QMutexLocker locker(&m_mutex);
+ if (m_finished) {
+ return Work();
+ }
+ Work ret = m_queue.dequeue();
+
+ //we ensure to have the wait condition in the right state
+ if (m_queue.isEmpty()) {
+ m_waitCondition.reset();
+ } else {
+ m_waitCondition.set();
+ }
+
+ return ret;
+ }
+
+ void WorkerThread::run()
+ {
+ while (m_finished == false) {
+ HANDLE handles[FILTER_COUNT +1];
+ handles[0] = m_waitCondition;
+ int count = 1;
+ for(int i = 0; i < FILTER_COUNT; ++i) {
+ if (m_graphHandle[i].graph) {
+ handles[count++] = m_graphHandle[i].handle;
+ }
+ }
+ DWORD result = ::WaitForMultipleObjects(count, handles, FALSE, INFINITE);
+ if (result == WAIT_OBJECT_0) {
+ if (m_finished) {
+ //that's the end if the thread execution
+ return;
+ }
+
+ handleTask();
+ } else {
+ //this is the event management
+ const Graph &graph = m_graphHandle[result - WAIT_OBJECT_0 - 1].graph;
+ long eventCode;
+ LONG_PTR param1, param2;
+
+ ComPointer<IMediaEvent> mediaEvent(graph, IID_IMediaEvent);
+ mediaEvent->GetEvent(&eventCode, &param1, &param2, 0);
+ emit eventReady(graph, eventCode, param1);
+ mediaEvent->FreeEventParams(eventCode, param1, param2);
+ }
+ }
+ }
+
+ //wants to know as soon as the state is set
+ void WorkerThread::addStateChangeRequest(Graph graph, OAFilterState state, QList<Filter> decoders)
+ {
+ QMutexLocker locker(&m_mutex);
+ bool found = false;
+ //we try to see if there is already an attempt to change the state and we remove it
+ for(int i = 0; !found && i < m_queue.size(); ++i) {
+ const Work &w = m_queue.at(i);
+ if (w.graph == graph && w.task == ChangeState) {
+ found = true;
+ m_queue.removeAt(i);
+ }
+ }
+
+ //now let's create the new task
+ Work w;
+ w.task = ChangeState;
+ w.id = m_currentWorkId++;
+ w.graph = graph;
+ w.state = state;
+ w.decoders = decoders;
+ m_queue.enqueue(w);
+ m_waitCondition.set();
+ }
+
+ quint16 WorkerThread::addSeekRequest(Graph graph, qint64 time)
+ {
+ QMutexLocker locker(&m_mutex);
+ bool found = false;
+ //we try to see if there is already an attempt to seek and we remove it
+ for(int i = 0; !found && i < m_queue.size(); ++i) {
+ const Work &w = m_queue.at(i);
+ if (w.graph == graph && w.task == Seek) {
+ found = true;
+ m_queue.removeAt(i);
+ }
+ }
+
+ Work w;
+ w.task = Seek;
+ //we create a new graph
+ w.graph = graph;
+ w.id = m_currentWorkId++;
+ w.time = time;
+ m_queue.enqueue(w);
+ m_waitCondition.set();
+ return w.id;
+ }
+
+ quint16 WorkerThread::addUrlToRender(const QString &url)
+ {
+ QMutexLocker locker(&m_mutex);
+ Work w;
+ w.task = Render;
+ //we create a new graph
+ w.graph = Graph(CLSID_FilterGraph, IID_IGraphBuilder);
+ w.url = url;
+ w.url.detach();
+ w.id = m_currentWorkId++;
+ m_queue.enqueue(w);
+ m_waitCondition.set();
+ return w.id;
+ }
+
+ quint16 WorkerThread::addFilterToRender(const Filter &filter)
+ {
+ QMutexLocker locker(&m_mutex);
+ Work w;
+ w.task = Render;
+ //we create a new graph
+ w.graph = Graph(CLSID_FilterGraph, IID_IGraphBuilder);
+ w.filter = filter;
+ w.id = m_currentWorkId++;
+ m_queue.enqueue(w);
+ m_waitCondition.set();
+ return w.id;
+ }
+
+ void WorkerThread::replaceGraphForEventManagement(Graph newGraph, Graph oldGraph)
+ {
+ QMutexLocker locker(&m_mutex);
+ Work w;
+ w.task = ReplaceGraph;
+ w.graph = newGraph;
+ w.oldGraph = oldGraph;
+ m_queue.enqueue(w);
+ m_waitCondition.set();
+ }
+
+ void WorkerThread::handleTask()
+ {
+ const Work w = dequeueWork();
+
+ if (m_finished) {
+ return;
+ }
+
+ HRESULT hr = S_OK;
+
+ m_currentRender = w.graph;
+ m_currentRenderId = w.id;
+ if (w.task == ReplaceGraph) {
+ QMutexLocker locker(&m_mutex);
+ HANDLE h;
+
+ int index = -1;
+ for(int i = 0; i < FILTER_COUNT; ++i) {
+ if (m_graphHandle[i].graph == w.oldGraph) {
+ m_graphHandle[i].graph = Graph();
+ index = i;
+ break;
+ } else if (index == -1 && m_graphHandle[i].graph == 0) {
+ //this is the first available slot
+ index = i;
+ }
+ }
+
+ Q_ASSERT(index != -1);
+
+ //add the new graph
+ if (SUCCEEDED(ComPointer<IMediaEvent>(w.graph, IID_IMediaEvent)
+ ->GetEventHandle(reinterpret_cast<OAEVENT*>(&h)))) {
+ m_graphHandle[index].graph = w.graph;
+ m_graphHandle[index].handle = h;
+ }
+ } else if (w.task == Render) {
+ if (w.filter) {
+ //let's render pins
+ w.graph->AddFilter(w.filter, 0);
+ const QList<OutputPin> outputs = BackendNode::pins(w.filter, PINDIR_OUTPUT);
+ for (int i = 0; i < outputs.count(); ++i) {
+ //blocking call
+ hr = w.graph->Render(outputs.at(i));
+ if (FAILED(hr)) {
+ break;
+ }
+ }
+ } else if (!w.url.isEmpty()) {
+ //let's render a url (blocking call)
+ hr = w.graph->RenderFile(reinterpret_cast<const wchar_t *>(w.url.utf16()), 0);
+ }
+ if (hr != E_ABORT) {
+ emit asyncRenderFinished(w.id, hr, w.graph);
+ }
+ } else if (w.task == Seek) {
+ //that's a seekrequest
+ ComPointer<IMediaSeeking> mediaSeeking(w.graph, IID_IMediaSeeking);
+ qint64 newtime = w.time * 10000;
+ hr = mediaSeeking->SetPositions(&newtime, AM_SEEKING_AbsolutePositioning,
+ 0, AM_SEEKING_NoPositioning);
+ qint64 currentTime = -1;
+ if (SUCCEEDED(hr)) {
+ hr = mediaSeeking->GetCurrentPosition(&currentTime);
+ if (SUCCEEDED(hr)) {
+ currentTime /= 10000; //convert to ms
+ }
+ }
+ emit asyncSeekingFinished(w.id, currentTime);
+ hr = E_ABORT; //to avoid emitting asyncRenderFinished
+ } else if (w.task == ChangeState) {
+
+ //remove useless decoders
+ QList<Filter> unused;
+ for (int i = 0; i < w.decoders.count(); ++i) {
+ const Filter &filter = w.decoders.at(i);
+ bool used = false;
+ const QList<OutputPin> pins = BackendNode::pins(filter, PINDIR_OUTPUT);
+ for( int i = 0; i < pins.count(); ++i) {
+ InputPin input;
+ if (pins.at(i)->ConnectedTo(input.pparam()) == S_OK) {
+ used = true;
+ }
+ }
+ if (!used) {
+ unused += filter;
+ }
+ }
+
+ //we can get the state
+ for (int i = 0; i < unused.count(); ++i) {
+ //we should remove this filter from the graph
+ w.graph->RemoveFilter(unused.at(i));
+ }
+
+
+ //we can get the state
+ ComPointer<IMediaControl> mc(w.graph, IID_IMediaControl);
+
+ //we change the state here
+ switch(w.state)
+ {
+ case State_Stopped:
+ mc->Stop();
+ break;
+ case State_Paused:
+ mc->Pause();
+ break;
+ case State_Running:
+ mc->Run();
+ break;
+ }
+ OAFilterState s;
+ //blocking call
+ HRESULT hr = mc->GetState(INFINITE, &s);
+
+ if (SUCCEEDED(hr)) {
+ if (s == State_Stopped) {
+ emit stateReady(w.graph, Phonon::StoppedState);
+ } else if (s == State_Paused) {
+ emit stateReady(w.graph, Phonon::PausedState);
+ } else /*if (s == State_Running)*/ {
+ emit stateReady(w.graph, Phonon::PlayingState);
+ }
+ }
+ }
+
+ m_currentRender = Graph();
+ m_currentRenderId = 0;
+
+ }
+
+ void WorkerThread::abortCurrentRender(qint16 renderId)
+ {
+ QMutexLocker locker(&m_mutex);
+ bool found = false;
+ //we try to see if there is already an attempt to seek and we remove it
+ for(int i = 0; !found && i < m_queue.size(); ++i) {
+ const Work &w = m_queue.at(i);
+ if (w.id == renderId) {
+ found = true;
+ m_queue.removeAt(i);
+ }
+ }
+
+ if (m_currentRender && m_currentRenderId == renderId) {
+ m_currentRender->Abort();
+ }
+ }
+
+ //tells the thread to stop processing
+ void WorkerThread::signalStop()
+ {
+ QMutexLocker locker(&m_mutex);
+ m_queue.clear();
+ if (m_currentRender) {
+ //in case we're currently rendering something
+ m_currentRender->Abort();
+
+ }
+
+ m_finished = true;
+ m_waitCondition.set();
+ }
+
+
+ MediaObject::MediaObject(QObject *parent) : BackendNode(parent),
+ transactionState(Phonon::StoppedState),
+ m_errorType(Phonon::NoError),
+ m_state(Phonon::LoadingState),
+ m_nextState(Phonon::StoppedState),
+ m_prefinishMark(0),
+ m_tickInterval(0),
+ m_buffering(false),
+ m_oldHasVideo(false),
+ m_prefinishMarkSent(false),
+ m_aboutToFinishSent(false),
+ m_nextSourceReadyToStart(false),
+#ifndef QT_NO_PHONON_MEDIACONTROLLER
+ m_autoplayTitles(true),
+ m_currentTitle(0),
+#endif //QT_NO_PHONON_MEDIACONTROLLER
+ m_targetTick(INFINITE)
+ {
+
+ for(int i = 0; i < FILTER_COUNT; ++i) {
+ m_graphs[i] = new MediaGraph(this, i);
+ }
+
+ connect(&m_thread, SIGNAL(stateReady(Graph, Phonon::State)),
+ SLOT(slotStateReady(Graph, Phonon::State)));
+
+ connect(&m_thread, SIGNAL(eventReady(Graph, long, long)),
+ SLOT(handleEvents(Graph, long, long)));
+
+ connect(&m_thread, SIGNAL(asyncRenderFinished(quint16, HRESULT, Graph)),
+ SLOT(finishLoading(quint16, HRESULT, Graph)));
+
+ connect(&m_thread, SIGNAL(asyncSeekingFinished(quint16, qint64)),
+ SLOT(finishSeeking(quint16, qint64)));
+ //really special case
+ m_mediaObject = this;
+ m_thread.start();
+ }
+
+ MediaObject::~MediaObject()
+ {
+ //be sure to finish the timer first
+ m_tickTimer.stop();
+
+ //we finish the worker thread here
+ m_thread.signalStop();
+ m_thread.wait();
+
+ //and then we delete the graphs
+ for (int i = 0; i < FILTER_COUNT; ++i) {
+ delete m_graphs[i];
+ }
+ }
+
+ WorkerThread *MediaObject::workerThread()
+ {
+ return &m_thread;
+ }
+
+ MediaGraph *MediaObject::currentGraph() const
+ {
+ return m_graphs[0];
+ }
+
+ MediaGraph *MediaObject::nextGraph() const
+ {
+ return m_graphs[FILTER_COUNT - 1];
+ }
+
+ //utility function to save the graph to a file
+ void MediaObject::timerEvent(QTimerEvent *e)
+ {
+ if (e->timerId() == m_tickTimer.timerId()) {
+
+ const qint64 current = currentTime();
+ const qint64 total = totalTime();
+
+ if ( m_tickInterval != 0 && current > m_targetTick) {
+ updateTargetTick();
+ emit tick(current);
+ }
+
+ //check that the title hasn't changed
+#ifndef QT_NO_PHONON_MEDIACONTROLLER
+ if (m_autoplayTitles && m_currentTitle < _iface_availableTitles() - 1) {
+
+ if (current >= total) {
+ //we go to the next title
+ _iface_setCurrentTitle(m_currentTitle + 1, false);
+ emit tick(current);
+ }
+ return;
+ }
+#endif //QT_NO_PHONON_MEDIACONTROLLER
+
+ if (total) {
+ const qint64 remaining = total - current;
+
+ if (m_transitionTime < 0 && m_nextSourceReadyToStart) {
+ if (remaining < -m_transitionTime + TIMER_INTERVAL/2) {
+ //we need to switch graphs to run the next source in the queue (with cross-fading)
+ switchToNextSource();
+ return;
+ } else if (current < -m_transitionTime) {
+ //we are currently crossfading
+ for (int i = 0; i < m_audioOutputs.count(); ++i) {
+ m_audioOutputs.at(i)->setCrossFadingProgress( currentGraph()->index(), qMin( qreal(1.), qreal(current) / qreal(-m_transitionTime)));
+ }
+ }
+ }
+
+ if (m_prefinishMark > 0 && !m_prefinishMarkSent && remaining < m_prefinishMark + TIMER_INTERVAL/2) {
+#ifdef GRAPH_DEBUG
+ qDebug() << "DS9: emit prefinishMarkReached" << remaining << QTime::currentTime().toString();
+#endif
+ m_prefinishMarkSent = true;
+
+ emit prefinishMarkReached( remaining );
+ }
+
+ if (!m_aboutToFinishSent && remaining < PRELOAD_TIME - m_transitionTime + TIMER_INTERVAL/2) {
+ //let's take a 2 seconds time time to actually load the next file
+#ifdef GRAPH_DEBUG
+ qDebug() << "DS9: emit aboutToFinish" << remaining << QTime::currentTime().toString();
+#endif
+ m_aboutToFinishSent = true;
+ emit aboutToFinish();
+ }
+ } else {
+ //total is 0: the stream is probably live (endless)
+ }
+
+ if (m_buffering) {
+ ComPointer<IAMNetworkStatus> status(currentGraph()->realSource(), IID_IAMNetworkStatus);
+ if (status) {
+ long l;
+ status->get_BufferingProgress(&l);
+ emit bufferStatus(l);
+#ifdef GRAPH_DEBUG
+ qDebug() << "emit bufferStatus(" << l << ")";
+#endif
+ }
+ }
+ }
+ }
+
+ void MediaObject::switchToNextSource()
+ {
+ m_prefinishMarkSent = false;
+ m_aboutToFinishSent = false;
+ m_nextSourceReadyToStart = false;
+
+ m_oldHasVideo = currentGraph()->hasVideo();
+
+ qSwap(m_graphs[0], m_graphs[1]); //swap the graphs
+
+ //we tell the video widgets to switch now to the new source
+#ifndef QT_NO_PHONON_VIDEO
+ for (int i = 0; i < m_videoWidgets.count(); ++i) {
+ m_videoWidgets.at(i)->setCurrentGraph(currentGraph()->index());
+ }
+#endif //QT_NO_PHONON_VIDEO
+
+ emit currentSourceChanged(currentGraph()->mediaSource());
+
+ if (currentGraph()->isLoading()) {
+ //will simply tell that when loading is finished
+ //it should start the playback
+ play();
+ }
+
+
+
+ emit metaDataChanged(currentGraph()->metadata());
+
+ if (nextGraph()->hasVideo() != currentGraph()->hasVideo()) {
+ emit hasVideoChanged(currentGraph()->hasVideo());
+ }
+
+ emit tick(0);
+ emit totalTimeChanged(totalTime());
+
+#ifndef QT_NO_PHONON_MEDIACONTROLLER
+ setTitles(currentGraph()->titles());
+#endif //QT_NO_PHONON_MEDIACONTROLLER
+
+ //this manages only gapless transitions
+ if (currentGraph()->mediaSource().type() != Phonon::MediaSource::Invalid) {
+ if (catchComError(currentGraph()->renderResult())) {
+ setState(Phonon::ErrorState);
+ } else {
+ play();
+ }
+ }
+ }
+
+ Phonon::State MediaObject::state() const
+ {
+ if (m_buffering) {
+ return Phonon::BufferingState;
+ } else {
+ return m_state;
+ }
+ }
+
+ bool MediaObject::hasVideo() const
+ {
+ return currentGraph()->hasVideo();
+ }
+
+ bool MediaObject::isSeekable() const
+ {
+ return currentGraph()->isSeekable();
+ }
+
+ qint64 MediaObject::totalTime() const
+ {
+#ifndef QT_NO_PHONON_MEDIACONTROLLER
+ //1st, check if there is more titles after
+ const qint64 ret = (m_currentTitle < _iface_availableTitles() - 1) ?
+ titleAbsolutePosition(m_currentTitle+1) : currentGraph()->absoluteTotalTime();
+
+ //this is the duration of the current title
+ return ret - titleAbsolutePosition(m_currentTitle);
+#else
+ return currentGraph()->absoluteTotalTime();
+#endif //QT_NO_PHONON_MEDIACONTROLLER
+ }
+
+ qint64 MediaObject::currentTime() const
+ {
+ //this handles inaccuracy when stopping on a title
+ return currentGraph()->absoluteCurrentTime()
+#ifndef QT_NO_PHONON_MEDIACONTROLLER
+ - titleAbsolutePosition(m_currentTitle)
+#endif //QT_NO_PHONON_MEDIACONTROLLER
+ ;
+ }
+
+ qint32 MediaObject::tickInterval() const
+ {
+ return m_tickInterval;
+ }
+
+ void MediaObject::setTickInterval(qint32 newTickInterval)
+ {
+ m_tickInterval = newTickInterval;
+ updateTargetTick();
+ }
+
+ void MediaObject::pause()
+ {
+ if (currentGraph()->isLoading()) {
+ m_nextState = Phonon::PausedState;
+ } else {
+ currentGraph()->pause();
+ }
+ }
+
+ void MediaObject::stop()
+ {
+ if (currentGraph()->isLoading()) {
+ m_nextState = Phonon::StoppedState;
+ } else {
+ currentGraph()->stop();
+ }
+ }
+
+ void MediaObject::ensureStopped()
+ {
+ currentGraph()->ensureStopped();
+ if (m_state == Phonon::ErrorState) {
+ //we reset the state here
+ m_state = Phonon::StoppedState;
+ }
+ }
+
+ void MediaObject::play()
+ {
+ if (currentGraph()->isLoading()) {
+ m_nextState = Phonon::PlayingState;
+ } else {
+ currentGraph()->play();
+ }
+ }
+
+ QString MediaObject::errorString() const
+ {
+ return m_errorString;
+ }
+
+ Phonon::ErrorType MediaObject::errorType() const
+ {
+ return m_errorType;
+ }
+
+
+ void MediaObject::updateTargetTick()
+ {
+ if (m_tickInterval) {
+ const qint64 current = currentTime();
+ m_targetTick = current / m_tickInterval * m_tickInterval;
+ if (current == 0 || m_targetTick < current) {
+ m_targetTick += m_tickInterval;
+ }
+ }
+ }
+
+ void MediaObject::setState(Phonon::State newstate)
+ {
+ if (newstate == Phonon::PlayingState) {
+ updateTargetTick();
+ }
+
+ if (newstate == m_state) {
+ return;
+ }
+
+ //manage the timer
+ if (newstate == Phonon::PlayingState) {
+ m_tickTimer.start(TIMER_INTERVAL, this);
+ } else {
+ m_tickTimer.stop();
+ }
+
+ Phonon::State oldstate = state();
+ m_state = newstate;
+ emit stateChanged(newstate, oldstate);
+ }
+
+
+ qint32 MediaObject::prefinishMark() const
+ {
+ return m_prefinishMark;
+ }
+
+ void MediaObject::setPrefinishMark(qint32 newPrefinishMark)
+ {
+ m_prefinishMark = newPrefinishMark;
+ }
+
+ qint32 MediaObject::transitionTime() const
+ {
+ return m_transitionTime;
+ }
+
+ void MediaObject::setTransitionTime(qint32 time)
+ {
+ m_transitionTime = time;
+ }
+
+ qint64 MediaObject::remainingTime() const
+ {
+ return totalTime() - currentTime();
+ }
+
+
+ Phonon::MediaSource MediaObject::source() const
+ {
+ return currentGraph()->mediaSource();
+ }
+
+ void MediaObject::setNextSource(const Phonon::MediaSource &source)
+ {
+ m_nextSourceReadyToStart = true;
+ const bool shouldSwitch = (m_state == Phonon::StoppedState || m_state == Phonon::ErrorState);
+ nextGraph()->loadSource(source); //let's preload the source
+
+ if (shouldSwitch) {
+ switchToNextSource();
+ }
+ }
+
+ void MediaObject::setSource(const Phonon::MediaSource &source)
+ {
+ m_nextSourceReadyToStart = false;
+ m_prefinishMarkSent = false;
+ m_aboutToFinishSent = false;
+
+ m_oldHasVideo = currentGraph()->hasVideo();
+ setState(Phonon::LoadingState);
+ //After loading we go into stopped state
+ m_nextState = Phonon::StoppedState;
+ catchComError(currentGraph()->loadSource(source));
+ emit currentSourceChanged(source);
+ }
+
+ void MediaObject::slotStateReady(Graph graph, Phonon::State newState)
+ {
+ if (graph == currentGraph()->graph() && !currentGraph()->isLoading()) {
+ setState(newState);
+ }
+ }
+
+ void MediaObject::loadingFinished(MediaGraph *mg)
+ {
+ if (mg == currentGraph()) {
+#ifndef QT_NO_PHONON_MEDIACONTROLLER
+ //Title interface
+ m_currentTitle = 0;
+ setTitles(currentGraph()->titles());
+#endif //QT_NO_PHONON_MEDIACONTROLLER
+
+ HRESULT hr = mg->renderResult();
+
+ if (catchComError(hr)) {
+ return;
+ }
+
+ if (m_oldHasVideo != currentGraph()->hasVideo()) {
+ emit hasVideoChanged(currentGraph()->hasVideo());
+ }
+
+#ifndef QT_NO_PHONON_VIDEO
+ if (currentGraph()->hasVideo()) {
+ updateVideoGeometry();
+ }
+#endif //QT_NO_PHONON_VIDEO
+
+ emit metaDataChanged(currentGraph()->metadata());
+ emit totalTimeChanged(totalTime());
+
+ //let's put the next state
+ switch(m_nextState)
+ {
+ case Phonon::PausedState:
+ pause();
+ break;
+ case Phonon::StoppedState:
+ stop();
+ break;
+ case Phonon::PlayingState:
+ play();
+ break;
+ case Phonon::ErrorState:
+ setState(Phonon::ErrorState);
+ break;
+ }
+ }
+ }
+
+ void MediaObject::seek(qint64 time)
+ {
+ //we seek into the current title
+ currentGraph()->absoluteSeek(time
+#ifndef QT_NO_PHONON_MEDIACONTROLLER
+ + titleAbsolutePosition(m_currentTitle)
+#endif //QT_NO_PHONON_MEDIACONTROLLER
+ );
+ }
+
+ void MediaObject::seekingFinished(MediaGraph *mg)
+ {
+ if (mg == currentGraph()) {
+
+ updateTargetTick();
+ if (currentTime() < totalTime() - m_prefinishMark) {
+ m_prefinishMarkSent = false;
+ }
+
+ if (currentTime() < totalTime() - PRELOAD_TIME + m_transitionTime) {
+ m_aboutToFinishSent = false;
+ }
+
+ //this helps the update of the application (seekslider for example)
+ if (m_state == PausedState || m_state == PlayingState) {
+ emit tick(currentTime());
+ }
+ }
+ }
+
+
+ bool MediaObject::catchComError(HRESULT hr)
+ {
+
+ m_errorString.clear();
+ m_errorType = Phonon::NoError;
+
+ if (hr != S_OK) {
+#ifdef GRAPH_DEBUG
+ qWarning("an error occurred 0x%x",hr);
+#endif
+ LPAMGETERRORTEXT getErrorText = (LPAMGETERRORTEXT)QLibrary::resolve(QLatin1String("quartz"), "AMGetErrorTextW");
+
+ ushort buffer[MAX_ERROR_TEXT_LEN];
+ if (getErrorText && getErrorText(hr, (WCHAR*)buffer, MAX_ERROR_TEXT_LEN)) {
+ m_errorString = QString::fromUtf16(buffer);
+ } else {
+ m_errorString = QString::fromLatin1("Unknown error");
+ }
+ const QString comError = QString::number(uint(hr), 16);
+ if (!m_errorString.toLower().contains(comError.toLower())) {
+ m_errorString += QString::fromLatin1(" (0x%1)").arg(comError);
+ }
+ if (FAILED(hr)) {
+ m_errorType = Phonon::FatalError;
+ setState(Phonon::ErrorState);
+ } else {
+ m_errorType = Phonon::NormalError;
+ m_nextState = Phonon::ErrorState;
+ }
+ } else {
+ m_errorType = Phonon::NoError;
+
+ }
+
+ return m_errorType == Phonon::FatalError;
+ }
+
+
+ void MediaObject::grabNode(BackendNode *node)
+ {
+ for (int i = 0; i < FILTER_COUNT; ++i) {
+ m_graphs[i]->grabNode(node);
+ }
+ node->setMediaObject(this);
+ }
+
+ bool MediaObject::connectNodes(BackendNode *source, BackendNode *sink)
+ {
+ bool ret = true;
+ for (int i = 0; i < FILTER_COUNT; ++i) {
+ ret = ret && m_graphs[i]->connectNodes(source, sink);
+ }
+ if (ret) {
+#ifndef QT_NO_PHONON_VIDEO
+ if (VideoWidget *video = qobject_cast<VideoWidget*>(sink)) {
+ m_videoWidgets += video;
+ } else
+#endif //QT_NO_PHONON_VIDEO
+ if (AudioOutput *audio = qobject_cast<AudioOutput*>(sink)) {
+ m_audioOutputs += audio;
+ }
+ }
+ return ret;
+ }
+
+ bool MediaObject::disconnectNodes(BackendNode *source, BackendNode *sink)
+ {
+ bool ret = true;
+ for (int i = 0; i < FILTER_COUNT; ++i) {
+ ret = ret && m_graphs[i]->disconnectNodes(source, sink);
+ }
+ if (ret) {
+#ifndef QT_NO_PHONON_VIDEO
+ if (VideoWidget *video = qobject_cast<VideoWidget*>(sink)) {
+ m_videoWidgets.removeOne(video);
+ } else
+#endif //QT_NO_PHONON_VIDEO
+ if (AudioOutput *audio = qobject_cast<AudioOutput*>(sink)) {
+ m_audioOutputs.removeOne(audio);
+ }
+ }
+ return ret;
+ }
+
+#ifndef QT_NO_PHONON_VIDEO
+ void MediaObject::updateVideoGeometry()
+ {
+ for (int i = 0; i < m_videoWidgets.count(); ++i) {
+ m_videoWidgets.at(i)->notifyVideoLoaded();
+ }
+ }
+#endif //QT_NO_PHONON_VIDEO
+
+ void MediaObject::handleComplete(IGraphBuilder *graph)
+ {
+ if (graph == currentGraph()->graph()) {
+ if (m_transitionTime >= PRELOAD_TIME || m_aboutToFinishSent == false) {
+ emit aboutToFinish(); //give a chance to the frontend to give a next source
+ m_aboutToFinishSent = true;
+ }
+
+ if (!m_nextSourceReadyToStart) {
+ //this is the last source, we simply finish
+ const qint64 current = currentTime();
+ const OAFilterState currentState = currentGraph()->syncGetRealState();
+
+ emit tick(current); //this ensures that the end of the seek slider is reached
+ emit finished();
+
+ if (currentTime() == current && currentGraph()->syncGetRealState() == currentState) {
+ //no seek operation in-between
+ pause();
+ setState(Phonon::PausedState); //we set it here
+ }
+
+ } else if (m_transitionTime == 0) {
+ //gapless transition
+ switchToNextSource(); //let's call the function immediately
+ } else if (m_transitionTime > 0) {
+ //management of the transition (if it is >= 0)
+ QTimer::singleShot(m_transitionTime, this, SLOT(switchToNextSource()));
+ }
+ } else {
+ //it is just the end of the previous source (in case of cross-fading)
+ nextGraph()->cleanup();
+ }
+ for (int i = 0; i < m_audioOutputs.count(); ++i) {
+ m_audioOutputs.at(i)->setCrossFadingProgress( currentGraph()->index(), 1.); //cross-fading is in any case finished
+ }
+ }
+
+ void MediaObject::finishLoading(quint16 workId, HRESULT hr, Graph graph)
+ {
+ for(int i = 0; i < FILTER_COUNT; ++i) {
+ m_graphs[i]->finishLoading(workId, hr, graph);
+ }
+ }
+
+ void MediaObject::finishSeeking(quint16 workId, qint64 time)
+ {
+ for(int i = 0; i < FILTER_COUNT; ++i) {
+ m_graphs[i]->finishSeeking(workId, time);
+ }
+ }
+
+
+ void MediaObject::handleEvents(Graph graph, long eventCode, long param1)
+ {
+ QString eventDescription;
+ switch (eventCode)
+ {
+ case EC_BUFFERING_DATA:
+ if (graph == currentGraph()->graph()) {
+ m_buffering = param1;
+ emit stateChanged(state(), m_state);
+ }
+ break;
+ case EC_LENGTH_CHANGED:
+ if (graph == currentGraph()->graph()) {
+ emit totalTimeChanged( totalTime() );
+ }
+ break;
+
+ case EC_COMPLETE:
+ handleComplete(graph);
+ break;
+
+#ifndef QT_NO_PHONON_VIDEO
+ case EC_VIDEO_SIZE_CHANGED:
+ if (graph == currentGraph()->graph()) {
+ updateVideoGeometry();
+ }
+ break;
+#endif //QT_NO_PHONON_VIDEO
+
+#ifdef GRAPH_DEBUG
+ case EC_ACTIVATE: qDebug() << "EC_ACTIVATE: A video window is being " << (param1 ? "ACTIVATED" : "DEACTIVATED"); break;
+ case EC_BUILT: qDebug() << "EC_BUILT: Send by the Video Control when a graph has been built. Not forwarded to applications."; break;
+ case EC_CLOCK_CHANGED: qDebug() << "EC_CLOCK_CHANGED"; break;
+ case EC_CLOCK_UNSET: qDebug() << "EC_CLOCK_UNSET: The clock provider was disconnected."; break;
+ case EC_CODECAPI_EVENT: qDebug() << "EC_CODECAPI_EVENT: Sent by an encoder to signal an encoding event."; break;
+ case EC_DEVICE_LOST: qDebug() << "EC_DEVICE_LOST: A Plug and Play device was removed or has become available again."; break;
+ case EC_DISPLAY_CHANGED: qDebug() << "EC_DISPLAY_CHANGED: The display mode has changed."; break;
+ case EC_END_OF_SEGMENT: qDebug() << "EC_END_OF_SEGMENT: The end of a segment has been reached."; break;
+ case EC_ERROR_STILLPLAYING: qDebug() << "EC_ERROR_STILLPLAYING: An asynchronous command to run the graph has failed."; break;
+ case EC_ERRORABORT: qDebug() << "EC_ERRORABORT: An operation was aborted because of an error."; break;
+ case EC_EXTDEVICE_MODE_CHANGE: qDebug() << "EC_EXTDEVICE_MODE_CHANGE: Not supported."; break;
+ case EC_FULLSCREEN_LOST: qDebug() << "EC_FULLSCREEN_LOST: The video renderer is switching out of full-screen mode."; break;
+ case EC_GRAPH_CHANGED: qDebug() << "EC_GRAPH_CHANGED: The filter graph has changed."; break;
+ case EC_NEED_RESTART: qDebug() << "EC_NEED_RESTART: A filter is requesting that the graph be restarted."; break;
+ case EC_NOTIFY_WINDOW: qDebug() << "EC_NOTIFY_WINDOW: Notifies a filter of the video renderer's window."; break;
+ case EC_OLE_EVENT: qDebug() << "EC_OLE_EVENT: A filter is passing a text string to the application."; break;
+ case EC_OPENING_FILE: qDebug() << "EC_OPENING_FILE: The graph is opening a file, or has finished opening a file."; break;
+ case EC_PALETTE_CHANGED: qDebug() << "EC_PALETTE_CHANGED: The video palette has changed."; break;
+ case EC_PAUSED: qDebug() << "EC_PAUSED: A pause request has completed."; break;
+ case EC_PREPROCESS_COMPLETE: qDebug() << "EC_PREPROCESS_COMPLETE: Sent by the WM ASF Writer filter when it completes the pre-processing for multipass encoding."; break;
+ case EC_QUALITY_CHANGE: qDebug() << "EC_QUALITY_CHANGE: The graph is dropping samples, for quality control."; break;
+ case EC_REPAINT: qDebug() << "EC_REPAINT: A video renderer requires a repaint."; break;
+ case EC_SEGMENT_STARTED: qDebug() << "EC_SEGMENT_STARTED: A new segment has started."; break;
+ case EC_SHUTTING_DOWN: qDebug() << "EC_SHUTTING_DOWN: The filter graph is shutting down, prior to being destroyed."; break;
+ case EC_SNDDEV_IN_ERROR: qDebug() << "EC_SNDDEV_IN_ERROR: A device error has occurred in an audio capture filter."; break;
+ case EC_SNDDEV_OUT_ERROR: qDebug() << "EC_SNDDEV_OUT_ERROR: A device error has occurred in an audio renderer filter."; break;
+ case EC_STARVATION: qDebug() << "EC_STARVATION: A filter is not receiving enough data."; break;
+ case EC_STATE_CHANGE: qDebug() << "EC_STATE_CHANGE: The filter graph has changed state."; break;
+ case EC_STEP_COMPLETE: qDebug() << "EC_STEP_COMPLETE: A filter performing frame stepping has stepped the specified number of frames."; break;
+ case EC_STREAM_CONTROL_STARTED: qDebug() << "EC_STREAM_CONTROL_STARTED: A stream-control start command has taken effect."; break;
+ case EC_STREAM_CONTROL_STOPPED: qDebug() << "EC_STREAM_CONTROL_STOPPED: A stream-control stop command has taken effect."; break;
+ case EC_STREAM_ERROR_STILLPLAYING: qDebug() << "EC_STREAM_ERROR_STILLPLAYING: An error has occurred in a stream. The stream is still playing."; break;
+ case EC_STREAM_ERROR_STOPPED: qDebug() << "EC_STREAM_ERROR_STOPPED: A stream has stopped because of an error."; break;
+ case EC_TIMECODE_AVAILABLE: qDebug() << "EC_TIMECODE_AVAILABLE: Not supported."; break;
+ case EC_UNBUILT: qDebug() << "Sent by the Video Control when a graph has been torn down. Not forwarded to applications."; break;
+ case EC_USERABORT: qDebug() << "EC_USERABORT: Send by the Video Control when a graph has been torn down. Not forwarded to applications."; break;
+ case EC_VMR_RECONNECTION_FAILED: qDebug() << "EC_VMR_RECONNECTION_FAILED: Sent by the VMR-7 and the VMR-9 when it was unable to accept a dynamic format change request from the upstream decoder."; break;
+ case EC_VMR_RENDERDEVICE_SET: qDebug() << "EC_VMR_RENDERDEVICE_SET: Sent when the VMR has selected its rendering mechanism."; break;
+ case EC_VMR_SURFACE_FLIPPED: qDebug() << "EC_VMR_SURFACE_FLIPPED: Sent when the VMR-7's allocator presenter has called the DirectDraw Flip method on the surface being presented."; break;
+ case EC_WINDOW_DESTROYED: qDebug() << "EC_WINDOW_DESTROYED: The video renderer was destroyed or removed from the graph"; break;
+ case EC_WMT_EVENT: qDebug() << "EC_WMT_EVENT: Sent by the Windows Media Format SDK when an application uses the ASF Reader filter to play ASF files protected by digital rights management (DRM)."; break;
+ case EC_WMT_INDEX_EVENT: qDebug() << "EC_WMT_INDEX_EVENT: Sent by the Windows Media Format SDK when an application uses the ASF Writer to index Windows Media Video files."; break;
+
+ //documented by Microsoft but not supported in the Platform SDK
+ // case EC_BANDWIDTHCHANGE : qDebug() << "EC_BANDWIDTHCHANGE: not supported"; break;
+ // case EC_CONTENTPROPERTY_CHANGED: qDebug() << "EC_CONTENTPROPERTY_CHANGED: not supported."; break;
+ // case EC_EOS_SOON: qDebug() << "EC_EOS_SOON: not supported"; break;
+ // case EC_ERRORABORTEX: qDebug() << "EC_ERRORABORTEX: An operation was aborted because of an error."; break;
+ // case EC_FILE_CLOSED: qDebug() << "EC_FILE_CLOSED: The source file was closed because of an unexpected event."; break;
+ // case EC_LOADSTATUS: qDebug() << "EC_LOADSTATUS: Notifies the application of progress when opening a network file."; break;
+ // case EC_MARKER_HIT: qDebug() << "EC_MARKER_HIT: not supported."; break;
+ // case EC_NEW_PIN: qDebug() << "EC_NEW_PIN: not supported."; break;
+ // case EC_PLEASE_REOPEN: qDebug() << "EC_PLEASE_REOPEN: The source file has changed."; break;
+ // case EC_PROCESSING_LATENCY: qDebug() << "EC_PROCESSING_LATENCY: Indicates the amount of time that a component is taking to process each sample."; break;
+ // case EC_RENDER_FINISHED: qDebug() << "EC_RENDER_FINISHED: Not supported."; break;
+ // case EC_SAMPLE_LATENCY: qDebug() << "EC_SAMPLE_LATENCY: Specifies how far behind schedule a component is for processing samples."; break;
+ // case EC_SAMPLE_NEEDED: qDebug() << "EC_SAMPLE_NEEDED: Requests a new input sample from the Enhanced Video Renderer (EVR) filter."; break;
+ // case EC_SCRUB_TIME: qDebug() << "EC_SCRUB_TIME: Specifies the time stamp for the most recent frame step."; break;
+ // case EC_STATUS: qDebug() << "EC_STATUS: Contains two arbitrary status strings."; break;
+ // case EC_VIDEOFRAMEREADY: qDebug() << "EC_VIDEOFRAMEREADY: A video frame is ready for display."; break;
+
+ default:
+ qDebug() << "Unknown event" << eventCode << "(" << param1 << ")";
+ break;
+#else
+ default:
+ break;
+#endif
+ }
+ }
+
+
+#ifndef QT_NO_PHONON_MEDIACONTROLLER
+ //interface management
+ bool MediaObject::hasInterface(Interface iface) const
+ {
+ return iface == AddonInterface::TitleInterface;
+ }
+
+ QVariant MediaObject::interfaceCall(Interface iface, int command, const QList<QVariant> &params)
+ {
+ if (hasInterface(iface)) {
+
+ switch (iface)
+ {
+ case TitleInterface:
+ switch (command)
+ {
+ case availableTitles:
+ return _iface_availableTitles();
+ case title:
+ return _iface_currentTitle();
+ case setTitle:
+ _iface_setCurrentTitle(params.first().toInt());
+ break;
+ case autoplayTitles:
+ return m_autoplayTitles;
+ case setAutoplayTitles:
+ m_autoplayTitles = params.first().toBool();
+ updateStopPosition();
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ return QVariant();
+ }
+
+
+ //TitleInterface
+
+ //this is called to set the time for the different titles
+ qint64 MediaObject::titleAbsolutePosition(int title) const
+ {
+ if (title >= 0 && title < m_titles.count()) {
+ return m_titles.at(title);
+ } else {
+ return 0;
+ }
+ }
+
+ void MediaObject::setTitles(const QList<qint64> &titles)
+ {
+ //this is called when the source is loaded
+ const bool emitSignal = m_titles.count() != titles.count();
+ m_titles = titles;
+ if (emitSignal) {
+ emit availableTitlesChanged(titles.count());
+ }
+ updateStopPosition();
+ }
+
+
+ int MediaObject::_iface_availableTitles() const
+ {
+ return m_titles.count() - 1;
+ }
+
+ int MediaObject::_iface_currentTitle() const
+ {
+ return m_currentTitle;
+ }
+
+ void MediaObject::_iface_setCurrentTitle(int title, bool bseek)
+ {
+#ifdef GRAPH_DEBUG
+ qDebug() << "_iface_setCurrentTitle" << title;
+#endif
+ const int oldTitle = m_currentTitle;
+ m_currentTitle = title;
+ updateStopPosition();
+ if (bseek) {
+ //let's seek to the beginning of the song
+ seek(0);
+ } else {
+ updateTargetTick();
+ }
+ if (oldTitle != title) {
+ emit titleChanged(title);
+ emit totalTimeChanged(totalTime());
+ }
+
+ }
+
+ void MediaObject::updateStopPosition()
+ {
+ if (!m_autoplayTitles && m_currentTitle < _iface_availableTitles() - 1) {
+ //stop position is set to the end of the track
+ currentGraph()->setStopPosition(titleAbsolutePosition(m_currentTitle+1));
+ } else {
+ //stop position is set to the end
+ currentGraph()->setStopPosition(-1);
+ }
+ }
+#endif //QT_NO_PHONON_QT_NO_PHONON_MEDIACONTROLLER
+
+ void MediaObject::switchFilters(int index, Filter oldFilter, Filter newFilter)
+ {
+ if (currentGraph()->index() == index) {
+ currentGraph()->switchFilters(oldFilter, newFilter);
+ } else {
+ nextGraph()->switchFilters(oldFilter, newFilter);
+ }
+
+ }
+
+
+ }
+}
+
+QT_END_NAMESPACE
+
+#include "moc_mediaobject.cpp"
diff --git a/src/3rdparty/phonon/ds9/mediaobject.h b/src/3rdparty/phonon/ds9/mediaobject.h
new file mode 100644
index 0000000000..2c34ffc35b
--- /dev/null
+++ b/src/3rdparty/phonon/ds9/mediaobject.h
@@ -0,0 +1,313 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library 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, either version 2.1 or 3 of the License.
+
+This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef PHONON_MEDIAOBJECT_H
+#define PHONON_MEDIAOBJECT_H
+
+#include <phonon/mediaobjectinterface.h>
+#include <phonon/addoninterface.h>
+
+#include <QtCore/QHash>
+#include <QtCore/QObject>
+#include <QtCore/QQueue>
+#include <QtCore/QBasicTimer>
+#include <QtCore/QMutex>
+#include <QtCore/QThread>
+
+#include "backendnode.h"
+#include "mediagraph.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+ class MediaSource;
+
+ namespace DS9
+ {
+ class VideoWidget;
+ class AudioOutput;
+
+ class QWinWaitCondition
+ {
+ public:
+ QWinWaitCondition() : m_handle(::CreateEvent(0,0,0,0))
+ {
+ }
+
+ ~QWinWaitCondition()
+ {
+ ::CloseHandle(m_handle);
+ }
+
+ void reset()
+ {
+ //will block
+ ::ResetEvent(m_handle);
+ }
+
+ void set()
+ {
+ //will unblock
+ ::SetEvent(m_handle);
+ }
+
+ operator HANDLE()
+ {
+ return m_handle;
+ }
+
+ operator HEVENT()
+ {
+ return reinterpret_cast<HEVENT>(m_handle);
+ }
+
+
+ private:
+ HANDLE m_handle;
+ };
+
+ class WorkerThread : public QThread
+ {
+ Q_OBJECT
+ public:
+ WorkerThread();
+ ~WorkerThread();
+
+ virtual void run();
+
+ //wants to know as soon as the state is set
+ void addStateChangeRequest(Graph graph, OAFilterState, QList<Filter> = QList<Filter>());
+
+ quint16 addSeekRequest(Graph graph, qint64 time);
+ quint16 addUrlToRender(const QString &url);
+ quint16 addFilterToRender(const Filter &filter);
+
+ void replaceGraphForEventManagement(Graph newGraph, Graph oldGraph);
+
+ void abortCurrentRender(qint16 renderId);
+
+ //tells the thread to stop processing
+ void signalStop();
+
+ Q_SIGNALS:
+ void asyncRenderFinished(quint16, HRESULT, Graph);
+ void asyncSeekingFinished(quint16, qint64);
+ void stateReady(Graph, Phonon::State);
+ void eventReady(Graph, long eventCode, long param1);
+
+ private:
+
+ enum Task
+ {
+ Render,
+ Seek,
+ ChangeState,
+ ReplaceGraph //just updates recalls WaitForMultipleObject
+ };
+
+ struct Work
+ {
+ Task task;
+ quint16 id;
+ Graph graph;
+ Graph oldGraph;
+ Filter filter;
+ QString url;
+ union
+ {
+ qint64 time;
+ OAFilterState state;
+ };
+ QList<Filter> decoders; //for the state change requests
+ };
+ Work dequeueWork();
+ void handleTask();
+
+ Graph m_currentRender;
+ qint16 m_currentRenderId;
+ QQueue<Work> m_queue;
+ bool m_finished;
+ quint16 m_currentWorkId;
+ QWinWaitCondition m_waitCondition;
+ QMutex m_mutex;
+
+ //this is for WaitForMultipleObjects
+ struct
+ {
+ Graph graph;
+ HANDLE handle;
+ } m_graphHandle[FILTER_COUNT];
+ };
+
+
+ class MediaObject : public BackendNode, public Phonon::MediaObjectInterface
+#ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ , public Phonon::AddonInterface
+#endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ {
+ friend class Stream;
+ Q_OBJECT
+ Q_INTERFACES(Phonon::MediaObjectInterface
+#ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ Phonon::AddonInterface
+#endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ )
+ public:
+ MediaObject(QObject *parent);
+ ~MediaObject();
+ Phonon::State state() const;
+ bool hasVideo() const;
+ bool isSeekable() const;
+ qint64 currentTime() const;
+ qint32 tickInterval() const;
+
+ void setTickInterval(qint32 newTickInterval);
+ void play();
+ void pause();
+ void stop();
+ void ensureStopped();
+ void seek(qint64 time);
+
+ QString errorString() const;
+ Phonon::ErrorType errorType() const;
+
+#ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ bool hasInterface(Interface) const;
+ QVariant interfaceCall(Interface iface, int command, const QList<QVariant> &params);
+#endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
+
+ qint64 totalTime() const;
+ qint32 prefinishMark() const;
+ void setPrefinishMark(qint32 newPrefinishMark);
+
+ qint32 transitionTime() const;
+ void setTransitionTime(qint32);
+
+ qint64 remainingTime() const;
+
+ MediaSource source() const;
+ void setSource(const MediaSource &source);
+ void setNextSource(const MediaSource &source);
+
+
+ //COM error management
+ bool catchComError(HRESULT hr);
+
+ void grabNode(BackendNode *node);
+ bool connectNodes(BackendNode *source, BackendNode *sink);
+ bool disconnectNodes(BackendNode *source, BackendNode *sink);
+
+ void switchFilters(int index, Filter oldFilter, Filter newFilter);
+
+ WorkerThread *workerThread();
+ void loadingFinished(MediaGraph *mg);
+ void seekingFinished(MediaGraph *mg);
+ MediaGraph *currentGraph() const;
+
+ //this is used by the backend only
+ Phonon::State transactionState;
+
+ private Q_SLOTS:
+ void switchToNextSource();
+ void slotStateReady(Graph, Phonon::State);
+ void handleEvents(Graph, long eventCode, long param1);
+ void finishLoading(quint16 workId, HRESULT hr, Graph);
+ void finishSeeking(quint16 workId, qint64 time);
+
+ Q_SIGNALS:
+ void stateChanged(Phonon::State newstate, Phonon::State oldstate);
+ void tick(qint64 time);
+ void metaDataChanged(QMultiMap<QString, QString>);
+ void seekableChanged(bool);
+ void hasVideoChanged(bool);
+ void bufferStatus(int);
+
+ // AddonInterface:
+ void titleChanged(int);
+ void availableTitlesChanged(int);
+ void chapterChanged(int);
+ void availableChaptersChanged(int);
+ void angleChanged(int);
+ void availableAnglesChanged(int);
+
+ void finished();
+ void prefinishMarkReached(qint32);
+ void aboutToFinish();
+ void totalTimeChanged(qint64 length) const;
+ void currentSourceChanged(const MediaSource &);
+
+ protected:
+ void setState(Phonon::State);
+ void timerEvent(QTimerEvent *e);
+
+ private:
+#ifndef QT_NO_PHONON_VIDEO
+ void updateVideoGeometry();
+#endif // QT_NO_PHONON_VIDEO
+ void handleComplete(IGraphBuilder *graph);
+ MediaGraph *nextGraph() const;
+
+ void updateTargetTick();
+ void updateStopPosition();
+
+ mutable QString m_errorString;
+ mutable Phonon::ErrorType m_errorType;
+
+ Phonon::State m_state;
+ Phonon::State m_nextState;
+ qint32 m_transitionTime;
+
+ qint32 m_prefinishMark;
+
+ QBasicTimer m_tickTimer;
+ qint32 m_tickInterval;
+
+ //the graph(s)
+ MediaGraph* m_graphs[FILTER_COUNT];
+
+ //...the videowidgets in the graph
+ QList<VideoWidget*> m_videoWidgets;
+ QList<AudioOutput*> m_audioOutputs;
+
+ bool m_buffering:1;
+ bool m_oldHasVideo:1;
+ bool m_prefinishMarkSent:1;
+ bool m_aboutToFinishSent:1;
+ bool m_nextSourceReadyToStart:1;
+
+ //for TitleInterface (and commands)
+#ifndef QT_NO_PHONON_MEDIACONTROLLER
+ bool m_autoplayTitles:1;
+ QList<qint64> m_titles;
+ int m_currentTitle;
+ int _iface_availableTitles() const;
+ int _iface_currentTitle() const;
+ void _iface_setCurrentTitle(int title, bool bseek = true);
+ void setTitles(const QList<qint64> &titles);
+ qint64 titleAbsolutePosition(int title) const;
+#endif //QT_NO_PHONON_MEDIACONTROLLER
+ qint64 m_targetTick;
+
+ WorkerThread m_thread;
+ };
+ }
+}
+
+QT_END_NAMESPACE
+
+#endif // PHONON_MEDIAOBJECT_H
diff --git a/src/3rdparty/phonon/ds9/phononds9_namespace.h b/src/3rdparty/phonon/ds9/phononds9_namespace.h
new file mode 100644
index 0000000000..e972d41f4a
--- /dev/null
+++ b/src/3rdparty/phonon/ds9/phononds9_namespace.h
@@ -0,0 +1,33 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library 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, either version 2.1 or 3 of the License.
+
+This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef PHONON_DS9_NAMESPACE_H
+#define PHONON_DS9_NAMESPACE_H
+
+#include <QtCore/qnamespace.h>
+
+#define FILTER_COUNT 2 //number of ds9 filters per object
+
+#ifndef QT_BEGIN_NAMESPACE
+#define QT_BEGIN_NAMESPACE
+#endif
+
+#ifndef QT_END_NAMESPACE
+#define QT_END_NAMESPACE
+#endif
+
+#endif
diff --git a/src/3rdparty/phonon/ds9/qasyncreader.cpp b/src/3rdparty/phonon/ds9/qasyncreader.cpp
new file mode 100644
index 0000000000..68ec1f8d1c
--- /dev/null
+++ b/src/3rdparty/phonon/ds9/qasyncreader.cpp
@@ -0,0 +1,198 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library 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, either version 2.1 or 3 of the License.
+
+This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <QtCore/QFile>
+
+#include "qasyncreader.h"
+#include "qbasefilter.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+ namespace DS9
+ {
+ QAsyncReader::QAsyncReader(QBaseFilter *parent, const QVector<AM_MEDIA_TYPE> &mediaTypes) : QPin(parent, PINDIR_OUTPUT, mediaTypes)
+ {
+ }
+
+ QAsyncReader::~QAsyncReader()
+ {
+ }
+
+ STDMETHODIMP QAsyncReader::QueryInterface(REFIID iid, void **out)
+ {
+ if (!out) {
+ return E_POINTER;
+ }
+
+ if (iid == IID_IAsyncReader) {
+ AddRef();
+ *out = static_cast<IAsyncReader*>(this);
+ return S_OK;
+ }
+
+ return QPin::QueryInterface(iid, out);
+ }
+
+ STDMETHODIMP_(ULONG) QAsyncReader::AddRef()
+ {
+ return QPin::AddRef();
+ }
+
+ STDMETHODIMP_(ULONG) QAsyncReader::Release()
+ {
+ return QPin::Release();
+ }
+
+
+ STDMETHODIMP QAsyncReader::RequestAllocator(IMemAllocator *preferred, ALLOCATOR_PROPERTIES *prop,IMemAllocator **actual)
+ {
+ ALLOCATOR_PROPERTIES prop2;
+
+ if (prop->cbAlign == 0) {
+ prop->cbAlign = 1; //align on 1 char
+ }
+
+ if (preferred && preferred->SetProperties(prop, &prop2) == S_OK) {
+ preferred->AddRef();
+ *actual = preferred;
+ return S_OK;
+ }
+
+ //we should try to create one memory allocator ourselves here
+ return E_FAIL;
+ }
+
+ STDMETHODIMP QAsyncReader::Request(IMediaSample *sample,DWORD_PTR user)
+ {
+ QMutexLocker mutexLocker(&m_mutexWait);
+ QWriteLocker locker(&m_lock);
+ if (m_flushing) {
+ return VFW_E_WRONG_STATE;
+ }
+
+ m_requestQueue.enqueue(AsyncRequest(sample, user));
+ m_requestWait.wakeOne();
+ return S_OK;
+ }
+
+ STDMETHODIMP QAsyncReader::WaitForNext(DWORD timeout, IMediaSample **sample, DWORD_PTR *user)
+ {
+ QMutexLocker locker(&m_mutexWait);
+ if (!sample ||!user) {
+ return E_POINTER;
+ }
+
+ *sample = 0;
+ *user = 0;
+
+ AsyncRequest r = getNextRequest();
+
+ if (r.sample == 0) {
+ //there is no request in the queue
+ if (isFlushing()) {
+ return VFW_E_WRONG_STATE;
+ } else {
+ //First we need to lock the mutex
+ if (m_requestWait.wait(&m_mutexWait, timeout) == false) {
+ return VFW_E_TIMEOUT;
+ }
+ if (isFlushing()) {
+ return VFW_E_WRONG_STATE;
+ }
+
+ r = getNextRequest();
+ }
+ }
+
+ //at this point we're sure to have a request to proceed
+ if (r.sample == 0) {
+ return E_FAIL;
+ }
+
+ *sample = r.sample;
+ *user = r.user;
+
+ return SyncReadAligned(r.sample);
+ }
+
+ STDMETHODIMP QAsyncReader::BeginFlush()
+ {
+ QMutexLocker mutexLocker(&m_mutexWait);
+ QWriteLocker locker(&m_lock);
+ m_flushing = true;
+ m_requestWait.wakeOne();
+ return S_OK;
+ }
+
+ STDMETHODIMP QAsyncReader::EndFlush()
+ {
+ QWriteLocker locker(&m_lock);
+ m_flushing = false;
+ return S_OK;
+ }
+
+ STDMETHODIMP QAsyncReader::SyncReadAligned(IMediaSample *sample)
+ {
+ if (!sample) {
+ return E_POINTER;
+ }
+
+ REFERENCE_TIME start = 0,
+ stop = 0;
+ HRESULT hr = sample->GetTime(&start, &stop);
+ if(FAILED(hr)) {
+ return hr;
+ }
+
+ LONGLONG startPos = start / 10000000;
+ LONG length = static_cast<LONG>((stop - start) / 10000000);
+
+ BYTE *buffer;
+ hr = sample->GetPointer(&buffer);
+ if(FAILED(hr)) {
+ return hr;
+ }
+
+ LONG actual = 0;
+ read(startPos, length, buffer, &actual);
+
+ return sample->SetActualDataLength(actual);
+ }
+
+ STDMETHODIMP QAsyncReader::SyncRead(LONGLONG pos, LONG length, BYTE *buffer)
+ {
+ return read(pos, length, buffer, 0);
+ }
+
+
+ //addition
+ QAsyncReader::AsyncRequest QAsyncReader::getNextRequest()
+ {
+ QWriteLocker locker(&m_lock);
+ AsyncRequest ret;
+ if (!m_requestQueue.isEmpty()) {
+ ret = m_requestQueue.dequeue();
+ }
+
+ return ret;
+ }
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/3rdparty/phonon/ds9/qasyncreader.h b/src/3rdparty/phonon/ds9/qasyncreader.h
new file mode 100644
index 0000000000..cb789ee7d4
--- /dev/null
+++ b/src/3rdparty/phonon/ds9/qasyncreader.h
@@ -0,0 +1,77 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library 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, either version 2.1 or 3 of the License.
+
+This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef PHONON_QASYNCREADER_H
+#define PHONON_QASYNCREADER_H
+
+#include <QtCore/QWaitCondition>
+#include <QtCore/QQueue>
+#include <QtCore/QMutex>
+
+#include "qpin.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+ namespace DS9
+ {
+ //his class reads asynchronously from a QIODevice
+ class QAsyncReader : public QPin, public IAsyncReader
+ {
+ public:
+ QAsyncReader(QBaseFilter *, const QVector<AM_MEDIA_TYPE> &mediaTypes);
+ ~QAsyncReader();
+
+ //reimplementation from IUnknown
+ STDMETHODIMP QueryInterface(REFIID iid, void** out);
+ STDMETHODIMP_(ULONG) AddRef();
+ STDMETHODIMP_(ULONG) Release();
+
+ //reimplementation from IAsyncReader
+ STDMETHODIMP RequestAllocator(IMemAllocator *,ALLOCATOR_PROPERTIES *,IMemAllocator **);
+ STDMETHODIMP Request(IMediaSample *,DWORD_PTR);
+ STDMETHODIMP WaitForNext(DWORD,IMediaSample **,DWORD_PTR *);
+ STDMETHODIMP SyncReadAligned(IMediaSample *);
+ STDMETHODIMP SyncRead(LONGLONG,LONG,BYTE *);
+ virtual STDMETHODIMP Length(LONGLONG *,LONGLONG *) = 0;
+ STDMETHODIMP BeginFlush();
+ STDMETHODIMP EndFlush();
+
+ protected:
+ virtual HRESULT read(LONGLONG pos, LONG length, BYTE *buffer, LONG *actual) = 0;
+
+ private:
+ struct AsyncRequest
+ {
+ AsyncRequest(IMediaSample *s = 0, DWORD_PTR u = 0) : sample(s), user(u) {}
+ IMediaSample *sample;
+ DWORD_PTR user;
+ };
+ AsyncRequest getNextRequest();
+
+ QMutex m_mutexWait;
+
+ QQueue<AsyncRequest> m_requestQueue;
+ QWaitCondition m_requestWait;
+ };
+ }
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/3rdparty/phonon/ds9/qaudiocdreader.cpp b/src/3rdparty/phonon/ds9/qaudiocdreader.cpp
new file mode 100644
index 0000000000..b9f9fd68b2
--- /dev/null
+++ b/src/3rdparty/phonon/ds9/qaudiocdreader.cpp
@@ -0,0 +1,332 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library 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, either version 2.1 or 3 of the License.
+
+This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "qaudiocdreader.h"
+#include <dshow.h>
+#include <initguid.h>
+
+#include <winioctl.h> // needed for FILE_DEVICE_CD_ROM etc
+
+#define IOCTL_CDROM_READ_TOC CTL_CODE(FILE_DEVICE_CD_ROM, 0x0000, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_CDROM_RAW_READ CTL_CODE(FILE_DEVICE_CD_ROM, 0x000F, METHOD_OUT_DIRECT, FILE_READ_ACCESS)
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_PHONON_MEDIACONTROLLER
+
+namespace Phonon
+{
+ namespace DS9
+ {
+ // {CA46BFE1-D55B-4adf-B803-BC2B9AD57824}
+ DEFINE_GUID(IID_ITitleInterface,
+ 0xca46bfe1, 0xd55b, 0x4adf, 0xb8, 0x3, 0xbc, 0x2b, 0x9a, 0xd5, 0x78, 0x24);
+
+ struct TRACK_DATA {
+ UCHAR Reserved;
+ UCHAR Control : 4;
+ UCHAR Adr : 4;
+ UCHAR TrackNumber;
+ UCHAR Reserved1;
+ UCHAR Address[4];
+ };
+
+ struct CDROM_TOC {
+ UCHAR Length[2];
+ UCHAR FirstTrack;
+ UCHAR LastTrack;
+ TRACK_DATA TrackData[100];
+ };
+
+ struct WaveStructure
+ {
+ WaveStructure();
+
+ char riff[4];
+ qint32 chunksize;
+ char wave[4];
+ char fmt[4];
+ const qint32 chunksize2;
+ const quint16 formatTag;
+ const quint16 nChannels;
+ const quint32 nSamplesPerSec;
+ const quint32 nAvgBytesPerSec;
+ const quint16 nBlockAlign;
+ const quint16 bitsPerSample;
+ char data[4];
+ qint32 dataLength;
+ };
+
+ enum TRACK_MODE_TYPE {
+ YellowMode2,
+ XAForm2,
+ CDDA
+ };
+
+
+ struct RAW_READ_INFO {
+ LARGE_INTEGER DiskOffset;
+ ULONG SectorCount;
+ TRACK_MODE_TYPE TrackMode;
+ };
+
+ class QAudioCDReader : public QAsyncReader, public ITitleInterface
+ {
+ public:
+ QAudioCDReader(QBaseFilter *parent, QChar drive = QChar());
+ ~QAudioCDReader();
+
+ //reimplementation from IUnknown
+ STDMETHODIMP_(ULONG) AddRef();
+ STDMETHODIMP_(ULONG) Release();
+
+ STDMETHODIMP Length(LONGLONG *,LONGLONG *);
+ STDMETHODIMP QueryInterface(REFIID iid, void** out);
+ QList<qint64> titles() const;
+
+ protected:
+ HRESULT read(LONGLONG pos, LONG length, BYTE *buffer, LONG *actual);
+
+ private:
+ HANDLE m_cddrive;
+ CDROM_TOC *m_toc;
+ WaveStructure *m_waveHeader;
+ qint64 m_trackAddress;
+ };
+
+
+#define SECTOR_SIZE 2352
+#define NB_SECTORS_READ 20
+
+ static AM_MEDIA_TYPE getAudioCDMediaType()
+ {
+ AM_MEDIA_TYPE mt;
+ qMemSet(&mt, 0, sizeof(AM_MEDIA_TYPE));
+ mt.majortype = MEDIATYPE_Stream;
+ mt.subtype = MEDIASUBTYPE_WAVE;
+ mt.bFixedSizeSamples = TRUE;
+ mt.bTemporalCompression = FALSE;
+ mt.lSampleSize = 1;
+ mt.formattype = GUID_NULL;
+ return mt;
+ }
+
+ int addressToSectors(UCHAR address[4])
+ {
+ return ((address[0] * 60 + address[1]) * 60 + address[2]) * 75 + address[3] - 150;
+ }
+
+ WaveStructure::WaveStructure() : chunksize(0), chunksize2(16),
+ formatTag(WAVE_FORMAT_PCM), nChannels(2), nSamplesPerSec(44100), nAvgBytesPerSec(176400), nBlockAlign(4), bitsPerSample(16),
+ dataLength(0)
+ {
+ qMemCopy(riff, "RIFF", 4);
+ qMemCopy(wave, "WAVE", 4);
+ qMemCopy(fmt, "fmt ", 4);
+ qMemCopy(data, "data", 4);
+ }
+
+
+ QAudioCDReader::QAudioCDReader(QBaseFilter *parent, QChar drive) : QAsyncReader(parent, QVector<AM_MEDIA_TYPE>() << getAudioCDMediaType())
+ {
+ m_toc = new CDROM_TOC;
+ m_waveHeader = new WaveStructure;
+
+ //now open the cd-drive
+ QString path;
+ if (drive.isNull()) {
+ path = QString::fromLatin1("\\\\.\\Cdrom0");
+ } else {
+ path = QString::fromLatin1("\\\\.\\%1:").arg(drive);
+ }
+
+ m_cddrive = QT_WA_INLINE (
+ ::CreateFile( (TCHAR*)path.utf16(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL ),
+ ::CreateFileA( path.toLocal8Bit().constData(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL )
+ );
+
+ qMemSet(m_toc, 0, sizeof(CDROM_TOC));
+ //read the TOC
+ DWORD bytesRead = 0;
+ bool tocRead = ::DeviceIoControl(m_cddrive, IOCTL_CDROM_READ_TOC, 0, 0, m_toc, sizeof(CDROM_TOC), &bytesRead, 0);
+
+ if (!tocRead) {
+ qWarning("unable to load the TOC from the CD");
+ return;
+ }
+
+ m_trackAddress = addressToSectors(m_toc->TrackData[0].Address);
+ const qint32 nbSectorsToRead = (addressToSectors(m_toc->TrackData[m_toc->LastTrack + 1 - m_toc->FirstTrack].Address)
+ - m_trackAddress);
+ const qint32 dataLength = nbSectorsToRead * SECTOR_SIZE;
+
+ m_waveHeader->chunksize = 4 + (8 + m_waveHeader->chunksize2) + (8 + dataLength);
+ m_waveHeader->dataLength = dataLength;
+ }
+
+ QAudioCDReader::~QAudioCDReader()
+ {
+ ::CloseHandle(m_cddrive);
+ delete m_toc;
+ delete m_waveHeader;
+
+ }
+
+ STDMETHODIMP_(ULONG) QAudioCDReader::AddRef()
+ {
+ return QAsyncReader::AddRef();
+ }
+
+ STDMETHODIMP_(ULONG) QAudioCDReader::Release()
+ {
+ return QAsyncReader::Release();
+ }
+
+
+ STDMETHODIMP QAudioCDReader::Length(LONGLONG *total,LONGLONG *available)
+ {
+ const LONGLONG length = sizeof(WaveStructure) + m_waveHeader->dataLength;
+ if (total) {
+ *total = length;
+ }
+ if (available) {
+ *available = length;
+ }
+
+ return S_OK;
+ }
+
+ STDMETHODIMP QAudioCDReader::QueryInterface(REFIID iid, void** out)
+ {
+ if (!out) {
+ return E_POINTER;
+ }
+
+ if (iid == IID_ITitleInterface) {
+ //we reroute that to the pin
+ *out = static_cast<ITitleInterface*>(this);
+ AddRef();
+ return S_OK;
+ } else {
+ return QAsyncReader::QueryInterface(iid, out);
+ }
+ }
+
+
+ HRESULT QAudioCDReader::read(LONGLONG pos, LONG length, BYTE *buffer, LONG *actual)
+ {
+ LONG nbRead = 0;
+
+ if (actual) {
+ *actual = 0;
+ }
+
+ if (pos < sizeof(WaveStructure)) {
+ //we first copy the content of the structure
+ nbRead = qMin(LONG(sizeof(WaveStructure) - pos), length);
+ qMemCopy(buffer, reinterpret_cast<char*>(m_waveHeader) + pos, nbRead);
+ }
+
+ const LONGLONG posInTrack = pos - sizeof(WaveStructure) + nbRead;
+ const int bytesLeft = qMin(m_waveHeader->dataLength - posInTrack, LONGLONG(length - nbRead));
+
+ if (bytesLeft > 0) {
+
+ //we need to read again
+
+ const int surplus = posInTrack % SECTOR_SIZE; //how many bytes too much at the beginning
+ const int firstSector = posInTrack / SECTOR_SIZE,
+ lastSector = (posInTrack + length - 1) / SECTOR_SIZE;
+ const int sectorsNeeded = lastSector - firstSector + 1;
+ int sectorsRead = 0;
+
+ QByteArray ba(sectorsNeeded * SECTOR_SIZE, 0);
+
+
+ RAW_READ_INFO ReadInfo;
+ ReadInfo.TrackMode = CDDA; // Always use CDDA (numerical: 2)
+ ReadInfo.DiskOffset.QuadPart = (m_trackAddress + firstSector) * 2048;
+ ReadInfo.SectorCount = qMin(sectorsNeeded - sectorsRead, NB_SECTORS_READ);
+ while (ReadInfo.SectorCount) {
+ DWORD dummy = 0;
+ if (::DeviceIoControl( m_cddrive, IOCTL_CDROM_RAW_READ,
+ &ReadInfo, sizeof(ReadInfo),
+ ba.data() + sectorsRead * SECTOR_SIZE,
+ ReadInfo.SectorCount * SECTOR_SIZE,
+ &dummy, NULL ) )
+ {
+ ReadInfo.DiskOffset.QuadPart += ReadInfo.SectorCount * 2048;
+ sectorsRead += ReadInfo.SectorCount;
+ ReadInfo.SectorCount = qMin(sectorsNeeded - sectorsRead, NB_SECTORS_READ);
+ }else {
+ qWarning("an error occurred while reading from the media");
+ return S_FALSE;
+ }
+
+ }
+
+ //consume bytes on the buffer
+ qMemCopy(buffer + nbRead, ba.data() + surplus, bytesLeft);
+
+ //at this point we have all we need in the buffer
+ nbRead += bytesLeft;
+ }
+
+ if (actual) {
+ *actual = nbRead;
+ }
+
+ return nbRead == length ? S_OK : S_FALSE;
+ }
+
+ QList<qint64> QAudioCDReader::titles() const
+ {
+ QList<qint64> ret;
+ ret << 0;
+ for(int i = m_toc->FirstTrack; i <= m_toc->LastTrack ; ++i) {
+ const uchar *address = m_toc->TrackData[i].Address;
+ ret << ((address[0] * 60 + address[1]) * 60 + address[2]) * 1000 + address[3]*1000/75 - 2000;
+
+ }
+ return ret;
+ }
+
+
+ QAudioCDPlayer::QAudioCDPlayer() : QBaseFilter(CLSID_NULL)
+ {
+ new QAudioCDReader(this);
+ }
+
+ QAudioCDPlayer::~QAudioCDPlayer()
+ {
+ }
+
+ STDMETHODIMP QAudioCDPlayer::QueryInterface(REFIID iid, void** out)
+ {
+ if (iid == IID_ITitleInterface) {
+ //we reroute that to the pin
+ return pins().first()->QueryInterface(iid, out);
+ } else {
+ return QBaseFilter::QueryInterface(iid, out);
+ }
+ }
+ }
+}
+
+#endif //QT_NO_PHONON_MEDIACONTROLLER
+
+QT_END_NAMESPACE
diff --git a/src/3rdparty/phonon/ds9/qaudiocdreader.h b/src/3rdparty/phonon/ds9/qaudiocdreader.h
new file mode 100644
index 0000000000..eff845dfe6
--- /dev/null
+++ b/src/3rdparty/phonon/ds9/qaudiocdreader.h
@@ -0,0 +1,58 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library 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, either version 2.1 or 3 of the License.
+
+This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef PHONON_QAUDIOCDREADER_H
+#define PHONON_QAUDIOCDREADER_H
+
+#include "qasyncreader.h"
+#include "qbasefilter.h"
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_PHONON_MEDIACONTROLLER
+
+namespace Phonon
+{
+ namespace DS9
+ {
+ struct CDROM_TOC;
+ struct WaveStructure;
+ EXTERN_C const IID IID_ITitleInterface;
+
+ //interface for the Titles
+ struct ITitleInterface : public IUnknown
+ {
+ virtual QList<qint64> titles() const = 0;
+ };
+
+
+ class QAudioCDPlayer : public QBaseFilter
+ {
+ public:
+ QAudioCDPlayer();
+ ~QAudioCDPlayer();
+ STDMETHODIMP QueryInterface(REFIID iid, void** out);
+ };
+
+ }
+}
+
+#endif //QT_NO_PHONON_MEDIACONTROLLER
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/3rdparty/phonon/ds9/qbasefilter.cpp b/src/3rdparty/phonon/ds9/qbasefilter.cpp
new file mode 100644
index 0000000000..95cab92f84
--- /dev/null
+++ b/src/3rdparty/phonon/ds9/qbasefilter.cpp
@@ -0,0 +1,831 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library 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, either version 2.1 or 3 of the License.
+
+This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "qbasefilter.h"
+#include "qpin.h"
+
+#include <QtCore/QMutex>
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+ namespace DS9
+ {
+
+ class QEnumPins : public IEnumPins
+ {
+ public:
+ QEnumPins(QBaseFilter *filter) : m_refCount(1),
+ m_filter(filter), m_pins(filter->pins()), m_index(0)
+ {
+ m_filter->AddRef();
+ }
+
+ virtual ~QEnumPins()
+ {
+ m_filter->Release();
+ }
+
+ STDMETHODIMP QueryInterface(const IID &iid,void **out)
+ {
+ if (!out) {
+ return E_POINTER;
+ }
+
+ HRESULT hr = S_OK;
+ if (iid == IID_IEnumPins) {
+ *out = static_cast<IEnumPins*>(this);
+ } else if (iid == IID_IUnknown) {
+ *out = static_cast<IUnknown*>(this);
+ } else {
+ *out = 0;
+ hr = E_NOINTERFACE;
+ }
+
+ if (S_OK)
+ AddRef();
+ return hr;
+ }
+
+ STDMETHODIMP_(ULONG) AddRef()
+ {
+ return InterlockedIncrement(&m_refCount);
+ }
+
+ STDMETHODIMP_(ULONG) Release()
+ {
+ ULONG refCount = InterlockedDecrement(&m_refCount);
+ if (refCount == 0) {
+ delete this;
+ }
+
+ return refCount;
+ }
+
+ STDMETHODIMP Next(ULONG count,IPin **ret,ULONG *fetched)
+ {
+ QMutexLocker locker(&m_mutex);
+ if (m_filter->pins() != m_pins) {
+ return VFW_E_ENUM_OUT_OF_SYNC;
+ }
+
+ if (fetched == 0 && count > 1) {
+ return E_INVALIDARG;
+ }
+
+ if (!ret) {
+ return E_POINTER;
+ }
+
+ int nbfetched = 0;
+ while (nbfetched < int(count) && m_index < m_pins.count()) {
+ IPin *current = m_pins[m_index];
+ current->AddRef();
+ ret[nbfetched] = current;
+ nbfetched++;
+ m_index++;
+ }
+
+ if (fetched) {
+ *fetched = nbfetched;
+ }
+
+ return nbfetched == count ? S_OK : S_FALSE;
+ }
+
+ STDMETHODIMP Skip(ULONG count)
+ {
+ QMutexLocker locker(&m_mutex);
+ if (m_filter->pins() != m_pins) {
+ return VFW_E_ENUM_OUT_OF_SYNC;
+ }
+
+ m_index = qMin(m_index + int(count), m_pins.count());
+ return m_index == m_pins.count() ? S_FALSE : S_OK;
+ }
+
+ STDMETHODIMP Reset()
+ {
+ QMutexLocker locker(&m_mutex);
+ m_index = 0;
+ return S_OK;
+ }
+
+ STDMETHODIMP Clone(IEnumPins **out)
+ {
+ QMutexLocker locker(&m_mutex);
+ if (m_filter->pins() != m_pins) {
+ return VFW_E_ENUM_OUT_OF_SYNC;
+ }
+
+ if (!out) {
+ return E_POINTER;
+ }
+
+ *out = new QEnumPins(m_filter);
+ (*out)->Skip(m_index);
+ return S_OK;
+ }
+
+
+ private:
+ LONG m_refCount;
+ QBaseFilter *m_filter;
+ QList<QPin*> m_pins;
+ int m_index;
+ QMutex m_mutex;
+ };
+
+
+ QBaseFilter::QBaseFilter(const CLSID &clsid):
+ m_refCount(1), m_clsid(clsid), m_clock(0), m_graph(0), m_state(State_Stopped)
+ {
+ }
+
+ QBaseFilter::~QBaseFilter()
+ {
+ while (!m_pins.isEmpty()) {
+ delete m_pins.first();
+ }
+ }
+
+ const QList<QPin *> QBaseFilter::pins() const
+ {
+ QReadLocker locker(&m_lock);
+ return m_pins;
+ }
+
+ void QBaseFilter::addPin(QPin *pin)
+ {
+ QWriteLocker locker(&m_lock);
+ m_pins.append(pin);
+ }
+
+ void QBaseFilter::removePin(QPin *pin)
+ {
+ QWriteLocker locker(&m_lock);
+ m_pins.removeAll(pin);
+ }
+
+ FILTER_STATE QBaseFilter::state() const
+ {
+ return m_state;
+ }
+
+ IFilterGraph *QBaseFilter::graph() const
+ {
+ return m_graph;
+ }
+
+ STDMETHODIMP QBaseFilter::QueryInterface(REFIID iid, void **out)
+ {
+ if (!out) {
+ return E_POINTER;
+ }
+
+ HRESULT hr = S_OK;
+
+ if (iid == IID_IBaseFilter) {
+ *out = static_cast<IBaseFilter*>(this);
+ } else if (iid == IID_IMediaFilter) {
+ *out = static_cast<IMediaFilter*>(this);
+ } else if (iid == IID_IPersist) {
+ *out = static_cast<IPersist*>(this);
+ } else if (iid == IID_IUnknown) {
+ *out = static_cast<IUnknown*>(static_cast<IBaseFilter*>(this));
+ }
+ else if (iid == IID_IMediaPosition || iid == IID_IMediaSeeking) {
+ if (inputPins().isEmpty()) {
+ if (*out = getUpStreamInterface(iid)) {
+ return S_OK; //we return here to avoid adding a reference
+ } else {
+ hr = E_NOINTERFACE;
+ }
+ } else if (iid == IID_IMediaSeeking) {
+ *out = static_cast<IMediaSeeking*>(this);
+ } else if (iid == IID_IMediaPosition ||iid == IID_IDispatch) {
+ *out = static_cast<IMediaPosition*>(this);
+ }
+ } else {
+ *out = 0;
+ hr = E_NOINTERFACE;
+ }
+
+ if (hr == S_OK) {
+ AddRef();
+ }
+
+ return hr;
+ }
+
+ STDMETHODIMP_(ULONG) QBaseFilter::AddRef()
+ {
+ return InterlockedIncrement(&m_refCount);
+ }
+
+ STDMETHODIMP_(ULONG) QBaseFilter::Release()
+ {
+ ULONG refCount = InterlockedDecrement(&m_refCount);
+ if (refCount == 0) {
+ delete this;
+ }
+
+ return refCount;
+ }
+
+ STDMETHODIMP QBaseFilter::GetClassID(CLSID *clsid)
+ {
+ QReadLocker locker(&m_lock);
+ *clsid = m_clsid;
+ return S_OK;
+ }
+
+ STDMETHODIMP QBaseFilter::Stop()
+ {
+ QWriteLocker locker(&m_lock);
+ m_state = State_Stopped;
+ return S_OK;
+ }
+
+ STDMETHODIMP QBaseFilter::Pause()
+ {
+ QWriteLocker locker(&m_lock);
+ m_state = State_Paused;
+ return S_OK;
+ }
+
+ STDMETHODIMP QBaseFilter::Run(REFERENCE_TIME)
+ {
+ QWriteLocker locker(&m_lock);
+ m_state = State_Running;
+ return S_OK;
+ }
+
+ STDMETHODIMP QBaseFilter::GetState(DWORD, FILTER_STATE *state)
+ {
+ QReadLocker locker(&m_lock);
+ if (!state) {
+ return E_POINTER;
+ }
+
+ *state = m_state;
+ return S_OK;
+ }
+
+ STDMETHODIMP QBaseFilter::SetSyncSource(IReferenceClock *clock)
+ {
+ QWriteLocker locker(&m_lock);
+ if (clock) {
+ clock->AddRef();
+ }
+ if (m_clock) {
+ m_clock->Release();
+ }
+ m_clock = clock;
+ return S_OK;
+ }
+
+ STDMETHODIMP QBaseFilter::GetSyncSource(IReferenceClock **clock)
+ {
+ QReadLocker locker(&m_lock);
+ if (!clock) {
+ return E_POINTER;
+ }
+
+ if (m_clock) {
+ m_clock->AddRef();
+ }
+
+ *clock = m_clock;
+ return S_OK;
+ }
+
+ STDMETHODIMP QBaseFilter::FindPin(LPCWSTR name, IPin**pin)
+ {
+ if (!pin) {
+ return E_POINTER;
+ }
+
+ for (int i = 0; i < m_pins.count(); ++i) {
+ IPin * current = m_pins.at(i);
+ PIN_INFO info;
+ current->QueryPinInfo(&info);
+ if (info.pFilter) {
+ info.pFilter->Release();
+ }
+ if ( wcscmp(info.achName, name) == 0) {
+ *pin = current;
+ current->AddRef();
+ return S_OK;
+ }
+ }
+
+ *pin = 0;
+ return VFW_E_NOT_FOUND;
+ }
+
+ STDMETHODIMP QBaseFilter::QueryFilterInfo(FILTER_INFO *info )
+ {
+ QReadLocker locker(&m_lock);
+ if (!info) {
+ return E_POINTER;
+ }
+ info->pGraph = m_graph;
+ if (m_graph) {
+ m_graph->AddRef();
+ }
+ qMemCopy(info->achName, m_name.utf16(), qMin(MAX_FILTER_NAME, m_name.length()+1) *2);
+ return S_OK;
+ }
+
+ STDMETHODIMP QBaseFilter::JoinFilterGraph(IFilterGraph *graph, LPCWSTR name)
+ {
+ QWriteLocker locker(&m_lock);
+ m_graph = graph;
+ m_name = QString::fromUtf16((const unsigned short*)name);
+ return S_OK;
+ }
+
+ STDMETHODIMP QBaseFilter::EnumPins( IEnumPins **ep)
+ {
+ if (!ep) {
+ return E_POINTER;
+ }
+
+ *ep = new QEnumPins(this);
+ return S_OK;
+ }
+
+
+ STDMETHODIMP QBaseFilter::QueryVendorInfo(LPWSTR *)
+ {
+ //we give no information on that
+ return E_NOTIMPL;
+ }
+
+ //implementation from IMediaSeeking
+ STDMETHODIMP QBaseFilter::GetCapabilities(DWORD *pCapabilities)
+ {
+ IMediaSeeking *ms = getUpstreamMediaSeeking();
+ if (!ms) {
+ return E_NOTIMPL;
+ }
+
+ HRESULT hr = ms->GetCapabilities(pCapabilities);
+ ms->Release();
+ return hr;
+ }
+
+ STDMETHODIMP QBaseFilter::CheckCapabilities(DWORD *pCapabilities)
+ {
+ IMediaSeeking *ms = getUpstreamMediaSeeking();
+ if (!ms) {
+ return E_NOTIMPL;
+ }
+
+ HRESULT hr = ms->CheckCapabilities(pCapabilities);
+ ms->Release();
+ return hr;
+ }
+
+ STDMETHODIMP QBaseFilter::IsFormatSupported(const GUID *pFormat)
+ {
+ IMediaSeeking *ms = getUpstreamMediaSeeking();
+ if (!ms) {
+ return E_NOTIMPL;
+ }
+
+ HRESULT hr = ms->IsFormatSupported(pFormat);
+ ms->Release();
+ return hr;
+ }
+
+ STDMETHODIMP QBaseFilter::QueryPreferredFormat(GUID *pFormat)
+ {
+ IMediaSeeking *ms = getUpstreamMediaSeeking();
+ if (!ms) {
+ return E_NOTIMPL;
+ }
+
+ HRESULT hr = ms->QueryPreferredFormat(pFormat);
+ ms->Release();
+ return hr;
+ }
+
+ STDMETHODIMP QBaseFilter::GetTimeFormat(GUID *pFormat)
+ {
+ IMediaSeeking *ms = getUpstreamMediaSeeking();
+ if (!ms) {
+ return E_NOTIMPL;
+ }
+
+ HRESULT hr = ms->GetTimeFormat(pFormat);
+ ms->Release();
+ return hr;
+ }
+
+ STDMETHODIMP QBaseFilter::IsUsingTimeFormat(const GUID *pFormat)
+ {
+ IMediaSeeking *ms = getUpstreamMediaSeeking();
+ if (!ms) {
+ return E_NOTIMPL;
+ }
+
+ HRESULT hr = ms->IsUsingTimeFormat(pFormat);
+ ms->Release();
+ return hr;
+ }
+
+ STDMETHODIMP QBaseFilter::SetTimeFormat(const GUID *pFormat)
+ {
+ IMediaSeeking *ms = getUpstreamMediaSeeking();
+ if (!ms) {
+ return E_NOTIMPL;
+ }
+
+ HRESULT hr = ms->SetTimeFormat(pFormat);
+ ms->Release();
+ return hr;
+ }
+
+ STDMETHODIMP QBaseFilter::GetDuration(LONGLONG *pDuration)
+ {
+ IMediaSeeking *ms = getUpstreamMediaSeeking();
+ if (!ms) {
+ return E_NOTIMPL;
+ }
+
+ HRESULT hr = ms->GetDuration(pDuration);
+ ms->Release();
+ return hr;
+ }
+
+ STDMETHODIMP QBaseFilter::GetStopPosition(LONGLONG *pStop)
+ {
+ IMediaSeeking *ms = getUpstreamMediaSeeking();
+ if (!ms) {
+ return E_NOTIMPL;
+ }
+
+ HRESULT hr = ms->GetStopPosition(pStop);
+ ms->Release();
+ return hr;
+ }
+
+ STDMETHODIMP QBaseFilter::GetCurrentPosition(LONGLONG *pCurrent)
+ {
+ IMediaSeeking *ms = getUpstreamMediaSeeking();
+ if (!ms) {
+ return E_NOTIMPL;
+ }
+
+ HRESULT hr = ms->GetCurrentPosition(pCurrent);
+ ms->Release();
+ return hr;
+ }
+
+ STDMETHODIMP QBaseFilter::ConvertTimeFormat(LONGLONG *pTarget,
+ const GUID *pTargetFormat, LONGLONG Source, const GUID *pSourceFormat)
+ {
+ IMediaSeeking *ms = getUpstreamMediaSeeking();
+ if (!ms) {
+ return E_NOTIMPL;
+ }
+
+ HRESULT hr = ms->ConvertTimeFormat(pTarget, pTargetFormat, Source, pSourceFormat);
+ ms->Release();
+ return hr;
+ }
+
+ STDMETHODIMP QBaseFilter::SetPositions(LONGLONG *pCurrent, DWORD dwCurrentFlags, LONGLONG *pStop, DWORD dwStopFlags)
+ {
+ IMediaSeeking *ms = getUpstreamMediaSeeking();
+ if (!ms) {
+ return E_NOTIMPL;
+ }
+
+ HRESULT hr = ms->SetPositions(pCurrent, dwCurrentFlags, pStop, dwStopFlags);
+ ms->Release();
+ return hr;
+ }
+
+ STDMETHODIMP QBaseFilter::GetPositions(LONGLONG *pCurrent, LONGLONG *pStop)
+ {
+ IMediaSeeking *ms = getUpstreamMediaSeeking();
+ if (!ms) {
+ return E_NOTIMPL;
+ }
+
+ HRESULT hr = ms->GetPositions(pCurrent, pStop);
+ ms->Release();
+ return hr;
+ }
+
+ STDMETHODIMP QBaseFilter::GetAvailable(LONGLONG *pEarliest, LONGLONG *pLatest)
+ {
+ IMediaSeeking *ms = getUpstreamMediaSeeking();
+ if (!ms) {
+ return E_NOTIMPL;
+ }
+
+ HRESULT hr = ms->GetAvailable(pEarliest, pLatest);
+ ms->Release();
+ return hr;
+ }
+
+ STDMETHODIMP QBaseFilter::SetRate(double dRate)
+ {
+ IMediaSeeking *ms = getUpstreamMediaSeeking();
+ if (!ms) {
+ return E_NOTIMPL;
+ }
+
+ HRESULT hr = ms->SetRate(dRate);
+ ms->Release();
+ return hr;
+ }
+
+ STDMETHODIMP QBaseFilter::GetRate(double *dRate)
+ {
+ IMediaSeeking *ms = getUpstreamMediaSeeking();
+ if (!ms) {
+ return E_NOTIMPL;
+ }
+
+ HRESULT hr = ms->GetRate(dRate);
+ ms->Release();
+ return hr;
+ }
+
+ STDMETHODIMP QBaseFilter::GetPreroll(LONGLONG *pllPreroll)
+ {
+ IMediaSeeking *ms = getUpstreamMediaSeeking();
+ if (!ms) {
+ return E_NOTIMPL;
+ }
+
+ HRESULT hr = ms->GetPreroll(pllPreroll);
+ ms->Release();
+ return hr;
+ }
+
+ //implementation from IMediaPosition
+ STDMETHODIMP QBaseFilter::get_Duration(REFTIME *plength)
+ {
+ IMediaPosition *mp = getUpstreamMediaPosition();
+ if (!mp) {
+ return E_NOTIMPL;
+ }
+
+ HRESULT hr = mp->get_Duration(plength);
+ mp->Release();
+ return hr;
+ }
+
+ STDMETHODIMP QBaseFilter::put_CurrentPosition(REFTIME llTime)
+ {
+ IMediaPosition *mp = getUpstreamMediaPosition();
+ if (!mp) {
+ return E_NOTIMPL;
+ }
+
+ HRESULT hr = mp->put_CurrentPosition(llTime);
+ mp->Release();
+ return hr;
+ }
+
+ STDMETHODIMP QBaseFilter::get_CurrentPosition(REFTIME *pllTime)
+ {
+ IMediaPosition *mp = getUpstreamMediaPosition();
+ if (!mp) {
+ return E_NOTIMPL;
+ }
+
+ HRESULT hr = mp->get_CurrentPosition(pllTime);
+ mp->Release();
+ return hr;
+ }
+
+ STDMETHODIMP QBaseFilter::get_StopTime(REFTIME *pllTime)
+ {
+ IMediaPosition *mp = getUpstreamMediaPosition();
+ if (!mp) {
+ return E_NOTIMPL;
+ }
+
+ HRESULT hr = mp->get_StopTime(pllTime);
+ mp->Release();
+ return hr;
+ }
+
+ STDMETHODIMP QBaseFilter::put_StopTime(REFTIME llTime)
+ {
+ IMediaPosition *mp = getUpstreamMediaPosition();
+ if (!mp) {
+ return E_NOTIMPL;
+ }
+
+ HRESULT hr = mp->put_StopTime(llTime);
+ mp->Release();
+ return hr;
+ }
+
+ STDMETHODIMP QBaseFilter::get_PrerollTime(REFTIME *pllTime)
+ {
+ IMediaPosition *mp = getUpstreamMediaPosition();
+ if (!mp) {
+ return E_NOTIMPL;
+ }
+
+ HRESULT hr = mp->get_PrerollTime(pllTime);
+ mp->Release();
+ return hr;
+ }
+
+ STDMETHODIMP QBaseFilter::put_PrerollTime(REFTIME llTime)
+ {
+ IMediaPosition *mp = getUpstreamMediaPosition();
+ if (!mp) {
+ return E_NOTIMPL;
+ }
+
+ HRESULT hr = mp->put_PrerollTime(llTime);
+ mp->Release();
+ return hr;
+ }
+
+ STDMETHODIMP QBaseFilter::put_Rate(double dRate)
+ {
+ IMediaPosition *mp = getUpstreamMediaPosition();
+ if (!mp) {
+ return E_NOTIMPL;
+ }
+
+ HRESULT hr = mp->put_Rate(dRate);
+ mp->Release();
+ return hr;
+ }
+
+ STDMETHODIMP QBaseFilter::get_Rate(double *pdRate)
+ {
+ IMediaPosition *mp = getUpstreamMediaPosition();
+ if (!mp) {
+ return E_NOTIMPL;
+ }
+
+ HRESULT hr = mp->get_Rate(pdRate);
+ mp->Release();
+ return hr;
+ }
+
+ STDMETHODIMP QBaseFilter::CanSeekForward(LONG *pCanSeekForward)
+ {
+ IMediaPosition *mp = getUpstreamMediaPosition();
+ if (!mp) {
+ return E_NOTIMPL;
+ }
+
+ HRESULT hr = mp->CanSeekForward(pCanSeekForward);
+ mp->Release();
+ return hr;
+ }
+
+ STDMETHODIMP QBaseFilter::CanSeekBackward(LONG *pCanSeekBackward)
+ {
+ IMediaPosition *mp = getUpstreamMediaPosition();
+ if (!mp) {
+ return E_NOTIMPL;
+ }
+
+ HRESULT hr = mp->CanSeekBackward(pCanSeekBackward);
+ mp->Release();
+ return hr;
+ }
+
+ STDMETHODIMP QBaseFilter::GetTypeInfoCount(UINT *pctinfo)
+ {
+ IMediaPosition *mp = getUpstreamMediaPosition();
+ if (!mp) {
+ return E_NOTIMPL;
+ }
+
+ HRESULT hr = mp->GetTypeInfoCount(pctinfo);
+ mp->Release();
+ return hr;
+ }
+
+ STDMETHODIMP QBaseFilter::GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
+ {
+ IMediaPosition *mp = getUpstreamMediaPosition();
+ if (!mp) {
+ return E_NOTIMPL;
+ }
+
+ HRESULT hr = mp->GetTypeInfo(iTInfo, lcid, ppTInfo);
+ mp->Release();
+ return hr;
+ }
+
+ STDMETHODIMP QBaseFilter::GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
+ {
+ IMediaPosition *mp = getUpstreamMediaPosition();
+ if (!mp) {
+ return E_NOTIMPL;
+ }
+
+ HRESULT hr = mp->GetIDsOfNames(riid, rgszNames, cNames, lcid, rgDispId);
+ mp->Release();
+ return hr;
+ }
+
+ STDMETHODIMP QBaseFilter::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
+ VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
+ {
+ IMediaPosition *mp = getUpstreamMediaPosition();
+ if (!mp) {
+ return E_NOTIMPL;
+ }
+
+ HRESULT hr = mp->Invoke(dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
+ mp->Release();
+ return hr;
+ }
+
+
+ IMediaSeeking *QBaseFilter::getUpstreamMediaSeeking()
+ {
+ return static_cast<IMediaSeeking*>(getUpStreamInterface(IID_IMediaSeeking));
+ }
+
+ IMediaPosition *QBaseFilter::getUpstreamMediaPosition()
+ {
+ return static_cast<IMediaPosition*>(getUpStreamInterface(IID_IMediaPosition));
+ }
+
+ QList<QPin*> QBaseFilter::inputPins() const
+ {
+ QList<QPin*> ret;
+ for(int i = 0; i < m_pins.count(); ++i) {
+ QPin * pin = m_pins.at(i);
+ if (pin->direction() == PINDIR_INPUT) {
+ ret += pin;
+ }
+ }
+ return ret;
+ }
+
+ QList<QPin*> QBaseFilter::outputPins() const
+ {
+ QList<QPin*> ret;
+ for(int i = 0; i < m_pins.count(); ++i) {
+ QPin * pin = m_pins.at(i);
+ if (pin->direction() == PINDIR_OUTPUT) {
+ ret += pin;
+ }
+ }
+ return ret;
+ }
+
+ void *QBaseFilter::getUpStreamInterface(const IID &iid) const
+ {
+ const QList<QPin*> inputs = inputPins();
+ for (int i = 0; i < inputs.count(); ++i) {
+ IPin *out = inputs.at(i)->connected();
+ if (out) {
+ void *ms = 0;
+ out->QueryInterface(iid, &ms);
+ if (ms) {
+ return ms;
+ }
+ }
+ }
+ //none was found
+ return 0;
+ }
+
+
+ //addition
+ HRESULT QBaseFilter::processSample(IMediaSample *)
+ {
+ return S_OK;
+ }
+
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/3rdparty/phonon/ds9/qbasefilter.h b/src/3rdparty/phonon/ds9/qbasefilter.h
new file mode 100644
index 0000000000..85f14316dc
--- /dev/null
+++ b/src/3rdparty/phonon/ds9/qbasefilter.h
@@ -0,0 +1,136 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library 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, either version 2.1 or 3 of the License.
+
+This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef PHONON_QBASEFILTER_H
+#define PHONON_QBASEFILTER_H
+
+#include "phononds9_namespace.h"
+
+#include <QtCore/QString>
+#include <QtCore/QList>
+#include <QtCore/QReadWriteLock>
+
+#include <dshow.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+ namespace DS9
+ {
+ class QPin;
+ class QBaseFilter : public IBaseFilter, public IMediaSeeking, public IMediaPosition
+ {
+ public:
+ QBaseFilter(const CLSID &clsid);
+ virtual ~QBaseFilter();
+
+ //implementation from IUnknown
+ STDMETHODIMP QueryInterface(REFIID iid, void** out);
+ STDMETHODIMP_(ULONG) AddRef();
+ STDMETHODIMP_(ULONG) Release();
+
+ //implementation from IPersist
+ STDMETHODIMP GetClassID(CLSID *);
+
+ //implementation from IMediaFilter
+ STDMETHODIMP Stop();
+ STDMETHODIMP Pause();
+ STDMETHODIMP Run(REFERENCE_TIME);
+ STDMETHODIMP GetState(DWORD, FILTER_STATE*);
+ STDMETHODIMP SetSyncSource(IReferenceClock*);
+ STDMETHODIMP GetSyncSource(IReferenceClock**);
+
+ //implementation from IBaseFilter
+ STDMETHODIMP EnumPins(IEnumPins**);
+ STDMETHODIMP FindPin(LPCWSTR, IPin**);
+ STDMETHODIMP QueryFilterInfo(FILTER_INFO*);
+ STDMETHODIMP JoinFilterGraph(IFilterGraph*, LPCWSTR);
+ STDMETHODIMP QueryVendorInfo(LPWSTR*);
+
+ //implementation from IMediaSeeking
+ STDMETHODIMP GetCapabilities(DWORD *pCapabilities);
+ STDMETHODIMP CheckCapabilities(DWORD *pCapabilities);
+ STDMETHODIMP IsFormatSupported(const GUID *pFormat);
+ STDMETHODIMP QueryPreferredFormat(GUID *pFormat);
+ STDMETHODIMP GetTimeFormat(GUID *pFormat);
+ STDMETHODIMP IsUsingTimeFormat(const GUID *pFormat);
+ STDMETHODIMP SetTimeFormat(const GUID *pFormat);
+ STDMETHODIMP GetDuration(LONGLONG *pDuration);
+ STDMETHODIMP GetStopPosition(LONGLONG *pStop);
+ STDMETHODIMP GetCurrentPosition(LONGLONG *pCurrent);
+ STDMETHODIMP ConvertTimeFormat(LONGLONG *pTarget, const GUID *pTargetFormat, LONGLONG Source, const GUID *pSourceFormat);
+ STDMETHODIMP SetPositions(LONGLONG *pCurrent, DWORD dwCurrentFlags, LONGLONG *pStop, DWORD dwStopFlags);
+ STDMETHODIMP GetPositions(LONGLONG *pCurrent, LONGLONG *pStop);
+ STDMETHODIMP GetAvailable(LONGLONG *pEarliest, LONGLONG *pLatest);
+ STDMETHODIMP SetRate(double dRate);
+ STDMETHODIMP GetRate(double *dRate);
+ STDMETHODIMP GetPreroll(LONGLONG *pllPreroll);
+
+ //implementation from IMediaPosition
+ STDMETHODIMP get_Duration(REFTIME *plength);
+ STDMETHODIMP put_CurrentPosition(REFTIME llTime);
+ STDMETHODIMP get_CurrentPosition(REFTIME *pllTime);
+ STDMETHODIMP get_StopTime(REFTIME *pllTime);
+ STDMETHODIMP put_StopTime(REFTIME llTime);
+ STDMETHODIMP get_PrerollTime(REFTIME *pllTime);
+ STDMETHODIMP put_PrerollTime(REFTIME llTime);
+ STDMETHODIMP put_Rate(double dRate);
+ STDMETHODIMP get_Rate(double *pdRate);
+ STDMETHODIMP CanSeekForward(LONG *pCanSeekForward);
+ STDMETHODIMP CanSeekBackward(LONG *pCanSeekBackward);
+
+ //implementation from IDispatch (coming from IMediaPosition)
+ STDMETHODIMP GetTypeInfoCount(UINT *pctinfo);
+ STDMETHODIMP GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo);
+ STDMETHODIMP GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId);
+ STDMETHODIMP Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
+ VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr);
+
+ //own methods
+ const QList<QPin *> pins() const;
+ void addPin(QPin *pin);
+ void removePin(QPin *pin);
+ IFilterGraph *graph() const;
+ FILTER_STATE state() const;
+
+
+ //reimplement this if you want specific processing of media sample
+ virtual HRESULT processSample(IMediaSample *);
+
+ private:
+ QList<QPin*> outputPins() const;
+ QList<QPin*> inputPins() const;
+
+ void *getUpStreamInterface(const IID &iid) const;
+ IMediaSeeking *getUpstreamMediaSeeking();
+ IMediaPosition *getUpstreamMediaPosition();
+
+ LONG m_refCount;
+ CLSID m_clsid;
+ QString m_name;
+ IReferenceClock *m_clock;
+ IFilterGraph *m_graph;
+ FILTER_STATE m_state;
+ QList<QPin *> m_pins;
+ mutable QReadWriteLock m_lock;
+ };
+ }
+}
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/3rdparty/phonon/ds9/qmeminputpin.cpp b/src/3rdparty/phonon/ds9/qmeminputpin.cpp
new file mode 100644
index 0000000000..0af1bfde26
--- /dev/null
+++ b/src/3rdparty/phonon/ds9/qmeminputpin.cpp
@@ -0,0 +1,357 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library 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, either version 2.1 or 3 of the License.
+
+This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "qmeminputpin.h"
+#include "qbasefilter.h"
+#include "compointer.h"
+
+#include <QtCore/QDebug>
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+ namespace DS9
+ {
+
+ QMemInputPin::QMemInputPin(QBaseFilter *parent, const QVector<AM_MEDIA_TYPE> &mt, bool transform) :
+ QPin(parent, PINDIR_INPUT, mt), m_shouldDuplicateSamples(true), m_transform(transform)
+ {
+ }
+
+ QMemInputPin::~QMemInputPin()
+ {
+ }
+
+ STDMETHODIMP QMemInputPin::QueryInterface(REFIID iid, void **out)
+ {
+ if (!out) {
+ return E_POINTER;
+ }
+
+ if (iid == IID_IMemInputPin) {
+ *out = static_cast<IMemInputPin*>(this);
+ AddRef();
+ return S_OK;
+ } else {
+ return QPin::QueryInterface(iid, out);
+ }
+ }
+
+ STDMETHODIMP_(ULONG) QMemInputPin::AddRef()
+ {
+ return QPin::AddRef();
+ }
+
+ STDMETHODIMP_(ULONG) QMemInputPin::Release()
+ {
+ return QPin::Release();
+ }
+
+ STDMETHODIMP QMemInputPin::EndOfStream()
+ {
+ //this allows to serialize with Receive calls
+ QMutexLocker locker(&m_mutexReceive);
+ for(int i = 0; i < m_outputs.count(); ++i) {
+ IPin *conn = m_outputs.at(i)->connected();
+ if (conn) {
+ conn->EndOfStream();
+ }
+ }
+ return S_OK;
+ }
+
+ STDMETHODIMP QMemInputPin::BeginFlush()
+ {
+ //pass downstream
+ for(int i = 0; i < m_outputs.count(); ++i) {
+ IPin *conn = m_outputs.at(i)->connected();
+ if (conn) {
+ conn->BeginFlush();
+ }
+ }
+ QWriteLocker locker(&m_lock);
+ m_flushing = true;
+ return S_OK;
+ }
+
+ STDMETHODIMP QMemInputPin::EndFlush()
+ {
+ //pass downstream
+ for(int i = 0; i < m_outputs.count(); ++i) {
+ IPin *conn = m_outputs.at(i)->connected();
+ if (conn) {
+ conn->EndFlush();
+ }
+ }
+ QWriteLocker locker(&m_lock);
+ m_flushing = false;
+ return S_OK;
+ }
+
+ STDMETHODIMP QMemInputPin::NewSegment(REFERENCE_TIME start, REFERENCE_TIME stop, double rate)
+ {
+ for(int i = 0; i < m_outputs.count(); ++i) {
+ m_outputs.at(i)->NewSegment(start, stop, rate);
+ }
+ return S_OK;
+ }
+
+ //reimplementation to set the type for the output pin
+ //no need to make a deep copy here
+ STDMETHODIMP QMemInputPin::ReceiveConnection(IPin *pin ,const AM_MEDIA_TYPE *mt)
+ {
+ HRESULT hr = QPin::ReceiveConnection(pin, mt);
+ if (hr == S_OK &&
+ mt->majortype != MEDIATYPE_NULL &&
+ mt->subtype != MEDIASUBTYPE_NULL &&
+ mt->formattype != GUID_NULL) {
+ //we tell the output pins that they should connect with this type
+ for(int i = 0; i < m_outputs.count(); ++i) {
+ hr = m_outputs.at(i)->setAcceptedMediaType(connectedType());
+ if (FAILED(hr)) {
+ break;
+ }
+ }
+ }
+ return hr;
+ }
+
+ STDMETHODIMP QMemInputPin::GetAllocator(IMemAllocator **alloc)
+ {
+ if (!alloc) {
+ return E_POINTER;
+ }
+
+ if (*alloc = memoryAllocator(true)) {
+ return S_OK;
+ }
+
+ return VFW_E_NO_ALLOCATOR;
+ }
+
+ STDMETHODIMP QMemInputPin::NotifyAllocator(IMemAllocator *alloc, BOOL readonly)
+ {
+ if (!alloc) {
+ return E_POINTER;
+ }
+
+ {
+ QWriteLocker locker(&m_lock);
+ m_shouldDuplicateSamples = m_transform && readonly;
+ }
+
+ setMemoryAllocator(alloc);
+
+ for(int i = 0; i < m_outputs.count(); ++i) {
+ IPin *pin = m_outputs.at(i)->connected();
+ if (pin) {
+ ComPointer<IMemInputPin> input(pin, IID_IMemInputPin);
+ input->NotifyAllocator(alloc, m_shouldDuplicateSamples);
+ }
+ }
+
+ return S_OK;
+ }
+
+ STDMETHODIMP QMemInputPin::GetAllocatorRequirements(ALLOCATOR_PROPERTIES *prop)
+ {
+ if (!prop) {
+ return E_POINTER;
+ }
+
+ //we have no particular requirements
+ return E_NOTIMPL;
+ }
+
+ STDMETHODIMP QMemInputPin::Receive(IMediaSample *sample)
+ {
+ QMutexLocker locker(&m_mutexReceive);
+ if (!sample) {
+ return E_POINTER;
+ }
+
+ if (filterState() == State_Stopped) {
+ return VFW_E_WRONG_STATE;
+ }
+
+ if (isFlushing()) {
+ return S_FALSE; //we are still flushing
+ }
+
+ if (!m_shouldDuplicateSamples) {
+ //we do it just once
+ HRESULT hr = m_parent->processSample(sample);
+ if (!SUCCEEDED(hr)) {
+ return hr;
+ }
+ }
+
+ for (int i = 0; i < m_outputs.count(); ++i) {
+ QPin *current = m_outputs.at(i);
+ IMediaSample *outSample = m_shouldDuplicateSamples ?
+ duplicateSampleForOutput(sample, current->memoryAllocator())
+ : sample;
+
+ if (m_shouldDuplicateSamples) {
+ m_parent->processSample(outSample);
+ }
+
+ IPin *pin = current->connected();
+ if (pin) {
+ ComPointer<IMemInputPin> input(pin, IID_IMemInputPin);
+ if (input) {
+ input->Receive(outSample);
+ }
+ }
+
+ if (m_shouldDuplicateSamples) {
+ outSample->Release();
+ }
+ }
+ return S_OK;
+ }
+
+ STDMETHODIMP QMemInputPin::ReceiveMultiple(IMediaSample **samples,long count,long *nbDone)
+ {
+ //no need to lock here: there is no access to member data
+ if (!samples || !nbDone) {
+ return E_POINTER;
+ }
+
+ *nbDone = 0; //initialization
+ while( *nbDone != count) {
+ HRESULT hr = Receive(samples[*nbDone]);
+ if (FAILED(hr)) {
+ return hr;
+ }
+ (*nbDone)++;
+ }
+
+ return S_OK;
+ }
+
+ STDMETHODIMP QMemInputPin::ReceiveCanBlock()
+ {
+ //we test the output to see if they can block
+ for(int i = 0; i < m_outputs.count(); ++i) {
+ IPin *input = m_outputs.at(i)->connected();
+ if (input) {
+ ComPointer<IMemInputPin> meminput(input, IID_IMemInputPin);
+ if (meminput && meminput->ReceiveCanBlock() != S_FALSE) {
+ return S_OK;
+ }
+ }
+ }
+ return S_FALSE;
+ }
+
+ //addition
+ //this should be used by the filter to tell it's input pins to which output they should route the samples
+
+ void QMemInputPin::addOutput(QPin *output)
+ {
+ QWriteLocker locker(&m_lock);
+ m_outputs += output;
+ }
+
+ void QMemInputPin::removeOutput(QPin *output)
+ {
+ QWriteLocker locker(&m_lock);
+ m_outputs.removeOne(output);
+ }
+
+ QList<QPin*> QMemInputPin::outputs() const
+ {
+ QReadLocker locker(&m_lock);
+ return m_outputs;
+ }
+
+ ALLOCATOR_PROPERTIES QMemInputPin::getDefaultAllocatorProperties() const
+ {
+ //those values reduce buffering a lot (good for the volume effect)
+ ALLOCATOR_PROPERTIES prop = {4096, 1, 1, 0};
+ return prop;
+ }
+
+
+ IMediaSample *QMemInputPin::duplicateSampleForOutput(IMediaSample *sample, IMemAllocator *alloc)
+ {
+ LONG length = sample->GetActualDataLength();
+
+ HRESULT hr = alloc->Commit();
+ if (hr == VFW_E_SIZENOTSET) {
+ ALLOCATOR_PROPERTIES prop = getDefaultAllocatorProperties();
+ prop.cbBuffer = qMax(prop.cbBuffer, length);
+ ALLOCATOR_PROPERTIES actual;
+ //we just try to set the properties...
+ alloc->SetProperties(&prop, &actual);
+ hr = alloc->Commit();
+ }
+
+ Q_ASSERT(SUCCEEDED(hr));
+
+ IMediaSample *out;
+ hr = alloc->GetBuffer(&out, 0, 0, AM_GBF_NOTASYNCPOINT);
+ Q_ASSERT(SUCCEEDED(hr));
+
+ //let's copy the sample
+ {
+ REFERENCE_TIME start, end;
+ sample->GetTime(&start, &end);
+ out->SetTime(&start, &end);
+ }
+
+ hr = out->SetActualDataLength(length);
+ Q_ASSERT(SUCCEEDED(hr));
+ hr = out->SetDiscontinuity(sample->IsDiscontinuity());
+ Q_ASSERT(SUCCEEDED(hr));
+
+ {
+ LONGLONG start, end;
+ hr = sample->GetMediaTime(&start, &end);
+ if (hr != VFW_E_MEDIA_TIME_NOT_SET) {
+ hr = out->SetMediaTime(&start, &end);
+ Q_ASSERT(SUCCEEDED(hr));
+ }
+ }
+
+ AM_MEDIA_TYPE *type = 0;
+ hr = sample->GetMediaType(&type);
+ Q_ASSERT(SUCCEEDED(hr));
+ hr = out->SetMediaType(type);
+ Q_ASSERT(SUCCEEDED(hr));
+
+ hr = out->SetPreroll(sample->IsPreroll());
+ Q_ASSERT(SUCCEEDED(hr));
+ hr = out->SetSyncPoint(sample->IsSyncPoint());
+ Q_ASSERT(SUCCEEDED(hr));
+
+ BYTE *dest = 0, *src = 0;
+ hr = out->GetPointer(&dest);
+ Q_ASSERT(SUCCEEDED(hr));
+ hr = sample->GetPointer(&src);
+ Q_ASSERT(SUCCEEDED(hr));
+
+ qMemCopy(dest, src, sample->GetActualDataLength());
+
+ return out;
+ }
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/3rdparty/phonon/ds9/qmeminputpin.h b/src/3rdparty/phonon/ds9/qmeminputpin.h
new file mode 100644
index 0000000000..c44972198b
--- /dev/null
+++ b/src/3rdparty/phonon/ds9/qmeminputpin.h
@@ -0,0 +1,82 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library 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, either version 2.1 or 3 of the License.
+
+This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef PHONON_QMEMINPUTPIN_H
+#define PHONON_QMEMINPUTPIN_H
+
+
+#include <QtCore/QList>
+#include <QtCore/QMutex>
+#include "qpin.h"
+
+#include <dshow.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+ namespace DS9
+ {
+ class QBaseFilter;
+
+ //this class will be used for our effects
+ class QMemInputPin : public QPin, public IMemInputPin
+ {
+ public:
+ QMemInputPin(QBaseFilter *, const QVector<AM_MEDIA_TYPE> &, bool transform);
+ ~QMemInputPin();
+
+ //reimplementation from IUnknown
+ STDMETHODIMP QueryInterface(REFIID iid, void** out);
+ STDMETHODIMP_(ULONG) AddRef();
+ STDMETHODIMP_(ULONG) Release();
+
+ //reimplementation from IPin
+ STDMETHODIMP ReceiveConnection(IPin *,const AM_MEDIA_TYPE *);
+ STDMETHODIMP BeginFlush();
+ STDMETHODIMP EndFlush();
+ STDMETHODIMP EndOfStream();
+ STDMETHODIMP NewSegment(REFERENCE_TIME start, REFERENCE_TIME stop, double rate);
+
+ //reimplementation from IMemAllocator
+ STDMETHODIMP GetAllocator(IMemAllocator **);
+ STDMETHODIMP NotifyAllocator(IMemAllocator *,BOOL);
+ STDMETHODIMP GetAllocatorRequirements(ALLOCATOR_PROPERTIES *);
+ STDMETHODIMP Receive(IMediaSample *);
+ STDMETHODIMP ReceiveMultiple(IMediaSample **,long,long *);
+ STDMETHODIMP ReceiveCanBlock();
+
+ //addition
+ void addOutput(QPin *output);
+ void removeOutput(QPin *output);
+ QList<QPin*> outputs() const;
+
+ private:
+ IMediaSample *duplicateSampleForOutput(IMediaSample *, IMemAllocator *);
+ ALLOCATOR_PROPERTIES getDefaultAllocatorProperties() const;
+
+ bool m_shouldDuplicateSamples;
+ const bool m_transform; //defines if the pin is transforming the samples
+ QList<QPin*> m_outputs;
+ QMutex m_mutexReceive;
+ };
+ }
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/3rdparty/phonon/ds9/qpin.cpp b/src/3rdparty/phonon/ds9/qpin.cpp
new file mode 100644
index 0000000000..37fe48d1e0
--- /dev/null
+++ b/src/3rdparty/phonon/ds9/qpin.cpp
@@ -0,0 +1,653 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library 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, either version 2.1 or 3 of the License.
+
+This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "qbasefilter.h"
+#include "qpin.h"
+#include "compointer.h"
+
+#include <QtCore/QMutex>
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+ namespace DS9
+ {
+
+ static const AM_MEDIA_TYPE defaultMediaType()
+ {
+ AM_MEDIA_TYPE ret;
+ ret.majortype = MEDIATYPE_NULL;
+ ret.subtype = MEDIASUBTYPE_NULL;
+ ret.bFixedSizeSamples = TRUE;
+ ret.bTemporalCompression = FALSE;
+ ret.lSampleSize = 1;
+ ret.formattype = GUID_NULL;
+ ret.pUnk = 0;
+ ret.cbFormat = 0;
+ ret.pbFormat = 0;
+ return ret;
+ }
+
+ class QEnumMediaTypes : public IEnumMediaTypes
+ {
+ public:
+ QEnumMediaTypes(QPin *pin) : m_refCount(1), m_pin(pin), m_index(0)
+ {
+ m_pin->AddRef();
+ }
+
+ ~QEnumMediaTypes()
+ {
+ m_pin->Release();
+ }
+
+ STDMETHODIMP QueryInterface(const IID &iid,void **out)
+ {
+ if (!out) {
+ return E_POINTER;
+ }
+
+ HRESULT hr = S_OK;
+ if (iid == IID_IEnumMediaTypes) {
+ *out = static_cast<IEnumMediaTypes*>(this);
+ } else if (iid == IID_IUnknown) {
+ *out = static_cast<IUnknown*>(this);
+ } else {
+ *out = 0;
+ hr = E_NOINTERFACE;
+ }
+
+ if (hr == S_OK) {
+ AddRef();
+ }
+ return hr;
+ }
+
+ STDMETHODIMP_(ULONG) AddRef()
+ {
+ return InterlockedIncrement(&m_refCount);
+ }
+
+ STDMETHODIMP_(ULONG) Release()
+ {
+ ULONG refCount = InterlockedDecrement(&m_refCount);
+ if (refCount == 0) {
+ delete this;
+ }
+
+ return refCount;
+ }
+
+ STDMETHODIMP Next(ULONG count, AM_MEDIA_TYPE **out, ULONG *fetched)
+ {
+ QMutexLocker locker(&m_mutex);
+ if (!out) {
+ return E_POINTER;
+ }
+
+ if (!fetched && count > 1) {
+ return E_INVALIDARG;
+ }
+
+ int nbFetched = 0;
+ while (nbFetched < int(count) && m_index < m_pin->mediaTypes().count()) {
+ //the caller will deallocate the memory
+ *out = static_cast<AM_MEDIA_TYPE *>(::CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE)));
+ const AM_MEDIA_TYPE original = m_pin->mediaTypes().at(m_index);
+ **out = QPin::copyMediaType(original);
+ nbFetched++;
+ m_index++;
+ out++;
+ }
+
+ if (fetched) {
+ *fetched = nbFetched;
+ }
+
+ return nbFetched == count ? S_OK : S_FALSE;
+ }
+
+ STDMETHODIMP Skip(ULONG count)
+ {
+ QMutexLocker locker(&m_mutex);
+ m_index = qMin(m_index + int(count), m_pin->mediaTypes().count());
+ return (m_index == m_pin->mediaTypes().count()) ? S_FALSE : S_OK;
+ }
+
+ STDMETHODIMP Reset()
+ {
+ QMutexLocker locker(&m_mutex);
+ m_index = 0;
+ return S_OK;
+ }
+
+ STDMETHODIMP Clone(IEnumMediaTypes **out)
+ {
+ QMutexLocker locker(&m_mutex);
+ if (!out) {
+ return E_POINTER;
+ }
+
+ *out = new QEnumMediaTypes(m_pin);
+ (*out)->Skip(m_index);
+ return S_OK;
+ }
+
+
+ private:
+ LONG m_refCount;
+ QPin *m_pin;
+ int m_index;
+ QMutex m_mutex;
+ };
+
+
+ QPin::QPin(QBaseFilter *parent, PIN_DIRECTION dir, const QVector<AM_MEDIA_TYPE> &mt) :
+ m_memAlloc(0), m_parent(parent), m_refCount(1), m_connected(0),
+ m_direction(dir), m_mediaTypes(mt), m_connectedType(defaultMediaType()),
+ m_flushing(false)
+ {
+ Q_ASSERT(m_parent);
+ m_parent->addPin(this);
+ }
+
+ QPin::~QPin()
+ {
+ m_parent->removePin(this);
+ setMemoryAllocator(0);
+ freeMediaType(m_connectedType);
+ }
+
+ //reimplementation from IUnknown
+ STDMETHODIMP QPin::QueryInterface(REFIID iid, void**out)
+ {
+ if (!out) {
+ return E_POINTER;
+ }
+
+ HRESULT hr = S_OK;
+
+ if (iid == IID_IPin) {
+ *out = static_cast<IPin*>(this);
+ } else if (iid == IID_IUnknown) {
+ *out = static_cast<IUnknown*>(this);
+ } else if (m_direction == PINDIR_OUTPUT && (iid == IID_IMediaSeeking || iid == IID_IMediaPosition)) {
+ return m_parent->QueryInterface(iid, out);
+ } else {
+ *out = 0;
+ hr = E_NOINTERFACE;
+ }
+
+ if (hr == S_OK) {
+ AddRef();
+ }
+ return hr;
+ }
+
+ STDMETHODIMP_(ULONG) QPin::AddRef()
+ {
+ return InterlockedIncrement(&m_refCount);
+ }
+
+ STDMETHODIMP_(ULONG) QPin::Release()
+ {
+ ULONG refCount = InterlockedDecrement(&m_refCount);
+ if (refCount == 0) {
+ delete this;
+ }
+
+ return refCount;
+ }
+
+ //this is called on the input pins
+ STDMETHODIMP QPin::ReceiveConnection(IPin *pin, const AM_MEDIA_TYPE *type)
+ {
+ if (!pin ||!type) {
+ return E_POINTER;
+ }
+
+ if (connected()) {
+ return VFW_E_ALREADY_CONNECTED;
+ }
+
+ if (filterState() != State_Stopped) {
+ return VFW_E_NOT_STOPPED;
+ }
+
+ if (QueryAccept(type) != S_OK) {
+ return VFW_E_TYPE_NOT_ACCEPTED;
+ }
+
+ setConnected(pin);
+ setConnectedType(*type);
+
+ return S_OK;
+ }
+
+ //this is called on the output pins
+ STDMETHODIMP QPin::Connect(IPin *pin, const AM_MEDIA_TYPE *type)
+ {
+ if (!pin) {
+ return E_POINTER;
+ }
+
+ if (connected()) {
+ return VFW_E_ALREADY_CONNECTED;
+ }
+
+ if (filterState() != State_Stopped) {
+ return VFW_E_NOT_STOPPED;
+ }
+
+ HRESULT hr = S_OK;
+
+ setConnected(pin);
+ if (!type) {
+
+ //let(s first try the output pin's mediaTypes
+ if (checkOutputMediaTypesConnection(pin) != S_OK &&
+ checkOwnMediaTypesConnection(pin) != S_OK) {
+ hr = VFW_E_NO_ACCEPTABLE_TYPES;
+ }
+ } else if (QueryAccept(type) == S_OK) {
+ setConnectedType(*type);
+ hr = pin->ReceiveConnection(this, type);
+ } else {
+ hr = VFW_E_TYPE_NOT_ACCEPTED;
+ }
+
+ if (FAILED(hr)) {
+ setConnected(0);
+ setConnectedType(defaultMediaType());
+ } else {
+ ComPointer<IMemInputPin> input(pin, IID_IMemInputPin);
+ if (input) {
+ ComPointer<IMemAllocator> alloc;
+ input->GetAllocator(alloc.pparam());
+ if (alloc) {
+ //be default we take the allocator from the input pin
+ //we have no reason to force using our own
+ setMemoryAllocator(alloc);
+ }
+ }
+ if (memoryAllocator() == 0) {
+ ALLOCATOR_PROPERTIES prop;
+ if (input && input->GetAllocatorRequirements(&prop) == S_OK) {
+ createDefaultMemoryAllocator(&prop);
+ } else {
+ createDefaultMemoryAllocator();
+ }
+ }
+
+ Q_ASSERT(memoryAllocator() != 0);
+ if (input) {
+ input->NotifyAllocator(memoryAllocator(), TRUE); //TRUE is arbitrarily chosen here
+ }
+
+ }
+
+ return hr;
+ }
+
+ STDMETHODIMP QPin::Disconnect()
+ {
+ if (!connected()) {
+ return S_FALSE;
+ }
+
+ if (filterState() != State_Stopped) {
+ return VFW_E_NOT_STOPPED;
+ }
+
+ setConnected(0);
+ setConnectedType(defaultMediaType());
+ if (m_direction == PINDIR_INPUT) {
+ setMemoryAllocator(0);
+ }
+ return S_OK;
+ }
+
+ STDMETHODIMP QPin::ConnectedTo(IPin **other)
+ {
+ if (!other) {
+ return E_POINTER;
+ }
+
+ *other = connected(true);
+ if (!(*other)) {
+ return VFW_E_NOT_CONNECTED;
+ }
+
+ return S_OK;
+ }
+
+ STDMETHODIMP QPin::ConnectionMediaType(AM_MEDIA_TYPE *type)
+ {
+ QReadLocker locker(&m_lock);
+ if (!type) {
+ return E_POINTER;
+ }
+
+ *type = copyMediaType(m_connectedType);
+ if (!m_connected) {
+ return VFW_E_NOT_CONNECTED;
+ } else {
+ return S_OK;
+ }
+ }
+
+ STDMETHODIMP QPin::QueryPinInfo(PIN_INFO *info)
+ {
+ QReadLocker locker(&m_lock);
+ if (!info) {
+ return E_POINTER;
+ }
+
+ info->dir = m_direction;
+ info->pFilter = m_parent;
+ m_parent->AddRef();
+ qMemCopy(info->achName, m_name.utf16(), qMin(MAX_FILTER_NAME, m_name.length()+1) *2);
+
+ return S_OK;
+ }
+
+ STDMETHODIMP QPin::QueryDirection(PIN_DIRECTION *dir)
+ {
+ QReadLocker locker(&m_lock);
+ if (!dir) {
+ return E_POINTER;
+ }
+
+ *dir = m_direction;
+ return S_OK;
+ }
+
+ STDMETHODIMP QPin::QueryId(LPWSTR *id)
+ {
+ QReadLocker locker(&m_lock);
+ if (!id) {
+ return E_POINTER;
+ }
+
+ int nbBytes = (m_name.length()+1)*2;
+ *id = static_cast<LPWSTR>(::CoTaskMemAlloc(nbBytes));
+ qMemCopy(*id, m_name.utf16(), nbBytes);
+ return S_OK;
+ }
+
+ STDMETHODIMP QPin::QueryAccept(const AM_MEDIA_TYPE *type)
+ {
+ QReadLocker locker(&m_lock);
+ if (!type) {
+ return E_POINTER;
+ }
+
+ for (int i = 0; i < m_mediaTypes.count(); ++i) {
+ const AM_MEDIA_TYPE &current = m_mediaTypes.at(i);
+ if ( (type->majortype == current.majortype) &&
+ (current.subtype == MEDIASUBTYPE_NULL || type->subtype == current.subtype) &&
+ (type->majortype == MEDIATYPE_Stream || type->formattype != GUID_NULL || current.formattype != GUID_NULL) &&
+ (current.formattype == GUID_NULL || type->formattype == current.formattype)
+ ) {
+ return S_OK;
+ }
+ }
+ return S_FALSE;
+ }
+
+
+ STDMETHODIMP QPin::EnumMediaTypes(IEnumMediaTypes **emt)
+ {
+ if (!emt) {
+ return E_POINTER;
+ }
+
+ *emt = new QEnumMediaTypes(this);
+ return S_OK;
+ }
+
+
+ STDMETHODIMP QPin::EndOfStream()
+ {
+ return E_UNEXPECTED;
+ }
+
+ STDMETHODIMP QPin::BeginFlush()
+ {
+ return E_UNEXPECTED;
+ }
+
+ STDMETHODIMP QPin::EndFlush()
+ {
+ return E_UNEXPECTED;
+ }
+
+ STDMETHODIMP QPin::NewSegment(REFERENCE_TIME start, REFERENCE_TIME stop, double rate)
+ {
+ QReadLocker locker(&m_lock);
+ if (m_direction == PINDIR_OUTPUT && m_connected) {
+ //we deliver this downstream
+ m_connected->NewSegment(start, stop, rate);
+ }
+ return S_OK;
+ }
+
+ STDMETHODIMP QPin::QueryInternalConnections(IPin **, ULONG*)
+ {
+ //this is not implemented on purpose (the input pins are connected to all the output pins)
+ return E_NOTIMPL;
+ }
+
+
+ HRESULT QPin::checkOutputMediaTypesConnection(IPin *pin)
+ {
+ IEnumMediaTypes *emt = 0;
+ HRESULT hr = pin->EnumMediaTypes(&emt);
+ if (hr != S_OK) {
+ return hr;
+ }
+
+ AM_MEDIA_TYPE *type = 0;
+ while (emt->Next(1, &type, 0) == S_OK) {
+ if (QueryAccept(type) == S_OK) {
+ setConnectedType(*type);
+ if (pin->ReceiveConnection(this, type) == S_OK) {
+ freeMediaType(type);
+ return S_OK;
+ } else {
+ setConnectedType(defaultMediaType());
+ freeMediaType(type);
+ }
+ }
+ }
+
+ //we didn't find a suitable type
+ return S_FALSE;
+ }
+
+ HRESULT QPin::checkOwnMediaTypesConnection(IPin *pin)
+ {
+ for(int i = 0; i < m_mediaTypes.count(); ++i) {
+ const AM_MEDIA_TYPE &current = m_mediaTypes.at(i);
+ setConnectedType(current);
+ HRESULT hr = pin->ReceiveConnection(this, &current);
+ if (hr == S_OK) {
+ return S_OK;
+ }
+ }
+
+ //we didn't find a suitable type
+ return S_FALSE;
+ }
+
+ void QPin::freeMediaType(const AM_MEDIA_TYPE &type)
+ {
+ if (type.cbFormat) {
+ ::CoTaskMemFree(type.pbFormat);
+ }
+ if (type.pUnk) {
+ type.pUnk->Release();
+ }
+ }
+
+ void QPin::freeMediaType(AM_MEDIA_TYPE *type)
+ {
+ freeMediaType(*type);
+ ::CoTaskMemFree(type);
+ }
+
+ //addition
+
+ PIN_DIRECTION QPin::direction() const
+ {
+ return m_direction;
+ }
+
+ void QPin::setConnectedType(const AM_MEDIA_TYPE &type)
+ {
+ QWriteLocker locker(&m_lock);
+
+ //1st we free memory
+ freeMediaType(m_connectedType);
+
+ m_connectedType = copyMediaType(type);
+ }
+
+ const AM_MEDIA_TYPE &QPin::connectedType() const
+ {
+ QReadLocker locker(&m_lock);
+ return m_connectedType;
+ }
+
+ void QPin::setConnected(IPin *pin)
+ {
+ QWriteLocker locker(&m_lock);
+ if (pin) {
+ pin->AddRef();
+ }
+ if (m_connected) {
+ m_connected->Release();
+ }
+ m_connected = pin;
+ }
+
+ IPin *QPin::connected(bool addref) const
+ {
+ QReadLocker locker(&m_lock);
+ if (addref && m_connected) {
+ m_connected->AddRef();
+ }
+ return m_connected;
+ }
+
+ bool QPin::isFlushing() const
+ {
+ QReadLocker locker(&m_lock);
+ return m_flushing;
+ }
+
+ FILTER_STATE QPin::filterState() const
+ {
+ QReadLocker locker(&m_lock);
+ FILTER_STATE fstate = State_Stopped;
+ m_parent->GetState(0, &fstate);
+ return fstate;
+ }
+
+ QVector<AM_MEDIA_TYPE> QPin::mediaTypes() const
+ {
+ QReadLocker locker(&m_lock);
+ return m_mediaTypes;
+ }
+
+ HRESULT QPin::setAcceptedMediaType(const AM_MEDIA_TYPE &mt)
+ {
+ const QVector<AM_MEDIA_TYPE> oldMediaTypes = m_mediaTypes;
+ m_mediaTypes = QVector<AM_MEDIA_TYPE>() << mt;
+
+ HRESULT hr = S_OK;
+
+ IPin *conn = connected();
+ if (conn) {
+ //try to reconnect to redefine the media type
+ conn->Disconnect();
+ Disconnect();
+ hr = Connect(conn, 0);
+ if (FAILED(hr)) {
+ m_mediaTypes = oldMediaTypes;
+ Connect(conn, 0); //just redo the connection with the old media types
+ }
+ }
+ return hr;
+ }
+
+ void QPin::createDefaultMemoryAllocator(ALLOCATOR_PROPERTIES *prop)
+ {
+ ComPointer<IMemAllocator> alloc(CLSID_MemoryAllocator, IID_IMemAllocator);
+ if (prop) {
+ alloc->SetProperties(prop, 0);
+ }
+ setMemoryAllocator(alloc);
+ }
+
+ void QPin::setMemoryAllocator(IMemAllocator *alloc)
+ {
+ QWriteLocker locker(&m_lock);
+ if (alloc) {
+ alloc->AddRef();
+ }
+ if (m_memAlloc) {
+ m_memAlloc->Release();
+ }
+ m_memAlloc = alloc;
+ }
+
+ IMemAllocator *QPin::memoryAllocator(bool addref) const
+ {
+ QReadLocker locker(&m_lock);
+ if (addref && m_memAlloc) {
+ m_memAlloc->AddRef();
+ }
+ return m_memAlloc;
+ }
+
+ AM_MEDIA_TYPE QPin::copyMediaType(const AM_MEDIA_TYPE &type)
+ {
+ AM_MEDIA_TYPE ret = type;
+
+ //make a deep copy here
+ if (ret.cbFormat == 0 || ret.pbFormat == 0) {
+ ret.cbFormat = 0;
+ ret.pbFormat = 0;
+ ret.formattype = GUID_NULL;
+ } else {
+ ret.pbFormat = reinterpret_cast<BYTE*>(::CoTaskMemAlloc(type.cbFormat));
+ qMemCopy(ret.pbFormat, type.pbFormat, type.cbFormat);
+ }
+
+ if (type.pUnk) {
+ type.pUnk->AddRef();
+ }
+ return ret;
+ }
+
+
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/3rdparty/phonon/ds9/qpin.h b/src/3rdparty/phonon/ds9/qpin.h
new file mode 100644
index 0000000000..a3287c45a8
--- /dev/null
+++ b/src/3rdparty/phonon/ds9/qpin.h
@@ -0,0 +1,121 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library 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, either version 2.1 or 3 of the License.
+
+This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef PHONON_QPIN_H
+#define PHONON_QPIN_H
+
+#include "phononds9_namespace.h"
+
+#include <QtCore/QString>
+#include <QtCore/QVector>
+#include <QtCore/QReadWriteLock>
+
+#include <dshow.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+ namespace DS9
+ {
+ class QBaseFilter;
+
+ //this is the base class for our self-implemented Pins
+ class QPin : public IPin
+ {
+ public:
+ QPin(QBaseFilter *parent, PIN_DIRECTION dir, const QVector<AM_MEDIA_TYPE> &mt);
+ virtual ~QPin();
+
+ //reimplementation from IUnknown
+ STDMETHODIMP QueryInterface(REFIID iid, void** out);
+ STDMETHODIMP_(ULONG) AddRef();
+ STDMETHODIMP_(ULONG) Release();
+
+ //reimplementation from IPin
+ STDMETHODIMP Connect(IPin *,const AM_MEDIA_TYPE *);
+ STDMETHODIMP ReceiveConnection(IPin *,const AM_MEDIA_TYPE *);
+ STDMETHODIMP Disconnect();
+ STDMETHODIMP ConnectedTo(IPin **);
+ STDMETHODIMP ConnectionMediaType(AM_MEDIA_TYPE *);
+ STDMETHODIMP QueryPinInfo(PIN_INFO *);
+ STDMETHODIMP QueryDirection(PIN_DIRECTION *);
+ STDMETHODIMP QueryId(LPWSTR*);
+ STDMETHODIMP QueryAccept(const AM_MEDIA_TYPE*);
+ STDMETHODIMP EnumMediaTypes(IEnumMediaTypes **);
+ STDMETHODIMP QueryInternalConnections(IPin **, ULONG*);
+ STDMETHODIMP EndOfStream();
+ STDMETHODIMP BeginFlush();
+ STDMETHODIMP EndFlush();
+ STDMETHODIMP NewSegment(REFERENCE_TIME, REFERENCE_TIME, double);
+
+ QVector<AM_MEDIA_TYPE> mediaTypes() const;
+
+ HRESULT setAcceptedMediaType(const AM_MEDIA_TYPE &);
+
+ bool isFlushing() const;
+ void setConnectedType(const AM_MEDIA_TYPE &type);
+ const AM_MEDIA_TYPE &connectedType() const;
+ void setConnected(IPin *pin);
+ IPin *connected(bool = false) const;
+ void setMemoryAllocator(IMemAllocator *alloc);
+ IMemAllocator *memoryAllocator(bool = false) const;
+ void createDefaultMemoryAllocator(ALLOCATOR_PROPERTIES * = 0);
+ PIN_DIRECTION direction() const;
+
+ FILTER_STATE filterState() const;
+
+ static AM_MEDIA_TYPE copyMediaType(const AM_MEDIA_TYPE &type);
+ static void freeMediaType(AM_MEDIA_TYPE *type);
+ static void freeMediaType(const AM_MEDIA_TYPE &type);
+
+ protected:
+ //this can be used by sub-classes
+ mutable QReadWriteLock m_lock;
+ QBaseFilter *m_parent;
+ bool m_flushing;
+
+ private:
+ HRESULT checkOutputMediaTypesConnection(IPin *pin);
+ HRESULT checkOwnMediaTypesConnection(IPin *pin);
+
+ LONG m_refCount;
+ IPin *m_connected;
+ const PIN_DIRECTION m_direction;
+ QVector<AM_MEDIA_TYPE> m_mediaTypes; //accepted media types
+ AM_MEDIA_TYPE m_connectedType;
+ QString m_name;
+ IMemAllocator *m_memAlloc;
+ };
+
+ //utility function
+ class QAMMediaType : public AM_MEDIA_TYPE
+ {
+ public:
+ ~QAMMediaType()
+ {
+ QPin::freeMediaType(*this);
+ }
+
+ };
+
+ }
+}
+
+QT_END_NAMESPACE
+
+#endif //PHONON_QPIN_H
diff --git a/src/3rdparty/phonon/ds9/videorenderer_soft.cpp b/src/3rdparty/phonon/ds9/videorenderer_soft.cpp
new file mode 100644
index 0000000000..dd6e07629a
--- /dev/null
+++ b/src/3rdparty/phonon/ds9/videorenderer_soft.cpp
@@ -0,0 +1,1011 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library 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, either version 2.1 or 3 of the License.
+
+This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#include "videorenderer_soft.h"
+
+#ifndef QT_NO_PHONON_VIDEO
+
+#include "qmeminputpin.h"
+#include "qbasefilter.h"
+
+#include <QtGui/QPainter>
+#include <QtGui/QPaintEngine>
+#include <QtGui/QApplication>
+#include <QtCore/QTime>
+
+#define _USE_MATH_DEFINES //for pi
+#include <QtCore/qmath.h> //for sin and cos
+/* M_PI is a #define that may or may not be handled in <cmath> */
+#ifndef M_PI
+#define M_PI 3.14159265358979323846264338327950288419717
+#endif
+
+#include <dvdmedia.h> //for VIDEOINFOHEADER2
+
+//this will make a display every second of how many frames were pocessed and actually displayed
+//#define FPS_COUNTER
+
+#ifdef Q_OS_WINCE
+#define QT_NO_OPENGL
+#endif
+
+#ifndef QT_NO_OPENGL
+#include <gl/gl.h>
+#ifndef GL_FRAGMENT_PROGRAM_ARB
+#define GL_FRAGMENT_PROGRAM_ARB 0x8804
+#define GL_PROGRAM_FORMAT_ASCII_ARB 0x8875
+#endif
+
+// support old OpenGL installations (1.2)
+// assume that if TEXTURE0 isn't defined, none are
+#ifndef GL_TEXTURE0
+# define GL_TEXTURE0 0x84C0
+# define GL_TEXTURE1 0x84C1
+# define GL_TEXTURE2 0x84C2
+#endif
+
+// arbfp1 fragment program for converting yuv (YV12) to rgb
+static const char yv12ToRgb[] =
+"!!ARBfp1.0"
+"PARAM c[5] = { program.local[0..1],"
+" { 1.164, 0, 1.596, 0.5 },"
+" { 0.0625, 1.164, -0.391, -0.81300002 },"
+" { 1.164, 2.0179999, 0 } };"
+"TEMP R0;"
+"TEX R0.x, fragment.texcoord[0], texture[1], 2D;"
+"ADD R0.y, R0.x, -c[2].w;"
+"TEX R0.x, fragment.texcoord[0], texture[2], 2D;"
+"ADD R0.x, R0, -c[2].w;"
+"MUL R0.z, R0.y, c[0].w;"
+"MAD R0.z, R0.x, c[0], R0;"
+"MUL R0.w, R0.x, c[0];"
+"MUL R0.z, R0, c[0].y;"
+"TEX R0.x, fragment.texcoord[0], texture[0], 2D;"
+"MAD R0.y, R0, c[0].z, R0.w;"
+"ADD R0.x, R0, -c[3];"
+"MUL R0.y, R0, c[0];"
+"MUL R0.z, R0, c[1].x;"
+"MAD R0.x, R0, c[0].y, c[0];"
+"MUL R0.y, R0, c[1].x;"
+"DP3 result.color.x, R0, c[2];"
+"DP3 result.color.y, R0, c[3].yzww;"
+"DP3 result.color.z, R0, c[4];"
+"MOV result.color.w, c[1].y;"
+"END";
+
+static const char yuy2ToRgb[] =
+ "!!ARBfp1.0"
+"PARAM c[5] = { program.local[0..1],"
+" { 0.5, 2, 1, 0.0625 },"
+" { 1.164, 0, 1.596, 2.0179999 },"
+" { 1.164, -0.391, -0.81300002 } };"
+"TEMP R0;"
+"TEMP R1;"
+"TEMP R2;"
+"FLR R1.z, fragment.texcoord[0].x;"
+"ADD R0.x, R1.z, c[2];"
+"ADD R1.z, fragment.texcoord[0].x, -R1;"
+"MUL R1.x, fragment.texcoord[0].z, R0;"
+"MOV R1.y, fragment.texcoord[0];"
+"TEX R0, R1, texture[0], 2D;"
+"ADD R1.y, R0.z, -R0.x;"
+"MUL R2.x, R1.z, R1.y;"
+"MAD R0.x, R2, c[2].y, R0;"
+"MOV R1.y, fragment.texcoord[0];"
+"ADD R1.x, fragment.texcoord[0].z, R1;"
+"TEX R1.xyw, R1, texture[0], 2D;"
+"ADD R2.x, R1, -R0.z;"
+"MAD R1.x, R1.z, c[2].y, -c[2].z;"
+"MAD R0.z, R1.x, R2.x, R0;"
+"ADD R1.xy, R1.ywzw, -R0.ywzw;"
+"ADD R0.z, R0, -R0.x;"
+"SGE R1.w, R1.z, c[2].x;"
+"MAD R0.x, R1.w, R0.z, R0;"
+"MAD R0.yz, R1.z, R1.xxyw, R0.xyww;"
+"ADD R0.xyz, R0, -c[2].wxxw;"
+"MUL R0.w, R0.y, c[0];"
+"MAD R0.w, R0.z, c[0].z, R0;"
+"MUL R0.z, R0, c[0].w;"
+"MAD R0.y, R0, c[0].z, R0.z;"
+"MUL R0.w, R0, c[0].y;"
+"MUL R0.y, R0, c[0];"
+"MUL R0.z, R0.w, c[1].x;"
+"MAD R0.x, R0, c[0].y, c[0];"
+"MUL R0.y, R0, c[1].x;"
+"DP3 result.color.x, R0, c[3];"
+"DP3 result.color.y, R0, c[4];"
+"DP3 result.color.z, R0, c[3].xwyw;"
+"MOV result.color.w, c[1].y;"
+"END";
+
+#endif //QT_NO_OPENGL
+
+#define CLIP_SHIFT_RIGHT_8(c) ((c) < 0 ? 0 : (c) > 0xffff ? 0xff : (c) >> 8)
+#define CLIP_SHIFT_LEFT_8(c) ((c) < 0 ? 0 : (c) > 0xffff ? 0xff0000 : ( ((c) << 8) & 0xff0000) )
+#define CLIP_NO_SHIFT(c) ((c) < 0 ? 0 : (c) > 0xffff ? 0xff00 : ((c) & 0xff00) )
+#define CLIPPED_PIXEL(base, r, g, b) (0xff000000u | CLIP_SHIFT_LEFT_8(base+r) | CLIP_NO_SHIFT(base+g) | CLIP_SHIFT_RIGHT_8(base+b))
+#define CLIPPED_PIXEL2(r, g, b) (0xff000000u | CLIP_SHIFT_LEFT_8(r) | CLIP_NO_SHIFT(g) | CLIP_SHIFT_RIGHT_8(b))
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+ namespace DS9
+ {
+ static const QVector<AM_MEDIA_TYPE> videoMediaTypes()
+ {
+ AM_MEDIA_TYPE mt;
+ qMemSet(&mt, 0, sizeof(AM_MEDIA_TYPE));
+ mt.majortype = MEDIATYPE_Video;
+
+ //we accept any video format
+ mt.formattype = GUID_NULL;
+ mt.cbFormat = 0;
+ mt.pbFormat = 0;
+
+ QVector<AM_MEDIA_TYPE> ret;
+
+ //we support YUV (YV12 and YUY2) and RGB32
+ mt.subtype = MEDIASUBTYPE_YV12;
+ ret << mt;
+ mt.subtype = MEDIASUBTYPE_YUY2;
+ ret << mt;
+ mt.subtype = MEDIASUBTYPE_RGB32;
+ ret << mt;
+
+ return ret;
+ }
+
+ class VideoRendererSoftFilter : public QBaseFilter
+ {
+ public:
+ VideoRendererSoftFilter(VideoRendererSoft *renderer);
+
+ ~VideoRendererSoftFilter();
+
+ QSize videoSize() const;
+
+#ifndef QT_NO_OPENGL
+ void freeGLResources()
+ {
+ if (m_usingOpenGL) {
+ //let's reinitialize those values
+ m_usingOpenGL = false;
+ //to be sure we recreate it
+ if (m_textureUploaded) {
+ glDeleteTextures(3, m_texture);
+ m_textureUploaded = false;
+ }
+ }
+ m_checkedPrograms = false;
+ }
+#endif // QT_NO_OPENGL
+
+ void freeResources()
+ {
+ QMutexLocker locker(&m_mutex);
+ m_sampleBuffer = ComPointer<IMediaSample>();
+#ifndef QT_NO_OPENGL
+ freeGLResources();
+#endif // QT_NO_OPENGL
+ m_textureUploaded = false;
+ }
+
+ void endOfStream()
+ {
+ //received from the input pin
+ ::SetEvent(m_receiveCanWait); //unblocks the flow
+
+ //we send the message to the graph
+ ComPointer<IMediaEventSink> sink(graph(), IID_IMediaEventSink);
+ if (sink) {
+ sink->Notify(EC_COMPLETE, S_OK,
+ reinterpret_cast<LONG_PTR>(static_cast<IBaseFilter*>(this)));
+ }
+ }
+
+ void freeMediaSample()
+ {
+ QMutexLocker locker(&m_mutex);
+ m_sampleBuffer = ComPointer<IMediaSample>();
+ }
+
+ void beginFlush()
+ {
+ freeMediaSample();
+ ::SetEvent(m_receiveCanWait); //unblocks the flow
+ }
+
+ void endFlush()
+ {
+ if (m_inputPin->connected() == 0) {
+ ::SetEvent(m_receiveCanWait); //unblock the flow in receive
+ } else {
+ ::ResetEvent(m_receiveCanWait); //block the flow again
+ }
+ }
+
+ STDMETHODIMP Stop()
+ {
+ HRESULT hr = QBaseFilter::Stop();
+ beginFlush();
+ return hr;
+ }
+
+ STDMETHODIMP Pause()
+ {
+ HRESULT hr = QBaseFilter::Pause();
+ if (m_inputPin->connected() == 0) {
+ ::SetEvent(m_receiveCanWait); //unblock the flow in receive
+ } else {
+ ::ResetEvent(m_receiveCanWait); //this will block
+ }
+ return hr;
+ }
+
+ STDMETHODIMP Run(REFERENCE_TIME start)
+ {
+ HRESULT hr = QBaseFilter::Run(start);
+ m_start = start;
+
+ if (m_inputPin->connected() == 0) {
+ endOfStream();
+ } else {
+ ::SetEvent(m_receiveCanWait); //unblocks the flow (this event will block then again)
+ }
+
+#ifdef FPS_COUNTER
+ fpsTime.restart();
+ nbFramesProcessed = 0;
+ nbFramesDisplayed = 0;
+#endif
+
+ return hr;
+ }
+
+ HRESULT processSample(IMediaSample *sample);
+
+ void applyMixerSettings(qreal brightness, qreal contrast, qreal hue, qreal saturation)
+ {
+ //let's normalize the values
+ m_brightness = brightness * 128;
+ m_contrast = contrast + 1.;
+ m_hue = hue * M_PI;
+ m_saturation = saturation + 1.;
+ }
+
+ QImage currentImage() const
+ {
+ return m_currentImage;
+ }
+
+ void setCurrentImage(const QImage &image)
+ {
+ QMutexLocker locker(&m_mutex);
+ m_currentImage = image;
+ }
+
+ //the following function is called from the GUI thread
+ void repaintCurrentFrame(QPainter &painter, const QRect &r);
+
+
+ protected:
+ static void convertYV12toRGB(const uchar *data, const QSize &s, QImage &dest,
+ qreal brightness, qreal contrast, qreal hue, qreal saturation);
+ static void convertYUY2toRGB(const uchar *data, const QSize &s, QImage &dest,
+ qreal brightness, qreal contrast, qreal hue, qreal saturation);
+ static void normalizeRGB(const uchar *data, const QSize &s, QImage &destImage);
+
+ private:
+ QPin *const m_inputPin;
+ ComPointer<IMediaSample> m_sampleBuffer;
+ QImage m_currentImage;
+
+
+ VideoRendererSoft *m_renderer;
+ mutable QMutex m_mutex;
+ REFERENCE_TIME m_start;
+ HANDLE m_renderEvent, m_receiveCanWait; // Signals sample to render
+ QSize m_size;
+ bool m_textureUploaded;
+
+ //mixer settings
+ qreal m_brightness,
+ m_contrast,
+ m_hue,
+ m_saturation;
+
+#ifdef FPS_COUNTER
+ QTime fpsTime;
+ int nbFramesProcessed;
+ int nbFramesDisplayed;
+#endif
+
+#ifndef QT_NO_OPENGL
+ enum Program
+ {
+ YV12toRGB = 0,
+ YUY2toRGB = 1,
+ ProgramCount = 2
+ };
+
+ void updateTexture();
+ bool checkGLPrograms();
+
+ // ARB_fragment_program
+ 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;
+ _glActiveTexture glActiveTexture;
+
+ bool m_checkedPrograms;
+ bool m_usingOpenGL;
+ GLuint m_program[2];
+ GLuint m_texture[3];
+#endif
+ };
+
+ class VideoRendererSoftPin : public QMemInputPin
+ {
+ public:
+ VideoRendererSoftPin(VideoRendererSoftFilter *parent) :
+ QMemInputPin(parent, videoMediaTypes(), false /*no transformation of the samples*/),
+ m_renderer(parent)
+ {
+ }
+
+ STDMETHODIMP EndOfStream()
+ {
+ m_renderer->endOfStream();
+ return QMemInputPin::EndOfStream();
+ }
+
+ STDMETHODIMP ReceiveCanBlock()
+ {
+ //yes, it can block
+ return S_OK;
+ }
+
+ STDMETHODIMP BeginFlush()
+ {
+ m_renderer->beginFlush();
+ return QMemInputPin::BeginFlush();
+ }
+
+ STDMETHODIMP EndFlush()
+ {
+ m_renderer->endFlush();
+ return QMemInputPin::EndFlush();
+ }
+
+
+ STDMETHODIMP GetAllocatorRequirements(ALLOCATOR_PROPERTIES *prop)
+ {
+ if (!prop) {
+ return E_POINTER;
+ }
+
+ //we need 2 buffers
+ prop->cBuffers = 2;
+ return S_OK;
+ }
+
+
+ STDMETHODIMP NotifyAllocator(IMemAllocator *alloc, BOOL readonly)
+ {
+ if (!alloc) {
+ return E_POINTER;
+ }
+ ALLOCATOR_PROPERTIES prop;
+ HRESULT hr = alloc->GetProperties(&prop);
+ if (SUCCEEDED(hr) && prop.cBuffers == 1) {
+ //we ask to get 2 buffers so that we don't block the flow
+ //when we addref the mediasample
+ prop.cBuffers = 2;
+ ALLOCATOR_PROPERTIES dummy;
+ alloc->SetProperties(&prop, &dummy);
+ }
+
+ return QMemInputPin::NotifyAllocator(alloc, readonly);
+ }
+
+
+
+ private:
+ VideoRendererSoftFilter * const m_renderer;
+
+ };
+
+ VideoRendererSoftFilter::VideoRendererSoftFilter(VideoRendererSoft *renderer) :
+ QBaseFilter(CLSID_NULL), m_inputPin(new VideoRendererSoftPin(this)),
+ m_renderer(renderer), m_start(0)
+#ifndef QT_NO_OPENGL
+ ,m_usingOpenGL(false), m_checkedPrograms(false), m_textureUploaded(false)
+#endif
+ {
+ m_renderEvent = ::CreateEvent(0, 0, 0, 0);
+ m_receiveCanWait = ::CreateEvent(0, 0, 0, 0);
+ //simply initialize the array with default values
+ applyMixerSettings(0., 0., 0., 0.);
+#ifndef QT_NO_OPENGL
+#endif
+ }
+
+ VideoRendererSoftFilter::~VideoRendererSoftFilter()
+ {
+ ::CloseHandle(m_renderEvent);
+ ::CloseHandle(m_receiveCanWait);
+ //this frees up resources
+ freeResources();
+ }
+
+ QSize VideoRendererSoftFilter::videoSize() const
+ {
+ QSize ret;
+ const AM_MEDIA_TYPE &mt = m_inputPin->connectedType();
+ if (mt.pbFormat && mt.pbFormat) {
+ if (mt.formattype == FORMAT_VideoInfo) {
+ const VIDEOINFOHEADER *header = reinterpret_cast<VIDEOINFOHEADER*>(mt.pbFormat);
+ const int h = qAbs(header->bmiHeader.biHeight),
+ w = qAbs(header->bmiHeader.biWidth);
+ ret = QSize(w, h);
+ } else if (mt.formattype == FORMAT_VideoInfo2) {
+ const VIDEOINFOHEADER2 *header = reinterpret_cast<VIDEOINFOHEADER2*>(mt.pbFormat);
+ const int h = qAbs(header->bmiHeader.biHeight),
+ w = qAbs(header->bmiHeader.biWidth);
+ ret = QSize(w, h);
+ }
+ }
+ return ret;
+ }
+
+
+ HRESULT VideoRendererSoftFilter::processSample(IMediaSample *sample)
+ {
+#ifdef FPS_COUNTER
+ if (fpsTime.elapsed() > 1000) {
+ qDebug("FPS_COUNTER: processed=%d, displayed=%d (%d)", nbFramesProcessed, nbFramesDisplayed, fpsTime.elapsed());
+ nbFramesProcessed = 0;
+ nbFramesDisplayed = 0;
+ fpsTime.restart();
+
+ }
+#endif
+
+ AM_MEDIA_TYPE *type = 0;
+ if (sample->GetMediaType(&type) == S_OK) {
+ //let's update the media type of the input pin
+ m_inputPin->setConnectedType(*type);
+ }
+
+
+ const AM_MEDIA_TYPE &mt = m_inputPin->connectedType();
+
+ if (mt.pbFormat == 0 || mt.cbFormat == 0) {
+ return VFW_E_INVALIDMEDIATYPE;
+ }
+
+ m_size = videoSize();
+ if (!m_size.isValid()) {
+ return VFW_E_INVALIDMEDIATYPE;
+ }
+
+#ifdef FPS_COUNTER
+ nbFramesProcessed++;
+#endif
+
+ REFERENCE_TIME start = 0, stop = 0;
+ HRESULT hr = sample->GetTime(&start, &stop);
+
+ ComPointer<IReferenceClock> clock;
+ GetSyncSource(clock.pparam());
+
+ const bool playing = SUCCEEDED(hr) && state() == State_Running && clock;
+
+ if (playing) {
+ REFERENCE_TIME current;
+ clock->GetTime(&current);
+
+ DWORD_PTR advise;
+
+ //let's synchronize here
+ clock->AdviseTime(m_start, start,
+ reinterpret_cast<HEVENT>(m_renderEvent), &advise);
+
+ HANDLE handles[] = {m_receiveCanWait, m_renderEvent};
+ if (::WaitForMultipleObjects(2, handles, false, INFINITE) == WAIT_OBJECT_0) {
+ if (state() != State_Stopped && !m_inputPin->isFlushing()) {
+ ::ResetEvent(m_receiveCanWait);
+ }
+ }
+ }
+
+
+ //the let's lock the sample to be used in the GUI thread
+ {
+ QMutexLocker locker(&m_mutex);
+ sample->AddRef();
+ m_sampleBuffer = ComPointer<IMediaSample>(sample);
+ }
+
+ //image is updated: we should update the widget
+ //we should never call directly members of target due to thread-safety
+ QApplication::postEvent(m_renderer, new QEvent(QEvent::UpdateRequest));
+
+ if (!playing) {
+ //useless to test the return value of WaitForSingleObject: timeout can't happen
+ ::WaitForSingleObject(m_receiveCanWait, INFINITE);
+ if (state() != State_Stopped && !m_inputPin->isFlushing()) {
+ ::ResetEvent(m_receiveCanWait);
+ }
+ }
+
+ //everything should be ok
+ return S_OK;
+ }
+
+#ifndef QT_NO_OPENGL
+ bool VideoRendererSoftFilter::checkGLPrograms()
+ {
+ if (!m_checkedPrograms) {
+ m_checkedPrograms = true;
+
+ glProgramStringARB = (_glProgramStringARB) wglGetProcAddress("glProgramStringARB");
+ glBindProgramARB = (_glBindProgramARB) wglGetProcAddress("glBindProgramARB");
+ glDeleteProgramsARB = (_glDeleteProgramsARB) wglGetProcAddress("glDeleteProgramsARB");
+ glGenProgramsARB = (_glGenProgramsARB) wglGetProcAddress("glGenProgramsARB");
+ glProgramLocalParameter4fARB = (_glProgramLocalParameter4fARB) wglGetProcAddress("glProgramLocalParameter4fARB");
+ glActiveTexture = (_glActiveTexture) wglGetProcAddress("glActiveTexture");
+
+ //we check only once if the widget is drawn using opengl
+ if (glProgramStringARB && glBindProgramARB && glDeleteProgramsARB &&
+ glGenProgramsARB && glActiveTexture && glProgramLocalParameter4fARB) {
+ glGenProgramsARB(2, m_program);
+
+ const char *code[] = {yv12ToRgb, yuy2ToRgb};
+
+ bool error = false;
+ for(int i = 0; i < ProgramCount && !error; ++i) {
+
+ glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, m_program[i]);
+
+ const GLbyte *gl_src = reinterpret_cast<const GLbyte *>(code[i]);
+ glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB,
+ strlen(code[i]), gl_src);
+
+ if (glGetError() != GL_NO_ERROR) {
+ error = true;
+ }
+ }
+
+ if (error) {
+ glDeleteProgramsARB(2, m_program);
+ } else {
+ //everything went fine we store the context here (we support YV12 and YUY2)
+ m_usingOpenGL = m_inputPin->connectedType().subtype == MEDIASUBTYPE_YV12
+ || m_inputPin->connectedType().subtype == MEDIASUBTYPE_YUY2;
+ //those "textures" will be used as byte streams
+ //to pass Y, U and V data to the graphics card
+ glGenTextures(3, m_texture);
+ }
+ }
+ }
+ return m_usingOpenGL;
+ }
+
+ void VideoRendererSoftFilter::updateTexture()
+ {
+ if (!m_sampleBuffer) {
+ return; //the texture is already up2date or their is no data yet
+ }
+
+ uchar *data = 0;
+ m_sampleBuffer->GetPointer(&data);
+
+ if (m_inputPin->connectedType().subtype == MEDIASUBTYPE_YV12) {
+ int w[3] = { m_size.width(), m_size.width()/2, m_size.width()/2 };
+ int h[3] = { m_size.height(), m_size.height()/2, m_size.height()/2 };
+ int offs[3] = { 0, m_size.width()*m_size.height(), m_size.width()*m_size.height()*5/4 };
+
+ for (int i = 0; i < 3; ++i) {
+ glBindTexture(GL_TEXTURE_2D, m_texture[i]);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, w[i], h[i], 0,
+ GL_LUMINANCE, GL_UNSIGNED_BYTE, data + offs[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_REPEAT);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ }
+ } else { //m_inputPin->connectedType().subtype == MEDIASUBTYPE_YUY2
+ //we upload 1 texture
+ glBindTexture(GL_TEXTURE_2D, m_texture[0]);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_size.width() / 2, m_size.height(), 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, data);
+
+ 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_REPEAT);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+
+ }
+ m_sampleBuffer = ComPointer<IMediaSample>();
+ m_textureUploaded = true;
+ }
+#endif
+
+ void VideoRendererSoftFilter::repaintCurrentFrame(QPainter &painter, const QRect &r)
+ {
+ QMutexLocker locker(&m_mutex);
+
+#ifdef FPS_COUNTER
+ nbFramesDisplayed++;
+#endif
+
+
+#ifndef QT_NO_OPENGL
+ if (painter.paintEngine() && painter.paintEngine()->type() == QPaintEngine::OpenGL && checkGLPrograms()) {
+ //for now we only support YUV (both YV12 and YUY2)
+ updateTexture();
+
+ if (!m_textureUploaded) {
+ //we simply fill the whole video with content
+ //the callee has already set the brush
+ painter.drawRect(r);
+ return;
+ }
+
+ //let's draw the texture
+
+ //Let's pass the other arguments
+ const Program prog = (m_inputPin->connectedType().subtype == MEDIASUBTYPE_YV12) ? YV12toRGB : YUY2toRGB;
+ glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, m_program[prog]);
+ //loading the parameters
+ glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 0, m_brightness / 256., m_contrast, qCos(m_hue), qSin(m_hue));
+ glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 1, m_saturation, painter.opacity() /*alpha */, 0. /*dummy*/, 0. /*dummy*/);
+
+ glEnable(GL_FRAGMENT_PROGRAM_ARB);
+
+ const float v_array[] = { r.left(), r.top(), r.right()+1, r.top(), r.right()+1, r.bottom()+1, r.left(), r.bottom()+1 };
+
+ float tx_array[12] = {0., 0., 0., 1.,
+ 0., 0., 1., 1.,
+ 0., 0., 1., 0.};
+
+ if (prog == YUY2toRGB) {
+ const float w = m_size.width() / 2,
+ iw = 1. / w;
+
+ tx_array[3] = w;
+ tx_array[6] = w;
+
+ for (int i = 0; i < 4; ++i) {
+ tx_array[3*i + 2] = iw;
+ }
+ }
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, m_texture[0]);
+
+ if (prog == YV12toRGB) {
+ glActiveTexture(GL_TEXTURE1);
+ glBindTexture(GL_TEXTURE_2D, m_texture[2]);
+ glActiveTexture(GL_TEXTURE2);
+ glBindTexture(GL_TEXTURE_2D, m_texture[1]);
+ glActiveTexture(GL_TEXTURE0);
+ }
+
+
+ glVertexPointer(2, GL_FLOAT, 0, v_array);
+ glTexCoordPointer(3, GL_FLOAT, 0, tx_array);
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glDrawArrays(GL_QUADS, 0, 4);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glDisableClientState(GL_VERTEX_ARRAY);
+
+ glDisable(GL_FRAGMENT_PROGRAM_ARB);
+ return;
+ } else
+#endif
+ if (m_sampleBuffer) {
+ //we need to get the sample data
+ uchar *data = 0;
+ m_sampleBuffer->GetPointer(&data);
+
+
+ //let's update the current image
+ if (m_inputPin->connectedType().subtype == MEDIASUBTYPE_YV12) {
+ convertYV12toRGB(data, m_size, m_currentImage,
+ m_brightness, m_contrast, m_hue, m_saturation);
+ } else if (m_inputPin->connectedType().subtype == MEDIASUBTYPE_YUY2) {
+ convertYUY2toRGB(data, m_size, m_currentImage,
+ m_brightness, m_contrast, m_hue, m_saturation);
+ } else if (m_inputPin->connectedType().subtype == MEDIASUBTYPE_RGB32) {
+ normalizeRGB(data, m_size, m_currentImage);
+ }
+ m_sampleBuffer = ComPointer<IMediaSample>();
+ }
+
+ if (m_currentImage.isNull()) {
+ //we simply fill the whole video with content
+ //the callee has alrtead set the brush
+ painter.drawRect(r);
+ } else {
+ painter.drawImage(0, 0, m_currentImage);
+ }
+ }
+
+
+ void VideoRendererSoftFilter::normalizeRGB(const uchar *data, const QSize &s, QImage &destImage)
+ {
+ const int w = s.width(),
+ h = s.height();
+ if (destImage.size() != s) {
+ destImage = QImage(w, h, QImage::Format_ARGB32_Premultiplied);
+ }
+ if (destImage.isNull()) {
+ return; //the system can't allocate the memory for the image drawing
+ }
+
+ const QRgb *rgb = reinterpret_cast<const QRgb*>(data);
+
+ //this sets the alpha channel to 0xff and flip the image vertically
+ for (int y = h - 1; y >= 0; --y) {
+ QRgb *dest = reinterpret_cast<QRgb*>(destImage.scanLine(y));
+ for(int i = w; i > 0; --i, ++rgb, ++dest) {
+ *dest = *rgb | (0xff << 24); //we force the alpha channel to 0xff
+ }
+ }
+ }
+
+
+ //we render data interpreted as YV12 into m_renderbuffer
+ void VideoRendererSoftFilter::convertYV12toRGB(const uchar *data, const QSize &s, QImage &destImage,
+ qreal brightness, qreal contrast, qreal hue, qreal saturation)
+ {
+ const int w = s.width(),
+ h = s.height();
+
+ //let's cache some computation
+ const int cosHx256 = qRound(qCos(hue) * contrast * saturation * 256),
+ sinHx256 = qRound(qSin(hue) * contrast * saturation * 256);
+
+ int Yvalue[256];
+ for(int i = 0;i<256;++i) {
+ Yvalue[i] = qRound(((i - 16) * contrast + brightness) * 298 + 128);
+ }
+
+
+ if (destImage.size() != s) {
+ destImage = QImage(w, h, QImage::Format_ARGB32_Premultiplied);
+ }
+
+ if (destImage.isNull()) {
+ return; //the system can't allocate the memory for the image drawing
+ }
+
+ QRgb *dest = reinterpret_cast<QRgb*>(destImage.bits());
+ const uchar *dataY = data,
+ *dataV = data + (w*h),
+ *dataU = dataV + (w*h)/4;
+
+ uint *line1 = dest,
+ *line2 = dest + w;
+
+ for(int l = (h >> 1); l > 0; --l) {
+ //we treat 2 lines by 2 lines
+
+ for(int x = (w >> 1); x > 0; --x) {
+
+ const int u = *dataU++ - 128,
+ v = *dataV++ - 128;
+ const int d = (u * cosHx256 + v * sinHx256) >> 8,
+ e = (v * cosHx256 + u * sinHx256) >> 8;
+
+ const int compRed = 409 * e,
+ compGreen = -100 * d - 208 * e,
+ compBlue = 516 * d;
+
+ const int y21 = Yvalue[ dataY[w] ],
+ y11 = Yvalue[ *dataY++ ],
+ y22 = Yvalue[ dataY[w] ],
+ y12 = Yvalue[ *dataY++ ];
+
+ //1st line 1st pixel
+ *line1++ = CLIPPED_PIXEL(y11, compRed, compGreen, compBlue);
+
+ //1st line, 2nd pixel
+ *line1++ = CLIPPED_PIXEL(y12, compRed, compGreen, compBlue);
+
+ //2nd line 1st pixel
+ *line2++ = CLIPPED_PIXEL(y21, compRed, compGreen, compBlue);
+
+ //2nd line 2nd pixel
+ *line2++ = CLIPPED_PIXEL(y22, compRed, compGreen, compBlue);
+
+ } //for
+
+ //end of the line
+ dataY += w;
+ line1 = line2;
+ line2 += w;
+
+ } //for
+
+ }
+
+ //we render data interpreted as YUY2 into m_renderbuffer
+ void VideoRendererSoftFilter::convertYUY2toRGB(const uchar *data, const QSize &s, QImage &destImage,
+ qreal brightness, qreal contrast, qreal hue, qreal saturation)
+ {
+ const int w = s.width(),
+ h = s.height();
+
+ //let's cache some computation
+ int Yvalue[256];
+ for(int i = 0;i<256;++i) {
+ Yvalue[i] = qRound(((i - 16) * contrast + brightness) * 298 + 128);
+ }
+
+ const int cosHx256 = qRound(qCos(hue) * contrast * saturation * 256),
+ sinHx256 = qRound(qSin(hue) * contrast * saturation * 256);
+
+ if (destImage.size() != s) {
+ //this will only allocate memory when needed
+ destImage = QImage(w, h, QImage::Format_ARGB32_Premultiplied);
+ }
+ if (destImage.isNull()) {
+ return; //the system can't allocate the memory for the image drawing
+ }
+
+ QRgb *dest = reinterpret_cast<QRgb*>(destImage.bits());
+
+ //the number of iterations is width * height / 2 because we treat 2 pixels at each iterations
+ for (int c = w * h / 2; c > 0 ; --c) {
+
+ //the idea of that algorithm comes from
+ //http://msdn2.microsoft.com/en-us/library/ms867704.aspx#yuvformats_identifying_yuv_formats_in_directshow
+
+ //we treat 2 pixels by 2 pixels (we start reading 2 pixels info ie. "YUYV"
+ const int y1 = Yvalue[*data++],
+ u = *data++ - 128,
+ y2 = Yvalue[*data++],
+ v = *data++ - 128;
+
+ const int d = (u * cosHx256 + v * sinHx256) >> 8,
+ e = (v * cosHx256 + u * sinHx256) >> 8;
+
+ const int compRed = 409 * e,
+ compGreen = -100 * d - 208 * e,
+ compBlue = 516 * d;
+
+ //first pixel
+ *dest++ = CLIPPED_PIXEL(y1, compRed, compGreen, compBlue);
+
+ //second pixel
+ *dest++ = CLIPPED_PIXEL(y2, compRed, compGreen, compBlue);
+ }
+ }
+
+
+ VideoRendererSoft::VideoRendererSoft(QWidget *target) :
+ m_renderer(new VideoRendererSoftFilter(this)), m_target(target)
+ {
+ m_filter = Filter(m_renderer);
+ }
+
+ VideoRendererSoft::~VideoRendererSoft()
+ {
+ }
+
+
+ bool VideoRendererSoft::isNative() const
+ {
+ return false;
+ }
+
+
+ void VideoRendererSoft::repaintCurrentFrame(QWidget *target, const QRect &rect)
+ {
+ QPainter painter(target);
+
+ QColor backColor = target->palette().color(target->backgroundRole());
+ painter.setBrush(backColor);
+ painter.setPen(Qt::NoPen);
+ if (!m_videoRect.contains(rect)) {
+ //we repaint the borders only when needed
+ const QVector<QRect> reg = (QRegion(rect) - m_videoRect).rects();
+ for (int i = 0; i < reg.count(); ++i) {
+ painter.drawRect(reg.at(i));
+ }
+ }
+
+ painter.setRenderHint(QPainter::SmoothPixmapTransform);
+ painter.setTransform(m_transform, true);
+ QSize vsize = videoSize();
+ m_renderer->repaintCurrentFrame(painter, QRect(0,0, vsize.width(), vsize.height()));
+ }
+
+ void VideoRendererSoft::notifyResize(const QSize &size,
+ Phonon::VideoWidget::AspectRatio aspectRatio, Phonon::VideoWidget::ScaleMode scaleMode)
+ {
+ const QSize vsize = videoSize();
+ internalNotifyResize(size, vsize, aspectRatio, scaleMode);
+
+ m_transform.reset();
+
+ if (vsize.isValid() && size.isValid()) {
+ m_transform.translate(m_dstX, m_dstY);
+ const qreal sx = qreal(m_dstWidth) / qreal(vsize.width()),
+ sy = qreal(m_dstHeight) / qreal(vsize.height());
+ m_transform.scale(sx, sy);
+ m_videoRect = m_transform.mapRect( QRect(0,0, vsize.width(), vsize.height()));
+ }
+ }
+
+ QSize VideoRendererSoft::videoSize() const
+ {
+ if (m_renderer->pins().first()->connected()) {
+ return m_renderer->videoSize();
+ } else {
+ return m_renderer->currentImage().size();
+ }
+ }
+
+ void VideoRendererSoft::applyMixerSettings(qreal brightness, qreal contrast, qreal hue, qreal saturation)
+ {
+ m_renderer->applyMixerSettings(brightness, contrast, hue, saturation);
+ }
+
+ QImage VideoRendererSoft::snapshot() const
+ {
+ return m_renderer->currentImage(); //not accurate (especially when using opengl...)
+ }
+
+ void VideoRendererSoft::setSnapshot(const QImage &image)
+ {
+ m_renderer->setCurrentImage(image);
+ }
+
+ bool VideoRendererSoft::event(QEvent *e)
+ {
+ if (e->type() == QEvent::UpdateRequest) {
+ m_target->update(m_videoRect);
+ return true;
+ }
+ return QObject::event(e);
+ }
+
+
+ }
+}
+
+QT_END_NAMESPACE
+
+#endif //QT_NO_PHONON_VIDEO
diff --git a/src/3rdparty/phonon/ds9/videorenderer_soft.h b/src/3rdparty/phonon/ds9/videorenderer_soft.h
new file mode 100644
index 0000000000..e47bca6f50
--- /dev/null
+++ b/src/3rdparty/phonon/ds9/videorenderer_soft.h
@@ -0,0 +1,68 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library 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, either version 2.1 or 3 of the License.
+
+This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#ifndef PHONON_VIDEORENDERER_SOFT_H
+#define PHONON_VIDEORENDERER_SOFT_H
+
+#include "abstractvideorenderer.h"
+
+QT_BEGIN_NAMESPACE
+#ifndef QT_NO_PHONON_VIDEO
+
+namespace Phonon
+{
+ namespace DS9
+ {
+ class VideoRendererSoftFilter;
+ //this class is used to render evrything in software (like in the Graphics View)
+ class VideoRendererSoft : public AbstractVideoRenderer,
+ public QObject //this is used to receive events
+ {
+ public:
+ VideoRendererSoft(QWidget *);
+ ~VideoRendererSoft();
+
+ //Implementation from AbstractVideoRenderer
+ void repaintCurrentFrame(QWidget *target, const QRect &rect);
+ void notifyResize(const QSize&, Phonon::VideoWidget::AspectRatio, Phonon::VideoWidget::ScaleMode);
+ QSize videoSize() const;
+ void applyMixerSettings(qreal brightness, qreal contrast, qreal hue, qreal saturation);
+ bool isNative() const;
+
+ QImage snapshot() const;
+ void setSnapshot(const QImage &);
+
+ protected:
+ bool event(QEvent *);
+
+ private:
+ VideoRendererSoftFilter *m_renderer;
+ QTransform m_transform;
+ QRect m_videoRect; //rectangle where the video is displayed
+ QWidget *m_target;
+ };
+ }
+}
+
+#endif //QT_NO_PHONON_VIDEO
+
+QT_END_NAMESPACE
+
+#endif
+
+
diff --git a/src/3rdparty/phonon/ds9/videorenderer_vmr9.cpp b/src/3rdparty/phonon/ds9/videorenderer_vmr9.cpp
new file mode 100644
index 0000000000..298e9fae74
--- /dev/null
+++ b/src/3rdparty/phonon/ds9/videorenderer_vmr9.cpp
@@ -0,0 +1,333 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library 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, either version 2.1 or 3 of the License.
+
+This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+
+#include "videorenderer_vmr9.h"
+
+#ifndef QT_NO_PHONON_VIDEO
+
+#include <QtGui/QWidget>
+#include <QtGui/QPainter>
+#include <QtCore/QTimerEvent>
+
+#ifndef Q_OS_WINCE
+#include <d3d9.h>
+#include <vmr9.h>
+#else
+#include <uuids.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+
+namespace Phonon
+{
+ namespace DS9
+ {
+ VideoRendererVMR9::~VideoRendererVMR9()
+ {
+ }
+
+ bool VideoRendererVMR9::isNative() const
+ {
+ return true;
+ }
+
+
+#ifdef Q_OS_WINCE
+ VideoRendererVMR9::VideoRendererVMR9(QWidget *target) : m_target(target)
+ {
+ m_target->setAttribute(Qt::WA_PaintOnScreen, true);
+ m_filter = Filter(CLSID_VideoRenderer, IID_IBaseFilter);
+ }
+
+ QSize VideoRendererVMR9::videoSize() const
+ {
+ LONG w = 0,
+ h = 0;
+ ComPointer<IBasicVideo> basic(m_filter, IID_IBasicVideo);
+ if (basic) {
+ basic->GetVideoSize( &w, &h);
+ }
+ return QSize(w, h);
+ }
+
+ void VideoRendererVMR9::repaintCurrentFrame(QWidget * /*target*/, const QRect & /*rect*/)
+ {
+ //nothing to do here: the renderer paints everything
+ }
+
+ void VideoRendererVMR9::notifyResize(const QSize &size, Phonon::VideoWidget::AspectRatio aspectRatio,
+ Phonon::VideoWidget::ScaleMode scaleMode)
+ {
+ if (!isActive()) {
+ ComPointer<IBasicVideo> basic(m_filter, IID_IBasicVideo);
+ if (basic) {
+ basic->SetDestinationPosition(0, 0, 0, 0);
+ }
+ return;
+ }
+
+ ComPointer<IVideoWindow> video(m_filter, IID_IVideoWindow);
+
+ OAHWND owner;
+ HRESULT hr = video->get_Owner(&owner);
+ if (FAILED(hr)) {
+ return;
+ }
+
+ const OAHWND newOwner = reinterpret_cast<OAHWND>(m_target->winId());
+ if (owner != newOwner) {
+ video->put_Owner(newOwner);
+ video->put_MessageDrain(newOwner);
+ video->put_WindowStyle(WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
+ }
+
+ //make sure the widget takes the whole size of the parent
+ video->SetWindowPosition(0, 0, size.width(), size.height());
+
+ const QSize vsize = videoSize();
+ internalNotifyResize(size, vsize, aspectRatio, scaleMode);
+
+ ComPointer<IBasicVideo> basic(m_filter, IID_IBasicVideo);
+ if (basic) {
+ basic->SetDestinationPosition(m_dstX, m_dstY, m_dstWidth, m_dstHeight);
+ }
+ }
+
+ void VideoRendererVMR9::applyMixerSettings(qreal /*brightness*/, qreal /*contrast*/, qreal /*m_hue*/, qreal /*saturation*/)
+ {
+ //this can't be supported for WinCE
+ }
+
+ QImage VideoRendererVMR9::snapshot() const
+ {
+ ComPointer<IBasicVideo> basic(m_filter, IID_IBasicVideo);
+ if (basic) {
+ LONG bufferSize = 0;
+ //1st we get the buffer size
+ basic->GetCurrentImage(&bufferSize, 0);
+
+ QByteArray buffer;
+ buffer.resize(bufferSize);
+ HRESULT hr = basic->GetCurrentImage(&bufferSize, reinterpret_cast<long*>(buffer.data()));
+
+ if (SUCCEEDED(hr)) {
+
+ const BITMAPINFOHEADER *bmi = reinterpret_cast<const BITMAPINFOHEADER*>(buffer.constData());
+
+ const int w = qAbs(bmi->biWidth),
+ h = qAbs(bmi->biHeight);
+
+ // Create image and copy data into image.
+ QImage ret(w, h, QImage::Format_RGB32);
+
+ if (!ret.isNull()) {
+ const char *data = buffer.constData() + bmi->biSize;
+ const int bytes_per_line = w * sizeof(QRgb);
+ for (int y = h - 1; y >= 0; --y) {
+ qMemCopy(ret.scanLine(y), //destination
+ data, //source
+ bytes_per_line);
+ data += bytes_per_line;
+ }
+ }
+ return ret;
+ }
+ }
+ return QImage();
+ }
+
+#else
+ VideoRendererVMR9::VideoRendererVMR9(QWidget *target) : m_target(target)
+ {
+ m_filter = Filter(CLSID_VideoMixingRenderer9, IID_IBaseFilter);
+ if (!m_filter) {
+ qWarning("the video widget could not be initialized correctly");
+ return;
+ }
+
+ ComPointer<IVMRFilterConfig9> config(m_filter, IID_IVMRFilterConfig9);
+ Q_ASSERT(config);
+ HRESULT hr = config->SetRenderingMode(VMR9Mode_Windowless);
+ Q_ASSERT(SUCCEEDED(hr));
+ hr = config->SetNumberOfStreams(1); //for now we limit it to 1 input stream
+ Q_ASSERT(SUCCEEDED(hr));
+ ComPointer<IVMRWindowlessControl9> windowlessControl(m_filter, IID_IVMRWindowlessControl9);
+ windowlessControl->SetVideoClippingWindow(reinterpret_cast<HWND>(target->winId()));
+ }
+
+ QImage VideoRendererVMR9::snapshot() const
+ {
+ ComPointer<IVMRWindowlessControl9> windowlessControl(m_filter, IID_IVMRWindowlessControl9);
+ if (windowlessControl) {
+ BYTE *buffer = 0;
+ HRESULT hr = windowlessControl->GetCurrentImage(&buffer);
+ if (SUCCEEDED(hr)) {
+
+ const BITMAPINFOHEADER *bmi = reinterpret_cast<BITMAPINFOHEADER*>(buffer);
+ const int w = qAbs(bmi->biWidth),
+ h = qAbs(bmi->biHeight);
+
+ // Create image and copy data into image.
+ QImage ret(w, h, QImage::Format_RGB32);
+
+ if (!ret.isNull()) {
+ uchar *data = buffer + bmi->biSize;
+ const int bytes_per_line = w * sizeof(QRgb);
+ for (int y = h - 1; y >= 0; --y) {
+ qMemCopy(ret.scanLine(y), //destination
+ data, //source
+ bytes_per_line);
+ data += bytes_per_line;
+ }
+ }
+ ::CoTaskMemFree(buffer);
+ return ret;
+ }
+ }
+ return QImage();
+ }
+
+ QSize VideoRendererVMR9::videoSize() const
+ {
+ LONG w = 0,
+ h = 0;
+ ComPointer<IVMRWindowlessControl9> windowlessControl(m_filter, IID_IVMRWindowlessControl9);
+ if (windowlessControl) {
+ windowlessControl->GetNativeVideoSize( &w, &h, 0, 0);
+ }
+ return QSize(w, h);
+ }
+
+ void VideoRendererVMR9::repaintCurrentFrame(QWidget *target, const QRect &rect)
+ {
+ HDC hDC = target->getDC();
+ // repaint the video
+ ComPointer<IVMRWindowlessControl9> windowlessControl(m_filter, IID_IVMRWindowlessControl9);
+
+ HRESULT hr = windowlessControl ? windowlessControl->RepaintVideo(target->winId(), hDC) : E_POINTER;
+ if (FAILED(hr) || m_dstY > 0 || m_dstX > 0) {
+ const QColor c = target->palette().color(target->backgroundRole());
+ COLORREF color = RGB(c.red(), c.green(), c.blue());
+ HPEN hPen = ::CreatePen(PS_SOLID, 1, color);
+ HBRUSH hBrush = ::CreateSolidBrush(color);
+ ::SelectObject(hDC, hPen);
+ ::SelectObject(hDC, hBrush);
+ // repaint the video
+ if (FAILED(hr)) {
+ //black background : we use the Win32 API to avoid the ghost effect of the backing store
+ ::Rectangle(hDC, 0, 0, target->width(), target->height());
+ } else {
+ if (m_dstY > 0) {
+ ::Rectangle(hDC, 0, 0, target->width(), m_dstY); //top
+ ::Rectangle(hDC, 0, target->height() - m_dstY, target->width(), target->height()); //bottom
+ }
+ if (m_dstX > 0) {
+ ::Rectangle(hDC, 0, m_dstY, m_dstX, m_dstHeight + m_dstY); //left
+ ::Rectangle(hDC, m_dstWidth + m_dstX, m_dstY, target->width(), m_dstHeight + m_dstY); //right
+ }
+ }
+ ::DeleteObject(hPen);
+ ::DeleteObject(hBrush);
+ }
+ target->releaseDC(hDC);
+
+ }
+
+ void VideoRendererVMR9::notifyResize(const QSize &size, Phonon::VideoWidget::AspectRatio aspectRatio,
+ Phonon::VideoWidget::ScaleMode scaleMode)
+ {
+ if (!isActive()) {
+ RECT dummyRect = { 0, 0, 0, 0};
+ ComPointer<IVMRWindowlessControl9> windowlessControl(m_filter, IID_IVMRWindowlessControl9);
+ windowlessControl->SetVideoPosition(&dummyRect, &dummyRect);
+ return;
+ }
+
+
+ const QSize vsize = videoSize();
+ internalNotifyResize(size, vsize, aspectRatio, scaleMode);
+
+ RECT dstRectWin = { m_dstX, m_dstY, m_dstWidth + m_dstX, m_dstHeight + m_dstY};
+ RECT srcRectWin = { 0, 0, vsize.width(), vsize.height()};
+
+ ComPointer<IVMRWindowlessControl9> windowlessControl(m_filter, IID_IVMRWindowlessControl9);
+ if (windowlessControl) {
+ windowlessControl->SetVideoPosition(&srcRectWin, &dstRectWin);
+ }
+ }
+
+ void VideoRendererVMR9::applyMixerSettings(qreal brightness, qreal contrast, qreal hue, qreal saturation)
+ {
+ InputPin sink = BackendNode::pins(m_filter, PINDIR_INPUT).first();
+ OutputPin source;
+ if (FAILED(sink->ConnectedTo(source.pparam()))) {
+ return; //it must be connected to work
+ }
+
+ //get the mixer (used for brightness/contrast/saturation/hue)
+ ComPointer<IVMRMixerControl9> mixer(m_filter, IID_IVMRMixerControl9);
+ Q_ASSERT(mixer);
+
+ VMR9ProcAmpControl ctrl;
+ ctrl.dwSize = sizeof(ctrl);
+ ctrl.dwFlags = ProcAmpControl9_Contrast | ProcAmpControl9_Brightness | ProcAmpControl9_Saturation | ProcAmpControl9_Hue;
+ VMR9ProcAmpControlRange range;
+ range.dwSize = sizeof(range);
+
+ range.dwProperty = ProcAmpControl9_Contrast;
+ HRESULT hr = mixer->GetProcAmpControlRange(0, &range);
+ if (FAILED(hr)) {
+ return;
+ }
+ ctrl.Contrast = ((contrast < 0 ? range.MinValue : range.MaxValue) - range.DefaultValue) * qAbs(contrast) + range.DefaultValue;
+
+ //brightness
+ range.dwProperty = ProcAmpControl9_Brightness;
+ hr = mixer->GetProcAmpControlRange(0, &range);
+ if (FAILED(hr)) {
+ return;
+ }
+ ctrl.Brightness = ((brightness < 0 ? range.MinValue : range.MaxValue) - range.DefaultValue) * qAbs(brightness) + range.DefaultValue;
+
+ //saturation
+ range.dwProperty = ProcAmpControl9_Saturation;
+ hr = mixer->GetProcAmpControlRange(0, &range);
+ if (FAILED(hr)) {
+ return;
+ }
+ ctrl.Saturation = ((saturation < 0 ? range.MinValue : range.MaxValue) - range.DefaultValue) * qAbs(saturation) + range.DefaultValue;
+
+ //hue
+ range.dwProperty = ProcAmpControl9_Hue;
+ hr = mixer->GetProcAmpControlRange(0, &range);
+ if (FAILED(hr)) {
+ return;
+ }
+ ctrl.Hue = ((hue < 0 ? range.MinValue : range.MaxValue) - range.DefaultValue) * qAbs(hue) + range.DefaultValue;
+
+ //finally set the settings
+ mixer->SetProcAmpControl(0, &ctrl);
+ }
+#endif
+ }
+}
+
+QT_END_NAMESPACE
+
+#endif //QT_NO_PHONON_VIDEO
diff --git a/src/3rdparty/phonon/ds9/videorenderer_vmr9.h b/src/3rdparty/phonon/ds9/videorenderer_vmr9.h
new file mode 100644
index 0000000000..4eb237e128
--- /dev/null
+++ b/src/3rdparty/phonon/ds9/videorenderer_vmr9.h
@@ -0,0 +1,56 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library 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, either version 2.1 or 3 of the License.
+
+This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef PHONON_VIDEORENDERER_VMR9_H
+#define PHONON_VIDEORENDERER_VMR9_H
+
+#include "abstractvideorenderer.h"
+#include "compointer.h"
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_PHONON_VIDEO
+
+namespace Phonon
+{
+ namespace DS9
+ {
+ class VideoRendererVMR9 : public AbstractVideoRenderer
+ {
+ public:
+ VideoRendererVMR9(QWidget *target);
+ ~VideoRendererVMR9();
+
+ //Implementation from AbstractVideoRenderer
+ void repaintCurrentFrame(QWidget *target, const QRect &rect);
+ void notifyResize(const QSize&, Phonon::VideoWidget::AspectRatio, Phonon::VideoWidget::ScaleMode);
+ QSize videoSize() const;
+ QImage snapshot() const;
+ void applyMixerSettings(qreal brightness, qreal contrast, qreal m_hue, qreal saturation);
+ bool isNative() const;
+ private:
+ QWidget *m_target;
+ };
+ }
+}
+
+#endif //QT_NO_PHONON_VIDEO
+
+QT_END_NAMESPACE
+
+#endif
+
diff --git a/src/3rdparty/phonon/ds9/videowidget.cpp b/src/3rdparty/phonon/ds9/videowidget.cpp
new file mode 100644
index 0000000000..de7ce5fc1f
--- /dev/null
+++ b/src/3rdparty/phonon/ds9/videowidget.cpp
@@ -0,0 +1,397 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library 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, either version 2.1 or 3 of the License.
+
+This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "videowidget.h"
+
+#include <QtGui/QPainter>
+#include <QtGui/QPaintEvent>
+#include <QtCore/QTimer>
+#include <QtCore/QSettings>
+
+#include "mediaobject.h"
+
+#include "videorenderer_vmr9.h"
+#include "videorenderer_soft.h"
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_PHONON_VIDEO
+
+namespace Phonon
+{
+ namespace DS9
+ {
+ //class used internally to return the widget where the video is shown on
+ class VideoWindow : public QWidget
+ {
+ public:
+ explicit VideoWindow(QWidget *parent, VideoWidget *vw)
+ : QWidget(parent), m_node(vw), m_currentRenderer(0)
+ {
+ //default background color
+ setPalette(QPalette(Qt::black));
+ setAttribute(Qt::WA_OpaquePaintEvent, true);
+ setAttribute(Qt::WA_NoSystemBackground, true);
+ setAttribute(Qt::WA_PaintOnScreen, true);
+ setAutoFillBackground(false);
+ }
+
+ QPaintEngine* paintEngine() const
+ {
+ return 0;
+ }
+
+ bool isEmbedded() const
+ {
+#if QT_VERSION >= 0x040400
+ return window()->testAttribute(Qt::WA_DontShowOnScreen);
+#else
+ return false;
+#endif
+ }
+
+ bool needsSoftRendering() const
+ {
+ QPaintDevice *dev = QPainter::redirected(this, 0);
+ return (dev && dev != this);
+ }
+
+ void resizeEvent(QResizeEvent *e)
+ {
+ m_node->updateVideoSize();
+ QWidget::resizeEvent(e);
+ }
+
+ AbstractVideoRenderer *currentRenderer() const
+ {
+ return m_currentRenderer;
+ }
+
+ void setCurrentRenderer(AbstractVideoRenderer *renderer)
+ {
+ m_currentRenderer = renderer;
+ update();
+ }
+
+ QSize sizeHint() const
+ {
+ return m_currentRenderer->sizeHint().expandedTo(QWidget::sizeHint());
+ }
+
+ void changeEvent(QEvent *e)
+ {
+ checkCurrentRenderingMode();
+ QWidget::changeEvent(e);
+ }
+
+ void setVisible(bool visible)
+ {
+ checkCurrentRenderingMode();
+ QWidget::setVisible(visible);
+ }
+
+ void paintEvent(QPaintEvent *e)
+ {
+ checkCurrentRenderingMode();
+ m_currentRenderer->repaintCurrentFrame(this, e->rect());
+ }
+
+ //this code manages the activation/deactivation of the screensaver
+ /*bool event(QEvent *e)
+ {
+ if (e->type() == QEvent::Resize) {
+ //we disable the screensaver if the video is in fullscreen mode
+ disableScreenSaver(window()->windowState() & Qt::WindowFullScreen);
+ }
+ return QWidget::event(e);
+ }*/
+
+ private:
+ //for fullscreen mode
+ void disableScreenSaver(bool b)
+ {
+ const QLatin1String screenSaverActive("ScreenSaveActive");
+ QSettings settings( QLatin1String("HKEY_CURRENT_USER\\Control Panel\\Desktop"), QSettings::NativeFormat);
+ if (b) {
+ if (m_restoreScreenSaverActive.isNull()) {
+ //we store the value to be able to restore it later
+ m_restoreScreenSaverActive = settings.value(screenSaverActive);
+ settings.setValue(screenSaverActive, QString::number(!b));
+ }
+ } else if (!m_restoreScreenSaverActive.isNull()) {
+ //we restore the previous value
+ settings.setValue(screenSaverActive, m_restoreScreenSaverActive);
+ }
+ }
+
+ void checkCurrentRenderingMode()
+ {
+ if (!m_currentRenderer)
+ return;
+
+ if (m_currentRenderer->isNative()) {
+ if (isEmbedded()) {
+ //we need to switch to software renderer
+ m_currentRenderer = m_node->switchRendering(m_currentRenderer);
+ setAttribute(Qt::WA_PaintOnScreen, false);
+ } else if (needsSoftRendering()) {
+ m_node->performSoftRendering(m_currentRenderer->snapshot());
+ }
+ } else if (!isEmbedded()) {
+ m_currentRenderer = m_node->switchRendering(m_currentRenderer);
+ setAttribute(Qt::WA_PaintOnScreen, true);
+ }
+ }
+
+ VideoWidget *m_node;
+ AbstractVideoRenderer *m_currentRenderer;
+ QVariant m_restoreScreenSaverActive;
+ };
+
+ VideoWidget::VideoWidget(QWidget *parent)
+ : BackendNode(parent), m_aspectRatio(Phonon::VideoWidget::AspectRatioAuto),
+ m_scaleMode(Phonon::VideoWidget::FitInView),
+ m_brightness(0.), m_contrast(0.), m_hue(0.), m_saturation(0.), m_noNativeRendererSupported(false)
+
+ {
+ //initialisation of the widget
+ m_widget = new VideoWindow(parent, this);
+
+ //initialization of the renderers
+ qMemSet(m_renderers, 0, sizeof(m_renderers));
+
+ for(int i = 0; i< FILTER_COUNT ;++i) {
+ //This might return a non native (ie Qt) renderer in case native is not supported
+ AbstractVideoRenderer *renderer = getRenderer(i, Native, true);
+ m_filters[i] = renderer->getFilter();
+ }
+
+ //by default, we take the first VideoWindow object
+ setCurrentGraph(0);
+ }
+
+ VideoWidget::~VideoWidget()
+ {
+ for (int i = 0; i < 4; ++i) {
+ delete m_renderers[i];
+ }
+ }
+
+ void VideoWidget::notifyVideoLoaded()
+ {
+ updateVideoSize();
+ m_widget->updateGeometry();
+ }
+
+ AbstractVideoRenderer *VideoWidget::switchRendering(AbstractVideoRenderer *current)
+ {
+ const bool toNative = !current->isNative();
+ if (toNative && m_noNativeRendererSupported)
+ return current; //no switch here
+
+ //firt we delete the renderer
+ //initialization of the widgets
+ for(int i = 0; i < FILTER_COUNT; ++i) {
+ Filter oldFilter = m_filters[i];
+
+ //Let's create a software renderer
+ AbstractVideoRenderer *renderer = getRenderer(i, toNative ? Native : NonNative, true);
+
+ if (m_mediaObject) {
+ m_mediaObject->switchFilters(i, oldFilter, renderer->getFilter());
+ }
+
+ m_filters[i] = renderer->getFilter();
+ }
+
+ return getRenderer(mediaObject()->currentGraph()->index(), toNative ? Native: NonNative);
+ }
+
+ void VideoWidget::performSoftRendering(const QImage &currentImage)
+ {
+ const int graphIndex = mediaObject()->currentGraph()->index();
+ VideoRendererSoft *r = static_cast<VideoRendererSoft*>(getRenderer(graphIndex, NonNative, true /*autocreation*/));
+ r->setSnapshot(currentImage);
+ r->notifyResize(m_widget->size(), m_aspectRatio, m_scaleMode);
+ r->repaintCurrentFrame(m_widget, m_widget->rect());
+
+ }
+
+ void VideoWidget::setCurrentGraph(int index)
+ {
+ for(int i = 0; i < 2; ++i) {
+ if (AbstractVideoRenderer *renderer = getRenderer(i, Native))
+ renderer->setActive(index == i);
+ }
+
+ //be sure to update all the things that needs an update
+ applyMixerSettings();
+ updateVideoSize();
+
+ AbstractVideoRenderer *r = m_widget->currentRenderer();
+
+ //we determine dynamically if it is native or non native
+ r = getRenderer(index, !r || r->isNative() ? Native : NonNative);
+ if (!r)
+ r = getRenderer(index, NonNative);
+ m_widget->setCurrentRenderer(r);
+ }
+
+
+ Phonon::VideoWidget::AspectRatio VideoWidget::aspectRatio() const
+ {
+ return m_aspectRatio;
+ }
+
+ void VideoWidget::setAspectRatio(Phonon::VideoWidget::AspectRatio aspectRatio)
+ {
+ m_aspectRatio = aspectRatio;
+ updateVideoSize();
+ }
+
+ Phonon::VideoWidget::ScaleMode VideoWidget::scaleMode() const
+ {
+ return m_scaleMode;
+ }
+
+
+ QWidget *VideoWidget::widget()
+ {
+ return m_widget;
+ }
+
+
+ void VideoWidget::setScaleMode(Phonon::VideoWidget::ScaleMode scaleMode)
+ {
+ m_scaleMode = scaleMode;
+ updateVideoSize();
+ }
+
+ void VideoWidget::setBrightness(qreal b)
+ {
+ m_brightness = b;
+ applyMixerSettings();
+ }
+
+ void VideoWidget::setContrast(qreal c)
+ {
+ m_contrast = c;
+ applyMixerSettings();
+ }
+
+ void VideoWidget::setHue(qreal h)
+ {
+ m_hue = h;
+ applyMixerSettings();
+ }
+
+ void VideoWidget::setSaturation(qreal s)
+ {
+ m_saturation = s;
+ applyMixerSettings();
+ }
+
+ qreal VideoWidget::brightness() const
+ {
+ return m_brightness;
+ }
+
+
+ qreal VideoWidget::contrast() const
+ {
+ return m_contrast;
+ }
+
+ qreal VideoWidget::hue() const
+ {
+ return m_hue;
+ }
+
+ qreal VideoWidget::saturation() const
+ {
+ return m_saturation;
+ }
+
+
+ AbstractVideoRenderer *VideoWidget::getRenderer(int graphIndex, RendererType type, bool autoCreate)
+ {
+ int index = graphIndex * 2 + type;
+ if (m_renderers[index] == 0 && autoCreate) {
+ AbstractVideoRenderer *renderer = 0;
+ if (type == Native) {
+ renderer = new VideoRendererVMR9(m_widget);
+ if (renderer->getFilter() == 0) {
+ //instanciating the renderer might fail with error VFW_E_DDRAW_CAPS_NOT_SUITABLE (0x80040273)
+ m_noNativeRendererSupported = true;
+ delete renderer;
+ renderer = 0;
+ }
+ }
+
+ if (renderer == 0) {
+ type = NonNative;
+ index = graphIndex * 2 + type;
+ if (m_renderers[index] == 0)
+ renderer = new VideoRendererSoft(m_widget); //this always succeeds
+ else
+ renderer = m_renderers[index];
+ }
+
+ m_renderers[index] = renderer;
+
+ //be sure to update all the things that needs an update
+ applyMixerSettings();
+ updateVideoSize();
+
+ }
+ return m_renderers[index];
+ }
+
+ //this must be called whe nthe node is actually connected
+ void VideoWidget::applyMixerSettings() const
+ {
+ for (int i = 0; i < 4; ++i) {
+ if (AbstractVideoRenderer *renderer = m_renderers[i])
+ renderer->applyMixerSettings(m_brightness, m_contrast, m_hue, m_saturation);
+ }
+ }
+
+ void VideoWidget::connected(BackendNode *, const InputPin&)
+ {
+ //in case of a connection, we simply reapply the mixer settings
+ applyMixerSettings();
+ updateVideoSize();
+ }
+
+ void VideoWidget::updateVideoSize() const
+ {
+ for (int i = 0; i < 4; ++i) {
+ if (AbstractVideoRenderer *renderer = m_renderers[i])
+ renderer->notifyResize(m_widget->size(), m_aspectRatio, m_scaleMode);
+ }
+ }
+
+
+
+ }
+}
+
+#endif //QT_NO_PHONON_VIDEO
+
+QT_END_NAMESPACE
+
+#include "moc_videowidget.cpp"
diff --git a/src/3rdparty/phonon/ds9/videowidget.h b/src/3rdparty/phonon/ds9/videowidget.h
new file mode 100644
index 0000000000..fc8a6e3879
--- /dev/null
+++ b/src/3rdparty/phonon/ds9/videowidget.h
@@ -0,0 +1,96 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library 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, either version 2.1 or 3 of the License.
+
+This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef PHONON_VIDEOWIDGET_H
+#define PHONON_VIDEOWIDGET_H
+
+#include <QtGui/QWidget>
+#include <phonon/videowidgetinterface.h>
+#include "backendnode.h"
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_PHONON_VIDEO
+
+namespace Phonon
+{
+ namespace DS9
+ {
+ class VideoWindow;
+ class AbstractVideoRenderer;
+
+ class VideoWidget : public BackendNode, public Phonon::VideoWidgetInterface
+ {
+ enum RendererType
+ {
+ Native = 0,
+ NonNative = 1
+ };
+
+ Q_OBJECT
+ Q_INTERFACES(Phonon::VideoWidgetInterface)
+ public:
+ VideoWidget(QWidget *parent = 0);
+ ~VideoWidget();
+
+ Phonon::VideoWidget::AspectRatio aspectRatio() const;
+ void setAspectRatio(Phonon::VideoWidget::AspectRatio aspectRatio);
+ Phonon::VideoWidget::ScaleMode scaleMode() const;
+ void setScaleMode(Phonon::VideoWidget::ScaleMode);
+ qreal brightness() const;
+ void setBrightness(qreal);
+ qreal contrast() const;
+ void setContrast(qreal);
+ qreal hue() const;
+ void setHue(qreal);
+ qreal saturation() const;
+ void setSaturation(qreal);
+
+ void setCurrentGraph(int index);
+
+ QWidget *widget();
+
+ void notifyVideoLoaded();
+ AbstractVideoRenderer *switchRendering(AbstractVideoRenderer *current);
+ void performSoftRendering(const QImage &currentImage);
+
+ //apply contrast/brightness/hue/saturation
+ void applyMixerSettings() const;
+ void updateVideoSize() const;
+
+ protected:
+ virtual void connected(BackendNode *, const InputPin& inpin);
+
+ private:
+ AbstractVideoRenderer *getRenderer(int graphIndex, RendererType type, bool autoCreate = false);
+
+ Phonon::VideoWidget::AspectRatio m_aspectRatio;
+ Phonon::VideoWidget::ScaleMode m_scaleMode;
+
+ VideoWindow *m_widget;
+ qreal m_brightness, m_contrast, m_hue, m_saturation;
+ AbstractVideoRenderer* m_renderers[4];
+ mutable bool m_noNativeRendererSupported;
+ };
+ }
+}
+
+QT_END_NAMESPACE
+
+#endif // PHONON_VIDEOWIDGET_H
+
+#endif //QT_NO_PHONON_VIDEO
diff --git a/src/3rdparty/phonon/ds9/volumeeffect.cpp b/src/3rdparty/phonon/ds9/volumeeffect.cpp
new file mode 100644
index 0000000000..2fd1afcc9f
--- /dev/null
+++ b/src/3rdparty/phonon/ds9/volumeeffect.cpp
@@ -0,0 +1,296 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library 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, either version 2.1 or 3 of the License.
+
+This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "volumeeffect.h"
+#include "qbasefilter.h"
+#include "qmeminputpin.h"
+
+#include <QtCore/qmath.h> //for sqrt
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_PHONON_VOLUMEFADEREFFECT
+
+
+namespace Phonon
+{
+ namespace DS9
+ {
+ /**************************************************************************
+ * curve functions
+ *************************************************************************/
+
+ static qreal curveValueFadeIn3dB(const qreal fadeStart, const qreal fadeDiff, const qreal completed)
+ {
+ return (fadeStart + fadeDiff * sqrt(completed));
+ }
+ static qreal curveValueFadeOut3dB(const qreal fadeStart, const qreal fadeDiff, const qreal completed)
+ {
+ return (fadeStart + fadeDiff * (1.0 - sqrt(1.0 - completed)));
+ }
+ // in == out for a linear fade
+ static qreal curveValueFade6dB(const qreal fadeStart, const qreal fadeDiff, const qreal completed)
+ {
+ return (fadeStart + fadeDiff * completed);
+ }
+ static qreal curveValueFadeIn9dB(const qreal fadeStart, const qreal fadeDiff, const qreal completed)
+ {
+ return (fadeStart + fadeDiff * pow(completed, 1.5));
+ }
+ static qreal curveValueFadeOut9dB(const qreal fadeStart, const qreal fadeDiff, const qreal completed)
+ {
+ return (fadeStart + fadeDiff * (1.0 - pow(1.0 - completed, 1.5)));
+ }
+ static qreal curveValueFadeIn12dB(const qreal fadeStart, const qreal fadeDiff, const qreal completed)
+ {
+ return (fadeStart + fadeDiff * completed * completed);
+ }
+ static qreal curveValueFadeOut12dB(const qreal fadeStart, const qreal fadeDiff, const qreal completed)
+ {
+ const qreal x = 1.0 - completed;
+ return (fadeStart + fadeDiff * (1.0 - x * x));
+ }
+
+ static const QVector<AM_MEDIA_TYPE> audioMediaType()
+ {
+ QVector<AM_MEDIA_TYPE> ret;
+
+ AM_MEDIA_TYPE mt;
+ mt.majortype = MEDIATYPE_Audio;
+ mt.subtype = MEDIASUBTYPE_PCM;
+ mt.bFixedSizeSamples = 1;
+ mt.bTemporalCompression = 0;
+ mt.pUnk = 0;
+ mt.lSampleSize = 1;
+ mt.cbFormat = 0;
+ mt.pbFormat = 0;
+ mt.formattype = GUID_NULL;
+ ret << mt;
+ return ret;
+ }
+
+ class VolumeMemInputPin : public QMemInputPin
+ {
+ public:
+ VolumeMemInputPin(QBaseFilter *parent, const QVector<AM_MEDIA_TYPE> &mt) : QMemInputPin(parent, mt, true /*transform*/)
+ {
+ }
+
+ ~VolumeMemInputPin()
+ {
+ }
+
+ STDMETHODIMP NotifyAllocator(IMemAllocator *alloc, BOOL b)
+ {
+ ALLOCATOR_PROPERTIES prop;
+ HRESULT hr = alloc->GetProperties(&prop);
+ if (SUCCEEDED(hr) && prop.cBuffers > 1) {
+ //this allows to reduce the latency for sound
+ //the problem is that too low numbers makes the whole thing fail...
+ ALLOCATOR_PROPERTIES actual;
+ prop.cBuffers = 1;
+ alloc->SetProperties(&prop, &actual);
+ }
+ return QMemInputPin::NotifyAllocator(alloc, b);
+ }
+
+ };
+
+ class VolumeMemOutputPin : public QPin
+ {
+ public:
+ VolumeMemOutputPin(QBaseFilter *parent, const QVector<AM_MEDIA_TYPE> &mt) : QPin(parent, PINDIR_OUTPUT, mt)
+ {
+ }
+
+ ~VolumeMemOutputPin()
+ {
+ }
+
+ };
+
+ class VolumeEffectFilter : public QBaseFilter
+ {
+ public:
+ VolumeEffectFilter(VolumeEffect *);
+
+ //reimplementation
+ virtual HRESULT processSample(IMediaSample *);
+
+ private:
+ void treatOneSamplePerChannel(BYTE **buffer, int sampleSize, int channelCount, int frequency);
+
+ QMemInputPin *m_input;
+ QPin *m_output;
+ VolumeEffect *m_volumeEffect;
+ };
+
+ VolumeEffectFilter::VolumeEffectFilter(VolumeEffect *ve) : QBaseFilter(CLSID_NULL),
+ m_volumeEffect(ve)
+ {
+ QVector<AM_MEDIA_TYPE> mt;
+
+ //creating the output
+ m_output = new VolumeMemOutputPin(this, mt);
+
+ //then creating the input
+ mt << audioMediaType();
+ m_input = new VolumeMemInputPin(this, mt);
+ m_input->addOutput(m_output); //make the connection here
+ }
+
+ void VolumeEffectFilter::treatOneSamplePerChannel(BYTE **buffer, int sampleSize, int channelCount, int frequency)
+ {
+ float volume = m_volumeEffect->volume();
+ if (m_volumeEffect->m_fading) {
+ const qreal lastSample = m_volumeEffect->m_fadeDuration * frequency / 1000;
+ const qreal completed = qreal(m_volumeEffect->m_fadeSamplePosition++) / lastSample;
+
+ if (qFuzzyCompare(completed, qreal(1.))) {
+ m_volumeEffect->setVolume(m_volumeEffect->m_targetVolume);
+ m_volumeEffect->m_fading = false; //we end the fading effect
+ } else {
+ volume = m_volumeEffect->m_fadeCurveFn(m_volumeEffect->m_initialVolume,
+ m_volumeEffect->m_targetVolume - m_volumeEffect->m_initialVolume,
+ completed);
+ }
+ }
+
+ for(int c = 0; c < channelCount; ++c) {
+ switch (sampleSize)
+ {
+ case 2:
+ {
+ short *shortBuffer = reinterpret_cast<short*>(*buffer);
+ *shortBuffer *= qRound(volume);
+ }
+ break;
+ case 1:
+ **buffer *= qRound(volume);
+ break;
+ default:
+ break;
+ }
+
+ *buffer += sampleSize;
+ }
+ }
+
+ HRESULT VolumeEffectFilter::processSample(IMediaSample * ms)
+ {
+ BYTE *buffer = 0;
+ ms->GetPointer(&buffer);
+ if (buffer) {
+ const AM_MEDIA_TYPE &mt = m_output->connectedType();
+ if (mt.formattype != FORMAT_WaveFormatEx) {
+ return VFW_E_INVALIDMEDIATYPE;
+ }
+ WAVEFORMATEX *format = reinterpret_cast<WAVEFORMATEX*>(mt.pbFormat);
+ const int channelCount = format->nChannels;
+ const int sampleSize = format->wBitsPerSample / 8; //...in bytes
+
+
+ const BYTE *end = buffer + ms->GetActualDataLength();
+ while (buffer < end) {
+ treatOneSamplePerChannel(&buffer, sampleSize, channelCount, format->nSamplesPerSec);
+ }
+ }
+
+ return S_OK;
+ }
+
+ VolumeEffect::VolumeEffect(QObject *parent) : Effect(parent),
+ m_volume(1), m_fadeCurve(Phonon::VolumeFaderEffect::Fade3Decibel),
+ m_fading(false), m_initialVolume(0), m_targetVolume(0), m_fadeDuration(0),
+ m_fadeSamplePosition(0)
+ {
+ //creation of the effects
+ for(int i = 0; i < FILTER_COUNT; ++i) {
+ VolumeEffectFilter *f = new VolumeEffectFilter(this);
+ m_filters[i] = Filter(f);
+ }
+ }
+
+ float VolumeEffect::volume() const
+ {
+ return m_volume;
+ }
+
+ void VolumeEffect::setVolume(float newVolume)
+ {
+ m_volume = newVolume;
+ }
+
+ Phonon::VolumeFaderEffect::FadeCurve VolumeEffect::fadeCurve() const
+ {
+ return m_fadeCurve;
+ }
+
+ void VolumeEffect::setFadeCurve(Phonon::VolumeFaderEffect::FadeCurve curve)
+ {
+ m_fadeCurve = curve;
+ }
+
+
+ void VolumeEffect::fadeTo(float vol, int duration)
+ {
+ m_fading = true; //will be set back to false when fading is finished
+ m_targetVolume = vol;
+ m_fadeSamplePosition = 0;
+ m_initialVolume = m_volume;
+ m_fadeDuration = duration;
+
+ //in or out?
+ const bool in = vol > m_volume;
+
+ switch(m_fadeCurve)
+ {
+ case Phonon::VolumeFaderEffect::Fade6Decibel:
+ m_fadeCurveFn = curveValueFade6dB;
+ break;
+ case Phonon::VolumeFaderEffect::Fade9Decibel:
+ if (in) {
+ m_fadeCurveFn = curveValueFadeIn9dB;
+ } else {
+ m_fadeCurveFn = curveValueFadeOut9dB;
+ }
+ break;
+ case Phonon::VolumeFaderEffect::Fade12Decibel:
+ if (in) {
+ m_fadeCurveFn = curveValueFadeIn12dB;
+ } else {
+ m_fadeCurveFn = curveValueFadeOut12dB;
+ }
+ break;
+ case Phonon::VolumeFaderEffect::Fade3Decibel:
+ default:
+ if (in) {
+ m_fadeCurveFn = curveValueFadeIn3dB;
+ } else {
+ m_fadeCurveFn = curveValueFadeOut3dB;
+ }
+ break;
+ }
+ }
+ }
+}
+
+#endif //QT_NO_PHONON_VOLUMEFADEREFFECT
+
+QT_END_NAMESPACE
+
+#include "moc_volumeeffect.cpp"
diff --git a/src/3rdparty/phonon/ds9/volumeeffect.h b/src/3rdparty/phonon/ds9/volumeeffect.h
new file mode 100644
index 0000000000..d1b0186f91
--- /dev/null
+++ b/src/3rdparty/phonon/ds9/volumeeffect.h
@@ -0,0 +1,71 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library 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, either version 2.1 or 3 of the License.
+
+This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef PHONON_VOLUMEEFFECT_H
+#define PHONON_VOLUMEEFFECT_H
+
+#include "effect.h"
+#include <phonon/volumefaderinterface.h>
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_PHONON_VOLUMEFADEREFFECT
+
+namespace Phonon
+{
+ namespace DS9
+ {
+ class VolumeEffectFilter;
+ class VolumeEffect : public Effect, public Phonon::VolumeFaderInterface
+ {
+ Q_OBJECT
+ Q_INTERFACES(Phonon::VolumeFaderInterface)
+ public:
+ VolumeEffect(QObject *parent);
+
+ //reimplementation
+ virtual float volume() const;
+ virtual void setVolume(float);
+ virtual Phonon::VolumeFaderEffect::FadeCurve fadeCurve() const;
+ virtual void setFadeCurve(Phonon::VolumeFaderEffect::FadeCurve);
+ virtual void fadeTo(float, int);
+
+ private:
+ float m_volume;
+
+ //paramaters used to fade
+ Phonon::VolumeFaderEffect::FadeCurve m_fadeCurve;
+
+ bool m_fading; //determines if we should be fading.
+ float m_initialVolume;
+ float m_targetVolume;
+ int m_fadeDuration;
+ int m_fadeSamplePosition;
+ qreal (*m_fadeCurveFn)(const qreal, const qreal, const qreal);
+
+ //allow the filter to get access to that
+ friend class VolumeEffectFilter;
+
+ };
+ }
+}
+
+#endif //QT_NO_PHONON_VOLUMEFADEREFFECT
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/3rdparty/phonon/gstreamer/CMakeLists.txt b/src/3rdparty/phonon/gstreamer/CMakeLists.txt
new file mode 100644
index 0000000000..4946f5fbe8
--- /dev/null
+++ b/src/3rdparty/phonon/gstreamer/CMakeLists.txt
@@ -0,0 +1,72 @@
+# Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+# Copyright (C) 2008 Matthias Kretz <kretz@kde.org>
+#
+# This library 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, either version 2 or 3 of the License.
+#
+# This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+project(phonon-gstreamer)
+include(ConfigureChecks.cmake)
+
+if (BUILD_PHONON_GSTREAMER)
+ include_directories(${GSTREAMER_INCLUDE_DIR} ${GLIB2_INCLUDE_DIR}
+ ${LIBXML2_INCLUDE_DIR})
+
+ set(phonon_gstreamer_SRCS
+ audiooutput.cpp
+ artssink.cpp
+ backend.cpp
+ devicemanager.cpp
+ effectmanager.cpp
+ gsthelper.cpp
+ mediaobject.cpp
+ medianode.cpp
+ effect.cpp
+ medianodeevent.cpp
+ videowidget.cpp
+ qwidgetvideosink.cpp
+ streamreader.cpp
+ phononsrc.cpp
+ message.cpp
+ audioeffect.cpp
+ abstractrenderer.cpp
+ x11renderer.cpp
+ widgetrenderer.cpp
+ glrenderer.cpp
+ volumefadereffect.cpp
+ )
+
+ find_package(Alsa)
+ if(ALSA_FOUND)
+ add_definitions(-DUSE_ALSASINK2)
+ include_directories(${ALSA_INCLUDES})
+ set(phonon_gstreamer_SRCS
+ ${phonon_gstreamer_SRCS}
+ alsasink2.c
+ )
+ endif(ALSA_FOUND)
+
+ automoc4(phonon_gstreamer phonon_gstreamer_SRCS)
+ add_library(phonon_gstreamer SHARED ${phonon_gstreamer_SRCS})
+ set_target_properties(phonon_gstreamer PROPERTIES PREFIX "")
+ target_link_libraries(phonon_gstreamer
+ ${QT_QTOPENGL_LIBRARY}
+ ${PHONON_LIBS} ${OPENGL_gl_LIBRARY}
+ ${GSTREAMER_LIBRARIES} ${GSTREAMER_BASE_LIBRARY} ${GSTREAMER_INTERFACE_LIBRARY}
+ ${GSTREAMER_PLUGIN_VIDEO_LIBRARIES} ${GSTREAMER_PLUGIN_AUDIO_LIBRARIES}
+ ${GLIB2_LIBRARIES} ${GOBJECT_LIBRARIES})
+ if(ALSA_FOUND)
+ target_link_libraries(phonon_gstreamer ${ASOUND_LIBRARY})
+ endif(ALSA_FOUND)
+
+ install(TARGETS phonon_gstreamer DESTINATION ${PLUGIN_INSTALL_DIR}/plugins/phonon_backend)
+ install(FILES gstreamer.desktop DESTINATION ${SERVICES_INSTALL_DIR}/phononbackends)
+endif (BUILD_PHONON_GSTREAMER)
diff --git a/src/3rdparty/phonon/gstreamer/ConfigureChecks.cmake b/src/3rdparty/phonon/gstreamer/ConfigureChecks.cmake
new file mode 100644
index 0000000000..f2922e10bb
--- /dev/null
+++ b/src/3rdparty/phonon/gstreamer/ConfigureChecks.cmake
@@ -0,0 +1,37 @@
+# Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+#
+# This library 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, either version 2 or 3 of the License.
+#
+# This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+macro_optional_find_package(GStreamer)
+macro_log_feature(GSTREAMER_FOUND "GStreamer" "gstreamer 0.10 is required for the multimedia backend" "http://gstreamer.freedesktop.org/modules/" FALSE "0.10")
+
+macro_optional_find_package(GStreamerPlugins)
+macro_log_feature(GSTREAMER_PLUGIN_VIDEO_LIBRARIES "GStreamer video plugin" "The gstreamer video plugin (part of gstreamer-plugins-base 0.10) is required for the multimedia gstreamer backend" "http://gstreamer.freedesktop.org/modules/" FALSE "0.10")
+
+macro_optional_find_package(GLIB2)
+macro_log_feature(GLIB2_FOUND "GLib2" "GLib 2 is required to compile the gstreamer backend for Phonon" "http://www.gtk.org/download/" FALSE)
+
+macro_optional_find_package(GObject)
+# No log, since GObject is bundled with GLib
+
+macro_optional_find_package(LibXml2)
+macro_log_feature(LIBXML2_FOUND "LibXml2" "LibXml2 is required to compile the gstreamer backend for Phonon" "http://xmlsoft.org/downloads.html" FALSE)
+
+macro_optional_find_package(OpenGL)
+macro_log_feature(OPENGL_FOUND "OpenGL" "OpenGL support is required to compile the gstreamer backend for Phonon" "" FALSE)
+
+if (GSTREAMER_FOUND AND GSTREAMER_PLUGIN_VIDEO_LIBRARIES AND GLIB2_FOUND AND GOBJECT_FOUND AND LIBXML2_FOUND AND OPENGL_FOUND)
+ set(BUILD_PHONON_GSTREAMER TRUE)
+else (GSTREAMER_FOUND AND GSTREAMER_PLUGIN_VIDEO_LIBRARIES AND GLIB2_FOUND AND GOBJECT_FOUND AND LIBXML2_FOUND AND OPENGL_FOUND)
+ set(BUILD_PHONON_GSTREAMER FALSE)
+endif (GSTREAMER_FOUND AND GSTREAMER_PLUGIN_VIDEO_LIBRARIES AND GLIB2_FOUND AND GOBJECT_FOUND AND LIBXML2_FOUND AND OPENGL_FOUND)
diff --git a/src/3rdparty/phonon/gstreamer/Messages.sh b/src/3rdparty/phonon/gstreamer/Messages.sh
new file mode 100644
index 0000000000..4fdf1efffb
--- /dev/null
+++ b/src/3rdparty/phonon/gstreamer/Messages.sh
@@ -0,0 +1,5 @@
+#! /usr/bin/env bash
+find ./ -maxdepth 1 -name "*.cpp" -print > files
+find ./ -maxdepth 1 -name "*.h" -print >> files
+$XGETTEXT_QT --copyright-holder=This_file_is_part_of_KDE --msgid-bugs-address=http://bugs.kde.org --files-from=files -o $podir/phonon_gstreamer.pot
+rm files
diff --git a/src/3rdparty/phonon/gstreamer/abstractrenderer.cpp b/src/3rdparty/phonon/gstreamer/abstractrenderer.cpp
new file mode 100644
index 0000000000..924b6118d6
--- /dev/null
+++ b/src/3rdparty/phonon/gstreamer/abstractrenderer.cpp
@@ -0,0 +1,56 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "abstractrenderer.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace Gstreamer
+{
+
+
+AbstractRenderer::~AbstractRenderer()
+{
+ if (m_videoSink) {
+ gst_object_unref (GST_OBJECT (m_videoSink)); //Take ownership
+ m_videoSink = 0;
+ }
+}
+
+void AbstractRenderer::aspectRatioChanged(Phonon::VideoWidget::AspectRatio aspectRatio)
+{
+ Q_UNUSED(aspectRatio);
+}
+
+void AbstractRenderer::scaleModeChanged(Phonon::VideoWidget::ScaleMode scaleMode)
+{
+ Q_UNUSED(scaleMode);
+}
+
+void AbstractRenderer::movieSizeChanged(const QSize &size)
+{
+ Q_UNUSED(size);
+}
+
+}
+} //namespace Phonon::Gstreamer
+
+QT_END_NAMESPACE
+
+
diff --git a/src/3rdparty/phonon/gstreamer/abstractrenderer.h b/src/3rdparty/phonon/gstreamer/abstractrenderer.h
new file mode 100644
index 0000000000..140413d142
--- /dev/null
+++ b/src/3rdparty/phonon/gstreamer/abstractrenderer.h
@@ -0,0 +1,62 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2 //Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).007 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef Phonon_GSTREAMER_ABSTRACTRENDERER_H
+#define Phonon_GSTREAMER_ABSTRACTRENDERER_H
+
+#include "backend.h"
+#include "common.h"
+#include "medianode.h"
+#include <phonon/videowidget.h>
+
+QT_BEGIN_NAMESPACE
+
+class QString;
+namespace Phonon
+{
+namespace Gstreamer
+{
+
+class VideoWidget;
+
+class AbstractRenderer
+{
+public:
+ AbstractRenderer(VideoWidget *video) :
+ m_videoWidget(video)
+ , m_videoSink(0) { }
+ virtual ~AbstractRenderer();
+ virtual GstElement *videoSink() {return m_videoSink;}
+ virtual void aspectRatioChanged(Phonon::VideoWidget::AspectRatio aspectRatio);
+ virtual void scaleModeChanged(Phonon::VideoWidget::ScaleMode scaleMode);
+ virtual void movieSizeChanged(const QSize &movieSize);
+ virtual void handleMediaNodeEvent(const MediaNodeEvent *event) = 0;
+ virtual bool eventFilter(QEvent *) = 0;
+ virtual void handlePaint(QPaintEvent *) {}
+ virtual bool paintsOnWidget() { return true; } // Controls overlays
+
+protected:
+ VideoWidget *m_videoWidget;
+ GstElement *m_videoSink;
+};
+
+}
+} //namespace Phonon::Gstreamer
+
+QT_END_NAMESPACE
+
+#endif // Phonon_GSTREAMER_ABSTRACTRENDERER_H
diff --git a/src/3rdparty/phonon/gstreamer/alsasink2.c b/src/3rdparty/phonon/gstreamer/alsasink2.c
new file mode 100644
index 0000000000..4dcb1400c5
--- /dev/null
+++ b/src/3rdparty/phonon/gstreamer/alsasink2.c
@@ -0,0 +1,1756 @@
+/* GStreamer
+ * Copyright (C) 2001 CodeFactory AB
+ * Copyright (C) 2001 Thomas Nyberg <thomas@codefactory.se>
+ * Copyright (C) 2001-2002 Andy Wingo <apwingo@eos.ncsu.edu>
+ * Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
+ * Copyright (C) 2005 Wim Taymans <wim@fluendo.com>
+ * Copyright (C) 2005, 2006 Tim-Philipp Müller <tim centricular net>
+ * Copyright (C) 2008 Matthias Kretz <kretz@kde.org>
+ *
+ * gstalsasink2.c:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * SECTION:element-alsasink2
+ * @short_description: play audio to an ALSA device
+ * @see_also: alsasrc, alsamixer
+ *
+ * <refsect2>
+ * <para>
+ * This element renders raw audio samples using the ALSA api.
+ * </para>
+ * <title>Example pipelines</title>
+ * <para>
+ * Play an Ogg/Vorbis file.
+ * </para>
+ * <programlisting>
+ * gst-launch -v filesrc location=sine.ogg ! oggdemux ! vorbisdec ! audioconvert ! audioresample ! alsasink2
+ * </programlisting>
+ * </refsect2>
+ *
+ * Last reviewed on 2006-03-01 (0.10.4)
+ */
+
+#define _XOPEN_SOURCE 600
+
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <getopt.h>
+#include <alsa/asoundlib.h>
+
+#include "alsasink2.h"
+
+#include <gst/interfaces/propertyprobe.h>
+#include <gst/audio/multichannel.h>
+
+#define _(text) (text)
+
+#define GST_CHECK_ALSA_VERSION(major,minor,micro) \
+ (SND_LIB_MAJOR > (major) || \
+ (SND_LIB_MAJOR == (major) && SND_LIB_MINOR > (minor)) || \
+ (SND_LIB_MAJOR == (major) && SND_LIB_MINOR == (minor) && \
+ SND_LIB_SUBMINOR >= (micro)))
+
+static const GList *
+gst_alsa_device_property_probe_get_properties (GstPropertyProbe * probe)
+{
+ GObjectClass *klass = G_OBJECT_GET_CLASS (probe);
+ static GList *list = NULL;
+
+ /* well, not perfect, but better than no locking at all.
+ * In the worst case we leak a list node, so who cares? */
+ GST_CLASS_LOCK (GST_OBJECT_CLASS (klass));
+
+ if (!list) {
+ GParamSpec *pspec;
+
+ pspec = g_object_class_find_property (klass, "device");
+ list = g_list_append (NULL, pspec);
+ }
+
+ GST_CLASS_UNLOCK (GST_OBJECT_CLASS (klass));
+
+ return list;
+}
+
+static GList *
+gst_alsa_get_device_list (snd_pcm_stream_t stream)
+{
+ snd_ctl_t *handle;
+ int card, err, dev;
+ snd_ctl_card_info_t *info;
+ snd_pcm_info_t *pcminfo;
+ gboolean mixer = (stream == ~0u);
+ GList *list = NULL;
+
+ if (stream == ~0u)
+ stream = 0;
+
+ snd_ctl_card_info_malloc (&info);
+ snd_pcm_info_malloc (&pcminfo);
+ card = -1;
+
+ if (snd_card_next (&card) < 0 || card < 0) {
+ /* no soundcard found */
+ return NULL;
+ }
+
+ while (card >= 0) {
+ gchar name[32];
+
+ g_snprintf (name, sizeof (name), "hw:%d", card);
+ if ((err = snd_ctl_open (&handle, name, 0)) < 0) {
+ goto next_card;
+ }
+ if ((err = snd_ctl_card_info (handle, info)) < 0) {
+ snd_ctl_close (handle);
+ goto next_card;
+ }
+
+ if (mixer) {
+ list = g_list_append (list, g_strdup (name));
+ } else {
+ g_snprintf (name, sizeof (name), "default:CARD=%d", card);
+ list = g_list_append (list, g_strdup (name));
+ dev = -1;
+ while (1) {
+ gchar *gst_device;
+
+ snd_ctl_pcm_next_device (handle, &dev);
+
+ if (dev < 0)
+ break;
+ snd_pcm_info_set_device (pcminfo, dev);
+ snd_pcm_info_set_subdevice (pcminfo, 0);
+ snd_pcm_info_set_stream (pcminfo, stream);
+ if ((err = snd_ctl_pcm_info (handle, pcminfo)) < 0) {
+ continue;
+ }
+
+ gst_device = g_strdup_printf ("hw:%d,%d", card, dev);
+ list = g_list_append (list, gst_device);
+ }
+ }
+ snd_ctl_close (handle);
+ next_card:
+ if (snd_card_next (&card) < 0) {
+ break;
+ }
+ }
+
+ snd_ctl_card_info_free (info);
+ snd_pcm_info_free (pcminfo);
+
+ return list;
+}
+
+static void
+gst_alsa_device_property_probe_probe_property (GstPropertyProbe * probe,
+ guint prop_id, const GParamSpec * pspec)
+{
+ if (!g_str_equal (pspec->name, "device")) {
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
+ }
+}
+
+static gboolean
+gst_alsa_device_property_probe_needs_probe (GstPropertyProbe * probe,
+ guint prop_id, const GParamSpec * pspec)
+{
+ /* don't cache probed data */
+ return TRUE;
+}
+
+static GValueArray *
+gst_alsa_device_property_probe_get_values (GstPropertyProbe * probe,
+ guint prop_id, const GParamSpec * pspec)
+{
+ GstElementClass *klass;
+ const GList *templates;
+ snd_pcm_stream_t mode = -1;
+ GValueArray *array;
+ GValue value = { 0, };
+ GList *l, *list;
+
+ if (!g_str_equal (pspec->name, "device")) {
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
+ return NULL;
+ }
+
+ klass = GST_ELEMENT_GET_CLASS (GST_ELEMENT (probe));
+
+ /* I'm pretty sure ALSA has a good way to do this. However, their cool
+ * auto-generated documentation is pretty much useless if you try to
+ * do function-wise look-ups. */
+ /* we assume one pad template at max [zero=mixer] */
+ templates = gst_element_class_get_pad_template_list (klass);
+ if (templates) {
+ if (GST_PAD_TEMPLATE_DIRECTION (templates->data) == GST_PAD_SRC)
+ mode = SND_PCM_STREAM_CAPTURE;
+ else
+ mode = SND_PCM_STREAM_PLAYBACK;
+ }
+
+ list = gst_alsa_get_device_list (mode);
+
+ if (list == NULL) {
+ GST_LOG_OBJECT (probe, "No devices found");
+ return NULL;
+ }
+
+ array = g_value_array_new (g_list_length (list));
+ g_value_init (&value, G_TYPE_STRING);
+ for (l = list; l != NULL; l = l->next) {
+ GST_LOG_OBJECT (probe, "Found device: %s", (gchar *) l->data);
+ g_value_take_string (&value, (gchar *) l->data);
+ l->data = NULL;
+ g_value_array_append (array, &value);
+ }
+ g_value_unset (&value);
+ g_list_free (list);
+
+ return array;
+}
+
+static void
+gst_alsa_property_probe_interface_init (GstPropertyProbeInterface * iface)
+{
+ iface->get_properties = gst_alsa_device_property_probe_get_properties;
+ iface->probe_property = gst_alsa_device_property_probe_probe_property;
+ iface->needs_probe = gst_alsa_device_property_probe_needs_probe;
+ iface->get_values = gst_alsa_device_property_probe_get_values;
+}
+
+static void
+gst_alsa_type_add_device_property_probe_interface (GType type)
+{
+ static const GInterfaceInfo probe_iface_info = {
+ (GInterfaceInitFunc) gst_alsa_property_probe_interface_init,
+ NULL,
+ NULL,
+ };
+
+ g_type_add_interface_static (type, GST_TYPE_PROPERTY_PROBE,
+ &probe_iface_info);
+}
+
+static GstCaps *
+gst_alsa_detect_rates (GstObject * obj, snd_pcm_hw_params_t * hw_params,
+ GstCaps * in_caps)
+{
+ GstCaps *caps;
+ guint min, max;
+ gint err, dir, min_rate, max_rate;
+ guint i;
+
+ GST_LOG_OBJECT (obj, "probing sample rates ...");
+
+ if ((err = snd_pcm_hw_params_get_rate_min (hw_params, &min, &dir)) < 0)
+ goto min_rate_err;
+
+ if ((err = snd_pcm_hw_params_get_rate_max (hw_params, &max, &dir)) < 0)
+ goto max_rate_err;
+
+ min_rate = min;
+ max_rate = max;
+
+ if (min_rate < 4000)
+ min_rate = 4000; /* random 'sensible minimum' */
+
+ if (max_rate <= 0)
+ max_rate = G_MAXINT; /* or maybe just use 192400 or so? */
+ else if (max_rate > 0 && max_rate < 4000)
+ max_rate = MAX (4000, min_rate);
+
+ GST_DEBUG_OBJECT (obj, "Min. rate = %u (%d)", min_rate, min);
+ GST_DEBUG_OBJECT (obj, "Max. rate = %u (%d)", max_rate, max);
+
+ caps = gst_caps_make_writable (in_caps);
+
+ for (i = 0; i < gst_caps_get_size (caps); ++i) {
+ GstStructure *s;
+
+ s = gst_caps_get_structure (caps, i);
+ if (min_rate == max_rate) {
+ gst_structure_set (s, "rate", G_TYPE_INT, min_rate, NULL);
+ } else {
+ gst_structure_set (s, "rate", GST_TYPE_INT_RANGE,
+ min_rate, max_rate, NULL);
+ }
+ }
+
+ return caps;
+
+ /* ERRORS */
+min_rate_err:
+ {
+ GST_ERROR_OBJECT (obj, "failed to query minimum sample rate: %s",
+ snd_strerror (err));
+ gst_caps_unref (in_caps);
+ return NULL;
+ }
+max_rate_err:
+ {
+ GST_ERROR_OBJECT (obj, "failed to query maximum sample rate: %s",
+ snd_strerror (err));
+ gst_caps_unref (in_caps);
+ return NULL;
+ }
+}
+
+static const struct
+{
+ const int width;
+ const int depth;
+ const int sformat;
+ const int uformat;
+} pcmformats[] = {
+ {
+ 8, 8, SND_PCM_FORMAT_S8, SND_PCM_FORMAT_U8}, {
+ 16, 16, SND_PCM_FORMAT_S16, SND_PCM_FORMAT_U16}, {
+ 32, 24, SND_PCM_FORMAT_S24, SND_PCM_FORMAT_U24}, {
+#if (G_BYTE_ORDER == G_LITTLE_ENDIAN) /* no endian-unspecific enum available */
+ 24, 24, SND_PCM_FORMAT_S24_3LE, SND_PCM_FORMAT_U24_3LE}, {
+#else
+ 24, 24, SND_PCM_FORMAT_S24_3BE, SND_PCM_FORMAT_U24_3BE}, {
+#endif
+ 32, 32, SND_PCM_FORMAT_S32, SND_PCM_FORMAT_U32}
+};
+
+static GstCaps *
+gst_alsa_detect_formats (GstObject * obj, snd_pcm_hw_params_t * hw_params,
+ GstCaps * in_caps)
+{
+ snd_pcm_format_mask_t *mask;
+ GstStructure *s;
+ GstCaps *caps;
+ guint i;
+
+ snd_pcm_format_mask_malloc (&mask);
+ snd_pcm_hw_params_get_format_mask (hw_params, mask);
+
+ caps = gst_caps_new_empty ();
+
+ for (i = 0; i < gst_caps_get_size (in_caps); ++i) {
+ GstStructure *scopy;
+ guint w;
+ gint width = 0, depth = 0;
+
+ s = gst_caps_get_structure (in_caps, i);
+ if (!gst_structure_has_name (s, "audio/x-raw-int")) {
+ GST_WARNING_OBJECT (obj, "skipping non-int format");
+ continue;
+ }
+ if (!gst_structure_get_int (s, "width", &width) ||
+ !gst_structure_get_int (s, "depth", &depth))
+ continue;
+ if (width == 0 || (width % 8) != 0)
+ continue; /* Only full byte widths are valid */
+ for (w = 0; w < G_N_ELEMENTS (pcmformats); w++)
+ if (pcmformats[w].width == width && pcmformats[w].depth == depth)
+ break;
+ if (w == G_N_ELEMENTS (pcmformats))
+ continue; /* Unknown format */
+
+ if (snd_pcm_format_mask_test (mask, pcmformats[w].sformat) &&
+ snd_pcm_format_mask_test (mask, pcmformats[w].uformat)) {
+ /* template contains { true, false } or just one, leave it as it is */
+ scopy = gst_structure_copy (s);
+ } else if (snd_pcm_format_mask_test (mask, pcmformats[w].sformat)) {
+ scopy = gst_structure_copy (s);
+ gst_structure_set (scopy, "signed", G_TYPE_BOOLEAN, TRUE, NULL);
+ } else if (snd_pcm_format_mask_test (mask, pcmformats[w].uformat)) {
+ scopy = gst_structure_copy (s);
+ gst_structure_set (scopy, "signed", G_TYPE_BOOLEAN, FALSE, NULL);
+ } else {
+ scopy = NULL;
+ }
+ if (scopy) {
+ if (width > 8) {
+ /* TODO: proper endianness detection, for now it's CPU endianness only */
+ gst_structure_set (scopy, "endianness", G_TYPE_INT, G_BYTE_ORDER, NULL);
+ }
+ gst_caps_append_structure (caps, scopy);
+ }
+ }
+
+ snd_pcm_format_mask_free (mask);
+ gst_caps_unref (in_caps);
+ return caps;
+}
+
+/* we don't have channel mappings for more than this many channels */
+#define GST_ALSA_MAX_CHANNELS 8
+
+static GstStructure *
+get_channel_free_structure (const GstStructure * in_structure)
+{
+ GstStructure *s = gst_structure_copy (in_structure);
+
+ gst_structure_remove_field (s, "channels");
+ return s;
+}
+
+static void
+caps_add_channel_configuration (GstCaps * caps,
+ const GstStructure * in_structure, gint min_chans, gint max_chans)
+{
+ GstAudioChannelPosition pos[8] = {
+ GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
+ GST_AUDIO_CHANNEL_POSITION_LFE,
+ GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT
+ };
+ GstStructure *s = NULL;
+ gint c;
+
+ if (min_chans == max_chans && max_chans <= 2) {
+ s = get_channel_free_structure (in_structure);
+ gst_structure_set (s, "channels", G_TYPE_INT, max_chans, NULL);
+ gst_caps_append_structure (caps, s);
+ return;
+ }
+
+ g_assert (min_chans >= 1);
+
+ /* mono and stereo don't need channel configurations */
+ if (min_chans == 2) {
+ s = get_channel_free_structure (in_structure);
+ gst_structure_set (s, "channels", G_TYPE_INT, 2, NULL);
+ gst_caps_append_structure (caps, s);
+ } else if (min_chans == 1 && max_chans >= 2) {
+ s = get_channel_free_structure (in_structure);
+ gst_structure_set (s, "channels", GST_TYPE_INT_RANGE, 1, 2, NULL);
+ gst_caps_append_structure (caps, s);
+ }
+
+ /* don't know whether to use 2.1 or 3.0 here - but I suspect
+ * alsa might work around that/fix it somehow. Can we tell alsa
+ * what our channel layout is like? */
+ if (max_chans >= 3 && min_chans <= 3) {
+ GstAudioChannelPosition pos_21[3] = {
+ GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
+ GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
+ GST_AUDIO_CHANNEL_POSITION_LFE
+ };
+
+ s = get_channel_free_structure (in_structure);
+ gst_structure_set (s, "channels", G_TYPE_INT, 3, NULL);
+ gst_audio_set_channel_positions (s, pos_21);
+ gst_caps_append_structure (caps, s);
+ }
+
+ /* everything else (4, 6, 8 channels) needs a channel layout */
+ for (c = MAX (4, min_chans); c <= 8; c += 2) {
+ if (max_chans >= c) {
+ s = get_channel_free_structure (in_structure);
+ gst_structure_set (s, "channels", G_TYPE_INT, c, NULL);
+ gst_audio_set_channel_positions (s, pos);
+ gst_caps_append_structure (caps, s);
+ }
+ }
+
+ for (c = MAX (9, min_chans); c <= max_chans; ++c) {
+ GstAudioChannelPosition *ch_layout;
+ gint i;
+
+ ch_layout = g_new (GstAudioChannelPosition, c);
+ for (i = 0; i < c; ++i) {
+ ch_layout[i] = GST_AUDIO_CHANNEL_POSITION_NONE;
+ }
+ s = get_channel_free_structure (in_structure);
+ gst_structure_set (s, "channels", G_TYPE_INT, c, NULL);
+ gst_audio_set_channel_positions (s, ch_layout);
+ gst_caps_append_structure (caps, s);
+ g_free (ch_layout);
+ }
+}
+
+static GstCaps *
+gst_alsa_detect_channels (GstObject * obj, snd_pcm_hw_params_t * hw_params,
+ GstCaps * in_caps)
+{
+ GstCaps *caps;
+ guint min, max;
+ gint min_chans, max_chans;
+ gint err;
+ guint i;
+
+ GST_LOG_OBJECT (obj, "probing channels ...");
+
+ if ((err = snd_pcm_hw_params_get_channels_min (hw_params, &min)) < 0)
+ goto min_chan_error;
+
+ if ((err = snd_pcm_hw_params_get_channels_max (hw_params, &max)) < 0)
+ goto max_chan_error;
+
+ /* note: the above functions may return (guint) -1 */
+ min_chans = min;
+ max_chans = max;
+
+ if (min_chans < 0) {
+ min_chans = 1;
+ max_chans = GST_ALSA_MAX_CHANNELS;
+ } else if (max_chans < 0) {
+ max_chans = GST_ALSA_MAX_CHANNELS;
+ }
+
+ if (min_chans > max_chans) {
+ gint temp;
+
+ GST_WARNING_OBJECT (obj, "minimum channels > maximum channels (%d > %d), "
+ "please fix your soundcard drivers", min, max);
+ temp = min_chans;
+ min_chans = max_chans;
+ max_chans = temp;
+ }
+
+ /* pro cards seem to return large numbers for min_channels */
+ if (min_chans > GST_ALSA_MAX_CHANNELS) {
+ GST_DEBUG_OBJECT (obj, "min_chans = %u, looks like a pro card", min_chans);
+ if (max_chans < min_chans) {
+ max_chans = min_chans;
+ } else {
+ /* only support [max_chans; max_chans] for these cards for now
+ * to avoid inflating the source caps with loads of structures ... */
+ min_chans = max_chans;
+ }
+ } else {
+ min_chans = MAX (min_chans, 1);
+ max_chans = MIN (GST_ALSA_MAX_CHANNELS, max_chans);
+ }
+
+ GST_DEBUG_OBJECT (obj, "Min. channels = %d (%d)", min_chans, min);
+ GST_DEBUG_OBJECT (obj, "Max. channels = %d (%d)", max_chans, max);
+
+ caps = gst_caps_new_empty ();
+
+ for (i = 0; i < gst_caps_get_size (in_caps); ++i) {
+ GstStructure *s;
+ GType field_type;
+ gint c_min = min_chans;
+ gint c_max = max_chans;
+
+ s = gst_caps_get_structure (in_caps, i);
+ /* the template caps might limit the number of channels (like alsasrc),
+ * in which case we don't want to return a superset, so hack around this
+ * for the two common cases where the channels are either a fixed number
+ * or a min/max range). Example: alsasrc template has channels = [1,2] and
+ * the detection will claim to support 8 channels for device 'plughw:0' */
+ field_type = gst_structure_get_field_type (s, "channels");
+ if (field_type == G_TYPE_INT) {
+ gst_structure_get_int (s, "channels", &c_min);
+ gst_structure_get_int (s, "channels", &c_max);
+ } else if (field_type == GST_TYPE_INT_RANGE) {
+ const GValue *val;
+
+ val = gst_structure_get_value (s, "channels");
+ c_min = CLAMP (gst_value_get_int_range_min (val), min_chans, max_chans);
+ c_max = CLAMP (gst_value_get_int_range_max (val), min_chans, max_chans);
+ } else {
+ c_min = min_chans;
+ c_max = max_chans;
+ }
+
+ caps_add_channel_configuration (caps, s, c_min, c_max);
+ }
+
+ gst_caps_unref (in_caps);
+
+ return caps;
+
+ /* ERRORS */
+min_chan_error:
+ {
+ GST_ERROR_OBJECT (obj, "failed to query minimum channel count: %s",
+ snd_strerror (err));
+ return NULL;
+ }
+max_chan_error:
+ {
+ GST_ERROR_OBJECT (obj, "failed to query maximum channel count: %s",
+ snd_strerror (err));
+ return NULL;
+ }
+}
+
+#ifndef GST_CHECK_VERSION
+#define GST_CHECK_VERSION(major,minor,micro) \
+ (GST_VERSION_MAJOR > (major) || \
+ (GST_VERSION_MAJOR == (major) && GST_VERSION_MINOR > (minor)) || \
+ (GST_VERSION_MAJOR == (major) && GST_VERSION_MINOR == (minor) && GST_VERSION_MICRO >= (micro)))
+#endif
+
+#if GST_CHECK_VERSION(0, 10, 18)
+snd_pcm_t *
+gst_alsa_open_iec958_pcm (GstObject * obj)
+{
+ char *iec958_pcm_name = NULL;
+ snd_pcm_t *pcm = NULL;
+ int res;
+ char devstr[256]; /* Storage for local 'default' device string */
+
+ /*
+ * Try and open our default iec958 device. Fall back to searching on card x
+ * if this fails, which should only happen on older alsa setups
+ */
+
+ /* The string will be one of these:
+ * SPDIF_CON: Non-audio flag not set:
+ * spdif:{AES0 0x0 AES1 0x82 AES2 0x0 AES3 0x2}
+ * SPDIF_CON: Non-audio flag set:
+ * spdif:{AES0 0x2 AES1 0x82 AES2 0x0 AES3 0x2}
+ */
+ sprintf (devstr,
+ "iec958:{AES0 0x%02x AES1 0x%02x AES2 0x%02x AES3 0x%02x}",
+ IEC958_AES0_CON_EMPHASIS_NONE | IEC958_AES0_NONAUDIO,
+ IEC958_AES1_CON_ORIGINAL | IEC958_AES1_CON_PCM_CODER,
+ 0, IEC958_AES3_CON_FS_48000);
+
+ GST_DEBUG_OBJECT (obj, "Generated device string \"%s\"", devstr);
+ iec958_pcm_name = devstr;
+
+ res = snd_pcm_open (&pcm, iec958_pcm_name, SND_PCM_STREAM_PLAYBACK, 0);
+ if (G_UNLIKELY (res < 0)) {
+ GST_DEBUG_OBJECT (obj, "failed opening IEC958 device: %s",
+ snd_strerror (res));
+ pcm = NULL;
+ }
+
+ return pcm;
+}
+#endif
+
+
+/*
+ * gst_alsa_probe_supported_formats:
+ *
+ * Takes the template caps and returns the subset which is actually
+ * supported by this device.
+ *
+ */
+
+GstCaps *
+gst_alsa_probe_supported_formats (GstObject * obj, snd_pcm_t * handle,
+ const GstCaps * template_caps)
+{
+ snd_pcm_hw_params_t *hw_params;
+ snd_pcm_stream_t stream_type;
+ GstCaps *caps;
+ gint err;
+
+ snd_pcm_hw_params_malloc (&hw_params);
+ if ((err = snd_pcm_hw_params_any (handle, hw_params)) < 0)
+ goto error;
+
+ stream_type = snd_pcm_stream (handle);
+
+ caps = gst_caps_copy (template_caps);
+
+ if (!(caps = gst_alsa_detect_formats (obj, hw_params, caps)))
+ goto subroutine_error;
+
+ if (!(caps = gst_alsa_detect_rates (obj, hw_params, caps)))
+ goto subroutine_error;
+
+ if (!(caps = gst_alsa_detect_channels (obj, hw_params, caps)))
+ goto subroutine_error;
+
+#if GST_CHECK_VERSION(0, 10, 18)
+ /* Try opening IEC958 device to see if we can support that format (playback
+ * only for now but we could add SPDIF capture later) */
+ if (stream_type == SND_PCM_STREAM_PLAYBACK) {
+ snd_pcm_t *pcm = gst_alsa_open_iec958_pcm (obj);
+
+ if (G_LIKELY (pcm)) {
+ gst_caps_append (caps, gst_caps_new_simple ("audio/x-iec958", NULL));
+ snd_pcm_close (pcm);
+ }
+ }
+#endif
+
+ snd_pcm_hw_params_free (hw_params);
+ return caps;
+
+ /* ERRORS */
+error:
+ {
+ GST_ERROR_OBJECT (obj, "failed to query formats: %s", snd_strerror (err));
+ snd_pcm_hw_params_free (hw_params);
+ return NULL;
+ }
+subroutine_error:
+ {
+ GST_ERROR_OBJECT (obj, "failed to query formats");
+ snd_pcm_hw_params_free (hw_params);
+ return NULL;
+ }
+}
+
+static gchar *
+gst_alsa_find_device_name_no_handle (GstObject * obj, const gchar * devcard,
+ gint device_num, snd_pcm_stream_t stream)
+{
+ snd_ctl_card_info_t *info = NULL;
+ snd_ctl_t *ctl = NULL;
+ gchar *ret = NULL;
+ gint dev = -1;
+
+ GST_LOG_OBJECT (obj, "[%s] device=%d", devcard, device_num);
+
+ if (snd_ctl_open (&ctl, devcard, 0) < 0)
+ return NULL;
+
+ snd_ctl_card_info_malloc (&info);
+ if (snd_ctl_card_info (ctl, info) < 0)
+ goto done;
+
+ while (snd_ctl_pcm_next_device (ctl, &dev) == 0 && dev >= 0) {
+ if (dev == device_num) {
+ snd_pcm_info_t *pcminfo;
+
+ snd_pcm_info_malloc (&pcminfo);
+ snd_pcm_info_set_device (pcminfo, dev);
+ snd_pcm_info_set_subdevice (pcminfo, 0);
+ snd_pcm_info_set_stream (pcminfo, stream);
+ if (snd_ctl_pcm_info (ctl, pcminfo) < 0) {
+ snd_pcm_info_free (pcminfo);
+ break;
+ }
+
+ ret = g_strdup (snd_pcm_info_get_name (pcminfo));
+ snd_pcm_info_free (pcminfo);
+ GST_LOG_OBJECT (obj, "name from pcminfo: %s", GST_STR_NULL (ret));
+ }
+ }
+
+ if (ret == NULL) {
+ char *name = NULL;
+ gint card;
+
+ GST_LOG_OBJECT (obj, "no luck so far, trying backup");
+ card = snd_ctl_card_info_get_card (info);
+ snd_card_get_name (card, &name);
+ ret = g_strdup (name);
+ free (name);
+ }
+
+done:
+ snd_ctl_card_info_free (info);
+ snd_ctl_close (ctl);
+
+ return ret;
+}
+
+gchar *
+gst_alsa_find_device_name (GstObject * obj, const gchar * device,
+ snd_pcm_t * handle, snd_pcm_stream_t stream)
+{
+ gchar *ret = NULL;
+
+ if (device != NULL) {
+ gchar *dev, *comma;
+ gint devnum;
+
+ GST_LOG_OBJECT (obj, "Trying to get device name from string '%s'", device);
+
+ /* only want name:card bit, but not devices and subdevices */
+ dev = g_strdup (device);
+ if ((comma = strchr (dev, ','))) {
+ *comma = '\0';
+ devnum = atoi (comma + 1);
+ ret = gst_alsa_find_device_name_no_handle (obj, dev, devnum, stream);
+ }
+ g_free (dev);
+ }
+
+ if (ret == NULL && handle != NULL) {
+ snd_pcm_info_t *info;
+
+ GST_LOG_OBJECT (obj, "Trying to get device name from open handle");
+ snd_pcm_info_malloc (&info);
+ snd_pcm_info (handle, info);
+ ret = g_strdup (snd_pcm_info_get_name (info));
+ snd_pcm_info_free (info);
+ }
+
+ GST_LOG_OBJECT (obj, "Device name for device '%s': %s",
+ GST_STR_NULL (device), GST_STR_NULL (ret));
+
+ return ret;
+}
+
+/* elementfactory information */
+static const GstElementDetails gst_alsasink2_details =
+GST_ELEMENT_DETAILS ("Audio sink (ALSA)",
+ "Sink/Audio",
+ "Output to a sound card via ALSA",
+ "Wim Taymans <wim@fluendo.com>");
+
+#define DEFAULT_DEVICE "default"
+#define DEFAULT_DEVICE_NAME ""
+#define SPDIF_PERIOD_SIZE 1536
+#define SPDIF_BUFFER_SIZE 15360
+
+enum
+{
+ PROP_0,
+ PROP_DEVICE,
+ PROP_DEVICE_NAME
+};
+
+static void gst_alsasink2_init_interfaces (GType type);
+
+GST_BOILERPLATE_FULL (_k_GstAlsaSink, gst_alsasink2, GstAudioSink,
+ GST_TYPE_AUDIO_SINK, gst_alsasink2_init_interfaces);
+
+static void gst_alsasink2_finalise (GObject * object);
+static void gst_alsasink2_set_property (GObject * object,
+ guint prop_id, const GValue * value, GParamSpec * pspec);
+static void gst_alsasink2_get_property (GObject * object,
+ guint prop_id, GValue * value, GParamSpec * pspec);
+
+static GstCaps *gst_alsasink2_getcaps (GstBaseSink * bsink);
+
+static gboolean gst_alsasink2_open (GstAudioSink * asink);
+static gboolean gst_alsasink2_prepare (GstAudioSink * asink,
+ GstRingBufferSpec * spec);
+static gboolean gst_alsasink2_unprepare (GstAudioSink * asink);
+static gboolean gst_alsasink2_close (GstAudioSink * asink);
+static guint gst_alsasink2_write (GstAudioSink * asink, gpointer data,
+ guint length);
+static guint gst_alsasink2_delay (GstAudioSink * asink);
+static void gst_alsasink2_reset (GstAudioSink * asink);
+
+static gint output_ref; /* 0 */
+static snd_output_t *output; /* NULL */
+static GStaticMutex output_mutex = G_STATIC_MUTEX_INIT;
+
+
+#if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
+# define ALSA_SINK2_FACTORY_ENDIANNESS "LITTLE_ENDIAN, BIG_ENDIAN"
+#else
+# define ALSA_SINK2_FACTORY_ENDIANNESS "BIG_ENDIAN, LITTLE_ENDIAN"
+#endif
+
+static GstStaticPadTemplate alsasink2_sink_factory =
+ GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("audio/x-raw-int, "
+ "endianness = (int) { " ALSA_SINK2_FACTORY_ENDIANNESS " }, "
+ "signed = (boolean) { TRUE, FALSE }, "
+ "width = (int) 32, "
+ "depth = (int) 32, "
+ "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]; "
+ "audio/x-raw-int, "
+ "endianness = (int) { " ALSA_SINK2_FACTORY_ENDIANNESS " }, "
+ "signed = (boolean) { TRUE, FALSE }, "
+ "width = (int) 24, "
+ "depth = (int) 24, "
+ "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]; "
+ "audio/x-raw-int, "
+ "endianness = (int) { " ALSA_SINK2_FACTORY_ENDIANNESS " }, "
+ "signed = (boolean) { TRUE, FALSE }, "
+ "width = (int) 32, "
+ "depth = (int) 24, "
+ "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]; "
+ "audio/x-raw-int, "
+ "endianness = (int) { " ALSA_SINK2_FACTORY_ENDIANNESS " }, "
+ "signed = (boolean) { TRUE, FALSE }, "
+ "width = (int) 16, "
+ "depth = (int) 16, "
+ "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ]; "
+ "audio/x-raw-int, "
+ "signed = (boolean) { TRUE, FALSE }, "
+ "width = (int) 8, "
+ "depth = (int) 8, "
+ "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ];"
+ "audio/x-iec958")
+ );
+
+static void
+gst_alsasink2_finalise (GObject * object)
+{
+ _k_GstAlsaSink *sink = GST_ALSA_SINK2 (object);
+
+ g_free (sink->device);
+ g_mutex_free (sink->alsa_lock);
+
+ g_static_mutex_lock (&output_mutex);
+ --output_ref;
+ if (output_ref == 0) {
+ snd_output_close (output);
+ output = NULL;
+ }
+ g_static_mutex_unlock (&output_mutex);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_alsasink2_init_interfaces (GType type)
+{
+ gst_alsa_type_add_device_property_probe_interface (type);
+}
+
+static void
+gst_alsasink2_base_init (gpointer g_class)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+
+ gst_element_class_set_details (element_class, &gst_alsasink2_details);
+
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&alsasink2_sink_factory));
+}
+static void
+gst_alsasink2_class_init (_k_GstAlsaSinkClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+ GstBaseSinkClass *gstbasesink_class;
+ GstBaseAudioSinkClass *gstbaseaudiosink_class;
+ GstAudioSinkClass *gstaudiosink_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+ gstbasesink_class = (GstBaseSinkClass *) klass;
+ gstbaseaudiosink_class = (GstBaseAudioSinkClass *) klass;
+ gstaudiosink_class = (GstAudioSinkClass *) klass;
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_alsasink2_finalise);
+ gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_alsasink2_get_property);
+ gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_alsasink2_set_property);
+
+ gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_alsasink2_getcaps);
+
+ gstaudiosink_class->open = GST_DEBUG_FUNCPTR (gst_alsasink2_open);
+ gstaudiosink_class->prepare = GST_DEBUG_FUNCPTR (gst_alsasink2_prepare);
+ gstaudiosink_class->unprepare = GST_DEBUG_FUNCPTR (gst_alsasink2_unprepare);
+ gstaudiosink_class->close = GST_DEBUG_FUNCPTR (gst_alsasink2_close);
+ gstaudiosink_class->write = GST_DEBUG_FUNCPTR (gst_alsasink2_write);
+ gstaudiosink_class->delay = GST_DEBUG_FUNCPTR (gst_alsasink2_delay);
+ gstaudiosink_class->reset = GST_DEBUG_FUNCPTR (gst_alsasink2_reset);
+
+ g_object_class_install_property (gobject_class, PROP_DEVICE,
+ g_param_spec_string ("device", "Device",
+ "ALSA device, as defined in an asound configuration file",
+ DEFAULT_DEVICE, G_PARAM_READWRITE));
+
+ g_object_class_install_property (gobject_class, PROP_DEVICE_NAME,
+ g_param_spec_string ("device-name", "Device name",
+ "Human-readable name of the sound device", DEFAULT_DEVICE_NAME,
+ G_PARAM_READABLE));
+}
+
+static void
+gst_alsasink2_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ _k_GstAlsaSink *sink;
+
+ sink = GST_ALSA_SINK2 (object);
+
+ switch (prop_id) {
+ case PROP_DEVICE:
+ g_free (sink->device);
+ sink->device = g_value_dup_string (value);
+ /* setting NULL restores the default device */
+ if (sink->device == NULL) {
+ sink->device = g_strdup (DEFAULT_DEVICE);
+ }
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_alsasink2_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ _k_GstAlsaSink *sink;
+
+ sink = GST_ALSA_SINK2 (object);
+
+ switch (prop_id) {
+ case PROP_DEVICE:
+ g_value_set_string (value, sink->device);
+ break;
+ case PROP_DEVICE_NAME:
+ g_value_take_string (value,
+ gst_alsa_find_device_name (GST_OBJECT_CAST (sink),
+ sink->device, sink->handle, SND_PCM_STREAM_PLAYBACK));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_alsasink2_init (_k_GstAlsaSink * alsasink2, _k_GstAlsaSinkClass * g_class)
+{
+ GST_DEBUG_OBJECT (alsasink2, "initializing alsasink2");
+
+ alsasink2->device = g_strdup (DEFAULT_DEVICE);
+ alsasink2->handle = NULL;
+ alsasink2->cached_caps = NULL;
+ alsasink2->alsa_lock = g_mutex_new ();
+
+ g_static_mutex_lock (&output_mutex);
+ if (output_ref == 0) {
+ snd_output_stdio_attach (&output, stdout, 0);
+ ++output_ref;
+ }
+ g_static_mutex_unlock (&output_mutex);
+}
+
+#define CHECK(call, error) \
+G_STMT_START { \
+if ((err = call) < 0) \
+ goto error; \
+} G_STMT_END;
+
+static GstCaps *
+gst_alsasink2_getcaps (GstBaseSink * bsink)
+{
+ GstElementClass *element_class;
+ GstPadTemplate *pad_template;
+ _k_GstAlsaSink *sink = GST_ALSA_SINK2 (bsink);
+ GstCaps *caps;
+
+ if (sink->handle == NULL) {
+ GST_DEBUG_OBJECT (sink, "device not open, using template caps");
+ return NULL; /* base class will get template caps for us */
+ }
+
+ if (sink->cached_caps) {
+ GST_LOG_OBJECT (sink, "Returning cached caps");
+ return gst_caps_ref (sink->cached_caps);
+ }
+
+ element_class = GST_ELEMENT_GET_CLASS (sink);
+ pad_template = gst_element_class_get_pad_template (element_class, "sink");
+ g_return_val_if_fail (pad_template != NULL, NULL);
+
+ caps = gst_alsa_probe_supported_formats (GST_OBJECT (sink), sink->handle,
+ gst_pad_template_get_caps (pad_template));
+
+ if (caps) {
+ sink->cached_caps = gst_caps_ref (caps);
+ }
+
+ GST_INFO_OBJECT (sink, "returning caps %" GST_PTR_FORMAT, caps);
+
+ return caps;
+}
+
+static int
+set_hwparams (_k_GstAlsaSink * alsa)
+{
+ guint rrate;
+ gint err, dir;
+ snd_pcm_hw_params_t *params;
+ guint period_time, buffer_time;
+
+ snd_pcm_hw_params_malloc (&params);
+
+ GST_DEBUG_OBJECT (alsa, "Negotiating to %d channels @ %d Hz (format = %s) "
+ "SPDIF (%d)", alsa->channels, alsa->rate,
+ snd_pcm_format_name (alsa->format), alsa->iec958);
+
+ /* start with requested values, if we cannot configure alsa for those values,
+ * we set these values to -1, which will leave the default alsa values */
+ buffer_time = alsa->buffer_time;
+ period_time = alsa->period_time;
+
+retry:
+ /* choose all parameters */
+ CHECK (snd_pcm_hw_params_any (alsa->handle, params), no_config);
+ /* set the interleaved read/write format */
+ CHECK (snd_pcm_hw_params_set_access (alsa->handle, params, alsa->access),
+ wrong_access);
+ /* set the sample format */
+#if GST_CHECK_VERSION(0, 10, 18)
+ if (alsa->iec958) {
+ /* Try to use big endian first else fallback to le and swap bytes */
+ if (snd_pcm_hw_params_set_format (alsa->handle, params, alsa->format) < 0) {
+ alsa->format = SND_PCM_FORMAT_S16_LE;
+ alsa->need_swap = TRUE;
+ GST_DEBUG_OBJECT (alsa, "falling back to little endian with swapping");
+ } else {
+ alsa->need_swap = FALSE;
+ }
+ }
+#endif
+ CHECK (snd_pcm_hw_params_set_format (alsa->handle, params, alsa->format),
+ no_sample_format);
+ /* set the count of channels */
+ CHECK (snd_pcm_hw_params_set_channels (alsa->handle, params, alsa->channels),
+ no_channels);
+ /* set the stream rate */
+ rrate = alsa->rate;
+ CHECK (snd_pcm_hw_params_set_rate_near (alsa->handle, params, &rrate, NULL),
+ no_rate);
+ if (rrate != alsa->rate)
+ goto rate_match;
+
+ /* get and dump some limits */
+ {
+ guint min, max;
+
+ snd_pcm_hw_params_get_buffer_time_min (params, &min, &dir);
+ snd_pcm_hw_params_get_buffer_time_max (params, &max, &dir);
+
+ GST_DEBUG_OBJECT (alsa, "buffer time %u, min %u, max %u",
+ alsa->buffer_time, min, max);
+
+ snd_pcm_hw_params_get_period_time_min (params, &min, &dir);
+ snd_pcm_hw_params_get_period_time_max (params, &max, &dir);
+
+ GST_DEBUG_OBJECT (alsa, "period time %u, min %u, max %u",
+ alsa->period_time, min, max);
+
+ snd_pcm_hw_params_get_periods_min (params, &min, &dir);
+ snd_pcm_hw_params_get_periods_max (params, &max, &dir);
+
+ GST_DEBUG_OBJECT (alsa, "periods min %u, max %u", min, max);
+ }
+
+ /* now try to configure the buffer time and period time, if one
+ * of those fail, we fall back to the defaults and emit a warning. */
+ if (buffer_time != ~0u && !alsa->iec958) {
+ /* set the buffer time */
+ if ((err = snd_pcm_hw_params_set_buffer_time_near (alsa->handle, params,
+ &buffer_time, &dir)) < 0) {
+ GST_ELEMENT_WARNING (alsa, RESOURCE, SETTINGS, (NULL),
+ ("Unable to set buffer time %i for playback: %s",
+ buffer_time, snd_strerror (err)));
+ /* disable buffer_time the next round */
+ buffer_time = -1;
+ goto retry;
+ }
+ GST_DEBUG_OBJECT (alsa, "buffer time %u", buffer_time);
+ }
+ if (period_time != ~0u && !alsa->iec958) {
+ /* set the period time */
+ if ((err = snd_pcm_hw_params_set_period_time_near (alsa->handle, params,
+ &period_time, &dir)) < 0) {
+ GST_ELEMENT_WARNING (alsa, RESOURCE, SETTINGS, (NULL),
+ ("Unable to set period time %i for playback: %s",
+ period_time, snd_strerror (err)));
+ /* disable period_time the next round */
+ period_time = -1;
+ goto retry;
+ }
+ GST_DEBUG_OBJECT (alsa, "period time %u", period_time);
+ }
+
+ /* Set buffer size and period size manually for SPDIF */
+ if (G_UNLIKELY (alsa->iec958)) {
+ snd_pcm_uframes_t buffer_size = SPDIF_BUFFER_SIZE;
+ snd_pcm_uframes_t period_size = SPDIF_PERIOD_SIZE;
+
+ CHECK (snd_pcm_hw_params_set_buffer_size_near (alsa->handle, params,
+ &buffer_size), buffer_size);
+ CHECK (snd_pcm_hw_params_set_period_size_near (alsa->handle, params,
+ &period_size, NULL), period_size);
+ }
+
+ /* write the parameters to device */
+ CHECK (snd_pcm_hw_params (alsa->handle, params), set_hw_params);
+
+ /* now get the configured values */
+ CHECK (snd_pcm_hw_params_get_buffer_size (params, &alsa->buffer_size),
+ buffer_size);
+ CHECK (snd_pcm_hw_params_get_period_size (params, &alsa->period_size, &dir),
+ period_size);
+
+ GST_DEBUG_OBJECT (alsa, "buffer size %lu, period size %lu", alsa->buffer_size,
+ alsa->period_size);
+
+ snd_pcm_hw_params_free (params);
+ return 0;
+
+ /* ERRORS */
+no_config:
+ {
+ GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
+ ("Broken configuration for playback: no configurations available: %s",
+ snd_strerror (err)));
+ snd_pcm_hw_params_free (params);
+ return err;
+ }
+wrong_access:
+ {
+ GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
+ ("Access type not available for playback: %s", snd_strerror (err)));
+ snd_pcm_hw_params_free (params);
+ return err;
+ }
+no_sample_format:
+ {
+ GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
+ ("Sample format not available for playback: %s", snd_strerror (err)));
+ snd_pcm_hw_params_free (params);
+ return err;
+ }
+no_channels:
+ {
+ gchar *msg = NULL;
+
+ if ((alsa->channels) == 1)
+ msg = g_strdup (_("Could not open device for playback in mono mode."));
+ if ((alsa->channels) == 2)
+ msg = g_strdup (_("Could not open device for playback in stereo mode."));
+ if ((alsa->channels) > 2)
+ msg =
+ g_strdup_printf (_
+ ("Could not open device for playback in %d-channel mode."),
+ alsa->channels);
+ GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (msg), (snd_strerror (err)));
+ g_free (msg);
+ snd_pcm_hw_params_free (params);
+ return err;
+ }
+no_rate:
+ {
+ GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
+ ("Rate %iHz not available for playback: %s",
+ alsa->rate, snd_strerror (err)));
+ return err;
+ }
+rate_match:
+ {
+ GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
+ ("Rate doesn't match (requested %iHz, get %iHz)", alsa->rate, err));
+ snd_pcm_hw_params_free (params);
+ return -EINVAL;
+ }
+buffer_size:
+ {
+ GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
+ ("Unable to get buffer size for playback: %s", snd_strerror (err)));
+ snd_pcm_hw_params_free (params);
+ return err;
+ }
+period_size:
+ {
+ GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
+ ("Unable to get period size for playback: %s", snd_strerror (err)));
+ snd_pcm_hw_params_free (params);
+ return err;
+ }
+set_hw_params:
+ {
+ GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
+ ("Unable to set hw params for playback: %s", snd_strerror (err)));
+ snd_pcm_hw_params_free (params);
+ return err;
+ }
+}
+
+static int
+set_swparams (_k_GstAlsaSink * alsa)
+{
+ int err;
+ snd_pcm_sw_params_t *params;
+
+ snd_pcm_sw_params_malloc (&params);
+
+ /* get the current swparams */
+ CHECK (snd_pcm_sw_params_current (alsa->handle, params), no_config);
+ /* start the transfer when the buffer is almost full: */
+ /* (buffer_size / avail_min) * avail_min */
+ CHECK (snd_pcm_sw_params_set_start_threshold (alsa->handle, params,
+ (alsa->buffer_size / alsa->period_size) * alsa->period_size),
+ start_threshold);
+
+ /* allow the transfer when at least period_size samples can be processed */
+ CHECK (snd_pcm_sw_params_set_avail_min (alsa->handle, params,
+ alsa->period_size), set_avail);
+
+#if GST_CHECK_ALSA_VERSION(1,0,16)
+ /* snd_pcm_sw_params_set_xfer_align() is deprecated, alignment is always 1 */
+#else
+ /* align all transfers to 1 sample */
+ CHECK (snd_pcm_sw_params_set_xfer_align (alsa->handle, params, 1), set_align);
+#endif
+
+ /* write the parameters to the playback device */
+ CHECK (snd_pcm_sw_params (alsa->handle, params), set_sw_params);
+
+ snd_pcm_sw_params_free (params);
+ return 0;
+
+ /* ERRORS */
+no_config:
+ {
+ GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
+ ("Unable to determine current swparams for playback: %s",
+ snd_strerror (err)));
+ snd_pcm_sw_params_free (params);
+ return err;
+ }
+start_threshold:
+ {
+ GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
+ ("Unable to set start threshold mode for playback: %s",
+ snd_strerror (err)));
+ snd_pcm_sw_params_free (params);
+ return err;
+ }
+set_avail:
+ {
+ GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
+ ("Unable to set avail min for playback: %s", snd_strerror (err)));
+ snd_pcm_sw_params_free (params);
+ return err;
+ }
+#if !GST_CHECK_ALSA_VERSION(1,0,16)
+set_align:
+ {
+ GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
+ ("Unable to set transfer align for playback: %s", snd_strerror (err)));
+ snd_pcm_sw_params_free (params);
+ return err;
+ }
+#endif
+set_sw_params:
+ {
+ GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
+ ("Unable to set sw params for playback: %s", snd_strerror (err)));
+ snd_pcm_sw_params_free (params);
+ return err;
+ }
+}
+
+static gboolean
+alsasink2_parse_spec (_k_GstAlsaSink * alsa, GstRingBufferSpec * spec)
+{
+ /* Initialize our boolean */
+ alsa->iec958 = FALSE;
+
+ switch (spec->type) {
+ case GST_BUFTYPE_LINEAR:
+ GST_DEBUG_OBJECT (alsa,
+ "Linear format : depth=%d, width=%d, sign=%d, bigend=%d", spec->depth,
+ spec->width, spec->sign, spec->bigend);
+
+ alsa->format = snd_pcm_build_linear_format (spec->depth, spec->width,
+ spec->sign ? 0 : 1, spec->bigend ? 1 : 0);
+ break;
+ case GST_BUFTYPE_FLOAT:
+ switch (spec->format) {
+ case GST_FLOAT32_LE:
+ alsa->format = SND_PCM_FORMAT_FLOAT_LE;
+ break;
+ case GST_FLOAT32_BE:
+ alsa->format = SND_PCM_FORMAT_FLOAT_BE;
+ break;
+ case GST_FLOAT64_LE:
+ alsa->format = SND_PCM_FORMAT_FLOAT64_LE;
+ break;
+ case GST_FLOAT64_BE:
+ alsa->format = SND_PCM_FORMAT_FLOAT64_BE;
+ break;
+ default:
+ goto error;
+ }
+ break;
+ case GST_BUFTYPE_A_LAW:
+ alsa->format = SND_PCM_FORMAT_A_LAW;
+ break;
+ case GST_BUFTYPE_MU_LAW:
+ alsa->format = SND_PCM_FORMAT_MU_LAW;
+ break;
+#if GST_CHECK_VERSION(0, 10, 18)
+ case GST_BUFTYPE_IEC958:
+ alsa->format = SND_PCM_FORMAT_S16_BE;
+ alsa->iec958 = TRUE;
+ break;
+#endif
+ default:
+ goto error;
+
+ }
+ alsa->rate = spec->rate;
+ alsa->channels = spec->channels;
+ alsa->buffer_time = spec->buffer_time;
+ alsa->period_time = spec->latency_time;
+ alsa->access = SND_PCM_ACCESS_RW_INTERLEAVED;
+
+ return TRUE;
+
+ /* ERRORS */
+error:
+ {
+ return FALSE;
+ }
+}
+
+static gboolean
+gst_alsasink2_open (GstAudioSink * asink)
+{
+ _k_GstAlsaSink *alsa;
+ gint err;
+
+ alsa = GST_ALSA_SINK2 (asink);
+
+ CHECK (snd_pcm_open (&alsa->handle, alsa->device, SND_PCM_STREAM_PLAYBACK,
+ SND_PCM_NONBLOCK), open_error);
+ GST_LOG_OBJECT (alsa, "Opened device %s", alsa->device);
+
+ return TRUE;
+
+ /* ERRORS */
+open_error:
+ {
+ if (err == -EBUSY) {
+ GST_ELEMENT_ERROR (alsa, RESOURCE, BUSY,
+ (_("Could not open audio device for playback. "
+ "Device is being used by another application.")),
+ ("Device '%s' is busy", alsa->device));
+ } else {
+ GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_WRITE,
+ (_("Could not open audio device for playback.")),
+ ("Playback open error on device '%s': %s", alsa->device,
+ snd_strerror (err)));
+ }
+ return FALSE;
+ }
+}
+
+static gboolean
+gst_alsasink2_prepare (GstAudioSink * asink, GstRingBufferSpec * spec)
+{
+ _k_GstAlsaSink *alsa;
+ gint err;
+
+ alsa = GST_ALSA_SINK2 (asink);
+
+#if GST_CHECK_VERSION(0, 10, 18)
+ if (spec->format == GST_IEC958) {
+ snd_pcm_close (alsa->handle);
+ alsa->handle = gst_alsa_open_iec958_pcm (GST_OBJECT (alsa));
+ if (G_UNLIKELY (!alsa->handle)) {
+ goto no_iec958;
+ }
+ }
+#endif
+
+ if (!alsasink2_parse_spec (alsa, spec))
+ goto spec_parse;
+
+ CHECK (set_hwparams (alsa), hw_params_failed);
+ CHECK (set_swparams (alsa), sw_params_failed);
+
+ alsa->bytes_per_sample = spec->bytes_per_sample;
+ spec->segsize = alsa->period_size * spec->bytes_per_sample;
+ spec->segtotal = alsa->buffer_size / alsa->period_size;
+
+ {
+ snd_output_t *out_buf = NULL;
+ char *msg = NULL;
+
+ snd_output_buffer_open (&out_buf);
+ snd_pcm_dump_hw_setup (alsa->handle, out_buf);
+ snd_output_buffer_string (out_buf, &msg);
+ GST_DEBUG_OBJECT (alsa, "Hardware setup: \n%s", msg);
+ snd_output_close (out_buf);
+ snd_output_buffer_open (&out_buf);
+ snd_pcm_dump_sw_setup (alsa->handle, out_buf);
+ snd_output_buffer_string (out_buf, &msg);
+ GST_DEBUG_OBJECT (alsa, "Software setup: \n%s", msg);
+ snd_output_close (out_buf);
+ }
+
+ return TRUE;
+
+ /* ERRORS */
+#if GST_CHECK_VERSION(0, 10, 18)
+no_iec958:
+ {
+ GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_WRITE, (NULL),
+ ("Could not open IEC958 (SPDIF) device for playback"));
+ return FALSE;
+ }
+#endif
+spec_parse:
+ {
+ GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
+ ("Error parsing spec"));
+ return FALSE;
+ }
+hw_params_failed:
+ {
+ GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
+ ("Setting of hwparams failed: %s", snd_strerror (err)));
+ return FALSE;
+ }
+sw_params_failed:
+ {
+ GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
+ ("Setting of swparams failed: %s", snd_strerror (err)));
+ return FALSE;
+ }
+}
+
+static gboolean
+gst_alsasink2_unprepare (GstAudioSink * asink)
+{
+ _k_GstAlsaSink *alsa;
+ gint err;
+
+ alsa = GST_ALSA_SINK2 (asink);
+
+ CHECK (snd_pcm_drop (alsa->handle), drop);
+
+ CHECK (snd_pcm_hw_free (alsa->handle), hw_free);
+
+ return TRUE;
+
+ /* ERRORS */
+drop:
+ {
+ GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
+ ("Could not drop samples: %s", snd_strerror (err)));
+ return FALSE;
+ }
+hw_free:
+ {
+ GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
+ ("Could not free hw params: %s", snd_strerror (err)));
+ return FALSE;
+ }
+}
+
+static gboolean
+gst_alsasink2_close (GstAudioSink * asink)
+{
+ _k_GstAlsaSink *alsa = GST_ALSA_SINK2 (asink);
+ gint err;
+
+ if (alsa->handle) {
+ CHECK (snd_pcm_close (alsa->handle), close_error);
+ alsa->handle = NULL;
+ }
+ gst_caps_replace (&alsa->cached_caps, NULL);
+
+ return TRUE;
+
+ /* ERRORS */
+close_error:
+ {
+ GST_ELEMENT_ERROR (alsa, RESOURCE, CLOSE, (NULL),
+ ("Playback close error: %s", snd_strerror (err)));
+ return FALSE;
+ }
+}
+
+
+/*
+ * Underrun and suspend recovery
+ */
+static gint
+xrun_recovery (_k_GstAlsaSink * alsa, snd_pcm_t * handle, gint err)
+{
+ GST_DEBUG_OBJECT (alsa, "xrun recovery %d", err);
+
+ if (err == -EPIPE) { /* under-run */
+ err = snd_pcm_prepare (handle);
+ if (err < 0) {
+ GST_WARNING_OBJECT (alsa,
+ "Can't recovery from underrun, prepare failed: %s",
+ snd_strerror (err));
+ }
+ return 0;
+ } else if (err == -ESTRPIPE) {
+ while ((err = snd_pcm_resume (handle)) == -EAGAIN)
+ g_usleep (100); /* wait until the suspend flag is released */
+
+ if (err < 0) {
+ err = snd_pcm_prepare (handle);
+ if (err < 0) {
+ GST_WARNING_OBJECT (alsa,
+ "Can't recovery from suspend, prepare failed: %s",
+ snd_strerror (err));
+ }
+ }
+ return 0;
+ }
+ return err;
+}
+
+static guint
+gst_alsasink2_write (GstAudioSink * asink, gpointer data, guint length)
+{
+ _k_GstAlsaSink *alsa;
+ gint err;
+ gint cptr;
+ gint16 *ptr = data;
+
+ alsa = GST_ALSA_SINK2 (asink);
+
+ if (alsa->iec958 && alsa->need_swap) {
+ guint i;
+
+ GST_DEBUG_OBJECT (asink, "swapping bytes");
+ for (i = 0; i < length / 2; i++) {
+ ptr[i] = GUINT16_SWAP_LE_BE (ptr[i]);
+ }
+ }
+
+ GST_LOG_OBJECT (asink, "received audio samples buffer of %u bytes", length);
+
+ cptr = length / alsa->bytes_per_sample;
+
+ GST_ALSA_SINK2_LOCK (asink);
+ while (cptr > 0) {
+ /* start by doing a blocking wait for free space. Set the timeout
+ * to 4 times the period time */
+ err = snd_pcm_wait (alsa->handle, (4 * alsa->period_time / 1000));
+ if (err < 0) {
+ GST_DEBUG_OBJECT (asink, "wait timeout, %d", err);
+ } else {
+ err = snd_pcm_writei (alsa->handle, ptr, cptr);
+ }
+
+ GST_DEBUG_OBJECT (asink, "written %d frames out of %d", err, cptr);
+ if (err < 0) {
+ GST_DEBUG_OBJECT (asink, "Write error: %s", snd_strerror (err));
+ if (err == -EAGAIN) {
+ continue;
+ } else if (xrun_recovery (alsa, alsa->handle, err) < 0) {
+ goto write_error;
+ }
+ continue;
+ }
+
+ ptr += snd_pcm_frames_to_bytes (alsa->handle, err);
+ cptr -= err;
+ }
+ GST_ALSA_SINK2_UNLOCK (asink);
+
+ return length - (cptr * alsa->bytes_per_sample);
+
+write_error:
+ {
+ GST_ALSA_SINK2_UNLOCK (asink);
+ return length; /* skip one period */
+ }
+}
+
+static guint
+gst_alsasink2_delay (GstAudioSink * asink)
+{
+ _k_GstAlsaSink *alsa;
+ snd_pcm_sframes_t delay;
+ int res;
+
+ alsa = GST_ALSA_SINK2 (asink);
+
+ res = snd_pcm_delay (alsa->handle, &delay);
+ if (G_UNLIKELY (res < 0)) {
+ /* on errors, report 0 delay */
+ GST_DEBUG_OBJECT (alsa, "snd_pcm_delay returned %d", res);
+ delay = 0;
+ }
+ if (G_UNLIKELY (delay < 0)) {
+ /* make sure we never return a negative delay */
+ GST_WARNING_OBJECT (alsa, "snd_pcm_delay returned negative delay");
+ delay = 0;
+ }
+
+ return delay;
+}
+
+static void
+gst_alsasink2_reset (GstAudioSink * asink)
+{
+ _k_GstAlsaSink *alsa;
+ gint err;
+
+ alsa = GST_ALSA_SINK2 (asink);
+
+ GST_ALSA_SINK2_LOCK (asink);
+ GST_DEBUG_OBJECT (alsa, "drop");
+ CHECK (snd_pcm_drop (alsa->handle), drop_error);
+ GST_DEBUG_OBJECT (alsa, "prepare");
+ CHECK (snd_pcm_prepare (alsa->handle), prepare_error);
+ GST_DEBUG_OBJECT (alsa, "reset done");
+ GST_ALSA_SINK2_UNLOCK (asink);
+
+ return;
+
+ /* ERRORS */
+drop_error:
+ {
+ GST_ERROR_OBJECT (alsa, "alsa-reset: pcm drop error: %s",
+ snd_strerror (err));
+ GST_ALSA_SINK2_UNLOCK (asink);
+ return;
+ }
+prepare_error:
+ {
+ GST_ERROR_OBJECT (alsa, "alsa-reset: pcm prepare error: %s",
+ snd_strerror (err));
+ GST_ALSA_SINK2_UNLOCK (asink);
+ return;
+ }
+}
+
+static void
+gst_alsa_error_wrapper (const char *file, int line, const char *function,
+ int err, const char *fmt, ...)
+{
+}
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+ int err;
+
+ if (!gst_element_register (plugin, "_k_alsasink", GST_RANK_PRIMARY,
+ GST_TYPE_ALSA_SINK2))
+ return FALSE;
+
+ err = snd_lib_error_set_handler (gst_alsa_error_wrapper);
+ if (err != 0)
+ GST_WARNING ("failed to set alsa error handler");
+
+ return TRUE;
+}
+
+#define PACKAGE ""
+GST_PLUGIN_DEFINE_STATIC (GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "_k_alsa",
+ "ALSA plugin library (hotfixed)",
+ plugin_init, "0.1", "LGPL", "Phonon-GStreamer", "")
+#undef PACKAGE
diff --git a/src/3rdparty/phonon/gstreamer/alsasink2.h b/src/3rdparty/phonon/gstreamer/alsasink2.h
new file mode 100644
index 0000000000..bec9933359
--- /dev/null
+++ b/src/3rdparty/phonon/gstreamer/alsasink2.h
@@ -0,0 +1,87 @@
+/* GStreamer
+ * Copyright (C) 2005 Wim Taymans <wim@fluendo.com>
+ * Copyright (C) 2008 Matthias Kretz <kretz@kde.org>
+ *
+ * gstalsasink2.h:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#ifndef ALSASINK2_H
+#define ALSASINK2_H
+
+#include <gst/gst.h>
+#include <gst/audio/gstaudiosink.h>
+#include <alsa/asoundlib.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_ALSA_SINK2 (gst_alsasink2_get_type())
+#define GST_ALSA_SINK2(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ALSA_SINK2,_k_GstAlsaSink))
+#define GST_ALSA_SINK2_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ALSA_SINK2,_k_GstAlsaSinkClass))
+#define GST_IS_ALSA_SINK2(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ALSA_SINK2))
+#define GST_IS_ALSA_SINK2_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ALSA_SINK2))
+#define GST_ALSA_SINK2_CAST(obj) ((_k_GstAlsaSink *) (obj))
+
+typedef struct _k_GstAlsaSink _k_GstAlsaSink;
+typedef struct _k_GstAlsaSinkClass _k_GstAlsaSinkClass;
+
+#define GST_ALSA_SINK2_GET_LOCK(obj) (GST_ALSA_SINK2_CAST (obj)->alsa_lock)
+#define GST_ALSA_SINK2_LOCK(obj) (g_mutex_lock (GST_ALSA_SINK2_GET_LOCK (obj)))
+#define GST_ALSA_SINK2_UNLOCK(obj) (g_mutex_unlock (GST_ALSA_SINK2_GET_LOCK (obj)))
+
+/**
+ * _k_GstAlsaSink:
+ *
+ * Opaque data structure
+ */
+struct _k_GstAlsaSink {
+ GstAudioSink sink;
+
+ gchar *device;
+
+ snd_pcm_t *handle;
+ snd_pcm_hw_params_t *hwparams;
+ snd_pcm_sw_params_t *swparams;
+
+ snd_pcm_access_t access;
+ snd_pcm_format_t format;
+ guint rate;
+ guint channels;
+ gint bytes_per_sample;
+ gboolean iec958;
+ gboolean need_swap;
+
+ guint buffer_time;
+ guint period_time;
+ snd_pcm_uframes_t buffer_size;
+ snd_pcm_uframes_t period_size;
+
+ GstCaps *cached_caps;
+
+ GMutex *alsa_lock;
+};
+
+struct _k_GstAlsaSinkClass {
+ GstAudioSinkClass parent_class;
+};
+
+GType gst_alsasink2_get_type(void);
+
+G_END_DECLS
+
+#endif /* ALSASINK2_H */
diff --git a/src/3rdparty/phonon/gstreamer/artssink.cpp b/src/3rdparty/phonon/gstreamer/artssink.cpp
new file mode 100644
index 0000000000..ff56da9d66
--- /dev/null
+++ b/src/3rdparty/phonon/gstreamer/artssink.cpp
@@ -0,0 +1,277 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library 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, either version 2.1 or 3 of the License.
+
+This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/*****************************************
+ *
+ * This is an aRts plugin for GStreamer
+ *
+ ****************************************/
+
+#include <gst/gst.h>
+#include <gst/audio/audio.h>
+#include <gst/audio/gstaudiosink.h>
+#include "artssink.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace Gstreamer
+{
+
+static GstStaticPadTemplate sinktemplate =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS (
+ "audio/x-raw-int, "
+ "width = (int) { 8, 16 }, "
+ "depth = (int) { 8, 16 }, "
+ "endianness = (int) BYTE_ORDER, "
+ "channels = (int) { 1, 2 }, "
+ "rate = (int) [ 8000, 96000 ]"
+ )
+);
+
+typedef int (*Ptr_arts_init)();
+typedef arts_stream_t (*Ptr_arts_play_stream)(int, int, int, const char*);
+typedef int (*Ptr_arts_close_stream)(arts_stream_t);
+typedef int (*Ptr_arts_stream_get)(arts_stream_t, arts_parameter_t_enum);
+typedef int (*Ptr_arts_stream_set)(arts_stream_t, arts_parameter_t_enum, int value);
+typedef int (*Ptr_arts_write)(arts_stream_t, const void *, int);
+typedef int (*Ptr_arts_suspended)();
+typedef void (*Ptr_arts_free)();
+
+static Ptr_arts_init p_arts_init = 0;
+static Ptr_arts_play_stream p_arts_play_stream = 0;
+static Ptr_arts_close_stream p_arts_close_stream = 0;
+static Ptr_arts_stream_get p_arts_stream_get= 0;
+static Ptr_arts_stream_set p_arts_stream_set= 0;
+static Ptr_arts_write p_arts_write = 0;
+static Ptr_arts_suspended p_arts_suspended = 0;
+static Ptr_arts_free p_arts_free = 0;
+
+static void arts_sink_dispose (GObject * object);
+static void arts_sink_reset (GstAudioSink * asink);
+static void arts_sink_finalize (GObject * object);
+static GstCaps *arts_sink_get_caps (GstBaseSink * bsink);
+static gboolean arts_sink_open (GstAudioSink * asink);
+static gboolean arts_sink_close (GstAudioSink * asink);
+static gboolean arts_sink_prepare (GstAudioSink * asink, GstRingBufferSpec * spec);
+static gboolean arts_sink_unprepare (GstAudioSink * asink);
+static guint arts_sink_write (GstAudioSink * asink, gpointer data, guint length);
+static guint arts_sink_delay (GstAudioSink * asink);
+
+static gboolean connected = false;
+static gboolean init = false;
+static int sinkCount;
+
+GST_BOILERPLATE (ArtsSink, arts_sink, GstAudioSink, GST_TYPE_AUDIO_SINK)
+
+// ArtsSink args
+enum
+{
+ ARG_0,
+ ARG_ARTSSINK
+};
+
+/* open the device with given specs */
+gboolean arts_sink_open(GstAudioSink *sink)
+{
+ Q_UNUSED(sink);
+
+ // We already have an open connection to this device
+ if (!init) {
+ GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_WRITE, (NULL), ("Could not connect to aRts", NULL));
+ return false;
+ } else if (connected) {
+ GST_ELEMENT_ERROR (sink, RESOURCE, BUSY, (NULL), ("Device is busy", NULL));
+ return false;
+ }
+
+ // Check if all symbols were resolved
+ if (!(p_arts_init && p_arts_play_stream && p_arts_close_stream
+ && p_arts_stream_get && p_arts_stream_set && p_arts_write && p_arts_free))
+ return FALSE;
+
+ // Check if arts_init succeeded
+ if (!init)
+ return false;
+
+ return true;
+}
+
+/* prepare resources and state to operate with the given specs */
+static gboolean arts_sink_prepare(GstAudioSink *sink, GstRingBufferSpec *spec)
+{
+ ArtsSink *asink = (ArtsSink*)sink;
+
+ if (!init)
+ return false;
+
+ asink->samplerate = spec->rate;
+ asink->samplebits = spec->depth;
+ asink->channels = spec->channels;
+ asink->bytes_per_sample = spec->bytes_per_sample;
+
+ static int id = 0;
+ asink->stream = p_arts_play_stream(spec->rate, spec->depth, spec->channels,
+ QString("gstreamer-%0").arg(id++).toLatin1().constData());
+ if (asink->stream)
+ connected = true;
+
+ return connected;
+}
+
+/* undo anything that was done in prepare() */
+static gboolean arts_sink_unprepare(GstAudioSink *sink)
+{
+ Q_UNUSED(sink);
+ ArtsSink *asink = (ArtsSink*)sink;
+ if (init && connected) {
+ p_arts_close_stream(asink->stream);
+ connected = false;
+ }
+ return true;
+}
+
+/* close the device */
+static gboolean arts_sink_close(GstAudioSink *sink)
+{
+ Q_UNUSED(sink);
+ return true;
+}
+
+/* write samples to the device */
+static guint arts_sink_write(GstAudioSink *sink, gpointer data, guint length)
+{
+ ArtsSink *asink = (ArtsSink*)sink;
+
+ if (!init)
+ return 0;
+
+ int errorcode = p_arts_write(asink->stream, (char*)data, length);
+
+ if (errorcode < 0)
+ GST_ELEMENT_ERROR (sink, RESOURCE, WRITE, (NULL), ("Could not write to device.", NULL));
+
+ return errorcode > 0 ? errorcode : 0;
+}
+
+/* get number of samples queued in the device */
+static guint arts_sink_delay(GstAudioSink *sink)
+{
+ ArtsSink *asink = (ArtsSink*)sink;
+ if (!init)
+ return 0;
+
+ // We get results in millisecons so we have to caculate the approximate size in samples
+ guint delay = p_arts_stream_get(asink->stream, ARTS_P_SERVER_LATENCY) * (asink->samplerate / 1000);
+ return delay;
+}
+
+/* reset the audio device, unblock from a write */
+static void arts_sink_reset(GstAudioSink *sink)
+{
+ // ### We are currently unable to gracefully recover
+ // after artsd has been restarted or killed.
+ Q_UNUSED(sink);
+}
+
+// Register element details
+static void arts_sink_base_init (gpointer g_class) {
+ GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
+ static gchar longname[] = "Experimental aRts sink",
+ klass[] = "Sink/Audio",
+ description[] = "aRts Audio Output Device",
+ author[] = "Nokia Corporation and/or its subsidiary(-ies) <qt-info@nokia.com>";
+ GstElementDetails details = GST_ELEMENT_DETAILS (longname,
+ klass,
+ description,
+ author);
+ gst_element_class_add_pad_template (gstelement_class, gst_static_pad_template_get (&sinktemplate));
+ gst_element_class_set_details (gstelement_class, &details);
+}
+
+static void arts_sink_class_init (ArtsSinkClass * klass)
+{
+ parent_class = (GstAudioSinkClass*)g_type_class_peek_parent(klass);
+
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ gobject_class->finalize = GST_DEBUG_FUNCPTR (arts_sink_finalize);
+ gobject_class->dispose = GST_DEBUG_FUNCPTR (arts_sink_dispose);
+
+ GstBaseSinkClass *gstbasesink_class = (GstBaseSinkClass *) klass;
+ gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (arts_sink_get_caps);
+
+ GstAudioSinkClass *gstaudiosink_class = (GstAudioSinkClass*)klass;
+ gstaudiosink_class->open = GST_DEBUG_FUNCPTR(arts_sink_open);
+ gstaudiosink_class->prepare = GST_DEBUG_FUNCPTR(arts_sink_prepare);
+ gstaudiosink_class->unprepare = GST_DEBUG_FUNCPTR(arts_sink_unprepare);
+ gstaudiosink_class->close = GST_DEBUG_FUNCPTR(arts_sink_close);
+ gstaudiosink_class->write = GST_DEBUG_FUNCPTR(arts_sink_write);
+ gstaudiosink_class->delay = GST_DEBUG_FUNCPTR(arts_sink_delay);
+ gstaudiosink_class->reset = GST_DEBUG_FUNCPTR(arts_sink_reset);
+}
+
+static void arts_sink_init (ArtsSink * src, ArtsSinkClass * g_class)
+{
+ Q_UNUSED(g_class);
+ GST_DEBUG_OBJECT (src, "initializing artssink");
+ src->stream = 0;
+
+ p_arts_init = (Ptr_arts_init)QLibrary::resolve(QLatin1String("artsc"), 0, "arts_init");
+ p_arts_play_stream = (Ptr_arts_play_stream)QLibrary::resolve(QLatin1String("artsc"), 0, "arts_play_stream");
+ p_arts_close_stream = (Ptr_arts_close_stream)QLibrary::resolve(QLatin1String("artsc"), 0, "arts_close_stream");
+ p_arts_stream_get = (Ptr_arts_stream_get)QLibrary::resolve(QLatin1String("artsc"), 0, "arts_stream_get");
+ p_arts_stream_set = (Ptr_arts_stream_set)QLibrary::resolve(QLatin1String("artsc"), 0, "arts_stream_set");
+ p_arts_write = (Ptr_arts_write)QLibrary::resolve(QLatin1String("artsc"), 0, "arts_write");
+ p_arts_suspended = (Ptr_arts_suspended)QLibrary::resolve(QLatin1String("artsc"), 0, "arts_suspended");
+ p_arts_free = (Ptr_arts_free)QLibrary::resolve(QLatin1String("artsc"), 0, "arts_free");
+
+ if (!sinkCount) {
+ int errorcode = p_arts_init();
+ if (!errorcode) {
+ init = TRUE;
+ }
+ }
+ sinkCount ++;
+}
+
+static void arts_sink_dispose (GObject * object)
+{
+ Q_UNUSED(object);
+ if (--sinkCount == 0) {
+ p_arts_free();
+ }
+}
+
+static void arts_sink_finalize (GObject * object)
+{
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static GstCaps *arts_sink_get_caps (GstBaseSink * bsink)
+{
+ Q_UNUSED(bsink);
+ return NULL;
+}
+
+}
+} //namespace Phonon::Gstreamer
+
+QT_END_NAMESPACE
diff --git a/src/3rdparty/phonon/gstreamer/artssink.h b/src/3rdparty/phonon/gstreamer/artssink.h
new file mode 100644
index 0000000000..169e73ed89
--- /dev/null
+++ b/src/3rdparty/phonon/gstreamer/artssink.h
@@ -0,0 +1,91 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library 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, either version 2.1 or 3 of the License.
+
+This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __ARTS_SINK_H__
+#define __ARTS_SINK_H__
+
+#include <QtCore>
+#include <sys/types.h>
+#include <gst/gst.h>
+#include <gst/audio/gstaudiosink.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace Gstreamer
+{
+
+G_BEGIN_DECLS
+
+extern "C" {
+
+#define GST_TYPE_ARTS_SINK (arts_sink_get_type())
+#define GST_ARTS_SINK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ARTS_SINK,ArtsSink))
+#define GST_ARTS_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ARTS_SINK,ArtsSinkClass))
+#define GST_IS_ARTS_SINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ARTS_SINK))
+#define GST_IS_ARTS_SINK_CLASS(klass)(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ARTS_SINK))
+
+typedef struct _ArtsSink ArtsSink;
+typedef struct _ArtsSinkClass ArtsSinkClass;
+
+enum arts_parameter_t_enum {
+ ARTS_P_BUFFER_SIZE = 1,
+ ARTS_P_BUFFER_TIME = 2,
+ ARTS_P_BUFFER_SPACE = 3,
+ ARTS_P_SERVER_LATENCY = 4,
+ ARTS_P_TOTAL_LATENCY = 5,
+ ARTS_P_BLOCKING = 6,
+ ARTS_P_PACKET_SIZE = 7,
+ ARTS_P_PACKET_COUNT = 8,
+ ARTS_P_PACKET_SETTINGS = 9
+};
+
+typedef void *arts_stream_t;
+
+struct _ArtsSink {
+ GstAudioSink sink;
+ arts_stream_t stream;
+ int samplerate;
+ int samplebits;
+ int channels;
+ int bytes_per_sample;
+};
+
+struct GConfClient;
+struct GError;
+typedef void (*Ptr_g_type_init)();
+typedef GConfClient* (*Ptr_gconf_client_get_default)();
+typedef char* (*Ptr_gconf_client_get_string)(GConfClient*, const char*, GError **);
+typedef void (*Ptr_g_object_unref)(void *);
+typedef void (*Ptr_g_error_free)(GError *);
+typedef void (*Ptr_g_free)(void*);
+
+struct _ArtsSinkClass {
+ GstAudioSinkClass parent_class;
+};
+
+GType arts_sink_get_type (void);
+}
+G_END_DECLS
+
+}
+} //namespace Phonon::Gstreamer
+
+QT_END_NAMESPACE
+
+#endif // __ARTS_SINK_H__
diff --git a/src/3rdparty/phonon/gstreamer/audioeffect.cpp b/src/3rdparty/phonon/gstreamer/audioeffect.cpp
new file mode 100644
index 0000000000..db72c8b593
--- /dev/null
+++ b/src/3rdparty/phonon/gstreamer/audioeffect.cpp
@@ -0,0 +1,78 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "common.h"
+#include "backend.h"
+#include "medianode.h"
+#include "effectmanager.h"
+#include "audioeffect.h"
+#include "gsthelper.h"
+
+#include <gst/gst.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace Gstreamer
+{
+AudioEffect::AudioEffect(Backend *backend, int effectId, QObject *parent)
+ : Effect(backend, parent, AudioSource | AudioSink)
+{
+ static int count = 0;
+ m_name = "AudioEffect" + QString::number(count++);
+ QList<EffectInfo*> audioEffects = backend->effectManager()->audioEffects();
+ if (effectId >= 0 && effectId < audioEffects.size()) {
+ m_effectName = audioEffects[effectId]->name();
+ init();
+ } else {
+ Q_ASSERT(0); // Effect ID out of range
+ }
+}
+
+GstElement* AudioEffect::createEffectBin()
+{
+ GstElement *audioBin = gst_bin_new(NULL);
+
+ // We need a queue to handle tee-connections from parent node
+ GstElement *queue= gst_element_factory_make ("queue", NULL);
+ gst_bin_add(GST_BIN(audioBin), queue);
+
+ GstElement *mconv= gst_element_factory_make ("audioconvert", NULL);
+ gst_bin_add(GST_BIN(audioBin), mconv);
+
+ m_effectElement = gst_element_factory_make (qPrintable(m_effectName), NULL);
+ gst_bin_add(GST_BIN(audioBin), m_effectElement);
+
+ //Link src pad
+ GstPad *srcPad= gst_element_get_pad (m_effectElement, "src");
+ gst_element_add_pad (audioBin, gst_ghost_pad_new ("src", srcPad));
+ gst_object_unref (srcPad);
+
+ //Link sink pad
+ gst_element_link_many(queue, mconv, m_effectElement, (const char*)NULL);
+ GstPad *sinkpad = gst_element_get_pad (queue, "sink");
+ gst_element_add_pad (audioBin, gst_ghost_pad_new ("sink", sinkpad));
+ gst_object_unref (sinkpad);
+ return audioBin;
+}
+
+}
+} //namespace Phonon::Gstreamer
+
+QT_END_NAMESPACE
+#include "moc_audioeffect.cpp"
diff --git a/src/3rdparty/phonon/gstreamer/audioeffect.h b/src/3rdparty/phonon/gstreamer/audioeffect.h
new file mode 100644
index 0000000000..3a985e553b
--- /dev/null
+++ b/src/3rdparty/phonon/gstreamer/audioeffect.h
@@ -0,0 +1,55 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef Phonon_GSTREAMER_AUDIOEFFECT_H
+#define Phonon_GSTREAMER_AUDIOEFFECT_H
+
+#include "common.h"
+#include "effect.h"
+#include "medianode.h"
+
+#include <phonon/effectparameter.h>
+#include <phonon/effectinterface.h>
+
+#include <QtCore/QObject>
+
+#include <gst/gst.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace Gstreamer
+{
+ class AudioOutput;
+ class EffectInfo;
+
+ class AudioEffect : public Effect
+ {
+ Q_OBJECT
+ public:
+ AudioEffect (Backend *backend, int effectId, QObject *parent);
+ protected:
+ GstElement* createEffectBin();
+ GstElement* audioElement() { return m_effectBin; }
+ QString m_effectName;
+ };
+}} //namespace Phonon::Gstreamer
+
+QT_END_NAMESPACE
+
+#endif // Phonon_GSTREAMER_AUDIOEFFECT_H
diff --git a/src/3rdparty/phonon/gstreamer/audiooutput.cpp b/src/3rdparty/phonon/gstreamer/audiooutput.cpp
new file mode 100644
index 0000000000..138a7e414c
--- /dev/null
+++ b/src/3rdparty/phonon/gstreamer/audiooutput.cpp
@@ -0,0 +1,257 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ Copyright (C) 2008 Matthias Kretz <kretz@kde.org>
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "common.h"
+#include "audiooutput.h"
+#include "backend.h"
+#include "mediaobject.h"
+#include "gsthelper.h"
+#include <phonon/audiooutput.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace Gstreamer
+{
+AudioOutput::AudioOutput(Backend *backend, QObject *parent)
+ : QObject(parent)
+ , MediaNode(backend, AudioSink)
+ , m_volumeLevel(1.0)
+ , m_device(0) // ### get from backend
+ , m_volumeElement(0)
+ , m_audioBin(0)
+ , m_audioSink(0)
+ , m_conv(0)
+{
+ static int count = 0;
+ m_name = "AudioOutput" + QString::number(count++);
+ if (m_backend->isValid()) {
+ g_set_application_name(qApp->applicationName().toUtf8());
+ m_audioBin = gst_bin_new (NULL);
+ gst_object_ref (GST_OBJECT (m_audioBin));
+ gst_object_sink (GST_OBJECT (m_audioBin));
+
+ m_conv = gst_element_factory_make ("audioconvert", NULL);
+
+ // Get category from parent
+ Phonon::Category category = Phonon::NoCategory;
+ if (Phonon::AudioOutput *audioOutput = qobject_cast<Phonon::AudioOutput *>(parent))
+ category = audioOutput->category();
+
+ m_audioSink = m_backend->deviceManager()->createAudioSink(category);
+ m_volumeElement = gst_element_factory_make ("volume", NULL);
+ GstElement *queue = gst_element_factory_make ("queue", NULL);
+ GstElement *audioresample = gst_element_factory_make ("audioresample", NULL);
+
+ if (queue && m_audioBin && m_conv && audioresample && m_audioSink && m_volumeElement) {
+ gst_bin_add_many (GST_BIN (m_audioBin), queue, m_conv, audioresample, m_volumeElement, m_audioSink, (const char*)NULL);
+
+ if (gst_element_link_many (queue, m_conv, audioresample, m_volumeElement, m_audioSink, (const char*)NULL)) {
+ // Add ghost sink for audiobin
+ GstPad *audiopad = gst_element_get_pad (queue, "sink");
+ gst_element_add_pad (m_audioBin, gst_ghost_pad_new ("sink", audiopad));
+ gst_object_unref (audiopad);
+ m_isValid = true; // Initialization ok, accept input
+ }
+ }
+ }
+}
+
+void AudioOutput::mediaNodeEvent(const MediaNodeEvent *event)
+{
+ if (!m_audioBin)
+ return;
+
+ switch (event->type()) {
+
+ default:
+ break;
+ }
+}
+
+
+AudioOutput::~AudioOutput()
+{
+ if (m_audioBin) {
+ gst_element_set_state (m_audioBin, GST_STATE_NULL);
+ gst_object_unref (m_audioBin);
+ }
+}
+
+qreal AudioOutput::volume() const
+{
+ return m_volumeLevel;
+}
+
+int AudioOutput::outputDevice() const
+{
+ return m_device;
+}
+
+void AudioOutput::setVolume(qreal newVolume)
+{
+ if (newVolume > 2.0 )
+ newVolume = 2.0;
+ else if (newVolume < 0.0)
+ newVolume = 0.0;
+
+ if (newVolume == m_volumeLevel)
+ return;
+
+ m_volumeLevel = newVolume;
+
+ if (m_volumeElement) {
+ g_object_set(G_OBJECT(m_volumeElement), "volume", newVolume, (const char*)NULL);
+ }
+
+ emit volumeChanged(newVolume);
+}
+
+bool AudioOutput::setOutputDevice(int newDevice)
+{
+ m_backend->logMessage(Q_FUNC_INFO + QString::number(newDevice), Backend::Info, this);
+ if (newDevice == m_device)
+ return true;
+
+ if (root()) {
+ root()->saveState();
+ if (gst_element_set_state(root()->pipeline(), GST_STATE_READY) == GST_STATE_CHANGE_FAILURE)
+ return false;
+ }
+
+ bool success = false;
+ const QList<AudioDevice> deviceList = m_backend->deviceManager()->audioOutputDevices();
+ if (m_audioSink && newDevice >= 0 && newDevice < deviceList.size()) {
+ // Save previous state
+ GstState oldState = GST_STATE(m_audioSink);
+ const QByteArray oldDeviceValue = GstHelper::property(m_audioSink, "device");
+ const QByteArray deviceId = deviceList.at(newDevice).gstId;
+ m_device = newDevice;
+
+ // We test if the device can be opened by checking if it can go from NULL to READY state
+ gst_element_set_state(m_audioSink, GST_STATE_NULL);
+ success = GstHelper::setProperty(m_audioSink, "device", deviceId);
+ if (success) {
+ success = (gst_element_set_state(m_audioSink, oldState) == GST_STATE_CHANGE_SUCCESS);
+ }
+ if (!success) { // Revert state
+ m_backend->logMessage(Q_FUNC_INFO +
+ QLatin1String(" Failed to change device ") +
+ deviceId, Backend::Info, this);
+
+ GstHelper::setProperty(m_audioSink, "device", oldDeviceValue);
+ gst_element_set_state(m_audioSink, oldState);
+ } else {
+ m_backend->logMessage(Q_FUNC_INFO +
+ QLatin1String(" Successfully changed device ") +
+ deviceId, Backend::Info, this);
+ }
+
+ // Note the stopped state should not really be neccessary, but seems to be required to
+ // properly reset after changing the audio state
+ if (root()) {
+ QMetaObject::invokeMethod(root(), "setState", Qt::QueuedConnection, Q_ARG(State, StoppedState));
+ root()->resumeState();
+ }
+ }
+ return success;
+}
+
+#if (PHONON_VERSION >= PHONON_VERSION_CHECK(4, 2, 0))
+bool AudioOutput::setOutputDevice(const AudioOutputDevice &newDevice)
+{
+ m_backend->logMessage(Q_FUNC_INFO, Backend::Info, this);
+ if (!m_audioSink || !newDevice.isValid()) {
+ return false;
+ }
+ const QVariant driver = newDevice.property("driver");
+ if (!driver.isValid()) {
+ return setOutputDevice(newDevice.index());
+ }
+ if (newDevice.index() == m_device) {
+ return true;
+ }
+
+ if (root()) {
+ root()->saveState();
+ if (gst_element_set_state(root()->pipeline(), GST_STATE_READY) == GST_STATE_CHANGE_FAILURE)
+ return false;
+ }
+
+ // Save previous state
+ const GstState oldState = GST_STATE(m_audioSink);
+ const QByteArray oldDeviceValue = GstHelper::property(m_audioSink, "device");
+
+ const QByteArray sinkName = GstHelper::property(m_audioSink, "name");
+ if (sinkName == "alsasink" || sinkName == "alsasink2") {
+ if (driver.toByteArray() != "alsa") {
+ return false;
+ }
+ }
+
+ const QVariant deviceIdsProperty = newDevice.property("deviceIds");
+ QStringList deviceIds;
+ if (deviceIdsProperty.type() == QVariant::StringList) {
+ deviceIds = deviceIdsProperty.toStringList();
+ } else if (deviceIdsProperty.type() == QVariant::String) {
+ deviceIds += deviceIdsProperty.toString();
+ }
+
+ // We test if the device can be opened by checking if it can go from NULL to READY state
+ foreach (const QString &deviceId, deviceIds) {
+ gst_element_set_state(m_audioSink, GST_STATE_NULL);
+ if (GstHelper::setProperty(m_audioSink, "device", deviceId.toUtf8())) {
+ m_backend->logMessage(Q_FUNC_INFO + QLatin1String("setProperty(device,") +
+ deviceId + QLatin1String(") succeeded"), Backend::Info, this);
+ if (gst_element_set_state(m_audioSink, oldState) == GST_STATE_CHANGE_SUCCESS) {
+ m_backend->logMessage(Q_FUNC_INFO + QLatin1String("go to old state on device") +
+ deviceId + QLatin1String(" succeeded"), Backend::Info, this);
+ m_device = newDevice.index();
+ if (root()) {
+ QMetaObject::invokeMethod(root(), "setState", Qt::QueuedConnection, Q_ARG(State, StoppedState));
+ root()->resumeState();
+ }
+ return true;
+ } else {
+ m_backend->logMessage(Q_FUNC_INFO + QLatin1String("go to old state on device") +
+ deviceId + QLatin1String(" failed"), Backend::Info, this);
+ }
+ } else {
+ m_backend->logMessage(Q_FUNC_INFO + QLatin1String("setProperty(device,") +
+ deviceId + QLatin1String(") failed"), Backend::Info, this);
+ }
+ }
+ // Revert state
+ GstHelper::setProperty(m_audioSink, "device", oldDeviceValue);
+ gst_element_set_state(m_audioSink, oldState);
+
+ if (root()) {
+ QMetaObject::invokeMethod(root(), "setState", Qt::QueuedConnection, Q_ARG(State, StoppedState));
+ root()->resumeState();
+ }
+
+ return false;
+}
+#endif
+
+}
+} //namespace Phonon::Gstreamer
+
+QT_END_NAMESPACE
+#include "moc_audiooutput.cpp"
diff --git a/src/3rdparty/phonon/gstreamer/audiooutput.h b/src/3rdparty/phonon/gstreamer/audiooutput.h
new file mode 100644
index 0000000000..846fa7bf57
--- /dev/null
+++ b/src/3rdparty/phonon/gstreamer/audiooutput.h
@@ -0,0 +1,82 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ Copyright (C) 2008 Matthias Kretz <kretz@kde.org>
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef Phonon_GSTREAMER_AUDIOOUTPUT_H
+#define Phonon_GSTREAMER_AUDIOOUTPUT_H
+
+#include "common.h"
+#include "medianode.h"
+
+#include <phonon/audiooutputinterface.h>
+#include <phonon/phononnamespace.h>
+
+#include <QtCore/QFile>
+
+#include <gst/gst.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace Gstreamer
+{
+class AudioOutput : public QObject, public AudioOutputInterface, public MediaNode
+{
+ Q_OBJECT
+ Q_INTERFACES(Phonon::AudioOutputInterface Phonon::Gstreamer::MediaNode)
+public:
+ AudioOutput(Backend *backend, QObject *parent);
+ ~AudioOutput();
+
+ qreal volume() const;
+ int outputDevice() const;
+ void setVolume(qreal newVolume);
+ bool setOutputDevice(int newDevice);
+#if (PHONON_VERSION >= PHONON_VERSION_CHECK(4, 2, 0))
+ bool setOutputDevice(const AudioOutputDevice &newDevice);
+#endif
+
+public:
+ GstElement *audioElement()
+ {
+ Q_ASSERT(m_audioBin);
+ return m_audioBin;
+ }
+
+ void mediaNodeEvent(const MediaNodeEvent *event);
+
+Q_SIGNALS:
+ void volumeChanged(qreal newVolume);
+ void audioDeviceFailed();
+
+private:
+
+ qreal m_volumeLevel;
+ int m_device;
+
+ GstElement *m_volumeElement;
+ GstElement *m_audioBin;
+ GstElement *m_audioSink;
+ GstElement *m_conv;
+};
+}
+} //namespace Phonon::Gstreamer
+
+QT_END_NAMESPACE
+
+#endif // Phonon_GSTREAMER_AUDIOOUTPUT_H
diff --git a/src/3rdparty/phonon/gstreamer/backend.cpp b/src/3rdparty/phonon/gstreamer/backend.cpp
new file mode 100644
index 0000000000..d05f6a64fc
--- /dev/null
+++ b/src/3rdparty/phonon/gstreamer/backend.cpp
@@ -0,0 +1,455 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "common.h"
+#include "backend.h"
+#include "audiooutput.h"
+#include "audioeffect.h"
+#include "mediaobject.h"
+#include "videowidget.h"
+#include "devicemanager.h"
+#include "effectmanager.h"
+#include "message.h"
+#include "volumefadereffect.h"
+#include <gst/interfaces/propertyprobe.h>
+
+#include <QtCore/QSet>
+#include <QtCore/QVariant>
+#include <QtCore/QtPlugin>
+
+QT_BEGIN_NAMESPACE
+
+Q_EXPORT_PLUGIN2(phonon_gstreamer, Phonon::Gstreamer::Backend)
+
+namespace Phonon
+{
+namespace Gstreamer
+{
+
+class MediaNode;
+
+Backend::Backend(QObject *parent, const QVariantList &)
+ : QObject(parent)
+ , m_deviceManager(0)
+ , m_effectManager(0)
+ , m_debugLevel(Warning)
+ , m_isValid(false)
+{
+ GError *err = 0;
+ bool wasInit = gst_init_check(0, 0, &err); //init gstreamer: must be called before any gst-related functions
+ if (err)
+ g_error_free(err);
+
+ qRegisterMetaType<Message>("Message");
+
+ setProperty("identifier", QLatin1String("phonon_gstreamer"));
+ setProperty("backendName", QLatin1String("Gstreamer"));
+ setProperty("backendComment", QLatin1String("Gstreamer plugin for Phonon"));
+ setProperty("backendVersion", QLatin1String("0.2"));
+ setProperty("backendWebsite", QLatin1String("http://qtsoftware.com/"));
+
+ //check if we should enable debug output
+ QString debugLevelString = qgetenv("PHONON_GST_DEBUG");
+ int debugLevel = debugLevelString.toInt();
+ if (debugLevel > 3) //3 is maximum
+ debugLevel = 3;
+ m_debugLevel = (DebugLevel)debugLevel;
+
+ if (wasInit) {
+ m_isValid = checkDependencies();
+ gchar *versionString = gst_version_string();
+ logMessage(QString("Using %0").arg(versionString));
+ g_free(versionString);
+ }
+ if (!m_isValid)
+ qWarning("Phonon::GStreamer::Backend: Failed to initialize GStreamer");
+
+ m_deviceManager = new DeviceManager(this);
+ m_effectManager = new EffectManager(this);
+}
+
+Backend::~Backend()
+{
+ gst_deinit();
+}
+
+gboolean Backend::busCall(GstBus *bus, GstMessage *msg, gpointer data)
+{
+ Q_UNUSED(bus);
+ Q_ASSERT(msg);
+
+ MediaObject *mediaObject = static_cast<MediaObject*>(data);
+ Q_ASSERT(mediaObject);
+
+ Message message(msg, mediaObject);
+ QMetaObject::invokeMethod(mediaObject->backend(), "handleBusMessage", Qt::QueuedConnection, Q_ARG(Message, message));
+
+ return true;
+}
+
+/***
+ * !reimp
+ */
+QObject *Backend::createObject(BackendInterface::Class c, QObject *parent, const QList<QVariant> &args)
+{
+ // Return nothing if dependencies are not met
+
+ switch (c) {
+ case MediaObjectClass:
+ return new MediaObject(this, parent);
+
+ case AudioOutputClass: {
+ AudioOutput *ao = new AudioOutput(this, parent);
+ m_audioOutputs.append(ao);
+ return ao;
+ }
+ case EffectClass:
+ return new AudioEffect(this, args[0].toInt(), parent);
+
+ case AudioDataOutputClass:
+ logMessage("createObject() : AudioDataOutput not implemented");
+ break;
+
+ case VideoDataOutputClass:
+ logMessage("createObject() : VideoDataOutput not implemented");
+ break;
+
+ case VideoWidgetClass: {
+ QWidget *widget = qobject_cast<QWidget*>(parent);
+ return new VideoWidget(this, widget);
+ }
+
+ case VolumeFaderEffectClass:
+ return new VolumeFaderEffect(this, parent);
+
+ case VisualizationClass: //Fall through
+ default:
+ logMessage("createObject() : Backend object not available");
+ }
+ return 0;
+}
+
+// Returns true if all dependencies are met
+// and gstreamer is usable, otherwise false
+bool Backend::isValid() const
+{
+ return m_isValid;
+}
+
+bool Backend::supportsVideo() const
+{
+ return isValid();
+}
+
+bool Backend::checkDependencies() const
+{
+ bool success = false;
+ // Verify that gst-plugins-base is installed
+ GstElementFactory *acFactory = gst_element_factory_find ("audioconvert");
+ if (acFactory) {
+ gst_object_unref(acFactory);
+ success = true;
+ // Check if gst-plugins-good is installed
+ GstElementFactory *csFactory = gst_element_factory_find ("videobalance");
+ if (csFactory) {
+ gst_object_unref(csFactory);
+ } else {
+ QString message = tr("Warning: You do not seem to have the package gstreamer0.10-plugins-good installed.\n"
+ " Some video features have been disabled.");
+ qDebug() << message;
+ }
+ } else {
+ qWarning() << tr("Warning: You do not seem to have the base GStreamer plugins installed.\n"
+ " All audio and video support has been disabled");
+ }
+ return success;
+}
+
+/***
+ * !reimp
+ */
+QStringList Backend::availableMimeTypes() const
+{
+ QStringList availableMimeTypes;
+
+ if (!isValid())
+ return availableMimeTypes;
+
+ GstElementFactory *mpegFactory;
+ // Add mp3 as a separate mime type as people are likely to look for it.
+ if ((mpegFactory = gst_element_factory_find ("ffmpeg")) ||
+ (mpegFactory = gst_element_factory_find ("mad"))) {
+ availableMimeTypes << QLatin1String("audio/x-mp3");
+ gst_object_unref(GST_OBJECT(mpegFactory));
+ }
+
+ // Iterate over all audio and video decoders and extract mime types from sink caps
+ GList* factoryList = gst_registry_get_feature_list(gst_registry_get_default (), GST_TYPE_ELEMENT_FACTORY);
+ for (GList* iter = g_list_first(factoryList) ; iter != NULL ; iter = g_list_next(iter)) {
+ GstPluginFeature *feature = GST_PLUGIN_FEATURE(iter->data);
+ QString klass = gst_element_factory_get_klass(GST_ELEMENT_FACTORY(feature));
+
+ if (klass == QLatin1String("Codec/Decoder/Audio") ||
+ klass == QLatin1String("Codec/Decoder/Video")) {
+
+ const GList *static_templates;
+ GstElementFactory *factory = GST_ELEMENT_FACTORY(feature);
+ static_templates = gst_element_factory_get_static_pad_templates(factory);
+
+ for (; static_templates != NULL ; static_templates = static_templates->next) {
+ GstStaticPadTemplate *padTemplate = (GstStaticPadTemplate *) static_templates->data;
+ if (padTemplate && padTemplate->direction == GST_PAD_SINK) {
+ GstCaps *caps = gst_static_pad_template_get_caps (padTemplate);
+
+ if (caps) {
+ const GstStructure* capsStruct = gst_caps_get_structure (caps, 0);
+ QString mime = QString::fromUtf8(gst_structure_get_name (capsStruct));
+ if (!availableMimeTypes.contains(mime))
+ availableMimeTypes.append(mime);
+ }
+ }
+ }
+ }
+ }
+ g_list_free(factoryList);
+ availableMimeTypes.sort();
+ return availableMimeTypes;
+}
+
+/***
+ * !reimp
+ */
+QList<int> Backend::objectDescriptionIndexes(ObjectDescriptionType type) const
+{
+ QList<int> list;
+
+ if (!isValid())
+ return list;
+
+ switch (type) {
+ case Phonon::AudioOutputDeviceType: {
+ QList<AudioDevice> deviceList = deviceManager()->audioOutputDevices();
+ for (int dev = 0 ; dev < deviceList.size() ; ++dev)
+ list.append(deviceList[dev].id);
+ break;
+ }
+ break;
+
+ case Phonon::EffectType: {
+ QList<EffectInfo*> effectList = effectManager()->audioEffects();
+ for (int eff = 0 ; eff < effectList.size() ; ++eff)
+ list.append(eff);
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ return list;
+}
+
+/***
+ * !reimp
+ */
+QHash<QByteArray, QVariant> Backend::objectDescriptionProperties(ObjectDescriptionType type, int index) const
+{
+
+ QHash<QByteArray, QVariant> ret;
+
+ if (!isValid())
+ return ret;
+
+ switch (type) {
+ case Phonon::AudioOutputDeviceType: {
+ QList<AudioDevice> audioDevices = deviceManager()->audioOutputDevices();
+ if (index >= 0 && index < audioDevices.size()) {
+ ret.insert("name", audioDevices[index].gstId);
+ ret.insert("description", audioDevices[index].description);
+ ret.insert("icon", QLatin1String("audio-card"));
+ }
+ }
+ break;
+
+ case Phonon::EffectType: {
+ QList<EffectInfo*> effectList = effectManager()->audioEffects();
+ if (index >= 0 && index <= effectList.size()) {
+ const EffectInfo *effect = effectList[index];
+ ret.insert("name", effect->name());
+ ret.insert("description", effect->description());
+ ret.insert("author", effect->author());
+ } else
+ Q_ASSERT(1); // Since we use list position as ID, this should not happen
+ }
+ default:
+ break;
+ }
+ return ret;
+}
+
+/***
+ * !reimp
+ */
+bool Backend::startConnectionChange(QSet<QObject *> objects)
+{
+ foreach (QObject *object, objects) {
+ MediaNode *sourceNode = qobject_cast<MediaNode *>(object);
+ MediaObject *media = sourceNode->root();
+ if (media) {
+ media->saveState();
+ return true;
+ }
+ }
+ return true;
+}
+
+/***
+ * !reimp
+ */
+bool Backend::connectNodes(QObject *source, QObject *sink)
+{
+ if (isValid()) {
+ MediaNode *sourceNode = qobject_cast<MediaNode *>(source);
+ MediaNode *sinkNode = qobject_cast<MediaNode *>(sink);
+ if (sourceNode && sinkNode) {
+ if (sourceNode->connectNode(sink)) {
+ sourceNode->root()->invalidateGraph();
+ logMessage(QString("Backend connected %0 to %1").arg(source->metaObject()->className()).arg(sink->metaObject()->className()));
+ return true;
+ }
+ }
+ }
+ logMessage(QString("Linking %0 to %1 failed").arg(source->metaObject()->className()).arg(sink->metaObject()->className()), Warning);
+ return false;
+}
+
+/***
+ * !reimp
+ */
+bool Backend::disconnectNodes(QObject *source, QObject *sink)
+{
+ MediaNode *sourceNode = qobject_cast<MediaNode *>(source);
+ MediaNode *sinkNode = qobject_cast<MediaNode *>(sink);
+
+ if (sourceNode && sinkNode)
+ return sourceNode->disconnectNode(sink);
+ else
+ return false;
+}
+
+/***
+ * !reimp
+ */
+bool Backend::endConnectionChange(QSet<QObject *> objects)
+{
+ foreach (QObject *object, objects) {
+ MediaNode *sourceNode = qobject_cast<MediaNode *>(object);
+ MediaObject *media = sourceNode->root();
+ if (media) {
+ media->resumeState();
+ return true;
+ }
+ }
+ return true;
+}
+
+/***
+ * Request bus messages for this mediaobject
+ */
+void Backend::addBusWatcher(MediaObject* node)
+{
+ Q_ASSERT(node);
+ GstBus *bus = gst_pipeline_get_bus (GST_PIPELINE(node->pipeline()));
+ gst_bus_add_watch (bus, busCall, node);
+ gst_object_unref(bus);
+}
+
+/***
+ * Ignore bus messages for this mediaobject
+ */
+void Backend::removeBusWatcher(MediaObject* node)
+{
+ Q_ASSERT(node);
+ g_source_remove_by_user_data(node);
+}
+
+/***
+ * Polls each mediaobject's pipeline and delivers
+ * pending any pending messages
+ */
+void Backend::handleBusMessage(Message message)
+{
+ MediaObject *mediaObject = message.source();
+ mediaObject->handleBusMessage(message);
+}
+
+DeviceManager* Backend::deviceManager() const
+{
+ return m_deviceManager;
+}
+
+EffectManager* Backend::effectManager() const
+{
+ return m_effectManager;
+}
+
+/**
+ * Returns a debuglevel that is determined by the
+ * PHONON_GSTREAMER_DEBUG environment variable.
+ *
+ * Warning - important warnings
+ * Info - general info
+ * Debug - gives extra info
+ */
+Backend::DebugLevel Backend::debugLevel() const
+{
+ return m_debugLevel;
+}
+
+/***
+ * Prints a conditional debug message based on the current debug level
+ * If obj is provided, classname and objectname will be printed as well
+ *
+ * see debugLevel()
+ */
+void Backend::logMessage(const QString &message, int priority, QObject *obj) const
+{
+ if (debugLevel() > 0) {
+ QString output;
+ if (obj) {
+ // Strip away namespace from className
+ QString className(obj->metaObject()->className());
+ int nameLength = className.length() - className.lastIndexOf(':') - 1;
+ className = className.right(nameLength);
+ output.sprintf("%s %s (%s %p)", message.toLatin1().constData(),
+ obj->objectName().toLatin1().constData(),
+ className.toLatin1().constData(), obj);
+ }
+ else {
+ output = message;
+ }
+ if (priority <= (int)debugLevel()) {
+ qDebug() << QString("PGST(%1): %2").arg(priority).arg(output);
+ }
+ }
+}
+
+}
+}
+
+QT_END_NAMESPACE
+
+#include "moc_backend.cpp"
diff --git a/src/3rdparty/phonon/gstreamer/backend.h b/src/3rdparty/phonon/gstreamer/backend.h
new file mode 100644
index 0000000000..2aab6fa0c1
--- /dev/null
+++ b/src/3rdparty/phonon/gstreamer/backend.h
@@ -0,0 +1,101 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef Phonon_GSTREAMER_BACKEND_H
+#define Phonon_GSTREAMER_BACKEND_H
+
+#include "common.h"
+#include "devicemanager.h"
+#include "medianode.h"
+
+#include <phonon/objectdescription.h>
+#include <phonon/backendinterface.h>
+
+#include <QtCore/QList>
+#include <QtCore/QPointer>
+#include <QtCore/QStringList>
+#include <QtCore/QTimer>
+
+#include <gst/gst.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace Gstreamer
+{
+class AudioOutput;
+class MediaNode;
+class MediaObject;
+class EffectManager;
+
+class Backend : public QObject, public BackendInterface
+{
+ Q_OBJECT
+ Q_INTERFACES(Phonon::BackendInterface)
+
+public:
+
+ enum DebugLevel {NoDebug, Warning, Info, Debug};
+ Backend(QObject *parent = 0, const QVariantList & = QVariantList());
+ virtual ~Backend();
+
+ DeviceManager* deviceManager() const;
+ EffectManager* effectManager() const;
+
+ QObject *createObject(BackendInterface::Class, QObject *parent, const QList<QVariant> &args);
+
+ bool isValid() const;
+ bool supportsVideo() const;
+ QStringList availableMimeTypes() const;
+
+ QList<int> objectDescriptionIndexes(ObjectDescriptionType type) const;
+ QHash<QByteArray, QVariant> objectDescriptionProperties(ObjectDescriptionType type, int index) const;
+
+ bool startConnectionChange(QSet<QObject *>);
+ bool connectNodes(QObject *, QObject *);
+ bool disconnectNodes(QObject *, QObject *);
+ bool endConnectionChange(QSet<QObject *>);
+
+ DebugLevel debugLevel() const;
+
+ void addBusWatcher(MediaObject* node);
+ void removeBusWatcher(MediaObject* node);
+ void logMessage(const QString &message, int priority = 2, QObject *obj=0) const;
+ bool checkDependencies() const;
+
+Q_SIGNALS:
+ void objectDescriptionChanged(ObjectDescriptionType);
+
+private Q_SLOTS:
+ void handleBusMessage(Message);
+
+private:
+ static gboolean busCall(GstBus *bus, GstMessage *msg, gpointer data);
+ QList<QPointer<AudioOutput> > m_audioOutputs;
+
+ DeviceManager *m_deviceManager;
+ EffectManager *m_effectManager;
+ DebugLevel m_debugLevel;
+ bool m_isValid;
+};
+}
+} // namespace Phonon::Gstreamer
+
+QT_END_NAMESPACE
+
+#endif // Phonon_GSTREAMER_BACKEND_H
diff --git a/src/3rdparty/phonon/gstreamer/common.h b/src/3rdparty/phonon/gstreamer/common.h
new file mode 100644
index 0000000000..355df50d2e
--- /dev/null
+++ b/src/3rdparty/phonon/gstreamer/common.h
@@ -0,0 +1,51 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef Phonon_GSTREAMER_COMMON_H
+#define Phonon_GSTREAMER_COMMON_H
+
+#include <phonon/phonon_export.h>
+
+#include <QtCore/QDebug>
+
+#ifdef DEBUG_IMPLEMENTED
+#define IMPLEMENTED qDebug() << "PGst:" << __FUNCTION__ << "(" << __FILE__ << "):"
+#else
+#define IMPLEMENTED if (1); else qDebug()
+#endif
+
+#ifdef DEBUG_HALF_IMPLEMENTED
+#define HALF_IMPLEMENTED qDebug() << "PGst: --- HALF IMPLEMENTED:" << __FUNCTION__ << "(" << __FILE__ << "):"
+#else
+#define HALF_IMPLEMENTED if (1); else qDebug()
+#endif
+
+#ifdef DEBUG_NOT_IMPLEMENTED
+#define NOT_IMPLEMENTED qDebug() << "PGst: *** NOT IMPLEMENTED:" << __FUNCTION__ << "(" << __FILE__ << "):"
+#else
+#define NOT_IMPLEMENTED if (1); else qDebug()
+#endif
+
+#ifdef DEBUG_IMPLEMENTED_SILENT
+#define IMPLEMENTED_SILENT qDebug() << "PGst: (silent)" << __FUNCTION__ << "(" << __FILE__ << "):"
+#else
+#define IMPLEMENTED_SILENT if (1); else qDebug()
+#endif
+
+#define BACKEND_WARNING qDebug() << "PGst: ____ WARNING ____" << Q_FUNC_INFO << ":"
+
+#endif // Phonon_GSTREAMER_COMMON_H
diff --git a/src/3rdparty/phonon/gstreamer/devicemanager.cpp b/src/3rdparty/phonon/gstreamer/devicemanager.cpp
new file mode 100644
index 0000000000..22403966d5
--- /dev/null
+++ b/src/3rdparty/phonon/gstreamer/devicemanager.cpp
@@ -0,0 +1,357 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <gst/interfaces/propertyprobe.h>
+#include "devicemanager.h"
+#include "backend.h"
+#include "gsthelper.h"
+#include "videowidget.h"
+#include "glrenderer.h"
+#include "widgetrenderer.h"
+#include "x11renderer.h"
+#include "artssink.h"
+
+#ifdef USE_ALSASINK2
+#include "alsasink2.h"
+#endif
+
+/*
+ * This class manages the list of currently
+ * active output devices
+ */
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace Gstreamer
+{
+
+AudioDevice::AudioDevice(DeviceManager *manager, const QByteArray &gstId)
+ : gstId(gstId)
+{
+ //get an id
+ static int counter = 0;
+ id = counter++;
+ //get name from device
+ if (gstId == "default") {
+ description = "Default audio device";
+ } else {
+ GstElement *aSink= manager->createAudioSink();
+
+ if (aSink) {
+ gchar *deviceDescription = NULL;
+
+ if (GST_IS_PROPERTY_PROBE(aSink) && gst_property_probe_get_property( GST_PROPERTY_PROBE(aSink), "device" ) ) {
+ g_object_set (G_OBJECT(aSink), "device", gstId.constData(), (const char*)NULL);
+ g_object_get (G_OBJECT(aSink), "device-name", &deviceDescription, (const char*)NULL);
+ description = QByteArray(deviceDescription);
+ g_free (deviceDescription);
+ gst_element_set_state(aSink, GST_STATE_NULL);
+ gst_object_unref (aSink);
+ }
+ }
+ }
+}
+
+DeviceManager::DeviceManager(Backend *backend)
+ : QObject(backend)
+ , m_backend(backend)
+{
+ QSettings settings(QLatin1String("Trolltech"));
+ settings.beginGroup(QLatin1String("Qt"));
+
+ m_audioSink = qgetenv("PHONON_GST_AUDIOSINK");
+ if (m_audioSink.isEmpty()) {
+ m_audioSink = settings.value(QLatin1String("audiosink"), "Auto").toByteArray().toLower();
+ }
+
+ m_videoSinkWidget = qgetenv("PHONON_GST_VIDEOMODE");
+ if (m_videoSinkWidget.isEmpty()) {
+ m_videoSinkWidget = settings.value(QLatin1String("videomode"), "Auto").toByteArray().toLower();
+ }
+
+ if (m_backend->isValid())
+ updateDeviceList();
+}
+
+DeviceManager::~DeviceManager()
+{
+ m_audioDeviceList.clear();
+}
+
+/***
+* Returns a Gst Audiosink based on GNOME configuration settings,
+* or 0 if the element is not available.
+*/
+GstElement *DeviceManager::createGNOMEAudioSink(Category category)
+{
+ GstElement *sink = gst_element_factory_make ("gconfaudiosink", NULL);
+
+ if (sink) {
+
+ // set profile property on the gconfaudiosink to "music and movies"
+ if (g_object_class_find_property (G_OBJECT_GET_CLASS (sink), "profile")) {
+ switch (category) {
+ case NotificationCategory:
+ g_object_set (G_OBJECT (sink), "profile", 0, (const char*)NULL); // 0 = 'sounds'
+ break;
+ case CommunicationCategory:
+ g_object_set (G_OBJECT (sink), "profile", 2, (const char*)NULL); // 2 = 'chat'
+ break;
+ default:
+ g_object_set (G_OBJECT (sink), "profile", 1, (const char*)NULL); // 1 = 'music and movies'
+ break;
+ }
+ }
+ }
+ return sink;
+}
+
+
+bool DeviceManager::canOpenDevice(GstElement *element) const
+{
+ if (!element)
+ return false;
+
+ if (gst_element_set_state(element, GST_STATE_READY) == GST_STATE_CHANGE_SUCCESS)
+ return true;
+
+ const QList<QByteArray> &list = GstHelper::extractProperties(element, "device");
+ foreach (const QByteArray &gstId, list) {
+ GstHelper::setProperty(element, "device", gstId);
+ if (gst_element_set_state(element, GST_STATE_READY) == GST_STATE_CHANGE_SUCCESS) {
+ return true;
+ }
+ }
+ // FIXME: the above can still fail for a valid alsasink because list only contains entries of
+ // the form "hw:X,Y". Would be better to use "default:X" or "dmix:X,Y"
+
+ gst_element_set_state(element, GST_STATE_NULL);
+ return false;
+}
+
+/*
+*
+* Returns a GstElement with a valid audio sink
+* based on the current value of PHONON_GSTREAMER_DRIVER
+*
+* Allowed values are auto (default), alsa, oss, arts and ess
+* does not exist
+*
+* If no real sound sink is available a fakesink will be returned
+*/
+GstElement *DeviceManager::createAudioSink(Category category)
+{
+ GstElement *sink = 0;
+
+ if (m_backend && m_backend->isValid())
+ {
+ if (m_audioSink == "auto") //this is the default value
+ {
+ //### TODO : get equivalent KDE settings here
+
+ if (!qgetenv("GNOME_DESKTOP_SESSION_ID").isEmpty()) {
+ sink = createGNOMEAudioSink(category);
+ if (canOpenDevice(sink))
+ m_backend->logMessage("AudioOutput using gconf audio sink");
+ else if (sink) {
+ gst_object_unref(sink);
+ sink = 0;
+ }
+ }
+
+#ifdef USE_ALSASINK2
+ if (!sink) {
+ sink = gst_element_factory_make ("_k_alsasink", NULL);
+ if (canOpenDevice(sink))
+ m_backend->logMessage("AudioOutput using alsa2 audio sink");
+ else if (sink) {
+ gst_object_unref(sink);
+ sink = 0;
+ }
+ }
+#endif
+
+ if (!sink) {
+ sink = gst_element_factory_make ("alsasink", NULL);
+ if (canOpenDevice(sink))
+ m_backend->logMessage("AudioOutput using alsa audio sink");
+ else if (sink) {
+ gst_object_unref(sink);
+ sink = 0;
+ }
+ }
+
+ if (!sink) {
+ sink = gst_element_factory_make ("autoaudiosink", NULL);
+ if (canOpenDevice(sink))
+ m_backend->logMessage("AudioOutput using auto audio sink");
+ else if (sink) {
+ gst_object_unref(sink);
+ sink = 0;
+ }
+ }
+
+ if (!sink) {
+ sink = gst_element_factory_make ("osssink", NULL);
+ if (canOpenDevice(sink))
+ m_backend->logMessage("AudioOutput using oss audio sink");
+ else if (sink) {
+ gst_object_unref(sink);
+ sink = 0;
+ }
+ }
+ } else if (m_audioSink == "fake") {
+ //do nothing as a fakesink will be created by default
+ } else if (m_audioSink == "artssink") {
+ sink = GST_ELEMENT(g_object_new(arts_sink_get_type(), NULL));
+ } else if (!m_audioSink.isEmpty()) { //Use a custom sink
+ sink = gst_element_factory_make (m_audioSink, NULL);
+ if (canOpenDevice(sink))
+ m_backend->logMessage(QString("AudioOutput using %0").arg(QString::fromUtf8(m_audioSink)));
+ else if (sink) {
+ gst_object_unref(sink);
+ sink = 0;
+ }
+ }
+ }
+
+ if (!sink) { //no suitable sink found so we'll make a fake one
+ sink = gst_element_factory_make("fakesink", NULL);
+ if (sink) {
+ m_backend->logMessage("AudioOutput Using fake audio sink");
+ //without sync the sink will pull the pipeline as fast as the CPU allows
+ g_object_set (G_OBJECT (sink), "sync", TRUE, (const char*)NULL);
+ }
+ }
+ Q_ASSERT(sink);
+ return sink;
+}
+
+AbstractRenderer *DeviceManager::createVideoRenderer(VideoWidget *parent)
+{
+#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES)
+ if (m_videoSinkWidget == "opengl") {
+ return new GLRenderer(parent);
+ } else
+#endif
+ if (m_videoSinkWidget == "software") {
+ return new WidgetRenderer(parent);
+ }
+#ifndef Q_WS_QWS
+ else if (m_videoSinkWidget == "xwindow") {
+ return new X11Renderer(parent);
+ } else {
+ GstElementFactory *srcfactory = gst_element_factory_find("ximagesink");
+ if (srcfactory) {
+ return new X11Renderer(parent);
+ }
+ }
+#endif
+ return new WidgetRenderer(parent);
+}
+
+/*
+ * Returns a positive device id or -1 if device
+ * does not exist
+ *
+ * The gstId is typically in the format hw:1,0
+ */
+int DeviceManager::deviceId(const QByteArray &gstId) const
+{
+ for (int i = 0 ; i < m_audioDeviceList.size() ; ++i) {
+ if (m_audioDeviceList[i].gstId == gstId) {
+ return m_audioDeviceList[i].id;
+ }
+ }
+ return -1;
+}
+
+/**
+ * Get a human-readable description from a device id
+ */
+QByteArray DeviceManager::deviceDescription(int id) const
+{
+ for (int i = 0 ; i < m_audioDeviceList.size() ; ++i) {
+ if (m_audioDeviceList[i].id == id) {
+ return m_audioDeviceList[i].description;
+ }
+ }
+ return QByteArray();
+}
+
+/**
+ * Updates the current list of active devices
+ */
+void DeviceManager::updateDeviceList()
+{
+ //fetch list of current devices
+ GstElement *audioSink= createAudioSink();
+
+ QList<QByteArray> list;
+
+ if (audioSink) {
+ list = GstHelper::extractProperties(audioSink, "device");
+ list.prepend("default");
+
+ for (int i = 0 ; i < list.size() ; ++i) {
+ QByteArray gstId = list.at(i);
+ if (deviceId(gstId) == -1) {
+ // This is a new device, add it
+ m_audioDeviceList.append(AudioDevice(this, gstId));
+ emit deviceAdded(deviceId(gstId));
+ m_backend->logMessage(QString("Found new audio device %0").arg(QString::fromUtf8(gstId)), Backend::Debug, this);
+ }
+ }
+
+ if (list.size() < m_audioDeviceList.size()) {
+ //a device was removed
+ for (int i = m_audioDeviceList.size() -1 ; i >= 0 ; --i) {
+ QByteArray currId = m_audioDeviceList[i].gstId;
+ bool found = false;
+ for (int k = list.size() -1 ; k >= 0 ; --k) {
+ if (currId == list[k]) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ m_backend->logMessage(QString("Audio device lost %0").arg(QString::fromUtf8(currId)), Backend::Debug, this);
+ emit deviceRemoved(deviceId(currId));
+ m_audioDeviceList.removeAt(i);
+ }
+ }
+ }
+ }
+
+ gst_element_set_state (audioSink, GST_STATE_NULL);
+ gst_object_unref (audioSink);
+}
+
+/**
+ * Returns a list of hardware id usable by gstreamer [i.e hw:1,0]
+ */
+const QList<AudioDevice> DeviceManager::audioOutputDevices() const
+{
+ return m_audioDeviceList;
+}
+
+}
+}
+
+QT_END_NAMESPACE
diff --git a/src/3rdparty/phonon/gstreamer/devicemanager.h b/src/3rdparty/phonon/gstreamer/devicemanager.h
new file mode 100644
index 0000000000..a5e8289969
--- /dev/null
+++ b/src/3rdparty/phonon/gstreamer/devicemanager.h
@@ -0,0 +1,80 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef Phonon_GSTREAMER_DEVICEMANAGER_H
+#define Phonon_GSTREAMER_DEVICEMANAGER_H
+
+#include "common.h"
+
+#include <phonon/audiooutputinterface.h>
+
+#include <QtCore/QObject>
+#include <QtCore/QTimer>
+
+#include <gst/gst.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon {
+namespace Gstreamer {
+class Backend;
+class DeviceManager;
+class AbstractRenderer;
+class VideoWidget;
+
+class AudioDevice {
+public :
+ AudioDevice(DeviceManager *s, const QByteArray &deviceId);
+ int id;
+ QByteArray gstId;
+ QByteArray description;
+};
+
+class DeviceManager : public QObject {
+ Q_OBJECT
+public:
+ DeviceManager(Backend *parent);
+ virtual ~DeviceManager();
+ const QList<AudioDevice> audioOutputDevices() const;
+ GstPad *requestPad(int device) const;
+ int deviceId(const QByteArray &gstId) const;
+ QByteArray deviceDescription(int id) const;
+ GstElement *createGNOMEAudioSink(Category category);
+ GstElement *createAudioSink(Category category = NoCategory);
+ AbstractRenderer *createVideoRenderer(VideoWidget *parent);
+
+signals:
+ void deviceAdded(int);
+ void deviceRemoved(int);
+
+public slots:
+ void updateDeviceList();
+
+private:
+ bool canOpenDevice(GstElement *element) const;
+ Backend *m_backend;
+ QList <AudioDevice> m_audioDeviceList;
+ QTimer m_devicePollTimer;
+ QByteArray m_audioSink;
+ QByteArray m_videoSinkWidget;
+};
+}
+} // namespace Phonon::Gstreamer
+
+QT_END_NAMESPACE
+
+#endif // Phonon_GSTREAMER_DEVICEMANAGER_H
diff --git a/src/3rdparty/phonon/gstreamer/effect.cpp b/src/3rdparty/phonon/gstreamer/effect.cpp
new file mode 100644
index 0000000000..f653535963
--- /dev/null
+++ b/src/3rdparty/phonon/gstreamer/effect.cpp
@@ -0,0 +1,246 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "effect.h"
+#include "common.h"
+#include "audiooutput.h"
+#include "backend.h"
+#include "medianode.h"
+#include "effectmanager.h"
+#include "gsthelper.h"
+
+#include <gst/gst.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace Gstreamer
+{
+Effect::Effect(Backend *backend, QObject *parent, NodeDescription description)
+ : QObject(parent),
+ MediaNode(backend, description)
+ , m_effectBin(0)
+ , m_effectElement(0)
+{
+}
+
+void Effect::init()
+{
+ m_effectBin = createEffectBin();
+ if (m_effectBin) {
+ setupEffectParams();
+ gst_object_ref (GST_OBJECT (m_effectBin)); // Take ownership
+ gst_object_sink (GST_OBJECT (m_effectBin));
+ m_isValid = true;
+ }
+}
+
+Effect::~Effect()
+{
+ if (m_effectBin) {
+ gst_element_set_state (m_effectBin, GST_STATE_NULL);
+ gst_object_unref (m_effectBin);
+ }
+}
+
+void Effect::setupEffectParams()
+{
+
+ Q_ASSERT(m_effectElement);
+
+ //query and store parameters
+ if (m_effectElement) {
+ GParamSpec **property_specs;
+ guint propertyCount, i;
+ property_specs = g_object_class_list_properties(G_OBJECT_GET_CLASS (m_effectElement), &propertyCount);
+ for (i = 0; i < propertyCount; i++) {
+ GParamSpec *param = property_specs[i];
+ if (param->flags & G_PARAM_WRITABLE) {
+ QString propertyName = g_param_spec_get_name (param);
+
+ // These properties should not be exposed to the front-end
+ if (propertyName == "qos" || propertyName == "name" || propertyName == "async-handling")
+ continue;
+
+ switch(param->value_type) {
+ case G_TYPE_UINT:
+ m_parameterList.append(Phonon::EffectParameter(i, propertyName,
+ 0, //hints
+ G_PARAM_SPEC_UINT(param)->default_value,
+ G_PARAM_SPEC_UINT(param)->minimum,
+ G_PARAM_SPEC_UINT(param)->maximum));
+ break;
+
+ case G_TYPE_STRING:
+ m_parameterList.append(Phonon::EffectParameter(i, propertyName,
+ 0, //hints
+ G_PARAM_SPEC_STRING(param)->default_value,
+ 0,
+ 0));
+ break;
+
+ case G_TYPE_INT:
+ m_parameterList.append(Phonon::EffectParameter(i, propertyName,
+ EffectParameter::IntegerHint, //hints
+ QVariant(G_PARAM_SPEC_INT(param)->default_value),
+ QVariant(G_PARAM_SPEC_INT(param)->minimum),
+ QVariant(G_PARAM_SPEC_INT(param)->maximum)));
+ break;
+
+ case G_TYPE_FLOAT:
+ m_parameterList.append(Phonon::EffectParameter(i, propertyName,
+ 0, //hints
+ QVariant((double)G_PARAM_SPEC_FLOAT(param)->default_value),
+ QVariant((double)G_PARAM_SPEC_FLOAT(param)->minimum),
+ QVariant((double)G_PARAM_SPEC_FLOAT(param)->maximum)));
+ break;
+
+ case G_TYPE_DOUBLE:
+ m_parameterList.append(Phonon::EffectParameter(i, propertyName,
+ 0, //hints
+ QVariant(G_PARAM_SPEC_DOUBLE(param)->default_value),
+ QVariant(G_PARAM_SPEC_DOUBLE(param)->minimum),
+ QVariant(G_PARAM_SPEC_DOUBLE(param)->maximum)));
+ break;
+
+ case G_TYPE_BOOLEAN:
+ m_parameterList.append(Phonon::EffectParameter(i, propertyName,
+ Phonon::EffectParameter::ToggledHint, //hints
+ QVariant((bool)G_PARAM_SPEC_BOOLEAN(param)->default_value),
+ QVariant((bool)false), QVariant((bool)true)));
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ }
+}
+
+QList<Phonon::EffectParameter> Effect::parameters() const
+{
+ return m_parameterList;
+}
+
+QVariant Effect::parameterValue(const EffectParameter &p) const
+{
+
+ Q_ASSERT(m_effectElement);
+
+ QVariant returnVal;
+ switch (p.type()) {
+ case QVariant::Int:
+ {
+ gint val = 0;
+ g_object_get(G_OBJECT(m_effectElement), qPrintable(p.name()), &val, (const char*)NULL);
+ returnVal = val;
+ }
+ break;
+
+ case QVariant::Bool:
+ {
+ gboolean val = 0;
+ g_object_get(G_OBJECT(m_effectElement), qPrintable(p.name()), &val, (const char*)NULL);
+ returnVal = val;
+ }
+ break;
+
+ case QVariant::String:
+ {
+ gchar *val = 0;
+ g_object_get(G_OBJECT(m_effectElement), qPrintable(p.name()), &val, (const char*)NULL);
+ returnVal = QString::fromUtf8(val);
+ g_free(val);
+ }
+ break;
+
+ case QVariant::Double:
+ {
+ GParamSpec* spec = g_object_class_find_property(G_OBJECT_GET_CLASS(m_effectElement), p.name().toLatin1().constData());
+ Q_ASSERT(spec);
+ if (spec && spec->value_type == G_TYPE_FLOAT) {
+ gfloat val = 0;
+ g_object_get(G_OBJECT(m_effectElement), qPrintable(p.name()), &val, (const char*)NULL);
+ returnVal = QVariant((float)val);
+ } else {
+ gdouble val = 0;
+ g_object_get(G_OBJECT(m_effectElement), qPrintable(p.name()), &val, (const char*)NULL);
+ returnVal = QVariant((float)val);
+ }
+ }
+ break;
+
+ default:
+ Q_ASSERT(0); //not a supported variant type
+ }
+ return returnVal;
+}
+
+
+void Effect::setParameterValue(const EffectParameter &p, const QVariant &v)
+{
+ Q_ASSERT(m_effectElement);
+
+ // Note that the frontend currently calls this after creation with a null-value
+ // for all parameters.
+
+ if (v.isValid()) {
+
+ switch (p.type()) {
+ // ### range values should really be checked by the front end, why isnt it working?
+ case QVariant::Int:
+ if (v.toInt() >= p.minimumValue().toInt() && v.toInt() <= p.maximumValue().toInt())
+ g_object_set(G_OBJECT(m_effectElement), qPrintable(p.name()), (gint)v.toInt(), (const char*)NULL);
+ break;
+
+ case QVariant::Double:
+ if (v.toDouble() >= p.minimumValue().toDouble() && v.toDouble() <= p.maximumValue().toDouble()) {
+ GParamSpec* spec = g_object_class_find_property(G_OBJECT_GET_CLASS(m_effectElement), p.name().toLatin1().constData());
+ Q_ASSERT(spec);
+ if (spec && spec->value_type == G_TYPE_FLOAT)
+ g_object_set(G_OBJECT(m_effectElement), qPrintable(p.name()), (gfloat)v.toDouble(), (const char*)NULL);
+ else
+ g_object_set(G_OBJECT(m_effectElement), qPrintable(p.name()), (gdouble)v.toDouble(), (const char*)NULL);
+ }
+ break;
+
+ case QVariant::UInt:
+ if (v.toUInt() >= p.minimumValue().toUInt() && v.toUInt() <= p.maximumValue().toUInt())
+ g_object_set(G_OBJECT(m_effectElement), qPrintable(p.name()), v.toUInt(), (const char*)NULL);
+ break;
+
+ case QVariant::String:
+ g_object_set(G_OBJECT(m_effectElement), qPrintable(p.name()), v.toString().toUtf8().constData(), (const char*)NULL);
+ break;
+
+ case QVariant::Bool:
+ g_object_set(G_OBJECT(m_effectElement), qPrintable(p.name()), (gboolean)v.toBool(), (const char*)NULL);
+ break;
+
+ default:
+ Q_ASSERT(0); //not a supported variant type
+ }
+ }
+}
+
+}
+} //namespace Phonon::Gstreamer
+
+QT_END_NAMESPACE
+#include "moc_effect.cpp"
diff --git a/src/3rdparty/phonon/gstreamer/effect.h b/src/3rdparty/phonon/gstreamer/effect.h
new file mode 100644
index 0000000000..dbbb45748c
--- /dev/null
+++ b/src/3rdparty/phonon/gstreamer/effect.h
@@ -0,0 +1,64 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef Phonon_GSTREAMER_EFFECT_H
+#define Phonon_GSTREAMER_EFFECT_H
+
+#include "common.h"
+#include "medianode.h"
+
+#include <phonon/effectparameter.h>
+#include <phonon/effectinterface.h>
+
+#include <QtCore/QObject>
+
+#include <gst/gst.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace Gstreamer
+{
+ class EffectInfo;
+
+ class Effect : public QObject, public Phonon::EffectInterface, public MediaNode
+ {
+ Q_OBJECT
+ Q_INTERFACES(Phonon::EffectInterface Phonon::Gstreamer::MediaNode)
+ public:
+ Effect (Backend *backend, QObject *parent, NodeDescription description);
+ virtual ~Effect ();
+
+ virtual QList<EffectParameter> parameters() const;
+ virtual QVariant parameterValue(const EffectParameter &) const;
+ virtual void setParameterValue(const EffectParameter &, const QVariant &);
+
+ virtual GstElement* createEffectBin() = 0;
+ virtual void init();
+ virtual void setupEffectParams();
+
+ protected:
+ GstElement *m_effectBin;
+ GstElement *m_effectElement;
+ QList<Phonon::EffectParameter> m_parameterList;
+ };
+}} //namespace Phonon::Gstreamer
+
+QT_END_NAMESPACE
+
+#endif // Phonon_GSTREAMER_EFFECT_H
diff --git a/src/3rdparty/phonon/gstreamer/effectmanager.cpp b/src/3rdparty/phonon/gstreamer/effectmanager.cpp
new file mode 100644
index 0000000000..563e6fc47d
--- /dev/null
+++ b/src/3rdparty/phonon/gstreamer/effectmanager.cpp
@@ -0,0 +1,105 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <gst/interfaces/propertyprobe.h>
+#include "effectmanager.h"
+#include "backend.h"
+#include "gsthelper.h"
+
+/*
+ * This class manages the list of currently
+ * available audio effects.
+ */
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace Gstreamer
+{
+
+EffectInfo::EffectInfo(const QString &name, const QString&description, const QString&author)
+ : m_name(name)
+ , m_description(description)
+ , m_author(author) {}
+
+EffectManager::EffectManager(Backend *backend)
+ : QObject(backend)
+ , m_backend(backend)
+{
+ GList* factoryList = gst_registry_get_feature_list(gst_registry_get_default (), GST_TYPE_ELEMENT_FACTORY);
+ QString name, klass, description, author;
+ for (GList* iter = g_list_first(factoryList) ; iter != NULL ; iter = g_list_next(iter)) {
+ GstPluginFeature *feature = GST_PLUGIN_FEATURE(iter->data);
+ klass = gst_element_factory_get_klass(GST_ELEMENT_FACTORY(feature));
+ if ( klass == "Filter/Effect/Audio" ) {
+ name = GST_PLUGIN_FEATURE_NAME(feature);
+
+ // These plugins simply make no sense to the frontend:
+ // "audiorate" Should be internal
+ // "volume" not needed
+ // "equalizer-nbands" not really useful at the moment
+
+ // These plugins simply dont work or have major stability issues:
+ // "iir" Does not seem to do much at the moment
+ // "audioinvert" Only works for some streams, should be invesigated
+ // "lpwsinc" Crashes for large values of filter kernel
+ // "name" Crashes for large values of filter kernel
+
+ // Seems to be working, but not well tested:
+ // name == "rglimiter" Seems functional
+ // name == "rgvolume" Seems to be working
+
+ QString pluginString = qgetenv("PHONON_GST_ALL_EFFECTS");
+ bool acceptAll = pluginString.toInt();
+
+ if (acceptAll
+ // Plugins that have been accepted so far
+ || name == "audiopanorama"
+ || name == "audioamplify"
+ || name == "audiodynamic"
+ || name == "equalizer-10bands"
+ || name == "speed")
+ {
+ description = gst_element_factory_get_description (GST_ELEMENT_FACTORY(feature));
+ author = gst_element_factory_get_author (GST_ELEMENT_FACTORY(feature));
+ EffectInfo *effect = new EffectInfo(name, description, author);
+ m_audioEffectList.append(effect);
+ }
+ }
+ }
+ g_list_free(factoryList);
+}
+
+EffectManager::~EffectManager()
+{
+ qDeleteAll(m_audioEffectList);
+ m_audioEffectList.clear();
+}
+
+/**
+ * Returns a list of available audio effects
+ */
+const QList<EffectInfo*> EffectManager::audioEffects() const
+{
+ return m_audioEffectList;
+}
+
+}
+}
+
+QT_END_NAMESPACE
diff --git a/src/3rdparty/phonon/gstreamer/effectmanager.h b/src/3rdparty/phonon/gstreamer/effectmanager.h
new file mode 100644
index 0000000000..f7d9c9666e
--- /dev/null
+++ b/src/3rdparty/phonon/gstreamer/effectmanager.h
@@ -0,0 +1,91 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef Phonon_GSTREAMER_EFFECTMANAGER_H
+#define Phonon_GSTREAMER_EFFECTMANAGER_H
+
+#include "common.h"
+
+#include <QtCore/QObject>
+#include <QtCore/QTimer>
+#include <QtCore/QStringList>
+
+#include <gst/gst.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace Gstreamer
+{
+class Backend;
+class EffectManager;
+
+class EffectInfo
+{
+public :
+ EffectInfo(const QString &name,
+ const QString &description,
+ const QString &author);
+
+ QString name() const
+ {
+ return m_name;
+ }
+ QString description() const
+ {
+ return m_description;
+ }
+ QString author() const
+ {
+ return m_author;
+ }
+ QStringList properties() const
+ {
+ return m_properties;
+ }
+ void addProperty(QString propertyName)
+ {
+ m_properties.append(propertyName);
+ }
+
+private:
+ QString m_name;
+ QString m_description;
+ QString m_author;
+ QStringList m_properties;
+};
+
+class EffectManager : public QObject
+{
+ Q_OBJECT
+public:
+ EffectManager(Backend *parent);
+ virtual ~EffectManager();
+ const QList<EffectInfo*> audioEffects() const;
+
+private:
+ Backend *m_backend;
+ QList <EffectInfo*> m_audioEffectList;
+ QList <EffectInfo*> m_visualizationList;
+};
+}
+} // namespace Phonon::Gstreamer
+
+QT_END_NAMESPACE
+
+#endif // Phonon_GSTREAMER_EFFECTMANAGER_H
diff --git a/src/3rdparty/phonon/gstreamer/glrenderer.cpp b/src/3rdparty/phonon/gstreamer/glrenderer.cpp
new file mode 100644
index 0000000000..6cf345942f
--- /dev/null
+++ b/src/3rdparty/phonon/gstreamer/glrenderer.cpp
@@ -0,0 +1,339 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <QtGui/QPainter>
+#include <QtGui/QResizeEvent>
+
+#ifndef QT_NO_OPENGL
+
+#include "common.h"
+#include "message.h"
+#include "mediaobject.h"
+#include "qwidgetvideosink.h"
+#include "glrenderer.h"
+#include "qrgb.h"
+
+#if !defined(QT_OPENGL_ES)
+
+#include <gst/gst.h>
+
+// support old OpenGL installations (1.2)
+// assume that if TEXTURE0 isn't defined, none are
+#ifndef GL_TEXTURE0
+# define GL_TEXTURE0 0x84C0
+# define GL_TEXTURE1 0x84C1
+# define GL_TEXTURE2 0x84C2
+#endif
+
+QT_BEGIN_NAMESPACE
+
+static void frameRendered()
+{
+ static QString displayFps = qgetenv("PHONON_GST_FPS");
+ if (displayFps.isEmpty())
+ return;
+
+ static int frames = 0;
+ static QTime lastTime = QTime::currentTime();
+ QTime time = QTime::currentTime();
+
+ int delta = lastTime.msecsTo(time);
+ if (delta > 2000) {
+ printf("FPS: %f\n", 1000.0 * frames / qreal(delta));
+ lastTime = time;
+ frames = 0;
+ }
+
+ ++frames;
+}
+
+namespace Phonon
+{
+namespace Gstreamer
+{
+
+GLRenderer::GLRenderer(VideoWidget* videoWidget) :
+ AbstractRenderer(videoWidget)
+ , m_glWindow(0)
+{
+ videoWidget->backend()->logMessage("Creating OpenGL renderer");
+ QGLFormat format = QGLFormat::defaultFormat();
+ format.setSwapInterval(1); // Enable vertical sync on draw to avoid tearing
+ m_glWindow = new GLRenderWidgetImplementation(videoWidget, format);
+
+ if ((m_videoSink = m_glWindow->createVideoSink())) { //if ((m_videoSink = m_glWindow->createVideoSink())) {
+ gst_object_ref (GST_OBJECT (m_videoSink)); //Take ownership
+ gst_object_sink (GST_OBJECT (m_videoSink));
+
+ QWidgetVideoSinkBase* sink = reinterpret_cast<QWidgetVideoSinkBase*>(m_videoSink);
+ // Let the videosink know which widget to direct frame updates to
+ sink->renderWidget = videoWidget;
+ }
+}
+
+GLRenderer::~GLRenderer()
+{
+ if (m_videoSink) {
+ gst_object_unref (GST_OBJECT (m_videoSink));
+ m_videoSink = 0;
+ }
+}
+
+
+bool GLRenderer::eventFilter(QEvent * event)
+{
+ if (event->type() == QEvent::User) {
+ NewFrameEvent *frameEvent= static_cast <NewFrameEvent *>(event);
+ m_glWindow->setNextFrame(frameEvent->frame, frameEvent->width, frameEvent->height);
+ return true;
+ }
+ else if (event->type() == QEvent::Resize) {
+ m_glWindow->setGeometry(m_videoWidget->geometry());
+ return true;
+ }
+ return false;
+}
+
+void GLRenderer::handleMediaNodeEvent(const MediaNodeEvent *event)
+{
+ switch (event->type()) {
+ case MediaNodeEvent::SourceChanged:
+ {
+ Q_ASSERT(m_glWindow);
+ m_glWindow->clearFrame();
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+GstElement* GLRenderWidgetImplementation::createVideoSink()
+{
+ if (hasYUVSupport())
+ return GST_ELEMENT(g_object_new(get_type_YUV(), NULL));
+ return 0;
+}
+
+void GLRenderWidgetImplementation::setNextFrame(const QByteArray &array, int w, int h)
+{
+ if (m_videoWidget->root()->state() == Phonon::LoadingState)
+ return;
+
+ m_frame = QImage();
+
+ if (hasYUVSupport())
+ updateTexture(array, w, h);
+ else
+ m_frame = QImage((uchar *)array.constData(), w, h, QImage::Format_RGB32);
+
+ m_array = array;
+ m_width = w;
+ m_height = h;
+
+ update();
+}
+
+void GLRenderWidgetImplementation::clearFrame()
+{
+ m_frame = QImage();
+ m_array = QByteArray();
+ update();
+}
+
+bool GLRenderWidgetImplementation::hasYUVSupport() const
+{
+ return m_yuvSupport;
+}
+
+static QImage convertFromYUV(const QByteArray &array, int w, int h)
+{
+ QImage result(w, h, QImage::Format_RGB32);
+
+ // TODO: bilinearly interpolate the U and V channels for better result
+
+ for (int y = 0; y < h; ++y) {
+ uint *sp = (uint *)result.scanLine(y);
+
+ const uchar *yp = (const uchar *)(array.constData() + y * w);
+ const uchar *up = (const uchar *)(array.constData() + w * h + (y/2)*(w/2));
+ const uchar *vp = (const uchar *)(array.constData() + w * h * 5/4 + (y/2)*(w/2));
+
+ for (int x = 0; x < w; ++x) {
+ const int sy = *yp;
+ const int su = *up;
+ const int sv = *vp;
+
+ const int R = int(1.164 * (sy - 16) + 1.596 * (sv - 128));
+ const int G = int(1.164 * (sy - 16) - 0.813 * (sv - 128) - 0.391 * (su - 128));
+ const int B = int(1.164 * (sy - 16) + 2.018 * (su - 128));
+
+ *sp = qRgb(qBound(0, R, 255),
+ qBound(0, G, 255),
+ qBound(0, B, 255));
+
+ ++yp;
+ ++sp;
+ if (x & 1) {
+ ++up;
+ ++vp;
+ }
+ }
+ }
+ return result;
+}
+
+const QImage &GLRenderWidgetImplementation::currentFrame() const
+{
+ if (m_frame.isNull() && !m_array.isNull())
+ m_frame = convertFromYUV(m_array, m_width, m_height);
+
+ return m_frame;
+}
+
+#ifndef GL_FRAGMENT_PROGRAM_ARB
+#define GL_FRAGMENT_PROGRAM_ARB 0x8804
+#define GL_PROGRAM_FORMAT_ASCII_ARB 0x8875
+#endif
+
+// arbfp1 fragment program for converting yuv to rgb
+const char *const yuvToRgb =
+ "!!ARBfp1.0"
+ "PARAM c[3] = { { 0.5, 0.0625 },"
+ "{ 1.164, 0, 1.596, 2.0179999 },"
+ "{ 1.164, -0.391, -0.81300002 } };"
+ "TEMP R0;"
+ "TEMP R1;"
+ "TEX R0.x, fragment.texcoord[0], texture[2], 2D;"
+ "ADD R1.z, R0.x, -c[0].x;"
+ "TEX R1.x, fragment.texcoord[0], texture[0], 2D;"
+ "TEX R0.x, fragment.texcoord[0], texture[1], 2D;"
+ "ADD R1.x, R1, -c[0].y;"
+ "ADD R1.y, R0.x, -c[0].x;"
+ "DP3 result.color.x, R1, c[1];"
+ "DP3 result.color.y, R1, c[2];"
+ "DP3 result.color.z, R1, c[1].xwyw;"
+ "END";
+
+GLRenderWidgetImplementation::GLRenderWidgetImplementation(VideoWidget*videoWidget, const QGLFormat &format) :
+ QGLWidget(format, videoWidget)
+ , m_program(0)
+ , m_yuvSupport(false)
+ , m_videoWidget(videoWidget)
+{
+ makeCurrent();
+ glGenTextures(3, m_texture);
+
+ glProgramStringARB = (_glProgramStringARB) context()->getProcAddress(QLatin1String("glProgramStringARB"));
+ glBindProgramARB = (_glBindProgramARB) context()->getProcAddress(QLatin1String("glBindProgramARB"));
+ glDeleteProgramsARB = (_glDeleteProgramsARB) context()->getProcAddress(QLatin1String("glDeleteProgramsARB"));
+ glGenProgramsARB = (_glGenProgramsARB) context()->getProcAddress(QLatin1String("glGenProgramsARB"));
+ glActiveTexture = (_glActiveTexture) context()->getProcAddress(QLatin1String("glActiveTexture"));
+
+ m_hasPrograms = glProgramStringARB && glBindProgramARB && glDeleteProgramsARB && glGenProgramsARB && glActiveTexture;
+
+ if (m_hasPrograms) {
+ glGenProgramsARB(1, &m_program);
+ glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, m_program);
+
+ const GLbyte *gl_src = reinterpret_cast<const GLbyte *>(yuvToRgb);
+ glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB,
+ int(strlen(yuvToRgb)), gl_src);
+
+ if (glGetError() != GL_NO_ERROR) {
+ glDeleteProgramsARB(1, &m_program);
+ m_hasPrograms = false;
+ } else {
+ m_yuvSupport = true;
+ }
+ }
+
+ QPalette palette;
+ palette.setColor(QPalette::Background, Qt::black);
+ setPalette(palette);
+ setAutoFillBackground(true);
+ // Videowidget allways have this property to allow hiding the mouse cursor
+ setMouseTracking(true);
+}
+
+void GLRenderWidgetImplementation::updateTexture(const QByteArray &array, int width, int height)
+{
+ m_width = width;
+ m_height = height;
+
+ makeCurrent();
+
+ int w[3] = { width, width/2, width/2 };
+ int h[3] = { height, height/2, height/2 };
+ int offs[3] = { 0, width*height, width*height*5/4 };
+
+ for (int i = 0; i < 3; ++i) {
+ glBindTexture(GL_TEXTURE_2D, m_texture[i]);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, w[i], h[i], 0,
+ GL_LUMINANCE, GL_UNSIGNED_BYTE, array.data() + offs[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);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
+ }
+}
+
+void GLRenderWidgetImplementation::paintEvent(QPaintEvent *)
+{
+ QPainter painter(this);
+ m_drawFrameRect = m_videoWidget->calculateDrawFrameRect();
+ if (m_yuvSupport && frameIsSet()) {
+ glEnable(GL_FRAGMENT_PROGRAM_ARB);
+ glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, m_program);
+ const float tx_array[] = { 0, 0, 1, 0, 1, 1, 0, 1};
+ const QRectF r = drawFrameRect();
+
+ const float v_array[] = { r.left(), r.top(), r.right(), r.top(), r.right(), r.bottom(), r.left(), r.bottom() };
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, m_texture[0]);
+ glActiveTexture(GL_TEXTURE1);
+ glBindTexture(GL_TEXTURE_2D, m_texture[1]);
+ glActiveTexture(GL_TEXTURE2);
+ glBindTexture(GL_TEXTURE_2D, m_texture[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_QUADS, 0, 4);
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glDisableClientState(GL_VERTEX_ARRAY);
+
+ glDisable(GL_FRAGMENT_PROGRAM_ARB);
+ } else {
+ painter.setRenderHint(QPainter::SmoothPixmapTransform);
+ painter.drawImage(drawFrameRect(), currentFrame());
+ }
+
+ frameRendered();
+}
+}
+} //namespace Phonon::Gstreamer
+
+QT_END_NAMESPACE
+
+#endif // QT_OPENGL_ES
+#endif // QT_NO_OPENGL
diff --git a/src/3rdparty/phonon/gstreamer/glrenderer.h b/src/3rdparty/phonon/gstreamer/glrenderer.h
new file mode 100644
index 0000000000..68dd14113e
--- /dev/null
+++ b/src/3rdparty/phonon/gstreamer/glrenderer.h
@@ -0,0 +1,101 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef Phonon_GSTREAMER_GLRENDERER_H
+#define Phonon_GSTREAMER_GLRENDERER_H
+
+#include "videowidget.h"
+#include "common.h"
+
+#ifndef QT_NO_OPENGL
+
+#include <QtOpenGL/QGLFormat>
+#include <QtOpenGL/QGLWidget>
+
+#ifndef QT_OPENGL_ES
+QT_BEGIN_NAMESPACE
+
+class QString;
+
+namespace Phonon
+{
+namespace Gstreamer
+{
+class GLRenderWidgetImplementation;
+
+class GLRenderer : public AbstractRenderer
+{
+public:
+ GLRenderer(VideoWidget *control);
+ ~GLRenderer();
+ void handleMediaNodeEvent(const MediaNodeEvent *event);
+ bool eventFilter(QEvent * event);
+ bool paintsOnWidget() { return false; }
+private:
+ GLRenderWidgetImplementation *m_glWindow;
+};
+
+class GLRenderWidgetImplementation : public QGLWidget
+{
+ Q_OBJECT
+
+ // ARB_fragment_program
+ typedef void (*_glProgramStringARB) (GLenum, GLenum, GLsizei, const GLvoid *);
+ typedef void (*_glBindProgramARB) (GLenum, GLuint);
+ typedef void (*_glDeleteProgramsARB) (GLsizei, const GLuint *);
+ typedef void (*_glGenProgramsARB) (GLsizei, GLuint *);
+ typedef void (*_glActiveTexture) (GLenum);
+public:
+ GLRenderWidgetImplementation(VideoWidget *control, const QGLFormat &format);
+ void paintEvent(QPaintEvent *event);
+ GstElement *createVideoSink();
+ void updateTexture(const QByteArray &array, int width, int height);
+ bool hasYUVSupport() const;
+ const QImage& currentFrame() const;
+ QRect drawFrameRect() const { return m_drawFrameRect; }
+ bool frameIsSet() const { return !m_array.isNull(); }
+ void setNextFrame(const QByteArray &array, int width, int height);
+ void clearFrame();
+private:
+ _glProgramStringARB glProgramStringARB;
+ _glBindProgramARB glBindProgramARB;
+ _glDeleteProgramsARB glDeleteProgramsARB;
+ _glGenProgramsARB glGenProgramsARB;
+ _glActiveTexture glActiveTexture;
+
+ mutable QImage m_frame;
+ QByteArray m_array;
+ int m_width;
+ int m_height;
+ QRect m_drawFrameRect;
+ GLuint m_texture[3];
+
+ bool m_hasPrograms;
+ GLuint m_program;
+ bool m_yuvSupport;
+ VideoWidget *m_videoWidget;
+};
+
+}
+} //namespace Phonon::Gstreamer
+
+QT_END_NAMESPACE
+
+#endif //QT_OPENGL_ES
+#endif // QT_NO_OPENGL
+
+#endif // Phonon_GSTREAMER_GLRENDERER_H
diff --git a/src/3rdparty/phonon/gstreamer/gsthelper.cpp b/src/3rdparty/phonon/gstreamer/gsthelper.cpp
new file mode 100644
index 0000000000..34d99facfb
--- /dev/null
+++ b/src/3rdparty/phonon/gstreamer/gsthelper.cpp
@@ -0,0 +1,170 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <gst/interfaces/propertyprobe.h>
+#include <gst/gst.h>
+#include "common.h"
+#include "gsthelper.h"
+
+#include <QtCore/QList>
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace Gstreamer
+{
+
+/**
+ * Probes a gstElement for a list of settable string-property values
+ *
+ * @return a QStringList containing a list of allwed string values for the given
+ * element
+ */
+QList<QByteArray> GstHelper::extractProperties(GstElement *elem, const QByteArray &value)
+{
+ Q_ASSERT(elem);
+ QList<QByteArray> list;
+
+ if (GST_IS_PROPERTY_PROBE(elem)) {
+ GstPropertyProbe *probe = GST_PROPERTY_PROBE(elem);
+ const GParamSpec *devspec = 0;
+ GValueArray *array = NULL;
+
+ if ((devspec = gst_property_probe_get_property (probe, value))) {
+ if ((array = gst_property_probe_probe_and_get_values (probe, devspec))) {
+ for (unsigned int device = 0; device < array->n_values; device++) {
+ GValue *deviceId = g_value_array_get_nth (array, device);
+ list.append(g_value_get_string(deviceId));
+ }
+ }
+ if (array)
+ g_value_array_free (array);
+ }
+ }
+ return list;
+}
+
+/**
+ * Sets the string value of a GstElement's property
+ *
+ * @return false if the value could not be set.
+ */
+bool GstHelper::setProperty(GstElement *elem, const char *propertyName, const QByteArray &propertyValue)
+{
+ Q_ASSERT(elem);
+ Q_ASSERT(propertyName && strlen(propertyName));
+
+ if (GST_IS_PROPERTY_PROBE(elem) && gst_property_probe_get_property( GST_PROPERTY_PROBE( elem), propertyName ) ) {
+ g_object_set(G_OBJECT(elem), propertyName, propertyValue.constData(), (const char*)NULL);
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Queries an element for the value of an object property
+ */
+QByteArray GstHelper::property(GstElement *elem, const char *propertyName)
+{
+ Q_ASSERT(elem);
+ Q_ASSERT(propertyName && strlen(propertyName));
+ QByteArray retVal;
+
+ if (GST_IS_PROPERTY_PROBE(elem) && gst_property_probe_get_property( GST_PROPERTY_PROBE(elem), propertyName)) {
+ gchar *value = NULL;
+ g_object_get (G_OBJECT(elem), propertyName, &value, (const char*)NULL);
+ retVal = QByteArray(value);
+ g_free (value);
+ }
+ return retVal;
+}
+
+/**
+ * Queries a GstObject for it's name
+ */
+QByteArray GstHelper::name(GstObject *obj)
+{
+ Q_ASSERT(obj);
+ QByteArray retVal;
+ gchar *value = NULL;
+ if ((value = gst_object_get_name (obj))) {
+ retVal = QByteArray(value);
+ g_free (value);
+ }
+ return retVal;
+}
+
+
+/***
+ * Creates an instance of a playbin with "audio-src" and
+ * "video-src" ghost pads to allow redirected output streams.
+ *
+ * ### This function is probably not required now that MediaObject is based
+ * on decodebin directly.
+ */
+GstElement* GstHelper::createPluggablePlaybin()
+{
+ GstElement *playbin = 0;
+ //init playbin and add to our pipeline
+ playbin = gst_element_factory_make("playbin", NULL);
+
+ //Create an identity element to redirect sound
+ GstElement *audioSinkBin = gst_bin_new (NULL);
+ GstElement *audioPipe = gst_element_factory_make("identity", NULL);
+ gst_bin_add(GST_BIN(audioSinkBin), audioPipe);
+
+ //Create a sinkpad on the identity
+ GstPad *audiopad = gst_element_get_pad (audioPipe, "sink");
+ gst_element_add_pad (audioSinkBin, gst_ghost_pad_new ("sink", audiopad));
+ gst_object_unref (audiopad);
+
+ //Create an "audio_src" source pad on the playbin
+ GstPad *audioPlaypad = gst_element_get_pad (audioPipe, "src");
+ gst_element_add_pad (playbin, gst_ghost_pad_new ("audio_src", audioPlaypad));
+ gst_object_unref (audioPlaypad);
+
+ //Done with our audio redirection
+ g_object_set (G_OBJECT(playbin), "audio-sink", audioSinkBin, (const char*)NULL);
+
+ // * * Redirect video to "video_src" pad : * *
+
+ //Create an identity element to redirect sound
+ GstElement *videoSinkBin = gst_bin_new (NULL);
+ GstElement *videoPipe = gst_element_factory_make("identity", NULL);
+ gst_bin_add(GST_BIN(videoSinkBin), videoPipe);
+
+ //Create a sinkpad on the identity
+ GstPad *videopad = gst_element_get_pad (videoPipe, "sink");
+ gst_element_add_pad (videoSinkBin, gst_ghost_pad_new ("sink", videopad));
+ gst_object_unref (videopad);
+
+ //Create an "audio_src" source pad on the playbin
+ GstPad *videoPlaypad = gst_element_get_pad (videoPipe, "src");
+ gst_element_add_pad (playbin, gst_ghost_pad_new ("video_src", videoPlaypad));
+ gst_object_unref (videoPlaypad);
+
+ //Done with our video redirection
+ g_object_set (G_OBJECT(playbin), "video-sink", videoSinkBin, (const char*)NULL);
+ return playbin;
+}
+
+
+} //namespace Gstreamer
+} //namespace Phonon
+
+QT_END_NAMESPACE
diff --git a/src/3rdparty/phonon/gstreamer/gsthelper.h b/src/3rdparty/phonon/gstreamer/gsthelper.h
new file mode 100644
index 0000000000..ff342a4d62
--- /dev/null
+++ b/src/3rdparty/phonon/gstreamer/gsthelper.h
@@ -0,0 +1,49 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef Phonon_GSTREAMER_GSTHELPER_H
+#define Phonon_GSTREAMER_GSTHELPER_H
+
+#include "common.h"
+
+#include <gst/gst.h>
+
+QT_BEGIN_NAMESPACE
+
+template<class T> class QList;
+class QByteArray;
+
+namespace Phonon
+{
+namespace Gstreamer
+{
+class GstHelper
+{
+public:
+ static QList<QByteArray> extractProperties(GstElement *elem, const QByteArray &value);
+ static bool setProperty(GstElement *elem, const char *propertyName, const QByteArray &propertyValue);
+ static QByteArray property(GstElement *elem, const char *propertyName);
+ static QByteArray name(GstObject *elem);
+ static GstElement* createPluggablePlaybin();
+};
+
+} // ns Gstreamer
+} // ns Phonon
+
+QT_END_NAMESPACE
+
+#endif // Phonon_GSTREAMER_GSTHELPER_H
diff --git a/src/3rdparty/phonon/gstreamer/gstreamer.desktop b/src/3rdparty/phonon/gstreamer/gstreamer.desktop
new file mode 100644
index 0000000000..b62472bab9
--- /dev/null
+++ b/src/3rdparty/phonon/gstreamer/gstreamer.desktop
@@ -0,0 +1,51 @@
+[Desktop Entry]
+Type=Service
+X-KDE-ServiceTypes=PhononBackend
+MimeType=application/x-annodex;video/quicktime;video/x-quicktime;audio/x-m4a;application/x-quicktimeplayer;video/mkv;video/msvideo;video/x-msvideo;video/x-flic;audio/x-aiff;audio/aiff;audio/x-pn-aiff;audio/x-realaudio;audio/basic;audio/x-basic;audio/x-pn-au;audio/x-8svx;audio/8svx;audio/x-16sv;audio/168sv;image/x-ilbm;image/ilbm;video/x-anim;video/anim;image/png;image/x-png;video/mng;video/x-mng;audio/x-ogg;audio/x-speex+ogg;application/ogg;application/ogg;audio/vnd.rn-realaudio;audio/x-pn-realaudio-plugin;audio/x-real-audio;application/vnd.rn-realmedia;video/mpeg;video/x-mpeg;audio/x-wav;audio/wav;audio/x-pn-wav;audio/x-pn-windows-acm;audio/mpeg2;audio/x-mpeg2;audio/mpeg3;audio/x-mpeg3;audio/mpeg;audio/x-mpeg;x-mpegurl;audio/x-mpegurl;audio/mp3;audio/mpeg;
+X-KDE-Library=phonon_gstreamer
+X-KDE-PhononBackendInfo-InterfaceVersion=1
+X-KDE-PhononBackendInfo-Version=0.1
+X-KDE-PhononBackendInfo-Website=http://gstreamer.freedesktop.org/
+Icon=phonon-gstreamer
+InitialPreference=10
+
+Name=GStreamer
+Name[pa]=ਜੀਸਟੀਰਮਰ
+Name[sr]=Гстример
+Name[sv]=Gstreamer
+Name[x-test]=xxGStreamerxx
+
+Comment=Phonon GStreamer backend
+Comment[bg]=Phonon GStreamer
+Comment[ca]=Dorsal GStreamer del Phonon
+Comment[da]=GStreamer-backend til Phonon
+Comment[de]=Phonon-Treiber für GStreamer
+Comment[el]=Σύστημα υποστήριξης GStreamer του Phonon
+Comment[es]=Motor GStreamer para Phonon
+Comment[et]=Phononi GStreameri taustaprogramm
+Comment[fr]=Système de gestion GStreamer pour Phonon
+Comment[ga]=Inneall GStreamer le haghaidh Phonon
+Comment[gl]=Infraestrutura de GStreamer para Phonon
+Comment[is]=Phonon GStreamer bakendi
+Comment[it]=Motore Gstreamer di Phonon
+Comment[ja]=Phonon GStreamer バックエンド
+Comment[ko]=Phonon GStreamer 백엔드
+Comment[ku]=Binesaza Phonon GStreamer
+Comment[lv]=Phonon GStreamer aizmugure
+Comment[nds]=Phonon-Hülpprogramm GStreamer
+Comment[nl]=GStreamer-backend (Phonon)
+Comment[nn]=Phonon-motor for GStreamer
+Comment[pa]=ਫੋਨੋਨ ਜਸਟੀਰਮਰ ਬੈਕਐਂਡ
+Comment[pl]=Obsługa GStreamera przez Phonon
+Comment[pt]=Infra-estrutura do GStreamer para o Phonon
+Comment[pt_BR]=Infraestrutura Phonon GStreamer
+Comment[sk]=GStreamer podsystém
+Comment[sl]=Phononova hrbtenica GStreamer
+Comment[sr]=Гстример као позадина Фонона
+Comment[sr@latin]=GStreamer kao pozadina Phonona
+Comment[sv]=Phonon Gstreamer-gränssnitt
+Comment[tr]=Phonon GStreamer arka ucu
+Comment[uk]=Сервер GStreamer для Phonon
+Comment[x-test]=xxPhonon GStreamer backendxx
+Comment[zh_CN]=Phonon GStreamer 后端
+Comment[zh_TW]=Phonon GStreamer 後端介面
diff --git a/src/3rdparty/phonon/gstreamer/lgpl-2.1.txt b/src/3rdparty/phonon/gstreamer/lgpl-2.1.txt
new file mode 100644
index 0000000000..5ab7695ab8
--- /dev/null
+++ b/src/3rdparty/phonon/gstreamer/lgpl-2.1.txt
@@ -0,0 +1,504 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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 library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/src/3rdparty/phonon/gstreamer/lgpl-3.txt b/src/3rdparty/phonon/gstreamer/lgpl-3.txt
new file mode 100644
index 0000000000..fc8a5de7ed
--- /dev/null
+++ b/src/3rdparty/phonon/gstreamer/lgpl-3.txt
@@ -0,0 +1,165 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+ This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+ 0. Additional Definitions.
+
+ As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+ "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+ An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+ A "Combined Work" is a work produced by combining or linking an
+Application with the Library. The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+ The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+ The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+ 1. Exception to Section 3 of the GNU GPL.
+
+ You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+ 2. Conveying Modified Versions.
+
+ If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+ a) under this License, provided that you make a good faith effort to
+ ensure that, in the event an Application does not supply the
+ function or data, the facility still operates, and performs
+ whatever part of its purpose remains meaningful, or
+
+ b) under the GNU GPL, with none of the additional permissions of
+ this License applicable to that copy.
+
+ 3. Object Code Incorporating Material from Library Header Files.
+
+ The object code form of an Application may incorporate material from
+a header file that is part of the Library. You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+ a) Give prominent notice with each copy of the object code that the
+ Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the object code with a copy of the GNU GPL and this license
+ document.
+
+ 4. Combined Works.
+
+ You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+ a) Give prominent notice with each copy of the Combined Work that
+ the Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
+ document.
+
+ c) For a Combined Work that displays copyright notices during
+ execution, include the copyright notice for the Library among
+ these notices, as well as a reference directing the user to the
+ copies of the GNU GPL and this license document.
+
+ d) Do one of the following:
+
+ 0) Convey the Minimal Corresponding Source under the terms of this
+ License, and the Corresponding Application Code in a form
+ suitable for, and under terms that permit, the user to
+ recombine or relink the Application with a modified version of
+ the Linked Version to produce a modified Combined Work, in the
+ manner specified by section 6 of the GNU GPL for conveying
+ Corresponding Source.
+
+ 1) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (a) uses at run time
+ a copy of the Library already present on the user's computer
+ system, and (b) will operate properly with a modified version
+ of the Library that is interface-compatible with the Linked
+ Version.
+
+ e) Provide Installation Information, but only if you would otherwise
+ be required to provide such information under section 6 of the
+ GNU GPL, and only to the extent that such information is
+ necessary to install and execute a modified version of the
+ Combined Work produced by recombining or relinking the
+ Application with a modified version of the Linked Version. (If
+ you use option 4d0, the Installation Information must accompany
+ the Minimal Corresponding Source and Corresponding Application
+ Code. If you use option 4d1, you must provide the Installation
+ Information in the manner specified by section 6 of the GNU GPL
+ for conveying Corresponding Source.)
+
+ 5. Combined Libraries.
+
+ You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+ a) Accompany the combined library with a copy of the same work based
+ on the Library, uncombined with any other library facilities,
+ conveyed under the terms of this License.
+
+ b) Give prominent notice with the combined library that part of it
+ is a work based on the Library, and explaining where to find the
+ accompanying uncombined form of the same work.
+
+ 6. Revised Versions of the GNU Lesser General Public License.
+
+ The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+ If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
diff --git a/src/3rdparty/phonon/gstreamer/medianode.cpp b/src/3rdparty/phonon/gstreamer/medianode.cpp
new file mode 100644
index 0000000000..72579722f9
--- /dev/null
+++ b/src/3rdparty/phonon/gstreamer/medianode.cpp
@@ -0,0 +1,456 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "common.h"
+#include "medianode.h"
+#include "mediaobject.h"
+#include "message.h"
+#include "backend.h"
+#include "gsthelper.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace Gstreamer
+{
+
+MediaNode::MediaNode(Backend *backend, NodeDescription description) :
+ m_isValid(false),
+ m_root(0),
+ m_audioTee(0),
+ m_videoTee(0),
+ m_fakeAudioSink(0),
+ m_fakeVideoSink(0),
+ m_backend(backend),
+ m_description(description)
+{
+ if ((description & AudioSink) && (description & VideoSink)) {
+ Q_ASSERT(0); // A node cannot accept both audio and video
+ }
+
+ if (description & AudioSource) {
+ m_audioTee = gst_element_factory_make("tee", NULL);
+ gst_object_ref (GST_OBJECT (m_audioTee));
+ gst_object_sink (GST_OBJECT (m_audioTee));
+
+ // Fake audio sink to swallow unconnected audio pads
+ m_fakeAudioSink = gst_element_factory_make("fakesink", NULL);
+ g_object_set (G_OBJECT (m_fakeAudioSink), "sync", TRUE, (const char*)NULL);
+ gst_object_ref (GST_OBJECT (m_fakeAudioSink));
+ gst_object_sink (GST_OBJECT (m_fakeAudioSink));
+ }
+
+ if (description & VideoSource) {
+ m_videoTee = gst_element_factory_make("tee", NULL);
+ gst_object_ref (GST_OBJECT (m_videoTee));
+ gst_object_sink (GST_OBJECT (m_videoTee));
+
+ // Fake video sink to swallow unconnected video pads
+ m_fakeVideoSink = gst_element_factory_make("fakesink", NULL);
+ g_object_set (G_OBJECT (m_fakeVideoSink), "sync", TRUE, (const char*)NULL);
+ gst_object_ref (GST_OBJECT (m_fakeVideoSink));
+ gst_object_sink (GST_OBJECT (m_fakeVideoSink));
+ }
+}
+
+MediaNode::~MediaNode()
+{
+ if (m_videoTee) {
+ gst_element_set_state(m_videoTee, GST_STATE_NULL);
+ gst_object_unref(m_videoTee);
+ }
+
+ if (m_audioTee) {
+ gst_element_set_state(m_audioTee, GST_STATE_NULL);
+ gst_object_unref(m_audioTee);
+ }
+
+ if (m_fakeAudioSink) {
+ gst_element_set_state(m_fakeAudioSink, GST_STATE_NULL);
+ gst_object_unref(m_fakeAudioSink);
+ }
+
+ if (m_fakeVideoSink) {
+ gst_element_set_state(m_fakeVideoSink, GST_STATE_NULL);
+ gst_object_unref(m_fakeVideoSink);
+ }
+}
+
+
+/**
+ * Connects children recursively from a mediaobject root
+ */
+bool MediaNode::buildGraph()
+{
+ Q_ASSERT(root()); //We cannot build the graph without a root element source
+
+ bool success = link();
+
+ if (success) {
+ // connect children recursively
+ for (int i=0; i< m_audioSinkList.size(); ++i) {
+ if (MediaNode *node = qobject_cast<MediaNode*>(m_audioSinkList[i])) {
+ node->setRoot(root());
+ if (!node->buildGraph())
+ success = false;
+ }
+ }
+
+ for (int i=0; i < m_videoSinkList.size(); ++i) {
+ if (MediaNode *node = qobject_cast<MediaNode*>(m_videoSinkList[i])) {
+ node->setRoot(root());
+ if (!node->buildGraph())
+ success = false;
+ }
+ }
+ }
+
+ if (!success)
+ unlink();
+
+ return success;
+}
+
+/**
+ * Disconnects children recursively
+ */
+bool MediaNode::breakGraph()
+{
+ for (int i=0; i<m_audioSinkList.size(); ++i) {
+ MediaNode *node = qobject_cast<MediaNode*>(m_audioSinkList[i]);
+ if (!node || !node->breakGraph())
+ return false;
+ node->setRoot(0);
+ }
+
+ for (int i=0; i <m_videoSinkList.size(); ++i) {
+ MediaNode *node = qobject_cast<MediaNode*>(m_videoSinkList[i]);
+ if (!node || !node->breakGraph())
+ return false;
+ node->setRoot(0);
+ }
+ unlink();
+ return true;
+}
+
+bool MediaNode::connectNode(QObject *obj)
+{
+ MediaNode *sink = qobject_cast<MediaNode*>(obj);
+
+ bool success = false;
+
+ if (sink) {
+
+ if (!sink->isValid()) {
+ m_backend->logMessage(QString("Trying to link to an invalid node (%0)").arg(sink->name()), Backend::Warning);
+ return false;
+ }
+
+ if (sink->root()) {
+ m_backend->logMessage("Trying to link a node that is already linked to a different mediasource ", Backend::Warning);
+ return false;
+ }
+
+ if ((m_description & AudioSource) && (sink->m_description & AudioSink)) {
+ m_audioSinkList << obj;
+ MediaNodeEvent event(MediaNodeEvent::AudioSinkAdded, sink);
+ root()->mediaNodeEvent(&event);
+ success = true;
+ }
+
+ if ((m_description & VideoSource) && (sink->m_description & VideoSink)) {
+ m_videoSinkList << obj;
+ MediaNodeEvent event(MediaNodeEvent::VideoSinkAdded, sink);
+ root()->mediaNodeEvent(&event);
+ success = true;
+ }
+
+ // If we have a root source, and we are connected
+ // try to link the gstreamer elements
+ if (success && root()) {
+ MediaNodeEvent mediaObjectConnected(MediaNodeEvent::MediaObjectConnected, root());
+ notify(&mediaObjectConnected);
+ root()->buildGraph();
+ }
+ }
+ return success;
+}
+
+bool MediaNode::disconnectNode(QObject *obj)
+{
+ MediaNode *sink = qobject_cast<MediaNode*>(obj);
+ if (root()) {
+ // Disconnecting elements while playing or paused seems to cause
+ // potential deadlock. Hence we force the pipeline into ready state
+ // before any nodes are disconnected.
+ gst_element_set_state(root()->pipeline(), GST_STATE_READY);
+
+ Q_ASSERT(sink->root()); //sink has to have a root since it is onnected
+
+ if (sink->description() & (AudioSink)) {
+ GstPad *sinkPad = gst_element_get_pad(sink->audioElement(), "sink");
+ // Release requested src pad from tee
+ GstPad *requestedPad = gst_pad_get_peer(sinkPad);
+ if (requestedPad) {
+ gst_element_release_request_pad(m_audioTee, requestedPad);
+ gst_object_unref(requestedPad);
+ }
+ if (GST_ELEMENT_PARENT(sink->audioElement()))
+ gst_bin_remove(GST_BIN(root()->audioGraph()), sink->audioElement());
+ gst_object_unref(sinkPad);
+ }
+
+ if (sink->description() & (VideoSink)) {
+ GstPad *sinkPad = gst_element_get_pad(sink->videoElement(), "sink");
+ // Release requested src pad from tee
+ GstPad *requestedPad = gst_pad_get_peer(sinkPad);
+ if (requestedPad) {
+ gst_element_release_request_pad(m_videoTee, requestedPad);
+ gst_object_unref(requestedPad);
+ }
+ if (GST_ELEMENT_PARENT(sink->videoElement()))
+ gst_bin_remove(GST_BIN(root()->videoGraph()), sink->videoElement());
+ gst_object_unref(sinkPad);
+ }
+
+ sink->breakGraph();
+ sink->setRoot(0);
+ }
+
+ m_videoSinkList.removeAll(obj);
+ m_audioSinkList.removeAll(obj);
+
+ if (sink->m_description & AudioSink) {
+ // Remove sink from graph
+ MediaNodeEvent event(MediaNodeEvent::AudioSinkRemoved, sink);
+ mediaNodeEvent(&event);
+ return true;
+ }
+
+ if ((m_description & VideoSource) && (sink->m_description & VideoSink)) {
+ // Remove sink from graph
+ MediaNodeEvent event(MediaNodeEvent::VideoSinkRemoved, sink);
+ mediaNodeEvent(&event);
+ return true;
+ }
+
+ return false;
+}
+
+void MediaNode::mediaNodeEvent(const MediaNodeEvent *) {}
+
+/**
+ * Propagates an event down the graph
+ * sender is responsible for deleting the event
+ */
+void MediaNode::notify(const MediaNodeEvent *event)
+{
+ Q_ASSERT(event);
+ mediaNodeEvent(event);
+ for (int i=0; i<m_audioSinkList.size(); ++i) {
+ MediaNode *node = qobject_cast<MediaNode*>(m_audioSinkList[i]);
+ node->notify(event);
+ }
+
+ for (int i=0; i<m_videoSinkList.size(); ++i) {
+ MediaNode *node = qobject_cast<MediaNode*>(m_videoSinkList[i]);
+ node->notify(event);
+ }
+}
+
+/*
+ * Requests a new tee pad and connects a node to it
+ */
+bool MediaNode::addOutput(MediaNode *output, GstElement *tee)
+{
+ Q_ASSERT(root());
+
+ bool success = true;
+
+ GstElement *sinkElement = 0;
+ if (output->description() & AudioSink)
+ sinkElement = output->audioElement();
+ else if (output->description() & VideoSink)
+ sinkElement = output->videoElement();
+
+ Q_ASSERT(sinkElement);
+
+ if (!sinkElement)
+ return false;
+
+ GstState state = GST_STATE (root()->pipeline());
+ GstPad *srcPad = gst_element_get_request_pad (tee, "src%d");
+ GstPad *sinkPad = gst_element_get_pad (sinkElement, "sink");
+
+ if (!sinkPad) {
+ success = false;
+ } else if (gst_pad_is_linked(sinkPad)) {
+ gst_object_unref (GST_OBJECT (sinkPad));
+ gst_object_unref (GST_OBJECT (srcPad));
+ return true;
+ }
+
+ if (success) {
+ if (output->description() & AudioSink)
+ gst_bin_add(GST_BIN(root()->audioGraph()), sinkElement);
+ else if (output->description() & VideoSink)
+ gst_bin_add(GST_BIN(root()->videoGraph()), sinkElement);
+ }
+
+ if (success) {
+ gst_pad_link(srcPad, sinkPad);
+ gst_element_set_state(sinkElement, state);
+ } else {
+ gst_element_release_request_pad(tee, srcPad);
+ }
+
+ gst_object_unref (GST_OBJECT (srcPad));
+ gst_object_unref (GST_OBJECT (sinkPad));
+
+ return success;
+}
+
+// Used to seal up unconnected source nodes by connecting unconnected src pads to fake sinks
+bool MediaNode::connectToFakeSink(GstElement *tee, GstElement *sink, GstElement *bin)
+{
+ bool success = true;
+ GstPad *sinkPad = gst_element_get_pad (sink, "sink");
+
+ if (GST_PAD_IS_LINKED (sinkPad)) {
+ //This fakesink is already connected
+ gst_object_unref (sinkPad);
+ return true;
+ }
+
+ GstPad *srcPad = gst_element_get_request_pad (tee, "src%d");
+ gst_bin_add(GST_BIN(bin), sink);
+ if (success)
+ success = (gst_pad_link (srcPad, sinkPad) == GST_PAD_LINK_OK);
+ if (success)
+ success = (gst_element_set_state(sink, GST_STATE(bin)) != GST_STATE_CHANGE_FAILURE);
+ gst_object_unref (srcPad);
+ gst_object_unref (sinkPad);
+ return success;
+}
+
+// Used to seal up unconnected source nodes by connecting unconnected src pads to fake sinks
+bool MediaNode::releaseFakeSinkIfConnected(GstElement *tee, GstElement *fakesink, GstElement *bin)
+{
+ if (GST_ELEMENT_PARENT(fakesink) == GST_ELEMENT(bin)) {
+ GstPad *sinkPad = gst_element_get_pad(fakesink, "sink");
+
+ // Release requested src pad from tee
+ GstPad *requestedPad = gst_pad_get_peer(sinkPad);
+ if (requestedPad) {
+ gst_element_release_request_pad(tee, requestedPad);
+ gst_object_unref(requestedPad);
+ }
+ gst_object_unref(sinkPad);
+
+ gst_element_set_state(fakesink, GST_STATE_NULL);
+ gst_bin_remove(GST_BIN(bin), fakesink);
+ Q_ASSERT(!GST_ELEMENT_PARENT(fakesink));
+ }
+ return true;
+}
+
+bool MediaNode::linkMediaNodeList(QList<QObject *> &list, GstElement *bin, GstElement *tee, GstElement *fakesink, GstElement *src)
+{
+ if (!GST_ELEMENT_PARENT(tee)) {
+ gst_bin_add(GST_BIN(bin), tee);
+ if (!gst_element_link_pads(src, "src", tee, "sink"))
+ return false;
+ gst_element_set_state(tee, GST_STATE(bin));
+ }
+ if (list.isEmpty()) {
+ //connect node to a fake sink to avoid clogging the pipeline
+ if (!connectToFakeSink(tee, fakesink, bin))
+ return false;
+ } else {
+ // Remove fake sink if previously connected
+ if (!releaseFakeSinkIfConnected(tee, fakesink, bin))
+ return false;
+
+ for (int i = 0 ; i < list.size() ; ++i) {
+ QObject *sink = list[i];
+ if (MediaNode *output = qobject_cast<MediaNode*>(sink)) {
+ if (!addOutput(output, tee))
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+bool MediaNode::link()
+{
+ // Rewire everything
+ if ((description() & AudioSource)) {
+ if (!linkMediaNodeList(m_audioSinkList, root()->audioGraph(), m_audioTee, m_fakeAudioSink, audioElement()))
+ return false;
+ }
+
+ if ((description() & VideoSource)) {
+ if (!linkMediaNodeList(m_videoSinkList, root()->videoGraph(), m_videoTee, m_fakeVideoSink, videoElement()))
+ return false;
+ }
+ return true;
+}
+
+bool MediaNode::unlink()
+{
+ Q_ASSERT(root());
+ if (description() & AudioSource) {
+ if (GST_ELEMENT_PARENT(m_audioTee) == GST_ELEMENT(root()->audioGraph())) {
+ gst_element_set_state(m_audioTee, GST_STATE_NULL);
+ gst_bin_remove(GST_BIN(root()->audioGraph()), m_audioTee);
+ }
+ for (int i=0; i<m_audioSinkList.size(); ++i) {
+ QObject *audioSink = m_audioSinkList[i];
+ if (MediaNode *output = qobject_cast<MediaNode*>(audioSink)) {
+ GstElement *element = output->audioElement();
+ if (GST_ELEMENT_PARENT(element) == GST_ELEMENT(root()->audioGraph())) {
+ gst_element_set_state(element, GST_STATE_NULL);
+ gst_bin_remove(GST_BIN(root()->audioGraph()), element);
+ }
+ }
+ }
+ } else if (description() & VideoSource) {
+ if (GST_ELEMENT_PARENT(m_videoTee) == GST_ELEMENT(root()->videoGraph())) {
+ gst_element_set_state(m_videoTee, GST_STATE_NULL);
+ gst_bin_remove(GST_BIN(root()->videoGraph()), m_videoTee);
+ }
+ for (int i=0; i <m_videoSinkList.size(); ++i) {
+ QObject *videoSink = m_videoSinkList[i];
+ if (MediaNode *vw = qobject_cast<MediaNode*>(videoSink)) {
+ GstElement *element = vw->videoElement();
+ if (GST_ELEMENT_PARENT(element) == GST_ELEMENT(root()->videoGraph())) {
+ gst_element_set_state(element, GST_STATE_NULL);
+ gst_bin_remove(GST_BIN(root()->videoGraph()), element);
+ }
+ }
+ }
+ }
+ return true;
+}
+
+
+} // ns Gstreamer
+} // ns Phonon
+
+QT_END_NAMESPACE
diff --git a/src/3rdparty/phonon/gstreamer/medianode.h b/src/3rdparty/phonon/gstreamer/medianode.h
new file mode 100644
index 0000000000..6e3850a483
--- /dev/null
+++ b/src/3rdparty/phonon/gstreamer/medianode.h
@@ -0,0 +1,128 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef Phonon_GSTREAMER_MEDIANODE_H
+#define Phonon_GSTREAMER_MEDIANODE_H
+
+#include "common.h"
+#include "medianodeevent.h"
+
+#include <QtCore/QObject>
+#include <QtCore/QList>
+#include <QtCore/QSize>
+
+#include <gst/gst.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon {
+namespace Gstreamer {
+
+class Message;
+class MediaObject;
+class Backend;
+
+class MediaNode {
+public:
+ enum NodeDescriptionEnum {
+ AudioSource = 0x1,
+ AudioSink = 0x2,
+ VideoSource = 0x4,
+ VideoSink = 0x8
+ };
+ Q_DECLARE_FLAGS(NodeDescription, NodeDescriptionEnum)
+
+ MediaNode(Backend *backend, NodeDescription description);
+
+ virtual ~MediaNode();
+
+ bool connectNode(QObject *other);
+ bool disconnectNode(QObject *other);
+
+ bool buildGraph();
+ bool breakGraph();
+
+ virtual bool link();
+ virtual bool unlink();
+
+ NodeDescription description() const {
+ return m_description;
+ }
+
+ bool isValid() {
+ return m_isValid;
+ }
+
+ MediaObject *root() {
+ return m_root;
+ }
+
+ void setRoot(MediaObject *mediaObject) {
+ m_root = mediaObject;
+ }
+
+ void notify(const MediaNodeEvent *event);
+
+ Backend *backend() {
+ return m_backend;
+ }
+
+ const QString &name() {
+ return m_name;
+ }
+
+ virtual GstElement *audioElement() {
+ return m_audioTee;
+ }
+
+ virtual GstElement *videoElement() {
+ return m_videoTee;
+ }
+
+protected:
+ bool connectToFakeSink(GstElement *tee, GstElement *sink, GstElement *bin);
+ bool releaseFakeSinkIfConnected(GstElement *tee, GstElement *sink, GstElement *bin);
+ bool linkMediaNodeList(QList<QObject *> &list, GstElement *bin, GstElement *tee, GstElement *sink, GstElement *src);
+
+ virtual void mediaNodeEvent(const MediaNodeEvent *event);
+ QList<QObject *> m_audioSinkList;
+ QList<QObject *> m_videoSinkList;
+
+ bool m_isValid;
+ MediaObject *m_root;
+ GstElement *m_audioTee;
+ GstElement *m_videoTee;
+ GstElement *m_fakeAudioSink;
+ GstElement *m_fakeVideoSink;
+ Backend *m_backend;
+ QString m_name;
+
+private:
+ bool addOutput(MediaNode *, GstElement *tee);
+ NodeDescription m_description;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(MediaNode::NodeDescription)
+
+} // ns Gstreamer
+} // ns Phonon
+
+Q_DECLARE_INTERFACE(Phonon::Gstreamer::MediaNode, "org.phonon.gstreamer.MediaNode")
+
+QT_END_NAMESPACE
+
+#endif // Phonon_GSTREAMER_MEDIANODE_H
diff --git a/src/3rdparty/phonon/gstreamer/medianodeevent.cpp b/src/3rdparty/phonon/gstreamer/medianodeevent.cpp
new file mode 100644
index 0000000000..20560ee375
--- /dev/null
+++ b/src/3rdparty/phonon/gstreamer/medianodeevent.cpp
@@ -0,0 +1,38 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "medianodeevent.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace Gstreamer
+{
+
+MediaNodeEvent::MediaNodeEvent(Type type, const void *data) :
+ eventType(type),
+ eventData(data)
+{}
+
+MediaNodeEvent::~MediaNodeEvent()
+{}
+
+}
+} // namespace Phonon::Gstreamer
+
+QT_END_NAMESPACE
diff --git a/src/3rdparty/phonon/gstreamer/medianodeevent.h b/src/3rdparty/phonon/gstreamer/medianodeevent.h
new file mode 100644
index 0000000000..cacf4a58c5
--- /dev/null
+++ b/src/3rdparty/phonon/gstreamer/medianodeevent.h
@@ -0,0 +1,70 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef Phonon_GSTREAMER_MEDIANODEEVENT_H
+#define Phonon_GSTREAMER_MEDIANODEEVENT_H
+
+#include "common.h"
+
+#include <QtCore>
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace Gstreamer
+{
+class MediaNodeEvent
+{
+public:
+ enum Type {
+ VideoAvailable,
+ AudioAvailable,
+ SourceChanged,
+ MediaObjectConnected,
+ StateChanged,
+ VideoSinkAdded,
+ VideoSinkRemoved,
+ AudioSinkAdded,
+ AudioSinkRemoved,
+ VideoHandleRequest,
+ VideoSizeChanged
+ };
+
+ MediaNodeEvent(Type type, const void *data = 0);
+ virtual ~MediaNodeEvent();
+
+ inline Type type() const
+ {
+ return eventType;
+ };
+ inline const void* data() const
+ {
+ return eventData;
+ };
+
+private:
+ Type eventType;
+ const void *eventData;
+};
+
+}
+} // namespace Phonon::Gstreamer
+
+QT_END_NAMESPACE
+
+#endif // Phonon_GSTREAMER_MEDIANODEEVENT_H
diff --git a/src/3rdparty/phonon/gstreamer/mediaobject.cpp b/src/3rdparty/phonon/gstreamer/mediaobject.cpp
new file mode 100644
index 0000000000..74fc1b4d19
--- /dev/null
+++ b/src/3rdparty/phonon/gstreamer/mediaobject.cpp
@@ -0,0 +1,1479 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include <cmath>
+#include <gst/interfaces/propertyprobe.h>
+#include "common.h"
+#include "mediaobject.h"
+#include "videowidget.h"
+#include "message.h"
+#include "backend.h"
+#include "streamreader.h"
+#include "phononsrc.h"
+#include <QtCore>
+#include <QtCore/QTimer>
+#include <QtCore/QVector>
+#include <QtCore/QFile>
+#include <QtCore/QByteRef>
+#include <QtCore/QStringList>
+#include <QtCore/QEvent>
+#include <QApplication>
+
+#define ABOUT_TO_FINNISH_TIME 2000
+#define MAX_QUEUE_TIME 20 * GST_SECOND
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace Gstreamer
+{
+
+MediaObject::MediaObject(Backend *backend, QObject *parent)
+ : QObject(parent)
+ , MediaNode(backend, AudioSource | VideoSource)
+ , m_resumeState(false)
+ , m_oldState(Phonon::LoadingState)
+ , m_oldPos(0)
+ , m_state(Phonon::LoadingState)
+ , m_pendingState(Phonon::LoadingState)
+ , m_tickTimer(new QTimer(this))
+ , m_prefinishMark(0)
+ , m_transitionTime(0)
+ , m_posAtSeek(-1)
+ , m_prefinishMarkReachedNotEmitted(true)
+ , m_aboutToFinishEmitted(false)
+ , m_loading(false)
+ , m_capsHandler(0)
+ , m_datasource(0)
+ , m_decodebin(0)
+ , m_audioPipe(0)
+ , m_videoPipe(0)
+ , m_totalTime(-1)
+ , m_bufferPercent(0)
+ , m_hasVideo(false)
+ , m_videoStreamFound(false)
+ , m_hasAudio(false)
+ , m_seekable(false)
+ , m_atEndOfStream(false)
+ , m_atStartOfStream(false)
+ , m_error(Phonon::NoError)
+ , m_pipeline(0)
+ , m_audioGraph(0)
+ , m_videoGraph(0)
+ , m_previousTickTime(-1)
+ , m_resetNeeded(false)
+ , m_autoplayTitles(true)
+ , m_availableTitles(0)
+ , m_currentTitle(1)
+{
+ qRegisterMetaType<GstCaps*>("GstCaps*");
+ qRegisterMetaType<State>("State");
+
+ static int count = 0;
+ m_name = "MediaObject" + QString::number(count++);
+
+ if (!m_backend->isValid()) {
+ setError(tr("Cannot start playback. \n\nCheck your Gstreamer installation and make sure you "
+ "\nhave libgstreamer-plugins-base installed."), Phonon::FatalError);
+ } else {
+ m_root = this;
+ createPipeline();
+ m_backend->addBusWatcher(this);
+ connect(m_tickTimer, SIGNAL(timeout()), SLOT(emitTick()));
+ }
+ connect(this, SIGNAL(stateChanged(Phonon::State, Phonon::State)),
+ this, SLOT(notifyStateChange(Phonon::State, Phonon::State)));
+
+}
+
+MediaObject::~MediaObject()
+{
+ m_backend->removeBusWatcher(this);
+ if (m_pipeline) {
+ gst_element_set_state(m_pipeline, GST_STATE_NULL);
+ gst_object_unref(m_pipeline);
+ }
+ if (m_audioGraph) {
+ gst_element_set_state(m_audioGraph, GST_STATE_NULL);
+ gst_object_unref(m_audioGraph);
+ }
+ if (m_videoGraph) {
+ gst_element_set_state(m_videoGraph, GST_STATE_NULL);
+ gst_object_unref(m_videoGraph);
+ }
+}
+
+QString stateString(const Phonon::State &state)
+{
+ switch (state) {
+ case Phonon::LoadingState:
+ return QString("LoadingState");
+ case Phonon::StoppedState:
+ return QString("StoppedState");
+ case Phonon::PlayingState:
+ return QString("PlayingState");
+ case Phonon::BufferingState:
+ return QString("BufferingState");
+ case Phonon::PausedState:
+ return QString("PausedState");
+ case Phonon::ErrorState:
+ return QString("ErrorState");
+ }
+ return QString();
+}
+
+void MediaObject::saveState()
+{
+ //Only first resumeState is respected
+ if (m_resumeState)
+ return;
+
+ if (m_pendingState == Phonon::PlayingState || m_pendingState == Phonon::PausedState) {
+ m_resumeState = true;
+ m_oldState = m_pendingState;
+ m_oldPos = getPipelinePos();
+ }
+}
+
+void MediaObject::resumeState()
+{
+ if (m_resumeState)
+ QMetaObject::invokeMethod(this, "setState", Qt::QueuedConnection, Q_ARG(State, m_oldState));
+}
+
+void MediaObject::newPadAvailable (GstPad *pad)
+{
+ GstCaps *caps;
+ GstStructure *str;
+ caps = gst_pad_get_caps (pad);
+ if (caps) {
+ str = gst_caps_get_structure (caps, 0);
+ QString mediaString(gst_structure_get_name (str));
+
+ if (mediaString.startsWith("video")) {
+ connectVideo(pad);
+ } else if (mediaString.startsWith("audio")) {
+ connectAudio(pad);
+ } else {
+ m_backend->logMessage("Could not connect pad", Backend::Warning);
+ }
+ gst_caps_unref (caps);
+ }
+}
+
+void MediaObject::cb_newpad (GstElement *decodebin,
+ GstPad *pad,
+ gboolean last,
+ gpointer data)
+{
+ Q_UNUSED(decodebin);
+ Q_UNUSED(pad);
+ Q_UNUSED(last);
+ Q_UNUSED(data);
+
+ MediaObject *media = static_cast<MediaObject*>(data);
+ Q_ASSERT(media);
+ media->newPadAvailable(pad);
+}
+
+void MediaObject::noMorePadsAvailable ()
+{
+ if (m_missingCodecs.size() > 0) {
+ bool canPlay = (m_hasAudio || m_videoStreamFound);
+ Phonon::ErrorType error = canPlay ? Phonon::NormalError : Phonon::FatalError;
+ if (error == Phonon::NormalError && m_hasVideo && !m_videoStreamFound) {
+ m_hasVideo = false;
+ emit hasVideoChanged(false);
+ }
+ QString codecs = m_missingCodecs.join(", ");
+ setError(QString(tr("A required codec is missing. You need to install the following codec(s) to play this content: %0")).arg(codecs), error);
+ m_missingCodecs.clear();
+ }
+}
+
+void MediaObject::cb_no_more_pads (GstElement * decodebin, gpointer data)
+{
+ Q_UNUSED(decodebin);
+ MediaObject *media = static_cast<MediaObject*>(data);
+ Q_ASSERT(media);
+ QMetaObject::invokeMethod(media, "noMorePadsAvailable", Qt::QueuedConnection);
+}
+
+typedef void (*Ptr_gst_pb_utils_init)();
+typedef gchar* (*Ptr_gst_pb_utils_get_codec_description)(const GstCaps *);
+
+void MediaObject::cb_unknown_type (GstElement *decodebin, GstPad *pad, GstCaps *caps, gpointer data)
+{
+ Q_UNUSED(decodebin);
+ Q_UNUSED(pad);
+ MediaObject *media = static_cast<MediaObject*>(data);
+ Q_ASSERT(media);
+
+ QString value = "unknown codec";
+
+ // These functions require GStreamer > 0.10.12
+ static Ptr_gst_pb_utils_init p_gst_pb_utils_init = 0;
+ static Ptr_gst_pb_utils_get_codec_description p_gst_pb_utils_get_codec_description = 0;
+ if (!p_gst_pb_utils_init) {
+ p_gst_pb_utils_init = (Ptr_gst_pb_utils_init)QLibrary::resolve(QLatin1String("gstpbutils-0.10"), 0, "gst_pb_utils_init");
+ p_gst_pb_utils_get_codec_description = (Ptr_gst_pb_utils_get_codec_description)QLibrary::resolve(QLatin1String("gstpbutils-0.10"), 0, "gst_pb_utils_get_codec_description");
+ if (p_gst_pb_utils_init)
+ p_gst_pb_utils_init();
+ }
+ if (p_gst_pb_utils_get_codec_description) {
+ gchar *codecName = NULL;
+ codecName = p_gst_pb_utils_get_codec_description (caps);
+ value = QString::fromUtf8(codecName);
+ g_free (codecName);
+ } else {
+ // For GStreamer versions < 0.10.12
+ GstStructure *str = gst_caps_get_structure (caps, 0);
+ value = QString::fromUtf8(gst_structure_get_name (str));
+ }
+ media->addMissingCodecName(value);
+}
+
+static void notifyVideoCaps(GObject *obj, GParamSpec *, gpointer data)
+{
+ GstPad *pad = GST_PAD(obj);
+ GstCaps *caps = gst_pad_get_caps (pad);
+ Q_ASSERT(caps);
+ MediaObject *media = static_cast<MediaObject*>(data);
+
+ // We do not want any more notifications until the source changes
+ g_signal_handler_disconnect(pad, media->capsHandler());
+
+ // setVideoCaps calls loadingComplete(), meaning we cannot call it from
+ // the streaming thread
+ QMetaObject::invokeMethod(media, "setVideoCaps", Qt::QueuedConnection, Q_ARG(GstCaps *, caps));
+}
+
+void MediaObject::setVideoCaps(GstCaps *caps)
+{
+ GstStructure *str;
+ gint width, height;
+
+ if ((str = gst_caps_get_structure (caps, 0))) {
+ if (gst_structure_get_int (str, "width", &width) && gst_structure_get_int (str, "height", &height)) {
+ gint aspectNum = 0;
+ gint aspectDenum = 0;
+ if (gst_structure_get_fraction(str, "pixel-aspect-ratio", &aspectNum, &aspectDenum)) {
+ if (aspectDenum > 0)
+ width = width*aspectNum/aspectDenum;
+ }
+ // Let child nodes know about our new video size
+ QSize size(width, height);
+ MediaNodeEvent event(MediaNodeEvent::VideoSizeChanged, &size);
+ notify(&event);
+ }
+ }
+ gst_caps_unref(caps);
+}
+
+// Adds an element to the pipeline if not previously added
+bool MediaObject::addToPipeline(GstElement *elem)
+{
+ bool success = true;
+ if (!GST_ELEMENT_PARENT(elem)) { // If not already in pipeline
+ success = gst_bin_add(GST_BIN(m_pipeline), elem);
+ }
+ return success;
+}
+
+void MediaObject::connectVideo(GstPad *pad)
+{
+ GstState currentState = GST_STATE(m_pipeline);
+ if (addToPipeline(m_videoGraph)) {
+ GstPad *videopad = gst_element_get_pad (m_videoGraph, "sink");
+ if (!GST_PAD_IS_LINKED (videopad) && (gst_pad_link (pad, videopad) == GST_PAD_LINK_OK)) {
+ gst_element_set_state(m_videoGraph, currentState == GST_STATE_PLAYING ? GST_STATE_PLAYING : GST_STATE_PAUSED);
+ m_videoStreamFound = true;
+ m_backend->logMessage("Video track connected", Backend::Info, this);
+ // Note that the notify::caps _must_ be installed after linking to work with Dapper
+ m_capsHandler = g_signal_connect(pad, "notify::caps", G_CALLBACK(notifyVideoCaps), this);
+
+ if (!m_loading && !m_hasVideo) {
+ m_hasVideo = m_videoStreamFound;
+ emit hasVideoChanged(m_hasVideo);
+ }
+ }
+ gst_object_unref (videopad);
+ } else {
+ m_backend->logMessage("The video stream could not be plugged.", Backend::Info, this);
+ }
+}
+
+void MediaObject::connectAudio(GstPad *pad)
+{
+ GstState currentState = GST_STATE(m_pipeline);
+ if (addToPipeline(m_audioGraph)) {
+ GstPad *audiopad = gst_element_get_pad (m_audioGraph, "sink");
+ if (!GST_PAD_IS_LINKED (audiopad) && (gst_pad_link (pad, audiopad)==GST_PAD_LINK_OK)) {
+ gst_element_set_state(m_audioGraph, currentState == GST_STATE_PLAYING ? GST_STATE_PLAYING : GST_STATE_PAUSED);
+ m_hasAudio = true;
+ m_backend->logMessage("Audio track connected", Backend::Info, this);
+ }
+ gst_object_unref (audiopad);
+ } else {
+ m_backend->logMessage("The audio stream could not be plugged.", Backend::Info, this);
+ }
+}
+
+void MediaObject::cb_pad_added(GstElement *decodebin,
+ GstPad *pad,
+ gpointer data)
+{
+ Q_UNUSED(decodebin);
+ GstPad *decodepad = static_cast<GstPad*>(data);
+ gst_pad_link (pad, decodepad);
+ gst_object_unref (decodepad);
+}
+
+/**
+ * Create a media source from a given URL.
+ *
+ * returns true if successful
+ */
+bool MediaObject::createPipefromURL(const QUrl &url)
+{
+ // Remove any existing data source
+ if (m_datasource) {
+ gst_bin_remove(GST_BIN(m_pipeline), m_datasource);
+ // m_pipeline has the only ref to datasource
+ m_datasource = 0;
+ }
+
+ // Verify that the uri can be parsed
+ if (!url.isValid()) {
+ m_backend->logMessage(QString("%1 is not a valid URI").arg(url.toString()));
+ return false;
+ }
+
+ // Create a new datasource based on the input URL
+ QByteArray encoded_cstr_url = url.toEncoded();
+ m_datasource = gst_element_make_from_uri(GST_URI_SRC, encoded_cstr_url.constData(), (const char*)NULL);
+ if (!m_datasource)
+ return false;
+
+ // Link data source into pipeline
+ gst_bin_add(GST_BIN(m_pipeline), m_datasource);
+ if (!gst_element_link(m_datasource, m_decodebin)) {
+ // For sources with dynamic pads (such as RtspSrc) we need to connect dynamically
+ GstPad *decodepad = gst_element_get_pad (m_decodebin, "sink");
+ g_signal_connect (m_datasource, "pad-added", G_CALLBACK (&cb_pad_added), decodepad);
+ }
+
+ return true;
+}
+
+/**
+ * Create a media source from a media stream
+ *
+ * returns true if successful
+ */
+bool MediaObject::createPipefromStream(const MediaSource &source)
+{
+ // Remove any existing data source
+ if (m_datasource) {
+ gst_bin_remove(GST_BIN(m_pipeline), m_datasource);
+ // m_pipeline has the only ref to datasource
+ m_datasource = 0;
+ }
+
+ m_datasource = GST_ELEMENT(g_object_new(phonon_src_get_type(), NULL));
+ if (!m_datasource)
+ return false;
+
+ StreamReader *streamReader = new StreamReader(source);
+ g_object_set (G_OBJECT (m_datasource), "iodevice", streamReader, (const char*)NULL);
+
+ // Link data source into pipeline
+ gst_bin_add(GST_BIN(m_pipeline), m_datasource);
+ if (!gst_element_link(m_datasource, m_decodebin)) {
+ gst_bin_remove(GST_BIN(m_pipeline), m_datasource);
+ return false;
+ }
+ return true;
+}
+
+void MediaObject::createPipeline()
+{
+ m_pipeline = gst_pipeline_new (NULL);
+ gst_object_ref (GST_OBJECT (m_pipeline));
+ gst_object_sink (GST_OBJECT (m_pipeline));
+
+ m_decodebin = gst_element_factory_make ("decodebin", NULL);
+ g_signal_connect (m_decodebin, "new-decoded-pad", G_CALLBACK (&cb_newpad), this);
+ g_signal_connect (m_decodebin, "unknown-type", G_CALLBACK (&cb_unknown_type), this);
+ g_signal_connect (m_decodebin, "no-more-pads", G_CALLBACK (&cb_no_more_pads), this);
+
+ gst_bin_add(GST_BIN(m_pipeline), m_decodebin);
+
+ // Create a bin to contain the gst elements for this medianode
+
+ // Set up audio graph
+ m_audioGraph = gst_bin_new(NULL);
+ gst_object_ref (GST_OBJECT (m_audioGraph));
+ gst_object_sink (GST_OBJECT (m_audioGraph));
+
+ // Note that these queues are only required for streaming content
+ // And should ideally be created on demand as they will disable
+ // pull-mode access. Also note that the max-size-time are increased to
+ // reduce buffer overruns as these are not gracefully handled at the moment.
+ m_audioPipe = gst_element_factory_make("queue", NULL);
+ g_object_set(G_OBJECT(m_audioPipe), "max-size-time", MAX_QUEUE_TIME, (const char*)NULL);
+ gst_bin_add(GST_BIN(m_audioGraph), m_audioPipe);
+ GstPad *audiopad = gst_element_get_pad (m_audioPipe, "sink");
+ gst_element_add_pad (m_audioGraph, gst_ghost_pad_new ("sink", audiopad));
+ gst_object_unref (audiopad);
+
+ // Set up video graph
+ m_videoGraph = gst_bin_new(NULL);
+ gst_object_ref (GST_OBJECT (m_videoGraph));
+ gst_object_sink (GST_OBJECT (m_videoGraph));
+
+ m_videoPipe = gst_element_factory_make("queue", NULL);
+ g_object_set(G_OBJECT(m_videoPipe), "max-size-time", MAX_QUEUE_TIME, (const char*)NULL);
+ gst_bin_add(GST_BIN(m_videoGraph), m_videoPipe);
+ GstPad *videopad = gst_element_get_pad (m_videoPipe, "sink");
+ gst_element_add_pad (m_videoGraph, gst_ghost_pad_new ("sink", videopad));
+ gst_object_unref (videopad);
+
+ if (m_pipeline && m_decodebin && m_audioGraph && m_videoGraph && m_audioPipe && m_videoPipe)
+ m_isValid = true;
+ else
+ m_backend->logMessage("Could not create pipeline for media object", Backend::Warning);
+}
+
+/**
+ * !reimp
+ */
+State MediaObject::state() const
+{
+ return m_state;
+}
+
+/**
+ * !reimp
+ */
+bool MediaObject::hasVideo() const
+{
+ return m_hasVideo;
+}
+
+/**
+ * !reimp
+ */
+bool MediaObject::isSeekable() const
+{
+ return m_seekable;
+}
+
+/**
+ * !reimp
+ */
+qint64 MediaObject::currentTime() const
+{
+ if (m_resumeState)
+ return m_oldPos;
+
+ switch (state()) {
+ case Phonon::PausedState:
+ case Phonon::BufferingState:
+ case Phonon::PlayingState:
+ return getPipelinePos();
+ case Phonon::StoppedState:
+ case Phonon::LoadingState:
+ return 0;
+ case Phonon::ErrorState:
+ break;
+ }
+ return -1;
+}
+
+/**
+ * !reimp
+ */
+qint32 MediaObject::tickInterval() const
+{
+ return m_tickInterval;
+}
+
+/**
+ * !reimp
+ */
+void MediaObject::setTickInterval(qint32 newTickInterval)
+{
+ m_tickInterval = newTickInterval;
+ if (m_tickInterval <= 0)
+ m_tickTimer->setInterval(50);
+ else
+ m_tickTimer->setInterval(newTickInterval);
+}
+
+/**
+ * !reimp
+ */
+void MediaObject::play()
+{
+ setState(Phonon::PlayingState);
+ m_resumeState = false;
+}
+
+/**
+ * !reimp
+ */
+QString MediaObject::errorString() const
+{
+ return m_errorString;
+}
+
+/**
+ * !reimp
+ */
+Phonon::ErrorType MediaObject::errorType() const
+{
+ return m_error;
+}
+
+/**
+ * Set the current state of the mediaObject.
+ *
+ * !### Note that both Playing and Paused states are set immediately
+ * This should obviously be done in response to actual gstreamer state changes
+ */
+void MediaObject::setState(State newstate)
+{
+ if (!isValid())
+ return;
+
+ if (m_state == newstate)
+ return;
+
+ if (m_loading) {
+ // We are still loading. The state will be requested
+ // when loading has completed.
+ m_pendingState = newstate;
+ return;
+ }
+
+ GstState currentState;
+ gst_element_get_state (m_pipeline, &currentState, NULL, 1000);
+
+ switch (newstate) {
+ case Phonon::BufferingState:
+ m_backend->logMessage("phonon state request: buffering", Backend::Info, this);
+ break;
+
+ case Phonon::PausedState:
+ m_backend->logMessage("phonon state request: paused", Backend::Info, this);
+ if (currentState == GST_STATE_PAUSED) {
+ changeState(Phonon::PausedState);
+ } else if (gst_element_set_state(m_pipeline, GST_STATE_PAUSED) != GST_STATE_CHANGE_FAILURE) {
+ m_pendingState = Phonon::PausedState;
+ } else {
+ m_backend->logMessage("phonon state request failed", Backend::Info, this);
+ }
+ break;
+
+ case Phonon::StoppedState:
+ m_backend->logMessage("phonon state request: Stopped", Backend::Info, this);
+ if (currentState == GST_STATE_READY) {
+ changeState(Phonon::StoppedState);
+ } else if (gst_element_set_state(m_pipeline, GST_STATE_READY) != GST_STATE_CHANGE_FAILURE) {
+ m_pendingState = Phonon::StoppedState;
+ } else {
+ m_backend->logMessage("phonon state request failed", Backend::Info, this);
+ }
+ m_atEndOfStream = false;
+ break;
+
+ case Phonon::PlayingState:
+ if (m_resetNeeded) {
+ // ### Note this is a workaround and it should really be gracefully
+ // handled by medianode when we implement live connections.
+ // This generally happens if medianodes have been connected after the MediaSource was set
+ // Note that a side-effect of this is that we resend all meta data.
+ gst_element_set_state(m_pipeline, GST_STATE_NULL);
+ m_resetNeeded = false;
+ // Send a source change so the X11 renderer
+ // will re-set the overlay
+ MediaNodeEvent event(MediaNodeEvent::SourceChanged);
+ notify(&event);
+ }
+ m_backend->logMessage("phonon state request: Playing", Backend::Info, this);
+ if (m_atEndOfStream) {
+ m_backend->logMessage("EOS already reached", Backend::Info, this);
+ } else if (currentState == GST_STATE_PLAYING) {
+ changeState(Phonon::PlayingState);
+ } else if (!m_atEndOfStream && gst_element_set_state(m_pipeline, GST_STATE_PLAYING) != GST_STATE_CHANGE_FAILURE) {
+ m_pendingState = Phonon::PlayingState;
+ } else {
+ m_backend->logMessage("phonon state request failed", Backend::Info, this);
+ }
+ break;
+
+ case Phonon::ErrorState:
+ m_backend->logMessage("phonon state request : Error", Backend::Warning, this);
+ m_backend->logMessage(QString("Last error : %0").arg(errorString()) , Backend::Warning, this);
+ changeState(Phonon::ErrorState); //immediately set error state
+ break;
+
+ case Phonon::LoadingState:
+ m_backend->logMessage("phonon state request: Loading", Backend::Info, this);
+ changeState(Phonon::LoadingState);
+ break;
+ }
+}
+
+/*
+ * Signals that the requested state has completed
+ * by emitting stateChanged and updates the internal state.
+ */
+void MediaObject::changeState(State newstate)
+{
+ if (newstate == m_state)
+ return;
+
+ Phonon::State oldState = m_state;
+ m_state = newstate; // m_state must be set before emitting, since
+ // Error state requires that state() will return the new value
+ m_pendingState = newstate;
+ emit stateChanged(newstate, oldState);
+
+ switch (newstate) {
+ case Phonon::PausedState:
+ m_backend->logMessage("phonon state changed: paused", Backend::Info, this);
+ break;
+
+ case Phonon::BufferingState:
+ m_backend->logMessage("phonon state changed: buffering", Backend::Info, this);
+ break;
+
+ case Phonon::PlayingState:
+ m_backend->logMessage("phonon state changed: Playing", Backend::Info, this);
+ break;
+
+ case Phonon::StoppedState:
+ m_backend->logMessage("phonon state changed: Stopped", Backend::Info, this);
+ m_tickTimer->stop();
+ break;
+
+ case Phonon::ErrorState:
+ m_loading = false;
+ m_backend->logMessage("phonon state changed : Error", Backend::Info, this);
+ m_backend->logMessage(errorString(), Backend::Warning, this);
+ break;
+
+ case Phonon::LoadingState:
+ m_backend->logMessage("phonon state changed: Loading", Backend::Info, this);
+ break;
+ }
+}
+
+void MediaObject::setError(const QString &errorString, Phonon::ErrorType error)
+{
+ m_errorString = errorString;
+ m_error = error;
+ m_tickTimer->stop();
+
+ if (error == Phonon::FatalError) {
+ m_hasVideo = false;
+ emit hasVideoChanged(false);
+ gst_element_set_state(m_pipeline, GST_STATE_READY);
+ changeState(Phonon::ErrorState);
+ } else {
+ if (m_loading) //Flag error only after loading has completed
+ m_pendingState = Phonon::ErrorState;
+ else
+ changeState(Phonon::ErrorState);
+ }
+}
+
+qint64 MediaObject::totalTime() const
+{
+ return m_totalTime;
+}
+
+qint32 MediaObject::prefinishMark() const
+{
+ return m_prefinishMark;
+}
+
+qint32 MediaObject::transitionTime() const
+{
+ return m_transitionTime;
+}
+
+void MediaObject::setTransitionTime(qint32 time)
+{
+ m_transitionTime = time;
+}
+
+qint64 MediaObject::remainingTime() const
+{
+ return totalTime() - currentTime();
+}
+
+MediaSource MediaObject::source() const
+{
+ return m_source;
+}
+
+void MediaObject::setNextSource(const MediaSource &source)
+{
+ if (source.type() == MediaSource::Invalid &&
+ source.type() == MediaSource::Empty)
+ return;
+ m_nextSource = source;
+}
+
+/**
+ * Update total time value from the pipeline
+ */
+bool MediaObject::updateTotalTime()
+{
+ GstFormat format = GST_FORMAT_TIME;
+ gint64 duration = 0;
+ if (gst_element_query_duration (GST_ELEMENT(m_pipeline), &format, &duration)) {
+ setTotalTime(duration / GST_MSECOND);
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Checks if the current source is seekable
+ */
+void MediaObject::updateSeekable()
+{
+ if (!isValid())
+ return;
+
+ GstQuery *query;
+ gboolean result;
+ gint64 start, stop;
+ query = gst_query_new_seeking(GST_FORMAT_TIME);
+ result = gst_element_query (m_pipeline, query);
+ if (result) {
+ gboolean seekable;
+ GstFormat format;
+ gst_query_parse_seeking (query, &format, &seekable, &start, &stop);
+
+ if (m_seekable != seekable) {
+ m_seekable = seekable;
+ emit seekableChanged(m_seekable);
+ }
+
+ if (m_seekable)
+ m_backend->logMessage("Stream is seekable", Backend::Info, this);
+ else
+ m_backend->logMessage("Stream is non-seekable", Backend::Info, this);
+ } else {
+ m_backend->logMessage("updateSeekable query failed", Backend::Info, this);
+ }
+ gst_query_unref (query);
+}
+
+qint64 MediaObject::getPipelinePos() const
+{
+ Q_ASSERT(m_pipeline);
+
+ // Note some formats (usually mpeg) do not allow us to accurately seek to the
+ // beginning or end of the file so we 'fake' it here rather than exposing the front end to potential issues.
+ if (m_atEndOfStream)
+ return totalTime();
+ if (m_atStartOfStream)
+ return 0;
+ if (m_posAtSeek >= 0)
+ return m_posAtSeek;
+
+ gint64 pos = 0;
+ GstFormat format = GST_FORMAT_TIME;
+ gst_element_query_position (GST_ELEMENT(m_pipeline), &format, &pos);
+ return (pos / GST_MSECOND);
+}
+
+/*
+ * Internal method to set a new total time for the media object
+ */
+void MediaObject::setTotalTime(qint64 newTime)
+{
+
+ if (newTime == m_totalTime)
+ return;
+
+ m_totalTime = newTime;
+
+ emit totalTimeChanged(m_totalTime);
+}
+
+/*
+ * !reimp
+ */
+void MediaObject::setSource(const MediaSource &source)
+{
+ if (!isValid())
+ return;
+
+ // We have to reset the state completely here, otherwise
+ // remnants of the old pipeline can result in strangenes
+ // such as failing duration queries etc
+ GstState state;
+ gst_element_set_state(m_pipeline, GST_STATE_NULL);
+ gst_element_get_state (m_pipeline, &state, NULL, 2000);
+
+ m_source = source;
+ emit currentSourceChanged(m_source);
+ m_previousTickTime = -1;
+ m_missingCodecs.clear();
+
+ // Go into to loading state
+ changeState(Phonon::LoadingState);
+ m_loading = true;
+ m_resetNeeded = false;
+ m_resumeState = false;
+ m_pendingState = Phonon::StoppedState;
+
+ // Make sure we start out unconnected
+ if (GST_ELEMENT_PARENT(m_audioGraph))
+ gst_bin_remove(GST_BIN(m_pipeline), m_audioGraph);
+ if (GST_ELEMENT_PARENT(m_videoGraph))
+ gst_bin_remove(GST_BIN(m_pipeline), m_videoGraph);
+
+ // Clear any existing errors
+ m_aboutToFinishEmitted = false;
+ m_error = NoError;
+ m_errorString = QString();
+
+ m_bufferPercent = 0;
+ m_prefinishMarkReachedNotEmitted = true;
+ m_aboutToFinishEmitted = false;
+ m_hasAudio = false;
+ m_videoStreamFound = false;
+ setTotalTime(-1);
+ m_atEndOfStream = false;
+
+ // Clear exising meta tags
+ m_metaData.clear();
+
+ switch (source.type()) {
+ case MediaSource::Url: {
+ if (createPipefromURL(source.url()))
+ m_loading = true;
+ else
+ setError(tr("Could not open media source."));
+ }
+ break;
+
+ case MediaSource::LocalFile: {
+ if (createPipefromURL(QUrl::fromLocalFile(source.fileName())))
+ m_loading = true;
+ else
+ setError(tr("Could not open media source."));
+ }
+ break;
+
+ case MediaSource::Invalid:
+ setError(tr("Invalid source type."), Phonon::NormalError);
+ break;
+
+ case MediaSource::Empty:
+ break;
+
+ case MediaSource::Stream:
+ if (createPipefromStream(source))
+ m_loading = true;
+ else
+ setError(tr("Could not open media source."));
+ break;
+
+ case MediaSource::Disc: // CD tracks can be specified by setting the url in the following way uri=cdda:4
+ {
+ QUrl cdurl(QLatin1String("cdda://"));
+ if (createPipefromURL(cdurl))
+ m_loading = true;
+ else
+ setError(tr("Could not open media source."));
+ }
+ break;
+
+ default:
+ m_backend->logMessage("Source type not currently supported", Backend::Warning, this);
+ setError(tr("Could not open media source."), Phonon::NormalError);
+ break;
+ }
+
+ MediaNodeEvent event(MediaNodeEvent::SourceChanged);
+ notify(&event);
+
+ // We need to link this node to ensure that fake sinks are connected
+ // before loading, otherwise the stream will be blocked
+ if (m_loading)
+ link();
+ beginLoad();
+}
+
+void MediaObject::beginLoad()
+{
+ if (gst_element_set_state(m_pipeline, GST_STATE_PAUSED) != GST_STATE_CHANGE_FAILURE) {
+ m_backend->logMessage("Begin source load", Backend::Info, this);
+ } else {
+ setError(tr("Could not open media source."));
+ }
+}
+
+// Called when we are ready to leave the loading state
+void MediaObject::loadingComplete()
+{
+ if (m_videoStreamFound) {
+ MediaNodeEvent event(MediaNodeEvent::VideoAvailable);
+ notify(&event);
+ }
+ getStreamInfo();
+ m_loading = false;
+
+ setState(m_pendingState);
+ emit metaDataChanged(m_metaData);
+}
+
+void MediaObject::getStreamInfo()
+{
+ updateSeekable();
+ updateTotalTime();
+
+ if (m_videoStreamFound != m_hasVideo) {
+ m_hasVideo = m_videoStreamFound;
+ emit hasVideoChanged(m_hasVideo);
+ }
+
+ m_availableTitles = 1;
+ gint64 titleCount;
+ GstFormat format = gst_format_get_by_nick("track");
+ if (gst_element_query_duration (m_pipeline, &format, &titleCount)) {
+ int oldAvailableTitles = m_availableTitles;
+ m_availableTitles = (int)titleCount;
+ if (m_availableTitles != oldAvailableTitles) {
+ emit availableTitlesChanged(m_availableTitles);
+ m_backend->logMessage(QString("Available titles changed: %0").arg(m_availableTitles), Backend::Info, this);
+ }
+ }
+
+}
+
+void MediaObject::setPrefinishMark(qint32 newPrefinishMark)
+{
+ m_prefinishMark = newPrefinishMark;
+ if (currentTime() < totalTime() - m_prefinishMark) // not about to finish
+ m_prefinishMarkReachedNotEmitted = true;
+}
+
+void MediaObject::pause()
+{
+ m_backend->logMessage("pause()", Backend::Info, this);
+ if (state() != Phonon::PausedState)
+ setState(Phonon::PausedState);
+ m_resumeState = false;
+}
+
+void MediaObject::stop()
+{
+ if (state() != Phonon::StoppedState) {
+ setState(Phonon::StoppedState);
+ m_prefinishMarkReachedNotEmitted = true;
+ }
+ m_resumeState = false;
+}
+
+void MediaObject::seek(qint64 time)
+{
+ if (!isValid())
+ return;
+
+ if (isSeekable()) {
+ switch (state()) {
+ case Phonon::PlayingState:
+ case Phonon::StoppedState:
+ case Phonon::PausedState:
+ case Phonon::BufferingState:
+ m_backend->logMessage(QString("Seek to pos %0").arg(time), Backend::Info, this);
+
+ if (time <= 0)
+ m_atStartOfStream = true;
+ else
+ m_atStartOfStream = false;
+
+ m_posAtSeek = getPipelinePos();
+ m_tickTimer->stop();
+
+ if (gst_element_seek(m_pipeline, 1.0, GST_FORMAT_TIME,
+ GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET,
+ time * GST_MSECOND, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE))
+ break;
+ case Phonon::LoadingState:
+ case Phonon::ErrorState:
+ return;
+ }
+
+ quint64 current = currentTime();
+ quint64 total = totalTime();
+
+ if (current < total - m_prefinishMark)
+ m_prefinishMarkReachedNotEmitted = true;
+ if (current < total - ABOUT_TO_FINNISH_TIME)
+ m_aboutToFinishEmitted = false;
+ m_atEndOfStream = false;
+ }
+}
+
+void MediaObject::emitTick()
+{
+ if (m_resumeState) {
+ return;
+ }
+
+ qint64 currentTime = getPipelinePos();
+ qint64 totalTime = m_totalTime;
+
+ if (m_tickInterval > 0 && currentTime != m_previousTickTime) {
+ emit tick(currentTime);
+ m_previousTickTime = currentTime;
+ }
+ if (m_state == Phonon::PlayingState) {
+ if (currentTime >= totalTime - m_prefinishMark) {
+ if (m_prefinishMarkReachedNotEmitted) {
+ m_prefinishMarkReachedNotEmitted = false;
+ emit prefinishMarkReached(totalTime - currentTime);
+ }
+ }
+ // Prepare load of next source
+ if (currentTime >= totalTime - ABOUT_TO_FINNISH_TIME) {
+ if (!m_aboutToFinishEmitted) {
+ m_aboutToFinishEmitted = true; // track is about to finish
+ emit aboutToFinish();
+ }
+ }
+ }
+}
+
+
+/*
+ * Used to iterate through the gst_tag_list and extract values
+ */
+void foreach_tag_function(const GstTagList *list, const gchar *tag, gpointer user_data)
+{
+ TagMap *newData = static_cast<TagMap *>(user_data);
+ QString value;
+ GType type = gst_tag_get_type(tag);
+ switch (type) {
+ case G_TYPE_STRING: {
+ char *str = 0;
+ gst_tag_list_get_string(list, tag, &str);
+ value = QString::fromUtf8(str);
+ g_free(str);
+ }
+ break;
+
+ case G_TYPE_BOOLEAN: {
+ int bval;
+ gst_tag_list_get_boolean(list, tag, &bval);
+ value = QString::number(bval);
+ }
+ break;
+
+ case G_TYPE_INT: {
+ int ival;
+ gst_tag_list_get_int(list, tag, &ival);
+ value = QString::number(ival);
+ }
+ break;
+
+ case G_TYPE_UINT: {
+ unsigned int uival;
+ gst_tag_list_get_uint(list, tag, &uival);
+ value = QString::number(uival);
+ }
+ break;
+
+ case G_TYPE_FLOAT: {
+ float fval;
+ gst_tag_list_get_float(list, tag, &fval);
+ value = QString::number(fval);
+ }
+ break;
+
+ case G_TYPE_DOUBLE: {
+ double dval;
+ gst_tag_list_get_double(list, tag, &dval);
+ value = QString::number(dval);
+ }
+ break;
+
+ default:
+ //qDebug("Unsupported tag type: %s", g_type_name(type));
+ break;
+ }
+
+ QString key = QString(tag).toUpper();
+ QString currVal = newData->value(key);
+ if (!value.isEmpty() && !(newData->contains(key) && currVal == value))
+ newData->insert(key, value);
+}
+
+/**
+ * Triggers playback after a song has completed in the current media queue
+ */
+void MediaObject::beginPlay()
+{
+ setSource(m_nextSource);
+ m_nextSource = MediaSource();
+ m_pendingState = Phonon::PlayingState;
+}
+
+/**
+ * Handle GStreamer bus messages
+ */
+void MediaObject::handleBusMessage(const Message &message)
+{
+
+ if (!isValid())
+ return;
+
+ GstMessage *gstMessage = message.rawMessage();
+ Q_ASSERT(m_pipeline);
+
+ if (m_backend->debugLevel() >= Backend::Debug) {
+ int type = GST_MESSAGE_TYPE(gstMessage);
+ gchar* name = gst_element_get_name(gstMessage->src);
+ QString msgString = QString("Bus: %0 (%1)").arg(gst_message_type_get_name ((GstMessageType)type)).arg(name);
+ g_free(name);
+ m_backend->logMessage(msgString, Backend::Debug, this);
+ }
+
+ switch (GST_MESSAGE_TYPE (gstMessage)) {
+
+ case GST_MESSAGE_EOS:
+ m_backend->logMessage("EOS recieved", Backend::Info, this);
+ handleEndOfStream();
+ break;
+
+ case GST_MESSAGE_TAG: {
+ GstTagList* tag_list = 0;
+ gst_message_parse_tag(gstMessage, &tag_list);
+ if (tag_list) {
+ TagMap oldMap = m_metaData; // Keep a copy of the old one for reference
+ // Append any new meta tags to the existing tag list
+ gst_tag_list_foreach (tag_list, &foreach_tag_function, &m_metaData);
+ m_backend->logMessage("Meta tags found", Backend::Info, this);
+ if (oldMap != m_metaData && !m_loading)
+ emit metaDataChanged(m_metaData);
+ gst_tag_list_free(tag_list);
+ }
+ }
+ break;
+
+ case GST_MESSAGE_STATE_CHANGED : {
+
+ if (gstMessage->src != GST_OBJECT(m_pipeline))
+ return;
+
+ GstState oldState;
+ GstState newState;
+ GstState pendingState;
+ gst_message_parse_state_changed (gstMessage, &oldState, &newState, &pendingState);
+
+ if (newState == pendingState)
+ return;
+
+ m_posAtSeek = -1;
+
+ switch (newState) {
+
+ case GST_STATE_PLAYING :
+ m_atStartOfStream = false;
+ m_backend->logMessage("gstreamer: pipeline state set to playing", Backend::Info, this);
+ m_tickTimer->start();
+ changeState(Phonon::PlayingState);
+ if (m_resumeState && m_oldState == Phonon::PlayingState) {
+ seek(m_oldPos);
+ m_resumeState = false;
+ }
+ break;
+
+ case GST_STATE_NULL:
+ m_backend->logMessage("gstreamer: pipeline state set to null", Backend::Info, this);
+ m_tickTimer->stop();
+ break;
+
+ case GST_STATE_PAUSED :
+ m_backend->logMessage("gstreamer: pipeline state set to paused", Backend::Info, this);
+ m_tickTimer->start();
+ if (state() == Phonon::LoadingState) {
+ // No_more_pads is not emitted from the decodebin in older versions (0.10.4)
+ noMorePadsAvailable();
+ loadingComplete();
+ } else if (m_resumeState && m_oldState == Phonon::PausedState) {
+ changeState(Phonon::PausedState);
+ m_resumeState = false;
+ break;
+ } else {
+ // A lot of autotests can break if we allow all paused changes through.
+ if (m_pendingState == Phonon::PausedState) {
+ changeState(Phonon::PausedState);
+ }
+ }
+ break;
+
+ case GST_STATE_READY :
+ if (!m_loading && m_pendingState == Phonon::StoppedState)
+ changeState(Phonon::StoppedState);
+ m_backend->logMessage("gstreamer: pipeline state set to ready", Backend::Debug, this);
+ m_tickTimer->stop();
+ break;
+
+ case GST_STATE_VOID_PENDING :
+ m_backend->logMessage("gstreamer: pipeline state set to pending (void)", Backend::Debug, this);
+ m_tickTimer->stop();
+ break;
+ }
+ break;
+ }
+
+ case GST_MESSAGE_ERROR: {
+ gchar *debug;
+ GError *err;
+ QString logMessage;
+ gst_message_parse_error (gstMessage, &err, &debug);
+ gchar *errorMessage = gst_error_get_message (err->domain, err->code);
+ logMessage.sprintf("Error: %s Message:%s (%s) Code:%d", debug, err->message, errorMessage, err->code);
+ m_backend->logMessage(logMessage, Backend::Warning);
+ g_free(errorMessage);
+ g_free (debug);
+
+ if (err->domain == GST_RESOURCE_ERROR) {
+ if (err->code == GST_RESOURCE_ERROR_NOT_FOUND) {
+ setError(tr("Could not locate media source."), Phonon::FatalError);
+ } else if (err->code == GST_RESOURCE_ERROR_OPEN_READ) {
+ setError(tr("Could not open media source."), Phonon::FatalError);
+ } else if (err->code == GST_RESOURCE_ERROR_BUSY) {
+ // We need to check if this comes from an audio device by looking at sink caps
+ GstPad* sinkPad = gst_element_get_static_pad(GST_ELEMENT(gstMessage->src), "sink");
+ if (sinkPad) {
+ GstCaps *caps = gst_pad_get_caps (sinkPad);
+ GstStructure *str = gst_caps_get_structure (caps, 0);
+ if (g_strrstr (gst_structure_get_name (str), "audio"))
+ setError(tr("Could not open audio device. The device is already in use."), Phonon::NormalError);
+ else
+ setError(err->message, Phonon::FatalError);
+ gst_caps_unref (caps);
+ gst_object_unref (sinkPad);
+ }
+ } else {
+ setError(QString(err->message), Phonon::FatalError);
+ }
+ } else if (err->domain == GST_STREAM_ERROR) {
+ switch (err->code) {
+ case GST_STREAM_ERROR_WRONG_TYPE:
+ case GST_STREAM_ERROR_TYPE_NOT_FOUND:
+ setError(tr("Could not decode media source."), Phonon::FatalError);
+ break;
+ default:
+ setError(tr("Could not open media source."), Phonon::FatalError);
+ break;
+ }
+ } else {
+ setError(QString(err->message), Phonon::FatalError);
+ }
+ g_error_free (err);
+ break;
+ }
+
+ case GST_MESSAGE_WARNING: {
+ gchar *debug;
+ GError *err;
+ gst_message_parse_warning(gstMessage, &err, &debug);
+ QString msgString;
+ msgString.sprintf("Warning: %s\nMessage:%s", debug, err->message);
+ m_backend->logMessage(msgString, Backend::Warning);
+ g_free (debug);
+ g_error_free (err);
+ break;
+ }
+
+ case GST_MESSAGE_ELEMENT: {
+ GstMessage *gstMessage = message.rawMessage();
+ const GstStructure *gstStruct = gst_message_get_structure(gstMessage); //do not free this
+ if (g_strrstr (gst_structure_get_name (gstStruct), "prepare-xwindow-id")) {
+ MediaNodeEvent videoHandleEvent(MediaNodeEvent::VideoHandleRequest);
+ notify(&videoHandleEvent);
+ }
+ break;
+ }
+
+ case GST_MESSAGE_DURATION: {
+ m_backend->logMessage("GST_MESSAGE_DURATION", Backend::Debug, this);
+ updateTotalTime();
+ break;
+ }
+
+ case GST_MESSAGE_BUFFERING: {
+ gint percent = 0;
+ gst_structure_get_int (gstMessage->structure, "buffer-percent", &percent); //gst_message_parse_buffering was introduced in 0.10.11
+
+ if (m_bufferPercent != percent) {
+ emit bufferStatus(percent);
+ m_backend->logMessage(QString("Stream buffering %0").arg(percent), Backend::Debug, this);
+ m_bufferPercent = percent;
+ }
+
+ if (m_state != Phonon::BufferingState)
+ emit stateChanged(m_state, Phonon::BufferingState);
+ else if (percent == 100)
+ emit stateChanged(Phonon::BufferingState, m_state);
+ break;
+ }
+ //case GST_MESSAGE_INFO:
+ //case GST_MESSAGE_STREAM_STATUS:
+ //case GST_MESSAGE_CLOCK_PROVIDE:
+ //case GST_MESSAGE_NEW_CLOCK:
+ //case GST_MESSAGE_STEP_DONE:
+ //case GST_MESSAGE_LATENCY: only from 0.10.12
+ //case GST_MESSAGE_ASYNC_DONE: only from 0.10.13
+ default:
+ break;
+ }
+}
+
+void MediaObject::handleEndOfStream()
+{
+ // If the stream is not seekable ignore
+ // otherwise chained radio broadcasts would stop
+
+
+ if (m_atEndOfStream)
+ return;
+
+ if (!m_seekable)
+ m_atEndOfStream = true;
+
+ if (m_autoplayTitles &&
+ m_availableTitles > 1 &&
+ m_currentTitle < m_availableTitles) {
+ _iface_setCurrentTitle(m_currentTitle + 1);
+ return;
+ }
+
+ if (m_nextSource.type() != MediaSource::Invalid
+ && m_nextSource.type() != MediaSource::Empty) { // We only emit finish when the queue is actually empty
+ QTimer::singleShot (qMax(0, transitionTime()), this, SLOT(beginPlay()));
+ } else {
+ m_pendingState = Phonon::PausedState;
+ emit finished();
+ if (!m_seekable) {
+ setState(Phonon::StoppedState);
+ // Note the behavior for live streams is not properly defined
+ // But since we cant seek to 0, we don't have much choice other than stopping
+ // the stream
+ } else {
+ // Only emit paused if the finished signal
+ // did not result in a new state
+ if (m_pendingState == Phonon::PausedState)
+ setState(m_pendingState);
+ }
+ }
+}
+
+// Notifes the pipeline about state changes in the media object
+void MediaObject::notifyStateChange(Phonon::State newstate, Phonon::State oldstate)
+{
+ Q_UNUSED(oldstate);
+ MediaNodeEvent event(MediaNodeEvent::StateChanged, &newstate);
+ notify(&event);
+}
+
+#ifndef QT_NO_PHONON_MEDIACONTROLLER
+//interface management
+bool MediaObject::hasInterface(Interface iface) const
+{
+ return iface == AddonInterface::TitleInterface;
+}
+
+QVariant MediaObject::interfaceCall(Interface iface, int command, const QList<QVariant> &params)
+{
+ if (hasInterface(iface)) {
+
+ switch (iface)
+ {
+ case TitleInterface:
+ switch (command)
+ {
+ case availableTitles:
+ return _iface_availableTitles();
+ case title:
+ return _iface_currentTitle();
+ case setTitle:
+ _iface_setCurrentTitle(params.first().toInt());
+ break;
+ case autoplayTitles:
+ return m_autoplayTitles;
+ case setAutoplayTitles:
+ m_autoplayTitles = params.first().toBool();
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ return QVariant();
+}
+#endif
+
+int MediaObject::_iface_availableTitles() const
+{
+ return m_availableTitles;
+}
+
+int MediaObject::_iface_currentTitle() const
+{
+ return m_currentTitle;
+}
+
+void MediaObject::_iface_setCurrentTitle(int title)
+{
+ GstFormat trackFormat = gst_format_get_by_nick("track");
+ m_backend->logMessage(QString("setCurrentTitle %0").arg(title), Backend::Info, this);
+ if ((title == m_currentTitle) || (title < 1) || (title > m_availableTitles))
+ return;
+
+ m_currentTitle = title;
+
+ //let's seek to the beginning of the song
+ if (gst_element_seek_simple(m_pipeline, trackFormat, GST_SEEK_FLAG_FLUSH, m_currentTitle - 1)) {
+ updateTotalTime();
+ m_atEndOfStream = false;
+ emit titleChanged(title);
+ emit totalTimeChanged(totalTime());
+ }
+}
+
+} // ns Gstreamer
+} // ns Phonon
+
+QT_END_NAMESPACE
+
+#include "moc_mediaobject.cpp"
diff --git a/src/3rdparty/phonon/gstreamer/mediaobject.h b/src/3rdparty/phonon/gstreamer/mediaobject.h
new file mode 100644
index 0000000000..64b3510b47
--- /dev/null
+++ b/src/3rdparty/phonon/gstreamer/mediaobject.h
@@ -0,0 +1,294 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef Phonon_GSTREAMER_MEDIAOBJECT_H
+#define Phonon_GSTREAMER_MEDIAOBJECT_H
+
+#include "backend.h"
+#include "common.h"
+#include "medianode.h"
+#include <phonon/mediaobjectinterface.h>
+#include <phonon/addoninterface.h>
+
+#include <QtCore/QHash>
+#include <QtCore/QString>
+#include <QtCore/QVariant>
+#include <QtCore/QObject>
+#include <QtCore/QDate>
+#include <QtCore/QEvent>
+#include <QtCore/QUrl>
+#include <gst/gst.h>
+
+QT_BEGIN_NAMESPACE
+
+class QTimer;
+typedef QMultiMap<QString, QString> TagMap;
+
+namespace Phonon
+{
+namespace Gstreamer
+{
+
+class VideoWidget;
+class AudioPath;
+class VideoPath;
+class AudioOutput;
+
+class MediaObject : public QObject, public MediaObjectInterface
+#ifndef QT_NO_PHONON_MEDIACONTROLLER
+ , public AddonInterface
+#endif
+ , public MediaNode
+{
+ friend class Stream;
+ Q_OBJECT
+ Q_INTERFACES(Phonon::MediaObjectInterface
+#ifndef QT_NO_PHONON_MEDIACONTROLLER
+ Phonon::AddonInterface
+#endif
+ Phonon::Gstreamer::MediaNode
+ )
+
+public:
+
+ MediaObject(Backend *backend, QObject *parent);
+ ~MediaObject();
+ Phonon::State state() const;
+
+ bool hasVideo() const;
+ bool isSeekable() const;
+
+ qint64 currentTime() const;
+ qint32 tickInterval() const;
+
+ void setTickInterval(qint32 newTickInterval);
+
+ void play();
+ void pause();
+ void stop();
+ void seek(qint64 time);
+
+ QString errorString() const;
+ Phonon::ErrorType errorType() const;
+
+ QUrl url() const;
+ qint64 totalTime() const;
+
+ qint32 prefinishMark() const;
+ void setPrefinishMark(qint32 newPrefinishMark);
+
+ qint32 transitionTime() const;
+ void setTransitionTime(qint32);
+ qint64 remainingTime() const;
+
+ void setSource(const MediaSource &source);
+ void setNextSource(const MediaSource &source);
+ MediaSource source() const;
+
+ // No additional interfaces currently supported
+#ifndef QT_NO_PHONON_MEDIACONTROLLER
+ bool hasInterface(Interface) const;
+ QVariant interfaceCall(Interface, int, const QList<QVariant> &);
+#endif
+ bool isLoading()
+ {
+ return m_loading;
+ }
+
+ bool audioAvailable()
+ {
+ return m_hasAudio;
+ }
+
+ bool videoAvailable()
+ {
+ return m_hasVideo;
+ }
+
+ GstElement *audioGraph()
+ {
+ return m_audioGraph;
+ }
+
+ GstElement *videoGraph()
+ {
+ return m_videoGraph;
+ }
+
+ GstElement *pipeline()
+ {
+ return m_pipeline;
+ };
+
+ gulong capsHandler()
+ {
+ return m_capsHandler;
+ };
+
+ void connectVideo(GstPad *videoPad);
+ void connectAudio(GstPad *audioPad);
+ void handleBusMessage(const Message &msg);
+ void handleEndOfStream();
+ void addMissingCodecName(const QString &codec) { m_missingCodecs.append(codec); }
+ void invalidateGraph() {
+ m_resetNeeded = true;
+ if (m_state == Phonon::PlayingState || m_state == Phonon::PausedState) {
+ changeState(Phonon::StoppedState);
+ }
+ }
+ static void cb_newpad (GstElement *decodebin, GstPad *pad, gboolean last, gpointer data);
+ static void cb_pad_added (GstElement *decodebin, GstPad *pad, gpointer data);
+ static void cb_unknown_type (GstElement *decodebin, GstPad *pad, GstCaps *caps, gpointer data);
+ static void cb_no_more_pads (GstElement * decodebin, gpointer data);
+ void saveState();
+ void resumeState();
+
+public Q_SLOTS:
+ void setState(State);
+
+Q_SIGNALS:
+ void currentSourceChanged(const MediaSource &newSource);
+ void stateChanged(Phonon::State newstate, Phonon::State oldstate);
+ void tick(qint64 time);
+ void metaDataChanged(QMultiMap<QString, QString>);
+ void seekableChanged(bool);
+ void hasVideoChanged(bool);
+
+ void finished();
+ void prefinishMarkReached(qint32);
+ void aboutToFinish();
+ void totalTimeChanged(qint64 length);
+ void bufferStatus(int percentFilled);
+
+ QMultiMap<QString, QString> metaData();
+ void setMetaData(QMultiMap<QString, QString> newData);
+
+ // AddonInterface:
+ void titleChanged(int);
+ void availableTitlesChanged(int);
+
+ // Not implemented
+ void chapterChanged(int);
+ void availableChaptersChanged(int);
+ void angleChanged(int);
+ void availableAnglesChanged(int);
+
+ void availableSubtitlesChanged();
+ void availableAudioChannelsChanged();
+
+protected:
+ void beginLoad();
+ void loadingComplete();
+ void newPadAvailable (GstPad *pad);
+ void changeState(State);
+ void setError(const QString &errorString, Phonon::ErrorType error = NormalError);
+ /*
+ * @param encodedUrl percent-encoded QString for source compat reasons. Should change to QUrl
+ */
+ bool createPipefromURL(const QUrl &url);
+ bool createPipefromStream(const MediaSource &);
+
+private Q_SLOTS:
+ void noMorePadsAvailable();
+ void getStreamInfo();
+ void emitTick();
+ void beginPlay();
+ void setVideoCaps(GstCaps *caps);
+ void notifyStateChange(Phonon::State newstate, Phonon::State oldstate);
+protected:
+ GstElement *audioElement()
+ {
+ Q_ASSERT(m_audioPipe);
+ return m_audioPipe;
+ }
+
+ GstElement *videoElement()
+ {
+ Q_ASSERT(m_videoPipe);
+ return m_videoPipe;
+ }
+
+private:
+
+ // GStreamer specific :
+ void createPipeline();
+ bool addToPipeline(GstElement *elem);
+ void setTotalTime(qint64 newTime);
+ void getStreamsInfo();
+ bool updateTotalTime();
+ void updateSeekable();
+ qint64 getPipelinePos() const;
+
+ int _iface_availableTitles() const;
+ int _iface_currentTitle() const;
+ void _iface_setCurrentTitle(int title);
+
+ bool m_resumeState;
+ State m_oldState;
+ quint64 m_oldPos;
+
+ State m_state;
+ State m_pendingState;
+ QTimer *m_tickTimer;
+ qint32 m_tickInterval;
+
+ MediaSource m_source;
+ MediaSource m_nextSource;
+ qint32 m_prefinishMark;
+ qint32 m_transitionTime;
+
+ qint64 m_posAtSeek;
+
+ bool m_prefinishMarkReachedNotEmitted;
+ bool m_aboutToFinishEmitted;
+ bool m_loading;
+ gulong m_capsHandler;
+
+ GstElement *m_datasource;
+ GstElement *m_decodebin;
+
+ GstElement *m_audioPipe;
+ GstElement *m_videoPipe;
+
+ qint64 m_totalTime;
+ int m_bufferPercent;
+ bool m_hasVideo;
+ bool m_videoStreamFound;
+ bool m_hasAudio;
+ bool m_seekable;
+ bool m_atEndOfStream;
+ bool m_atStartOfStream;
+ Phonon::ErrorType m_error;
+ QString m_errorString;
+
+ GstElement *m_pipeline;
+ GstElement *m_audioGraph;
+ GstElement *m_videoGraph;
+ int m_previousTickTime;
+ bool m_resetNeeded;
+ QStringList m_missingCodecs;
+ QMultiMap<QString, QString> m_metaData;
+ bool m_autoplayTitles;
+ int m_availableTitles;
+ int m_currentTitle;
+};
+}
+} //namespace Phonon::Gstreamer
+
+QT_END_NAMESPACE
+
+#endif // Phonon_GSTREAMER_MEDIAOBJECT_H
diff --git a/src/3rdparty/phonon/gstreamer/message.cpp b/src/3rdparty/phonon/gstreamer/message.cpp
new file mode 100644
index 0000000000..154e0bbccd
--- /dev/null
+++ b/src/3rdparty/phonon/gstreamer/message.cpp
@@ -0,0 +1,75 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <gst/gst.h>
+
+#include "message.h"
+
+
+QT_BEGIN_NAMESPACE
+
+static int wuchi = qRegisterMetaType<Phonon::Gstreamer::Message>();
+
+namespace Phonon
+{
+namespace Gstreamer
+{
+
+/*!
+ \class gstreamer::Message
+ \internal
+*/
+Message::Message():
+ m_message(0),
+ m_source(0)
+{}
+
+Message::Message(GstMessage* message, MediaObject *source):
+ m_message(message),
+ m_source(source)
+{
+ Q_ASSERT(m_message);
+ gst_message_ref(m_message);
+}
+
+Message::Message(const Message &other)
+{
+ m_message = other.m_message;
+ gst_message_ref(m_message);
+ m_source = other.m_source;
+}
+
+Message::~Message()
+{
+ gst_message_unref(m_message);
+}
+
+GstMessage* Message::rawMessage() const
+{
+ return m_message;
+}
+
+MediaObject *Message::source() const
+{
+ return m_source;
+}
+
+} // ns gstreamer
+} // ns phonon
+
+QT_END_NAMESPACE
+
diff --git a/src/3rdparty/phonon/gstreamer/message.h b/src/3rdparty/phonon/gstreamer/message.h
new file mode 100644
index 0000000000..cadb948620
--- /dev/null
+++ b/src/3rdparty/phonon/gstreamer/message.h
@@ -0,0 +1,58 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef Phonon_GSTREAMER_MESSAGE_H
+#define Phonon_GSTREAMER_MESSAGE_H
+
+#include "common.h"
+
+#include <QtCore/QMetaType>
+
+#include <gst/gst.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace Gstreamer
+{
+
+class MediaObject;
+class Message
+{
+public:
+ Message();
+ Message(GstMessage* message, MediaObject *source);
+ ~Message();
+
+ GstMessage* rawMessage() const;
+ MediaObject *source() const;
+ Message(const Message &other);
+
+private:
+ GstMessage* m_message;
+ MediaObject *m_source;
+};
+
+} // ns gstreamer
+} // ns phonon
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(Phonon::Gstreamer::Message)
+
+#endif // Phonon_GSTREAMER_MESSAGE_H
diff --git a/src/3rdparty/phonon/gstreamer/phononsrc.cpp b/src/3rdparty/phonon/gstreamer/phononsrc.cpp
new file mode 100644
index 0000000000..f893fb50b8
--- /dev/null
+++ b/src/3rdparty/phonon/gstreamer/phononsrc.cpp
@@ -0,0 +1,257 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library 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, either version 2.1 or 3 of the License.
+
+This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <gst/gst.h>
+#include <gst/base/gstbasesrc.h>
+#include "phononsrc.h"
+#include "streamreader.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace Gstreamer
+{
+
+static GstStaticPadTemplate srctemplate =
+ GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS_ANY);
+
+GST_DEBUG_CATEGORY_STATIC (phonon_src_debug);
+
+// PhononSrc args
+enum
+{
+ ARG_0,
+ ARG_PHONONSRC
+};
+
+static void phonon_src_finalize (GObject * object);
+
+static void phonon_src_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void phonon_src_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+static gboolean phonon_src_start (GstBaseSrc * basesrc);
+static gboolean phonon_src_stop (GstBaseSrc * basesrc);
+
+static gboolean phonon_src_is_seekable (GstBaseSrc * src);
+static gboolean phonon_src_get_size (GstBaseSrc * src, guint64 * size);
+static GstFlowReturn phonon_src_create (GstBaseSrc * src, guint64 offset,
+ guint length, GstBuffer ** buffer);
+
+static void _do_init (GType filesrc_type)
+{
+ Q_UNUSED(filesrc_type);
+ GST_DEBUG_CATEGORY_INIT (phonon_src_debug, "phononsrc", 0, "QIODevice element");
+}
+
+GST_BOILERPLATE_FULL (PhononSrc, phonon_src, GstBaseSrc, GST_TYPE_BASE_SRC, _do_init)
+
+// Register element details
+static void phonon_src_base_init (gpointer g_class) {
+ GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
+ static gchar longname[] = "Phonon Stream Source",
+ klass[] = "Source/File",
+ description[] = "Read from a Phonon StreamInterface",
+ author[] = "Nokia Corporation and/or its subsidiary(-ies) <qt-info@nokia.com>";
+ GstElementDetails details = GST_ELEMENT_DETAILS (longname,
+ klass,
+ description,
+ author);
+ gst_element_class_set_details (gstelement_class, &details);
+ gst_element_class_add_pad_template (gstelement_class, gst_static_pad_template_get (&srctemplate));
+}
+
+static void phonon_src_class_init (PhononSrcClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+ GstBaseSrcClass *gstbasesrc_class;
+
+ gobject_class = G_OBJECT_CLASS (klass);
+ gstelement_class = GST_ELEMENT_CLASS (klass);
+ gstbasesrc_class = GST_BASE_SRC_CLASS (klass);
+
+ gobject_class->set_property = phonon_src_set_property;
+ gobject_class->get_property = phonon_src_get_property;
+
+ g_object_class_install_property (gobject_class, ARG_PHONONSRC,
+ g_param_spec_pointer ("iodevice", "A Phonon StreamReader",
+ "A Phonon::GStreamer::StreamReader to read from", GParamFlags(G_PARAM_READWRITE)));
+
+ gobject_class->finalize = GST_DEBUG_FUNCPTR (phonon_src_finalize);
+
+ gstbasesrc_class->start = GST_DEBUG_FUNCPTR (phonon_src_start);
+ gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (phonon_src_stop);
+ gstbasesrc_class->is_seekable = GST_DEBUG_FUNCPTR (phonon_src_is_seekable);
+ gstbasesrc_class->get_size = GST_DEBUG_FUNCPTR (phonon_src_get_size);
+ gstbasesrc_class->create = GST_DEBUG_FUNCPTR (phonon_src_create);
+}
+
+static void phonon_src_init (PhononSrc * src, PhononSrcClass * g_class)
+{
+ Q_UNUSED(g_class);
+ src->device = 0;
+}
+
+static void phonon_src_finalize (GObject * object)
+{
+ PhononSrc *src;
+ src = GST_PHONON_SRC (object);
+ delete src->device;
+ src->device = 0;
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static gboolean phonon_src_set_device(PhononSrc * src, StreamReader* device)
+{
+ GstState state;
+ // The element must be stopped in order to do this
+ GST_OBJECT_LOCK (src);
+ state = GST_STATE (src);
+
+ if (state != GST_STATE_READY && state != GST_STATE_NULL)
+ goto wrong_state;
+
+ GST_OBJECT_UNLOCK (src);
+
+ src->device = device;
+ g_object_notify (G_OBJECT (src), "iodevice");
+ return TRUE;
+
+ // Error
+wrong_state:
+ {
+ //GST_DEBUG_OBJECT (src, "setting location in wrong state");
+ GST_OBJECT_UNLOCK (src);
+ return FALSE;
+ }
+}
+
+static void phonon_src_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+ PhononSrc *src;
+ g_return_if_fail (GST_IS_PHONON_SRC (object));
+ src = GST_PHONON_SRC (object);
+
+ switch (prop_id) {
+ case ARG_PHONONSRC:
+ {
+ StreamReader *dev = (StreamReader*)(g_value_get_pointer(value));
+ if (dev)
+ phonon_src_set_device(src, dev);
+ break;
+ }
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void phonon_src_get_property (GObject * object, guint prop_id, GValue * value,
+ GParamSpec * pspec)
+{
+ PhononSrc *src;
+ g_return_if_fail (GST_IS_PHONON_SRC (object));
+ src = GST_PHONON_SRC (object);
+
+ switch (prop_id) {
+ case ARG_PHONONSRC:
+ g_value_set_pointer(value, src->device);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static GstFlowReturn phonon_src_create_read (PhononSrc * src, guint64 offset, guint length, GstBuffer ** buffer)
+{
+ Q_ASSERT(src->device);
+ if (!src->device)
+ return GST_FLOW_ERROR;
+
+ GstBuffer *buf = gst_buffer_new_and_alloc (length);
+ GST_BUFFER_SIZE (buf) = length;
+ GST_BUFFER_OFFSET (buf) = offset;
+ GST_BUFFER_OFFSET_END (buf) = offset + length;
+
+ bool success = src->device->read(offset, length, (char*)GST_BUFFER_DATA (buf));
+ //GST_LOG_OBJECT (src, "Reading %d bytes", length);
+
+ if (success) {
+ *buffer = buf;
+ return GST_FLOW_OK;
+ }
+
+ gst_mini_object_unref(GST_MINI_OBJECT(buf));
+ return GST_FLOW_ERROR;
+}
+
+static GstFlowReturn phonon_src_create (GstBaseSrc * basesrc, guint64 offset, guint length, GstBuffer ** buffer)
+{
+ PhononSrc *src;
+ GstFlowReturn ret;
+ src = GST_PHONON_SRC (basesrc);
+ ret = phonon_src_create_read (src, offset, length, buffer);
+ return ret;
+}
+
+static gboolean phonon_src_is_seekable (GstBaseSrc * basesrc)
+{
+ PhononSrc *src = GST_PHONON_SRC (basesrc);
+ if (src->device)
+ return src->device->streamSeekable();
+ return false;
+}
+
+static gboolean phonon_src_get_size (GstBaseSrc * basesrc, guint64 * size)
+{
+ PhononSrc *src;
+ src = GST_PHONON_SRC (basesrc);
+ if (src->device && src->device->streamSeekable()) {
+ *size = src->device->streamSize();
+ return TRUE;
+ }
+ *size = 0;
+ return FALSE;
+}
+
+// Necessary to go to READY state
+static gboolean phonon_src_start (GstBaseSrc * basesrc)
+{
+ Q_UNUSED(basesrc);
+ // Opening the device is handled by the frontend
+ // We can only assume it is already open
+ return TRUE;
+}
+
+static gboolean phonon_src_stop (GstBaseSrc * basesrc)
+{
+ Q_UNUSED(basesrc);
+ // Closing the device is handled by the frontend
+ return TRUE;
+}
+
+}
+} //namespace Phonon::Gstreamer
+
+QT_END_NAMESPACE
diff --git a/src/3rdparty/phonon/gstreamer/phononsrc.h b/src/3rdparty/phonon/gstreamer/phononsrc.h
new file mode 100644
index 0000000000..a2cd8b39ff
--- /dev/null
+++ b/src/3rdparty/phonon/gstreamer/phononsrc.h
@@ -0,0 +1,69 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library 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, either version 2.1 or 3 of the License.
+
+This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __PHONON_SRC_H__
+#define __PHONON_SRC_H__
+
+#include <sys/types.h>
+#include <gst/gst.h>
+#include <gst/base/gstbasesrc.h>
+#include "streamreader.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace Gstreamer
+{
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_PHONON_SRC \
+ (phonon_src_get_type())
+#define GST_PHONON_SRC(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PHONON_SRC,PhononSrc))
+#define GST_PHONON_SRC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PHONON_SRC,PhononSrcClass))
+#define GST_IS_PHONON_SRC(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PHONON_SRC))
+#define GST_IS_PHONON_SRC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PHONON_SRC))
+
+typedef struct _PhononSrc PhononSrc;
+typedef struct _PhononSrcClass PhononSrcClass;
+
+// PhononSrc:
+struct _PhononSrc {
+ GstBaseSrc element;
+ StreamReader *device;
+};
+
+struct _PhononSrcClass {
+ GstBaseSrcClass parent_class;
+};
+
+GType phonon_src_get_type (void);
+
+G_END_DECLS
+
+}
+} //namespace Phonon::Gstreamer
+
+QT_END_NAMESPACE
+
+
+#endif // __PHONON_SRC_H__
diff --git a/src/3rdparty/phonon/gstreamer/qwidgetvideosink.cpp b/src/3rdparty/phonon/gstreamer/qwidgetvideosink.cpp
new file mode 100644
index 0000000000..89d5a9db9e
--- /dev/null
+++ b/src/3rdparty/phonon/gstreamer/qwidgetvideosink.cpp
@@ -0,0 +1,221 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <QApplication>
+#include "videowidget.h"
+#include "qwidgetvideosink.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace Gstreamer
+{
+
+static GstVideoSinkClass* parentClass;
+
+/*!
+ \class gstreamer::QWidgetVideoSink
+ \internal
+*/
+
+template <VideoFormat FMT>
+GstCaps* QWidgetVideoSink<FMT>::get_caps(GstBaseSink* sink)
+{
+ Q_UNUSED(sink);
+ return 0;
+}
+
+template <>
+const char* QWidgetVideoSinkClass<VideoFormat_YUV>::get_name()
+{
+ return "QWidgetVideoSinkYUV";
+}
+
+template <>
+const char* QWidgetVideoSinkClass<VideoFormat_RGB>::get_name()
+{
+ return "QWidgetVideoSinkRGB";
+}
+
+template <VideoFormat FMT>
+gboolean QWidgetVideoSink<FMT>::set_caps(GstBaseSink* sink, GstCaps* caps)
+{
+ GstStructure* data;
+ QWidgetVideoSink<FMT> *self = G_TYPE_CHECK_INSTANCE_CAST(sink, QWidgetVideoSinkClass<FMT>::get_type(), QWidgetVideoSink<FMT>);
+
+ data = gst_caps_get_structure(caps, 0);
+
+ gst_structure_get_int(data, "width", &self->width);
+ gst_structure_get_int(data, "height", &self->height);
+ gst_structure_get_int(data, "bpp", &self->bpp);
+ gst_structure_get_int(data, "depth", &self->depth);
+ return TRUE;
+}
+
+template <VideoFormat FMT>
+GstStateChangeReturn QWidgetVideoSink<FMT>::change_state(GstElement* element, GstStateChange transition)
+{
+ return GST_ELEMENT_CLASS(parentClass)->change_state(element, transition);
+}
+
+template <VideoFormat FMT>
+GstFlowReturn QWidgetVideoSink<FMT>::render(GstBaseSink* sink, GstBuffer* buf)
+{
+ GstFlowReturn rc = GST_FLOW_OK;
+
+ if (buf != 0)
+ {
+ QWidgetVideoSink<FMT> *self = G_TYPE_CHECK_INSTANCE_CAST(sink, QWidgetVideoSinkClass<FMT>::get_type(), QWidgetVideoSink<FMT>);
+ QByteArray frame;
+ frame.resize(buf->size);
+ memcpy(frame.data(), buf->data, buf->size);
+ NewFrameEvent *frameEvent = new NewFrameEvent(frame, self->width, self->height);
+ QApplication::postEvent(self->renderWidget, frameEvent);
+ }
+ else
+ rc = GST_FLOW_ERROR;
+ return rc;
+}
+
+static GstStaticPadTemplate template_factory_yuv =
+ GST_STATIC_PAD_TEMPLATE("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS("video/x-raw-yuv, "
+ "framerate = (fraction) [ 0, MAX ], "
+ "width = (int) [ 1, MAX ], "
+ "height = (int) [ 1, MAX ],"
+ "bpp = (int) 32"));
+
+static GstStaticPadTemplate template_factory_rgb =
+ 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 ],"
+ "bpp = (int) 32"));
+
+template <VideoFormat FMT>
+struct template_factory;
+
+
+template <>
+struct template_factory<VideoFormat_YUV>
+{
+ static GstStaticPadTemplate *getFactory()
+ {
+ return &template_factory_yuv;
+ }
+};
+
+template <>
+struct template_factory<VideoFormat_RGB>
+{
+ static GstStaticPadTemplate *getFactory()
+ {
+ return &template_factory_rgb;
+ }
+};
+
+template <VideoFormat FMT>
+void QWidgetVideoSink<FMT>::base_init(gpointer g_class)
+{
+ gst_element_class_add_pad_template(GST_ELEMENT_CLASS(g_class),
+ gst_static_pad_template_get(template_factory<FMT>::getFactory()));
+}
+
+template <VideoFormat FMT>
+void QWidgetVideoSink<FMT>::instance_init(GTypeInstance *instance, gpointer g_class)
+{
+ Q_UNUSED(g_class);
+
+ QWidgetVideoSink<FMT>* self = reinterpret_cast<QWidgetVideoSink<FMT>*>(instance);
+
+ self->renderWidget = 0;
+ self->width = 0;
+ self->height = 0;
+ self->bpp = 0;
+ self->depth = 0;
+}
+
+// QWidgetVideoSinkClass
+template <VideoFormat FMT>
+void QWidgetVideoSinkClass<FMT>::class_init(gpointer g_class, gpointer class_data)
+{
+ Q_UNUSED(class_data);
+ GstBaseSinkClass* gstBaseSinkClass = (GstBaseSinkClass*)g_class;
+ GstElementClass* gstElementClass = (GstElementClass*)g_class;
+
+ parentClass = reinterpret_cast<GstVideoSinkClass*>(g_type_class_peek_parent(g_class));
+
+ // base
+ gstBaseSinkClass->set_caps = QWidgetVideoSink<FMT>::set_caps;
+ gstBaseSinkClass->preroll = QWidgetVideoSink<FMT>::render;
+ gstBaseSinkClass->render = QWidgetVideoSink<FMT>::render;
+
+ // element
+ gstElementClass->change_state = QWidgetVideoSink<FMT>::change_state;
+}
+
+template <VideoFormat FMT>
+GType QWidgetVideoSinkClass<FMT>::get_type()
+{
+ static GType type = 0;
+
+ if (type == 0)
+ {
+ static const GTypeInfo info =
+ {
+ sizeof(QWidgetVideoSinkClass<FMT>), // class_size
+ QWidgetVideoSink<FMT>::base_init, // base init
+ NULL, // base_finalize
+
+ QWidgetVideoSinkClass<FMT>::class_init, // class_init
+ NULL, // class_finalize
+ NULL, // class_data
+
+ sizeof(QWidgetVideoSink<FMT>), // instance_size
+ 0, // n_preallocs
+ QWidgetVideoSink<FMT>::instance_init, // instance_init
+ 0 // value_table
+ };
+
+ type = g_type_register_static(GST_TYPE_VIDEO_SINK,
+ QWidgetVideoSinkClass<FMT>::get_name(),
+ &info,
+ GTypeFlags(0));
+ }
+ return type;
+}
+
+GType get_type_YUV()
+{
+ return QWidgetVideoSinkClass<VideoFormat_YUV>::get_type();
+}
+
+GType get_type_RGB()
+{
+ return QWidgetVideoSinkClass<VideoFormat_RGB>::get_type();
+}
+
+}
+} //namespace Phonon::Gstreamer
+
+QT_END_NAMESPACE
diff --git a/src/3rdparty/phonon/gstreamer/qwidgetvideosink.h b/src/3rdparty/phonon/gstreamer/qwidgetvideosink.h
new file mode 100644
index 0000000000..73a494a213
--- /dev/null
+++ b/src/3rdparty/phonon/gstreamer/qwidgetvideosink.h
@@ -0,0 +1,97 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef Phonon_GSTREAMER_VIDEOSINK_H
+#define Phonon_GSTREAMER_VIDEOSINK_H
+
+#include "common.h"
+
+#include <QtCore/QByteArray>
+#include <QtCore/QEvent>
+
+#include <gst/video/gstvideosink.h>
+
+QT_BEGIN_NAMESPACE
+
+class NewFrameEvent : public QEvent
+{
+public:
+ NewFrameEvent(const QByteArray &newFrame, int w, int h) :
+ QEvent(QEvent::User),
+ frame(newFrame),
+ width(w),
+ height(h)
+ {
+ }
+
+ QByteArray frame;
+ int width;
+ int height;
+};
+
+namespace Phonon
+{
+namespace Gstreamer
+{
+
+enum VideoFormat {
+ VideoFormat_YUV,
+ VideoFormat_RGB
+};
+
+class QWidgetVideoSinkBase
+{
+public:
+ GstVideoSink videoSink;
+
+ QWidget * renderWidget;
+ gint width;
+ gint height;
+ gint bpp;
+ gint depth;
+};
+
+template <VideoFormat FMT>
+class QWidgetVideoSink : public QWidgetVideoSinkBase
+{
+public:
+ static GstCaps* get_caps(GstBaseSink* sink);
+ static gboolean set_caps(GstBaseSink* sink, GstCaps* caps);
+ static GstStateChangeReturn change_state(GstElement* element, GstStateChange transition);
+ static GstFlowReturn render(GstBaseSink* sink, GstBuffer* buf);
+ static void base_init(gpointer g_class);
+ static void instance_init(GTypeInstance *instance, gpointer g_class);
+};
+
+template <VideoFormat FMT>
+struct QWidgetVideoSinkClass
+{
+ GstVideoSinkClass parent_class;
+ static void class_init(gpointer g_class, gpointer class_data);
+ static GType get_type();
+ static const char* get_name();
+};
+
+GType get_type_YUV();
+GType get_type_RGB();
+
+}
+} //namespace Phonon::Gstreamer
+
+QT_END_NAMESPACE
+
+#endif // Phonon_GSTREAMER_VIDEOSINK_H
diff --git a/src/3rdparty/phonon/gstreamer/streamreader.cpp b/src/3rdparty/phonon/gstreamer/streamreader.cpp
new file mode 100644
index 0000000000..04fa6ccb04
--- /dev/null
+++ b/src/3rdparty/phonon/gstreamer/streamreader.cpp
@@ -0,0 +1,53 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library 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, either version 2.1 or 3 of the License.
+
+This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "streamreader.h"
+#include <QtCore/QMutex>
+#include <phonon/streaminterface.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace Gstreamer
+{
+
+bool StreamReader::read(quint64 pos, int length, char * buffer)
+{
+ if (currentPos() - currentBufferSize() != pos) {
+ if (!streamSeekable())
+ return false;
+ setCurrentPos(pos);
+ }
+
+ while (currentBufferSize() < length) {
+ int oldSize = currentBufferSize();
+ needData();
+ if (oldSize == currentBufferSize())
+ return false; // We didn't get any data
+ }
+
+ qMemCopy(buffer, m_buffer.data(), length);
+ //truncate the buffer
+ m_buffer = m_buffer.mid(pos);
+ return true;
+}
+
+}
+}
+
+QT_END_NAMESPACE
diff --git a/src/3rdparty/phonon/gstreamer/streamreader.h b/src/3rdparty/phonon/gstreamer/streamreader.h
new file mode 100644
index 0000000000..c2e61c8302
--- /dev/null
+++ b/src/3rdparty/phonon/gstreamer/streamreader.h
@@ -0,0 +1,96 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library 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, either version 2.1 or 3 of the License.
+
+This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef PHONON_IODEVICEREADER_H
+#define PHONON_IODEVICEREADER_H
+
+#include <phonon/mediasource.h>
+#include <phonon/streaminterface.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+ class MediaSource;
+ namespace Gstreamer
+ {
+ class StreamReader : public Phonon::StreamInterface
+ {
+ public:
+
+ StreamReader(const Phonon::MediaSource &source)
+ : m_pos(0)
+ , m_size(0)
+ , m_seekable(false)
+ {
+ connectToSource(source);
+ }
+
+ int currentBufferSize() const
+ {
+ return m_buffer.size();
+ }
+
+ void writeData(const QByteArray &data) {
+ m_pos += data.size();
+ m_buffer += data;
+ }
+
+ void setCurrentPos(qint64 pos)
+ {
+ m_pos = pos;
+ seekStream(pos);
+ m_buffer.clear();
+ }
+
+ quint64 currentPos() const
+ {
+ return m_pos;
+ }
+
+ bool read(quint64 offset, int length, char * buffer);
+
+ void endOfData() {}
+
+ void setStreamSize(qint64 newSize) {
+ m_size = newSize;
+ }
+
+ qint64 streamSize() const {
+ return m_size;
+ }
+
+ void setStreamSeekable(bool s) {
+ m_seekable = s;
+ }
+
+ bool streamSeekable() const {
+ return m_seekable;
+ }
+
+private:
+ QByteArray m_buffer;
+ quint64 m_pos;
+ quint64 m_size;
+ bool m_seekable;
+ };
+ }
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/3rdparty/phonon/gstreamer/videowidget.cpp b/src/3rdparty/phonon/gstreamer/videowidget.cpp
new file mode 100644
index 0000000000..efc750a16e
--- /dev/null
+++ b/src/3rdparty/phonon/gstreamer/videowidget.cpp
@@ -0,0 +1,387 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "videowidget.h"
+#include <QtCore/QEvent>
+#include <QtGui/QResizeEvent>
+#include <QtGui/QPalette>
+#include <QtGui/QImage>
+#include <QtGui/QPainter>
+#include <QtGui/QBoxLayout>
+#include <QApplication>
+#include <gst/gst.h>
+#include <gst/interfaces/propertyprobe.h>
+#include "mediaobject.h"
+#include "message.h"
+#include "common.h"
+
+#include "glrenderer.h"
+#include "widgetrenderer.h"
+#include "x11renderer.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace Gstreamer
+{
+
+VideoWidget::VideoWidget(Backend *backend, QWidget *parent) :
+ QWidget(parent),
+ MediaNode(backend, VideoSink),
+ m_videoBin(0),
+ m_renderer(0),
+ m_aspectRatio(Phonon::VideoWidget::AspectRatioAuto),
+ m_brightness(0.0),
+ m_hue(0.0),
+ m_contrast(0.0),
+ m_saturation(0.0),
+ m_scaleMode(Phonon::VideoWidget::FitInView),
+ m_videoBalance(0),
+ m_colorspace(0),
+ m_videoplug(0)
+{
+ setupVideoBin();
+}
+
+VideoWidget::~VideoWidget()
+{
+ if (m_videoBin) {
+ gst_element_set_state (m_videoBin, GST_STATE_NULL);
+ gst_object_unref (m_videoBin);
+ }
+
+ if (m_renderer)
+ delete m_renderer;
+}
+
+
+void VideoWidget::setupVideoBin()
+{
+
+ m_renderer = m_backend->deviceManager()->createVideoRenderer(this);
+ GstElement *videoSink = m_renderer->videoSink();
+
+ m_videoBin = gst_bin_new (NULL);
+ Q_ASSERT(m_videoBin);
+ gst_object_ref (GST_OBJECT (m_videoBin)); //Take ownership
+ gst_object_sink (GST_OBJECT (m_videoBin));
+
+ //The videoplug element is the final element before the pluggable videosink
+ m_videoplug = gst_element_factory_make ("identity", NULL);
+
+ //Colorspace ensures that the output of the stream matches the input format accepted by our video sink
+ m_colorspace = gst_element_factory_make ("ffmpegcolorspace", NULL);
+
+ //Video scale is used to prepare the correct aspect ratio and scale.
+ GstElement *videoScale = gst_element_factory_make ("videoscale", NULL);
+
+ //We need a queue to support the tee from parent node
+ GstElement *queue = gst_element_factory_make ("queue", NULL);
+
+ if (queue && m_videoBin && videoScale && m_colorspace && videoSink && m_videoplug) {
+ //Ensure that the bare essentials are prepared
+ gst_bin_add_many (GST_BIN (m_videoBin), queue, m_colorspace, m_videoplug, videoScale, videoSink, (const char*)NULL);
+ bool success = false;
+ //Video balance controls color/sat/hue in the YUV colorspace
+ m_videoBalance = gst_element_factory_make ("videobalance", NULL);
+ if (m_videoBalance) {
+ // For video balance to work we have to first ensure that the video is in YUV colorspace,
+ // then hand it off to the videobalance filter before finally converting it back to RGB.
+ // Hence we nede a videoFilter to convert the colorspace before and after videobalance
+ GstElement *m_colorspace2 = gst_element_factory_make ("ffmpegcolorspace", NULL);
+ gst_bin_add_many(GST_BIN(m_videoBin), m_videoBalance, m_colorspace2, (const char*)NULL);
+ success = gst_element_link_many(queue, m_colorspace, m_videoBalance, m_colorspace2, videoScale, m_videoplug, videoSink, (const char*)NULL);
+ } else {
+ //If video balance is not available, just connect to sink directly
+ success = gst_element_link_many(queue, m_colorspace, videoScale, m_videoplug, videoSink, (const char*)NULL);
+ }
+
+ if (success) {
+ GstPad *videopad = gst_element_get_pad (queue, "sink");
+ gst_element_add_pad (m_videoBin, gst_ghost_pad_new ("sink", videopad));
+ gst_object_unref (videopad);
+ QWidget *parentWidget = qobject_cast<QWidget*>(parent());
+ if (parentWidget)
+ parentWidget->winId(); // Due to some existing issues with alien in 4.4,
+ // we must currently force the creation of a parent widget.
+ m_isValid = true; //initialization ok, accept input
+ }
+ }
+}
+
+void VideoWidget::paintEvent(QPaintEvent *event)
+{
+ Q_ASSERT(m_renderer);
+ m_renderer->handlePaint(event);
+}
+
+void VideoWidget::setVisible(bool val) {
+ Q_ASSERT(m_renderer);
+
+ // Disable overlays for graphics view
+ if (root() && window() && window()->testAttribute(Qt::WA_DontShowOnScreen) && !m_renderer->paintsOnWidget()) {
+ m_backend->logMessage(QString("Widget rendering forced"), Backend::Info, this);
+ GstElement *videoSink = m_renderer->videoSink();
+ Q_ASSERT(videoSink);
+
+ gst_element_set_state (videoSink, GST_STATE_NULL);
+ gst_bin_remove(GST_BIN(m_videoBin), videoSink);
+ delete m_renderer;
+ m_renderer = 0;
+
+ // Use widgetRenderer as a fallback
+ m_renderer = new WidgetRenderer(this);
+ videoSink = m_renderer->videoSink();
+ gst_bin_add(GST_BIN(m_videoBin), videoSink);
+ gst_element_link(m_videoplug, videoSink);
+ gst_element_set_state (videoSink, GST_STATE_PAUSED);
+
+ // Request return to current state
+ root()->invalidateGraph();
+ root()->setState(root()->state());
+ }
+ QWidget::setVisible(val);
+}
+
+bool VideoWidget::event(QEvent *event)
+{
+ if (m_renderer && m_renderer->eventFilter(event))
+ return true;
+ return QWidget::event(event);
+}
+
+Phonon::VideoWidget::AspectRatio VideoWidget::aspectRatio() const
+{
+ return m_aspectRatio;
+}
+
+QSize VideoWidget::sizeHint() const
+{
+ if (!m_movieSize.isEmpty())
+ return m_movieSize;
+ else
+ return QSize(640, 480);
+}
+
+void VideoWidget::setAspectRatio(Phonon::VideoWidget::AspectRatio aspectRatio)
+{
+ m_aspectRatio = aspectRatio;
+ if (m_renderer)
+ m_renderer->aspectRatioChanged(aspectRatio);
+}
+
+Phonon::VideoWidget::ScaleMode VideoWidget::scaleMode() const
+{
+ return m_scaleMode;
+}
+
+QRect VideoWidget::scaleToAspect(QRect srcRect, int w, int h) const
+{
+ float width = srcRect.width();
+ float height = srcRect.width() * (float(h) / float(w));
+ if (height > srcRect.height()) {
+ height = srcRect.height();
+ width = srcRect.height() * (float(w) / float(h));
+ }
+ return QRect(0, 0, (int)width, (int)height);
+}
+
+/***
+ * Calculates the actual rectangle the movie will be presented with
+ **/
+QRect VideoWidget::calculateDrawFrameRect() const
+{
+ QRect widgetRect = rect();
+ QRect drawFrameRect;
+ // Set m_drawFrameRect to be the size of the smallest possible
+ // rect conforming to the aspect and containing the whole frame:
+ switch (aspectRatio()) {
+
+ case Phonon::VideoWidget::AspectRatioWidget:
+ drawFrameRect = widgetRect;
+ // No more calculations needed.
+ return drawFrameRect;
+
+ case Phonon::VideoWidget::AspectRatio4_3:
+ drawFrameRect = scaleToAspect(widgetRect, 4, 3);
+ break;
+
+ case Phonon::VideoWidget::AspectRatio16_9:
+ drawFrameRect = scaleToAspect(widgetRect, 16, 9);
+ break;
+
+ case Phonon::VideoWidget::AspectRatioAuto:
+ default:
+ drawFrameRect = QRect(0, 0, movieSize().width(), movieSize().height());
+ break;
+ }
+
+ // Scale m_drawFrameRect to fill the widget
+ // without breaking aspect:
+ float widgetWidth = widgetRect.width();
+ float widgetHeight = widgetRect.height();
+ float frameWidth = widgetWidth;
+ float frameHeight = drawFrameRect.height() * float(widgetWidth) / float(drawFrameRect.width());
+
+ switch (scaleMode()) {
+ case Phonon::VideoWidget::ScaleAndCrop:
+ if (frameHeight < widgetHeight) {
+ frameWidth *= float(widgetHeight) / float(frameHeight);
+ frameHeight = widgetHeight;
+ }
+ break;
+ case Phonon::VideoWidget::FitInView:
+ default:
+ if (frameHeight > widgetHeight) {
+ frameWidth *= float(widgetHeight) / float(frameHeight);
+ frameHeight = widgetHeight;
+ }
+ break;
+ }
+ drawFrameRect.setSize(QSize(int(frameWidth), int(frameHeight)));
+ drawFrameRect.moveTo(int((widgetWidth - frameWidth) / 2.0f),
+ int((widgetHeight - frameHeight) / 2.0f));
+ return drawFrameRect;
+}
+
+void VideoWidget::setScaleMode(Phonon::VideoWidget::ScaleMode scaleMode)
+{
+ m_scaleMode = scaleMode;
+ if (m_renderer)
+ m_renderer->scaleModeChanged(scaleMode);
+}
+
+qreal VideoWidget::brightness() const
+{
+ return m_brightness;
+}
+
+qreal clampedValue(qreal val)
+{
+ if (val > 1.0 )
+ return 1.0;
+ else if (val < -1.0)
+ return -1.0;
+ else return val;
+}
+
+void VideoWidget::setBrightness(qreal newValue)
+{
+ newValue = clampedValue(newValue);
+
+ if (newValue == m_brightness)
+ return;
+
+ m_brightness = newValue;
+
+ if (m_videoBalance)
+ g_object_set(G_OBJECT(m_videoBalance), "brightness", newValue, (const char*)NULL); //gstreamer range is [-1, 1]
+
+}
+
+qreal VideoWidget::contrast() const
+{
+ return m_contrast;
+}
+
+void VideoWidget::setContrast(qreal newValue)
+{
+ newValue = clampedValue(newValue);
+
+ if (newValue == m_contrast)
+ return;
+
+ m_contrast = newValue;
+
+ if (m_videoBalance)
+ g_object_set(G_OBJECT(m_videoBalance), "contrast", (newValue + 1.0), (const char*)NULL); //gstreamer range is [0-2]
+}
+
+qreal VideoWidget::hue() const
+{
+ return m_hue;
+}
+
+void VideoWidget::setHue(qreal newValue)
+{
+ if (newValue == m_hue)
+ return;
+
+ newValue = clampedValue(newValue);
+
+ m_hue = newValue;
+
+ if (m_videoBalance)
+ g_object_set(G_OBJECT(m_videoBalance), "hue", newValue, (const char*)NULL); //gstreamer range is [-1, 1]
+}
+
+qreal VideoWidget::saturation() const
+{
+ return m_saturation;
+}
+
+void VideoWidget::setSaturation(qreal newValue)
+{
+ newValue = clampedValue(newValue);
+
+ if (newValue == m_saturation)
+ return;
+
+ m_saturation = newValue;
+
+ if (m_videoBalance)
+ g_object_set(G_OBJECT(m_videoBalance), "saturation", newValue + 1.0, (const char*)NULL); //gstreamer range is [0, 2]
+}
+
+
+void VideoWidget::setMovieSize(const QSize &size)
+{
+ m_backend->logMessage(QString("New video size %0 x %1").arg(size.width()).arg(size.height()), Backend::Info);
+ if (size == m_movieSize)
+ return;
+ m_movieSize = size;
+ widget()->updateGeometry();
+ widget()->update();
+
+ if (m_renderer)
+ m_renderer->movieSizeChanged(m_movieSize);
+}
+
+void VideoWidget::mediaNodeEvent(const MediaNodeEvent *event)
+{
+ switch (event->type()) {
+ case MediaNodeEvent::VideoSizeChanged: {
+ const QSize *size = static_cast<const QSize*>(event->data());
+ setMovieSize(*size);
+ }
+ break;
+ default:
+ break;
+ }
+
+ // Forward events to renderer
+ if (m_renderer)
+ m_renderer->handleMediaNodeEvent(event);
+}
+
+}
+} //namespace Phonon::Gstreamer
+
+QT_END_NAMESPACE
+
+#include "moc_videowidget.cpp"
diff --git a/src/3rdparty/phonon/gstreamer/videowidget.h b/src/3rdparty/phonon/gstreamer/videowidget.h
new file mode 100644
index 0000000000..a0ebe5f820
--- /dev/null
+++ b/src/3rdparty/phonon/gstreamer/videowidget.h
@@ -0,0 +1,106 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2 //Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).007 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef Phonon_GSTREAMER_VIDEOWIDGET_H
+#define Phonon_GSTREAMER_VIDEOWIDGET_H
+
+#include <phonon/videowidget.h>
+#include <phonon/videowidgetinterface.h>
+
+#include "backend.h"
+#include "common.h"
+#include "medianode.h"
+#include "abstractrenderer.h"
+
+#include <gst/gst.h>
+
+QT_BEGIN_NAMESPACE
+
+class QString;
+
+namespace Phonon
+{
+namespace Gstreamer
+{
+
+class VideoWidget : public QWidget, public Phonon::VideoWidgetInterface, public MediaNode
+{
+ Q_OBJECT
+ Q_INTERFACES(Phonon::VideoWidgetInterface Phonon::Gstreamer::MediaNode)
+public:
+ VideoWidget(Backend *backend, QWidget *parent = 0);
+ ~VideoWidget();
+
+ void setupVideoBin();
+ void paintEvent(QPaintEvent *event);
+ void mediaNodeEvent(const MediaNodeEvent *event);
+ void setVisible(bool);
+
+ Phonon::VideoWidget::AspectRatio aspectRatio() const;
+ void setAspectRatio(Phonon::VideoWidget::AspectRatio aspectRatio);
+ Phonon::VideoWidget::ScaleMode scaleMode() const;
+ void setScaleMode(Phonon::VideoWidget::ScaleMode);
+ qreal brightness() const;
+ void setBrightness(qreal);
+ qreal contrast() const;
+ void setContrast(qreal);
+ qreal hue() const;
+ void setHue(qreal);
+ qreal saturation() const;
+ void setSaturation(qreal);
+ void setMovieSize(const QSize &size);
+ QSize sizeHint() const;
+ QRect scaleToAspect(QRect srcRect, int w, int h) const;
+ QRect calculateDrawFrameRect() const;
+
+ GstElement *videoElement()
+ {
+ Q_ASSERT(m_videoBin);
+ return m_videoBin;
+ }
+
+ QSize movieSize() const {
+ return m_movieSize;
+ }
+
+ bool event(QEvent *);
+
+ QWidget *widget() {
+ return this;
+ }
+
+protected:
+ GstElement *m_videoBin;
+ QSize m_movieSize;
+ AbstractRenderer *m_renderer;
+
+private:
+ Phonon::VideoWidget::AspectRatio m_aspectRatio;
+ qreal m_brightness, m_hue, m_contrast, m_saturation;
+ Phonon::VideoWidget::ScaleMode m_scaleMode;
+
+ GstElement *m_videoBalance;
+ GstElement *m_colorspace;
+ GstElement *m_videoplug;
+};
+
+}
+} //namespace Phonon::Gstreamer
+
+QT_END_NAMESPACE
+
+#endif // Phonon_GSTREAMER_VIDEOWIDGET_H
diff --git a/src/3rdparty/phonon/gstreamer/volumefadereffect.cpp b/src/3rdparty/phonon/gstreamer/volumefadereffect.cpp
new file mode 100644
index 0000000000..d7ee11bfcc
--- /dev/null
+++ b/src/3rdparty/phonon/gstreamer/volumefadereffect.cpp
@@ -0,0 +1,162 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "volumefadereffect.h"
+#include "common.h"
+#include <QtCore>
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace Gstreamer
+{
+
+VolumeFaderEffect::VolumeFaderEffect(Backend *backend, QObject *parent)
+ : Effect(backend, parent, AudioSource | AudioSink)
+ , m_fadeCurve(Phonon::VolumeFaderEffect::Fade3Decibel)
+ , m_fadeTimer(0)
+ , m_fadeDuration(0)
+ , m_fadeFromVolume(0)
+ , m_fadeToVolume(0)
+{
+ m_effectElement = gst_element_factory_make ("volume", NULL);
+ if (m_effectElement)
+ init();
+}
+
+VolumeFaderEffect::~VolumeFaderEffect()
+{
+ if (m_fadeTimer)
+ killTimer(m_fadeTimer);
+}
+
+GstElement* VolumeFaderEffect::createEffectBin()
+{
+ GstElement *audioBin = gst_bin_new(NULL);
+
+ // We need a queue to handle tee-connections from parent node
+ GstElement *queue= gst_element_factory_make ("queue", NULL);
+ gst_bin_add(GST_BIN(audioBin), queue);
+
+ GstElement *mconv= gst_element_factory_make ("audioconvert", NULL);
+ gst_bin_add(GST_BIN(audioBin), mconv);
+ gst_bin_add(GST_BIN(audioBin), m_effectElement);
+
+ // Link src pad
+ GstPad *srcPad= gst_element_get_pad (m_effectElement, "src");
+ gst_element_add_pad (audioBin, gst_ghost_pad_new ("src", srcPad));
+ gst_object_unref (srcPad);
+
+ // Link sink pad
+ gst_element_link_many(queue, mconv, m_effectElement, (const char*)NULL);
+ GstPad *sinkpad = gst_element_get_pad (queue, "sink");
+ gst_element_add_pad (audioBin, gst_ghost_pad_new ("sink", sinkpad));
+ gst_object_unref (sinkpad);
+ return audioBin;
+}
+
+float VolumeFaderEffect::volume() const
+{
+ gdouble val = 0.0;
+ if (m_effectElement)
+ g_object_get(G_OBJECT(m_effectElement), "volume", &val, (const char*)NULL);
+ return (float)val;
+}
+
+void VolumeFaderEffect::setVolume(float volume)
+{
+ g_object_set(G_OBJECT(m_effectElement), "volume", volume, (const char*)NULL);
+}
+
+Phonon::VolumeFaderEffect::FadeCurve VolumeFaderEffect::fadeCurve() const
+{
+ return m_fadeCurve;
+}
+
+void VolumeFaderEffect::setFadeCurve(Phonon::VolumeFaderEffect::FadeCurve fadeCurve)
+{
+ m_fadeCurve = fadeCurve;
+}
+
+void VolumeFaderEffect::fadeTo(float targetVolume, int fadeTime)
+{
+ m_fadeToVolume = targetVolume;
+ m_fadeDuration = fadeTime;
+ m_fadeFromVolume = volume();
+ m_fadeStartTime.start();
+
+ if (m_fadeTimer)
+ killTimer(m_fadeTimer);
+ m_fadeTimer = startTimer(30);
+}
+
+void VolumeFaderEffect::updateFade()
+{
+ double currVal = 0.0;
+ float step = float(m_fadeStartTime.elapsed()) / float(m_fadeDuration);
+ if (step > 1){
+ step = 1;
+ if (m_fadeTimer) {
+ killTimer(m_fadeTimer);
+ m_fadeTimer = 0;
+ }
+ }
+ // This is a very loose and interpretation of the API
+ // But in fact when fading between arbitrary values, the decibel values make no sense
+ // Note : seems like we will change the API to re-use names from QTimeline for this
+ switch (fadeCurve()) {
+ case Phonon::VolumeFaderEffect::Fade3Decibel: // Slow in the beginning
+ currVal = step * step;
+ break;
+ case Phonon::VolumeFaderEffect::Fade6Decibel: // Linear fade
+ currVal = step;
+ break;
+ case Phonon::VolumeFaderEffect::Fade9Decibel: // Fast in the beginning / Linear
+ currVal = step * 0.5 + (1.0-(1.0-step)*(1.0-step)) * 0.5;
+ break;
+ case Phonon::VolumeFaderEffect::Fade12Decibel: // Fast in the beginning
+ currVal = 1.0 - (1.0-step) * (1.0-step);
+ break;
+ default:
+ break;
+ }
+ const double volume = (1.0 - currVal) * m_fadeFromVolume + currVal * m_fadeToVolume;
+ setVolume(volume);
+}
+
+bool VolumeFaderEffect::event(QEvent *event)
+{
+ switch (event->type()){
+ case QEvent::Timer:
+ {
+ QTimerEvent *timerEvent = static_cast<QTimerEvent *>(event);
+ if (timerEvent->timerId() == m_fadeTimer)
+ updateFade();
+ break;
+ }
+ default:
+ break;
+ }
+ return QObject::event(event);
+}
+
+}} //namespace Phonon::Gstreamer
+
+QT_END_NAMESPACE
+
+#include "moc_volumefadereffect.cpp"
diff --git a/src/3rdparty/phonon/gstreamer/volumefadereffect.h b/src/3rdparty/phonon/gstreamer/volumefadereffect.h
new file mode 100644
index 0000000000..d74014cefb
--- /dev/null
+++ b/src/3rdparty/phonon/gstreamer/volumefadereffect.h
@@ -0,0 +1,70 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef Phonon_GSTREAMER_VOLUMEFADEREFFECT_H
+#define Phonon_GSTREAMER_VOLUMEFADEREFFECT_H
+
+#include "medianode.h"
+#include "effect.h"
+
+#include <phonon/effectinterface.h>
+#include <phonon/effectparameter.h>
+#include <phonon/volumefaderinterface.h>
+
+#include <QtCore>
+
+#include <gst/gst.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace Gstreamer
+{
+ class VolumeFaderEffect : public Effect, public VolumeFaderInterface
+ {
+ Q_OBJECT
+ Q_INTERFACES(Phonon::VolumeFaderInterface)
+
+ public:
+ VolumeFaderEffect(Backend *backend, QObject *parent = 0);
+ ~VolumeFaderEffect();
+
+ GstElement* createEffectBin();
+ GstElement *audioElement() { return m_effectBin; }
+ bool event(QEvent *);
+ void updateFade();
+
+ // VolumeFaderInterface:
+ float volume() const;
+ void setVolume(float volume);
+ Phonon::VolumeFaderEffect::FadeCurve fadeCurve() const;
+ void setFadeCurve(Phonon::VolumeFaderEffect::FadeCurve fadeCurve);
+ void fadeTo(float volume, int fadeTime);
+
+ Phonon::VolumeFaderEffect::FadeCurve m_fadeCurve;
+ int m_fadeTimer;
+ int m_fadeDuration;
+ float m_fadeFromVolume;
+ float m_fadeToVolume;
+ QTime m_fadeStartTime;
+ };
+}} //namespace Phonon::Gstreamer
+
+QT_END_NAMESPACE
+
+#endif // Phonon_GSTREAMER_VOLUMEFADEREFFECT_H
diff --git a/src/3rdparty/phonon/gstreamer/widgetrenderer.cpp b/src/3rdparty/phonon/gstreamer/widgetrenderer.cpp
new file mode 100644
index 0000000000..d4a411ffc5
--- /dev/null
+++ b/src/3rdparty/phonon/gstreamer/widgetrenderer.cpp
@@ -0,0 +1,150 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <QtGui/QPainter>
+#include <gst/gst.h>
+#include "common.h"
+#include "message.h"
+#include "mediaobject.h"
+#include "qwidgetvideosink.h"
+#include "widgetrenderer.h"
+#include "qrgb.h"
+
+// support old OpenGL installations (1.2)
+// assume that if TEXTURE0 isn't defined, none are
+#ifndef GL_TEXTURE0
+# define GL_TEXTURE0 0x84C0
+# define GL_TEXTURE1 0x84C1
+# define GL_TEXTURE2 0x84C2
+#endif
+
+QT_BEGIN_NAMESPACE
+
+static void frameRendered()
+{
+ static QString displayFps = qgetenv("PHONON_GST_FPS");
+ if (displayFps.isEmpty())
+ return;
+
+ static int frames = 0;
+ static QTime lastTime = QTime::currentTime();
+ QTime time = QTime::currentTime();
+
+ int delta = lastTime.msecsTo(time);
+ if (delta > 2000) {
+ printf("FPS: %f\n", 1000.0 * frames / qreal(delta));
+ lastTime = time;
+ frames = 0;
+ }
+
+ ++frames;
+}
+
+namespace Phonon
+{
+namespace Gstreamer
+{
+
+WidgetRenderer::WidgetRenderer(VideoWidget *videoWidget)
+ : AbstractRenderer(videoWidget)
+ , m_width(0)
+ , m_height(0)
+{
+ videoWidget->backend()->logMessage("Creating QWidget renderer");
+ if ((m_videoSink = GST_ELEMENT(g_object_new(get_type_RGB(), NULL)))) {
+ gst_object_ref (GST_OBJECT (m_videoSink)); //Take ownership
+ gst_object_sink (GST_OBJECT (m_videoSink));
+
+ QWidgetVideoSinkBase* sink = reinterpret_cast<QWidgetVideoSinkBase*>(m_videoSink);
+ // Let the videosink know which widget to direct frame updates to
+ sink->renderWidget = videoWidget;
+ }
+
+ // Clear the background with black by default
+ QPalette palette;
+ palette.setColor(QPalette::Background, Qt::black);
+ m_videoWidget->setPalette(palette);
+ m_videoWidget->setAutoFillBackground(true);
+ m_videoWidget->setAttribute(Qt::WA_NoSystemBackground, false);
+ m_videoWidget->setAttribute(Qt::WA_PaintOnScreen, false);
+}
+
+void WidgetRenderer::setNextFrame(const QByteArray &array, int w, int h)
+{
+ if (m_videoWidget->root()->state() == Phonon::LoadingState)
+ return;
+
+ m_frame = QImage();
+ {
+ m_frame = QImage((uchar *)array.constData(), w, h, QImage::Format_RGB32);
+ }
+
+ m_array = array;
+ m_width = w;
+ m_height = h;
+
+ m_videoWidget->update();
+}
+
+void WidgetRenderer::handleMediaNodeEvent(const MediaNodeEvent *event)
+{
+ switch (event->type()) {
+ case MediaNodeEvent::SourceChanged:
+ {
+ clearFrame();
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+void WidgetRenderer::clearFrame()
+{
+ m_frame = QImage();
+ m_array = QByteArray();
+ m_videoWidget->update();
+}
+
+const QImage &WidgetRenderer::currentFrame() const
+{
+ return m_frame;
+}
+
+void WidgetRenderer::handlePaint(QPaintEvent *event)
+{
+ Q_UNUSED(event);
+ QPainter painter(m_videoWidget);
+ m_drawFrameRect = m_videoWidget->calculateDrawFrameRect();
+ painter.drawImage(drawFrameRect(), currentFrame());
+ frameRendered();
+}
+
+bool WidgetRenderer::eventFilter(QEvent * event)
+{
+ if (event->type() == QEvent::User) {
+ NewFrameEvent *frameEvent= static_cast <NewFrameEvent *>(event);
+ setNextFrame(frameEvent->frame, frameEvent->width, frameEvent->height);
+ return true;
+ }
+ return false;
+}
+
+}
+} //namespace Phonon::Gstreamer
+
+QT_END_NAMESPACE
diff --git a/src/3rdparty/phonon/gstreamer/widgetrenderer.h b/src/3rdparty/phonon/gstreamer/widgetrenderer.h
new file mode 100644
index 0000000000..ff64fa7d32
--- /dev/null
+++ b/src/3rdparty/phonon/gstreamer/widgetrenderer.h
@@ -0,0 +1,63 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef Phonon_GSTREAMER_WIDGETRENDERER_H
+#define Phonon_GSTREAMER_WIDGETRENDERER_H
+
+#include "videowidget.h"
+#include "common.h"
+
+#ifndef QT_NO_OPENGL
+#include <QtOpenGL/QGLFormat>
+#include <QtOpenGL/QGLWidget>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QString;
+
+namespace Phonon
+{
+namespace Gstreamer
+{
+
+class WidgetRenderer : public AbstractRenderer
+{
+public:
+ WidgetRenderer(VideoWidget *videoWidget);
+ bool eventFilter(QEvent * event);
+ void handlePaint(QPaintEvent *paintEvent);
+ void handleMediaNodeEvent(const MediaNodeEvent *event);
+ const QImage& currentFrame() const;
+ QRect drawFrameRect() const { return m_drawFrameRect; }
+ void setNextFrame(const QByteArray &array, int width, int height);
+ bool frameIsSet() { return !m_array.isNull(); }
+ void clearFrame();
+private:
+ mutable QImage m_frame;
+ QByteArray m_array;
+ int m_width;
+ int m_height;
+ QRect m_drawFrameRect;
+};
+
+}
+} //namespace Phonon::Gstreamer
+
+QT_END_NAMESPACE
+
+#endif // Phonon_GSTREAMER_WIDGETRENDERER_H
diff --git a/src/3rdparty/phonon/gstreamer/x11renderer.cpp b/src/3rdparty/phonon/gstreamer/x11renderer.cpp
new file mode 100644
index 0000000000..73877a8f14
--- /dev/null
+++ b/src/3rdparty/phonon/gstreamer/x11renderer.cpp
@@ -0,0 +1,194 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "videowidget.h"
+#include "x11renderer.h"
+
+#ifndef Q_WS_QWS
+
+#include <QtGui/QPalette>
+#include <QtGui/QApplication>
+#include <QtGui/QPainter>
+#include <X11/Xlib.h>
+#include <gst/gst.h>
+#include <gst/interfaces/xoverlay.h>
+#include <gst/interfaces/propertyprobe.h>
+#include "common.h"
+#include "mediaobject.h"
+#include "message.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace Gstreamer
+{
+
+class OverlayWidget : public QWidget
+{
+public:
+ OverlayWidget(VideoWidget *videoWidget, X11Renderer *renderer) :
+ QWidget(videoWidget),
+ m_videoWidget(videoWidget),
+ m_renderer(renderer) { }
+ void paintEvent(QPaintEvent *) {
+ Phonon::State state = m_videoWidget->root() ? m_videoWidget->root()->state() : Phonon::LoadingState;
+ if (state == Phonon::PlayingState || state == Phonon::PausedState) {
+ m_renderer->windowExposed();
+ } else {
+ QPainter painter(this);
+ painter.fillRect(m_videoWidget->rect(), m_videoWidget->palette().background());
+ }
+ }
+private:
+ VideoWidget *m_videoWidget;
+ X11Renderer *m_renderer;
+};
+
+X11Renderer::X11Renderer(VideoWidget *videoWidget)
+ : AbstractRenderer(videoWidget)
+{
+ m_renderWidget = new OverlayWidget(videoWidget, this);
+ videoWidget->backend()->logMessage("Creating X11 overlay renderer");
+ QPalette palette;
+ palette.setColor(QPalette::Background, Qt::black);
+ m_videoWidget->setPalette(palette);
+ m_videoWidget->setAutoFillBackground(true);
+ m_renderWidget->setMouseTracking(true);
+ m_videoSink = createVideoSink();
+ aspectRatioChanged(videoWidget->aspectRatio());
+ setOverlay();
+}
+
+X11Renderer::~X11Renderer()
+{
+ m_renderWidget->setAttribute(Qt::WA_PaintOnScreen, false);
+ m_renderWidget->setAttribute(Qt::WA_NoSystemBackground, false);
+ delete m_renderWidget;
+}
+
+GstElement* X11Renderer::createVideoSink()
+{
+ GstElement *videoSink = gst_element_factory_make ("xvimagesink", NULL);
+ if (videoSink) {
+ // Check if the xv sink is usable
+ if (gst_element_set_state(videoSink, GST_STATE_READY) != GST_STATE_CHANGE_SUCCESS) {
+ gst_object_unref(GST_OBJECT(videoSink));
+ videoSink = 0;
+ } else {
+ // Note that this should not really be neccessary as these are
+ // default values, though under certain conditions values are retained
+ // even between application instances. (reproducible on 0.10.16/Gutsy)
+ g_object_set(G_OBJECT(videoSink), "brightness", 0, (const char*)NULL);
+ g_object_set(G_OBJECT(videoSink), "contrast", 0, (const char*)NULL);
+ g_object_set(G_OBJECT(videoSink), "hue", 0, (const char*)NULL);
+ g_object_set(G_OBJECT(videoSink), "saturation", 0, (const char*)NULL);
+ }
+ }
+
+ if (!videoSink)
+ videoSink = gst_element_factory_make ("ximagesink", NULL);
+
+ gst_object_ref (GST_OBJECT (videoSink)); //Take ownership
+ gst_object_sink (GST_OBJECT (videoSink));
+
+ return videoSink;
+}
+
+void X11Renderer::handleMediaNodeEvent(const MediaNodeEvent *event)
+{
+ switch (event->type()) {
+ case MediaNodeEvent::SourceChanged:
+ setOverlay(); // We need to do this whenever the pipeline is reset
+ break; // otherwise the videosink will open in its own window
+ default:
+ break;
+ }
+}
+
+
+void X11Renderer::aspectRatioChanged(Phonon::VideoWidget::AspectRatio)
+{
+ if (m_renderWidget) {
+ m_renderWidget->setGeometry(m_videoWidget->calculateDrawFrameRect());
+ }
+}
+
+void X11Renderer::scaleModeChanged(Phonon::VideoWidget::ScaleMode)
+{
+ if (m_renderWidget) {
+ m_renderWidget->setGeometry(m_videoWidget->calculateDrawFrameRect());
+ }
+}
+
+void X11Renderer::movieSizeChanged(const QSize &movieSize)
+{
+ Q_UNUSED(movieSize);
+ if (m_renderWidget) {
+ m_renderWidget->setGeometry(m_videoWidget->calculateDrawFrameRect());
+ }
+}
+
+bool X11Renderer::eventFilter(QEvent *e)
+{
+ if (e->type() == QEvent::Show) {
+ // Setting these values ensures smooth resizing since it
+ // will prevent the system from clearing the background
+ m_renderWidget->setAttribute(Qt::WA_NoSystemBackground, true);
+ m_renderWidget->setAttribute(Qt::WA_PaintOnScreen, true);
+ setOverlay();
+ } else if (e->type() == QEvent::Resize) {
+ // This is a workaround for missing background repaints
+ // when reducing window size
+ m_renderWidget->setGeometry(m_videoWidget->calculateDrawFrameRect());
+ windowExposed();
+ }
+ return false;
+}
+
+void X11Renderer::handlePaint(QPaintEvent *)
+{
+ QPainter painter(m_videoWidget);
+ painter.fillRect(m_videoWidget->rect(), m_videoWidget->palette().background());
+}
+
+void X11Renderer::setOverlay()
+{
+ if (m_videoSink && GST_IS_X_OVERLAY(m_videoSink)) {
+ WId windowId = m_renderWidget->winId();
+ // Even if we have created a winId at this point, other X applications
+ // need to be aware of it.
+ QApplication::syncX();
+ gst_x_overlay_set_xwindow_id ( GST_X_OVERLAY(m_videoSink) , windowId );
+ }
+ windowExposed();
+ m_overlaySet = true;
+}
+
+void X11Renderer::windowExposed()
+{
+ QApplication::syncX();
+ if (m_videoSink && GST_IS_X_OVERLAY(m_videoSink))
+ gst_x_overlay_expose(GST_X_OVERLAY(m_videoSink));
+}
+
+}
+} //namespace Phonon::Gstreamer
+
+QT_END_NAMESPACE
+
+#endif // Q_WS_QWS
diff --git a/src/3rdparty/phonon/gstreamer/x11renderer.h b/src/3rdparty/phonon/gstreamer/x11renderer.h
new file mode 100644
index 0000000000..f7140da151
--- /dev/null
+++ b/src/3rdparty/phonon/gstreamer/x11renderer.h
@@ -0,0 +1,68 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef Phonon_GSTREAMER_X11RENDERER_H
+#define Phonon_GSTREAMER_X11RENDERER_H
+
+#include "videowidget.h"
+#include "common.h"
+
+#include <QtGui/QWidget>
+
+#include <gst/gst.h>
+
+QT_BEGIN_NAMESPACE
+
+#ifndef Q_WS_QWS
+
+class QString;
+
+namespace Phonon
+{
+namespace Gstreamer
+{
+
+class OverlayWidget;
+class X11Renderer : public AbstractRenderer
+{
+public:
+ X11Renderer(VideoWidget *videoWidget);
+ ~X11Renderer();
+ void handlePaint(QPaintEvent *event);
+ void aspectRatioChanged(Phonon::VideoWidget::AspectRatio aspectRatio);
+ void scaleModeChanged(Phonon::VideoWidget::ScaleMode scaleMode);
+ void movieSizeChanged(const QSize &movieSize);
+ void handleMediaNodeEvent(const MediaNodeEvent *event);
+ bool eventFilter(QEvent *);
+ bool paintsOnWidget() { return false; }
+ bool overlaySet() const { return m_overlaySet; }
+ void setOverlay();
+ void windowExposed();
+ GstElement *createVideoSink();
+private:
+ OverlayWidget *m_renderWidget;
+ bool m_overlaySet;
+};
+
+}
+} //namespace Phonon::Gstreamer
+
+#endif // Q_WS_QWS
+
+QT_END_NAMESPACE
+
+#endif // Phonon_GSTREAMER_X11RENDERER_H
diff --git a/src/3rdparty/phonon/includes/CMakeLists.txt b/src/3rdparty/phonon/includes/CMakeLists.txt
new file mode 100644
index 0000000000..349acd87a3
--- /dev/null
+++ b/src/3rdparty/phonon/includes/CMakeLists.txt
@@ -0,0 +1,49 @@
+install( FILES
+ Phonon/AbstractAudioOutput
+ Phonon/AbstractMediaStream
+ Phonon/AbstractVideoOutput
+ Phonon/AddonInterface
+ Phonon/AudioDevice
+ Phonon/AudioDeviceEnumerator
+ Phonon/AudioOutput
+ Phonon/AudioOutputDevice
+ Phonon/AudioOutputDeviceModel
+ Phonon/AudioOutputInterface
+ Phonon/BackendCapabilities
+ Phonon/BackendInterface
+ Phonon/Effect
+ Phonon/EffectDescription
+ Phonon/EffectDescriptionModel
+ Phonon/EffectInterface
+ Phonon/EffectParameter
+ Phonon/EffectWidget
+ Phonon/Global
+ Phonon/MediaController
+ Phonon/MediaNode
+ Phonon/MediaObject
+ Phonon/MediaObjectInterface
+ Phonon/MediaSource
+ Phonon/ObjectDescription
+ Phonon/ObjectDescriptionModel
+ Phonon/Path
+ Phonon/PlatformPlugin
+ Phonon/SeekSlider
+ Phonon/StreamInterface
+ Phonon/VideoPlayer
+ Phonon/VideoWidget
+ Phonon/VideoWidgetInterface
+ Phonon/VolumeFaderEffect
+ Phonon/VolumeFaderInterface
+ Phonon/VolumeSlider
+DESTINATION ${INCLUDE_INSTALL_DIR}/KDE/Phonon)
+
+install(FILES
+ Phonon/Experimental/AbstractVideoDataOutput
+ Phonon/Experimental/AudioDataOutput
+ Phonon/Experimental/SnapshotInterface
+ Phonon/Experimental/VideoDataOutput
+ Phonon/Experimental/VideoDataOutputInterface
+ Phonon/Experimental/VideoFrame
+ Phonon/Experimental/VideoFrame2
+ Phonon/Experimental/Visualization
+DESTINATION ${INCLUDE_INSTALL_DIR}/KDE/Phonon/Experimental)
diff --git a/src/3rdparty/phonon/includes/Phonon/AbstractAudioOutput b/src/3rdparty/phonon/includes/Phonon/AbstractAudioOutput
new file mode 100644
index 0000000000..46d766848c
--- /dev/null
+++ b/src/3rdparty/phonon/includes/Phonon/AbstractAudioOutput
@@ -0,0 +1 @@
+#include "../../phonon/abstractaudiooutput.h"
diff --git a/src/3rdparty/phonon/includes/Phonon/AbstractMediaStream b/src/3rdparty/phonon/includes/Phonon/AbstractMediaStream
new file mode 100644
index 0000000000..77837cf9da
--- /dev/null
+++ b/src/3rdparty/phonon/includes/Phonon/AbstractMediaStream
@@ -0,0 +1 @@
+#include "../../phonon/abstractmediastream.h"
diff --git a/src/3rdparty/phonon/includes/Phonon/AbstractVideoOutput b/src/3rdparty/phonon/includes/Phonon/AbstractVideoOutput
new file mode 100644
index 0000000000..da05eb0428
--- /dev/null
+++ b/src/3rdparty/phonon/includes/Phonon/AbstractVideoOutput
@@ -0,0 +1 @@
+#include "../../phonon/abstractvideooutput.h"
diff --git a/src/3rdparty/phonon/includes/Phonon/AddonInterface b/src/3rdparty/phonon/includes/Phonon/AddonInterface
new file mode 100644
index 0000000000..448993a145
--- /dev/null
+++ b/src/3rdparty/phonon/includes/Phonon/AddonInterface
@@ -0,0 +1 @@
+#include "../../phonon/addoninterface.h"
diff --git a/src/3rdparty/phonon/includes/Phonon/AudioDevice b/src/3rdparty/phonon/includes/Phonon/AudioDevice
new file mode 100644
index 0000000000..b1b516213f
--- /dev/null
+++ b/src/3rdparty/phonon/includes/Phonon/AudioDevice
@@ -0,0 +1 @@
+#include "../../phonon/audiodevice.h"
diff --git a/src/3rdparty/phonon/includes/Phonon/AudioDeviceEnumerator b/src/3rdparty/phonon/includes/Phonon/AudioDeviceEnumerator
new file mode 100644
index 0000000000..d971a3d03a
--- /dev/null
+++ b/src/3rdparty/phonon/includes/Phonon/AudioDeviceEnumerator
@@ -0,0 +1 @@
+#include "../../phonon/audiodeviceenumerator.h"
diff --git a/src/3rdparty/phonon/includes/Phonon/AudioOutput b/src/3rdparty/phonon/includes/Phonon/AudioOutput
new file mode 100644
index 0000000000..d67ac914ad
--- /dev/null
+++ b/src/3rdparty/phonon/includes/Phonon/AudioOutput
@@ -0,0 +1 @@
+#include "../../phonon/audiooutput.h"
diff --git a/src/3rdparty/phonon/includes/Phonon/AudioOutputDevice b/src/3rdparty/phonon/includes/Phonon/AudioOutputDevice
new file mode 100644
index 0000000000..3f75a1da80
--- /dev/null
+++ b/src/3rdparty/phonon/includes/Phonon/AudioOutputDevice
@@ -0,0 +1 @@
+#include "../../phonon/objectdescription.h"
diff --git a/src/3rdparty/phonon/includes/Phonon/AudioOutputDeviceModel b/src/3rdparty/phonon/includes/Phonon/AudioOutputDeviceModel
new file mode 100644
index 0000000000..eae8aecb75
--- /dev/null
+++ b/src/3rdparty/phonon/includes/Phonon/AudioOutputDeviceModel
@@ -0,0 +1 @@
+#include "../../phonon/objectdescriptionmodel.h"
diff --git a/src/3rdparty/phonon/includes/Phonon/AudioOutputInterface b/src/3rdparty/phonon/includes/Phonon/AudioOutputInterface
new file mode 100644
index 0000000000..b0ef2e7bc8
--- /dev/null
+++ b/src/3rdparty/phonon/includes/Phonon/AudioOutputInterface
@@ -0,0 +1 @@
+#include "../../phonon/audiooutputinterface.h"
diff --git a/src/3rdparty/phonon/includes/Phonon/BackendCapabilities b/src/3rdparty/phonon/includes/Phonon/BackendCapabilities
new file mode 100644
index 0000000000..b1236135eb
--- /dev/null
+++ b/src/3rdparty/phonon/includes/Phonon/BackendCapabilities
@@ -0,0 +1 @@
+#include "../../phonon/backendcapabilities.h"
diff --git a/src/3rdparty/phonon/includes/Phonon/BackendInterface b/src/3rdparty/phonon/includes/Phonon/BackendInterface
new file mode 100644
index 0000000000..389c124741
--- /dev/null
+++ b/src/3rdparty/phonon/includes/Phonon/BackendInterface
@@ -0,0 +1 @@
+#include "../../phonon/backendinterface.h"
diff --git a/src/3rdparty/phonon/includes/Phonon/Effect b/src/3rdparty/phonon/includes/Phonon/Effect
new file mode 100644
index 0000000000..009eb1576f
--- /dev/null
+++ b/src/3rdparty/phonon/includes/Phonon/Effect
@@ -0,0 +1 @@
+#include "../../phonon/effect.h"
diff --git a/src/3rdparty/phonon/includes/Phonon/EffectDescription b/src/3rdparty/phonon/includes/Phonon/EffectDescription
new file mode 100644
index 0000000000..3f75a1da80
--- /dev/null
+++ b/src/3rdparty/phonon/includes/Phonon/EffectDescription
@@ -0,0 +1 @@
+#include "../../phonon/objectdescription.h"
diff --git a/src/3rdparty/phonon/includes/Phonon/EffectDescriptionModel b/src/3rdparty/phonon/includes/Phonon/EffectDescriptionModel
new file mode 100644
index 0000000000..eae8aecb75
--- /dev/null
+++ b/src/3rdparty/phonon/includes/Phonon/EffectDescriptionModel
@@ -0,0 +1 @@
+#include "../../phonon/objectdescriptionmodel.h"
diff --git a/src/3rdparty/phonon/includes/Phonon/EffectInterface b/src/3rdparty/phonon/includes/Phonon/EffectInterface
new file mode 100644
index 0000000000..d5a5bc30a0
--- /dev/null
+++ b/src/3rdparty/phonon/includes/Phonon/EffectInterface
@@ -0,0 +1 @@
+#include "../../phonon/effectinterface.h"
diff --git a/src/3rdparty/phonon/includes/Phonon/EffectParameter b/src/3rdparty/phonon/includes/Phonon/EffectParameter
new file mode 100644
index 0000000000..301fe1620c
--- /dev/null
+++ b/src/3rdparty/phonon/includes/Phonon/EffectParameter
@@ -0,0 +1 @@
+#include "../../phonon/effectparameter.h"
diff --git a/src/3rdparty/phonon/includes/Phonon/EffectWidget b/src/3rdparty/phonon/includes/Phonon/EffectWidget
new file mode 100644
index 0000000000..72e687ffd0
--- /dev/null
+++ b/src/3rdparty/phonon/includes/Phonon/EffectWidget
@@ -0,0 +1 @@
+#include "../../phonon/effectwidget.h"
diff --git a/src/3rdparty/phonon/includes/Phonon/Experimental/AbstractVideoDataOutput b/src/3rdparty/phonon/includes/Phonon/Experimental/AbstractVideoDataOutput
new file mode 100644
index 0000000000..c0192159cc
--- /dev/null
+++ b/src/3rdparty/phonon/includes/Phonon/Experimental/AbstractVideoDataOutput
@@ -0,0 +1 @@
+#include "../../../phonon/experimental/abstractvideodataoutput.h"
diff --git a/src/3rdparty/phonon/includes/Phonon/Experimental/AudioDataOutput b/src/3rdparty/phonon/includes/Phonon/Experimental/AudioDataOutput
new file mode 100644
index 0000000000..06d181dc48
--- /dev/null
+++ b/src/3rdparty/phonon/includes/Phonon/Experimental/AudioDataOutput
@@ -0,0 +1 @@
+#include "../../../phonon/experimental/audiodataoutput.h"
diff --git a/src/3rdparty/phonon/includes/Phonon/Experimental/SnapshotInterface b/src/3rdparty/phonon/includes/Phonon/Experimental/SnapshotInterface
new file mode 100644
index 0000000000..5e59306bd7
--- /dev/null
+++ b/src/3rdparty/phonon/includes/Phonon/Experimental/SnapshotInterface
@@ -0,0 +1 @@
+#include "../../../phonon/experimental/snapshotinterface.h"
diff --git a/src/3rdparty/phonon/includes/Phonon/Experimental/VideoDataOutput b/src/3rdparty/phonon/includes/Phonon/Experimental/VideoDataOutput
new file mode 100644
index 0000000000..9878ccff0d
--- /dev/null
+++ b/src/3rdparty/phonon/includes/Phonon/Experimental/VideoDataOutput
@@ -0,0 +1 @@
+#include "../../../phonon/experimental/videodataoutput.h"
diff --git a/src/3rdparty/phonon/includes/Phonon/Experimental/VideoDataOutputInterface b/src/3rdparty/phonon/includes/Phonon/Experimental/VideoDataOutputInterface
new file mode 100644
index 0000000000..870f68336e
--- /dev/null
+++ b/src/3rdparty/phonon/includes/Phonon/Experimental/VideoDataOutputInterface
@@ -0,0 +1 @@
+#include "../../../phonon/experimental/videodataoutputinterface.h"
diff --git a/src/3rdparty/phonon/includes/Phonon/Experimental/VideoFrame b/src/3rdparty/phonon/includes/Phonon/Experimental/VideoFrame
new file mode 100644
index 0000000000..97c137eede
--- /dev/null
+++ b/src/3rdparty/phonon/includes/Phonon/Experimental/VideoFrame
@@ -0,0 +1 @@
+#include "../../../phonon/experimental/videoframe.h"
diff --git a/src/3rdparty/phonon/includes/Phonon/Experimental/VideoFrame2 b/src/3rdparty/phonon/includes/Phonon/Experimental/VideoFrame2
new file mode 100644
index 0000000000..29d1af9a17
--- /dev/null
+++ b/src/3rdparty/phonon/includes/Phonon/Experimental/VideoFrame2
@@ -0,0 +1 @@
+#include "../../../phonon/experimental/videoframe2.h"
diff --git a/src/3rdparty/phonon/includes/Phonon/Experimental/Visualization b/src/3rdparty/phonon/includes/Phonon/Experimental/Visualization
new file mode 100644
index 0000000000..b5aab387f1
--- /dev/null
+++ b/src/3rdparty/phonon/includes/Phonon/Experimental/Visualization
@@ -0,0 +1 @@
+#include "../../../phonon/experimental/visualization.h"
diff --git a/src/3rdparty/phonon/includes/Phonon/Global b/src/3rdparty/phonon/includes/Phonon/Global
new file mode 100644
index 0000000000..4215e3bace
--- /dev/null
+++ b/src/3rdparty/phonon/includes/Phonon/Global
@@ -0,0 +1 @@
+#include "../../phonon/phononnamespace.h"
diff --git a/src/3rdparty/phonon/includes/Phonon/MediaController b/src/3rdparty/phonon/includes/Phonon/MediaController
new file mode 100644
index 0000000000..666be3e048
--- /dev/null
+++ b/src/3rdparty/phonon/includes/Phonon/MediaController
@@ -0,0 +1 @@
+#include "../../phonon/mediacontroller.h"
diff --git a/src/3rdparty/phonon/includes/Phonon/MediaNode b/src/3rdparty/phonon/includes/Phonon/MediaNode
new file mode 100644
index 0000000000..80831582af
--- /dev/null
+++ b/src/3rdparty/phonon/includes/Phonon/MediaNode
@@ -0,0 +1 @@
+#include "../../phonon/medianode.h"
diff --git a/src/3rdparty/phonon/includes/Phonon/MediaObject b/src/3rdparty/phonon/includes/Phonon/MediaObject
new file mode 100644
index 0000000000..fa6d33b515
--- /dev/null
+++ b/src/3rdparty/phonon/includes/Phonon/MediaObject
@@ -0,0 +1 @@
+#include "../../phonon/mediaobject.h"
diff --git a/src/3rdparty/phonon/includes/Phonon/MediaObjectInterface b/src/3rdparty/phonon/includes/Phonon/MediaObjectInterface
new file mode 100644
index 0000000000..c78243beee
--- /dev/null
+++ b/src/3rdparty/phonon/includes/Phonon/MediaObjectInterface
@@ -0,0 +1 @@
+#include "../../phonon/mediaobjectinterface.h"
diff --git a/src/3rdparty/phonon/includes/Phonon/MediaSource b/src/3rdparty/phonon/includes/Phonon/MediaSource
new file mode 100644
index 0000000000..6ee2a72b3f
--- /dev/null
+++ b/src/3rdparty/phonon/includes/Phonon/MediaSource
@@ -0,0 +1 @@
+#include "../../phonon/mediasource.h"
diff --git a/src/3rdparty/phonon/includes/Phonon/ObjectDescription b/src/3rdparty/phonon/includes/Phonon/ObjectDescription
new file mode 100644
index 0000000000..3f75a1da80
--- /dev/null
+++ b/src/3rdparty/phonon/includes/Phonon/ObjectDescription
@@ -0,0 +1 @@
+#include "../../phonon/objectdescription.h"
diff --git a/src/3rdparty/phonon/includes/Phonon/ObjectDescriptionModel b/src/3rdparty/phonon/includes/Phonon/ObjectDescriptionModel
new file mode 100644
index 0000000000..eae8aecb75
--- /dev/null
+++ b/src/3rdparty/phonon/includes/Phonon/ObjectDescriptionModel
@@ -0,0 +1 @@
+#include "../../phonon/objectdescriptionmodel.h"
diff --git a/src/3rdparty/phonon/includes/Phonon/Path b/src/3rdparty/phonon/includes/Phonon/Path
new file mode 100644
index 0000000000..1b3d2d55aa
--- /dev/null
+++ b/src/3rdparty/phonon/includes/Phonon/Path
@@ -0,0 +1 @@
+#include "../../phonon/path.h"
diff --git a/src/3rdparty/phonon/includes/Phonon/PlatformPlugin b/src/3rdparty/phonon/includes/Phonon/PlatformPlugin
new file mode 100644
index 0000000000..258f33941a
--- /dev/null
+++ b/src/3rdparty/phonon/includes/Phonon/PlatformPlugin
@@ -0,0 +1 @@
+#include "../../phonon/platformplugin.h"
diff --git a/src/3rdparty/phonon/includes/Phonon/SeekSlider b/src/3rdparty/phonon/includes/Phonon/SeekSlider
new file mode 100644
index 0000000000..3dde9a821a
--- /dev/null
+++ b/src/3rdparty/phonon/includes/Phonon/SeekSlider
@@ -0,0 +1 @@
+#include "../../phonon/seekslider.h"
diff --git a/src/3rdparty/phonon/includes/Phonon/StreamInterface b/src/3rdparty/phonon/includes/Phonon/StreamInterface
new file mode 100644
index 0000000000..efd8c20902
--- /dev/null
+++ b/src/3rdparty/phonon/includes/Phonon/StreamInterface
@@ -0,0 +1 @@
+#include "../../phonon/streaminterface.h"
diff --git a/src/3rdparty/phonon/includes/Phonon/VideoPlayer b/src/3rdparty/phonon/includes/Phonon/VideoPlayer
new file mode 100644
index 0000000000..68c0fd3588
--- /dev/null
+++ b/src/3rdparty/phonon/includes/Phonon/VideoPlayer
@@ -0,0 +1 @@
+#include "../../phonon/videoplayer.h"
diff --git a/src/3rdparty/phonon/includes/Phonon/VideoWidget b/src/3rdparty/phonon/includes/Phonon/VideoWidget
new file mode 100644
index 0000000000..9420f6b993
--- /dev/null
+++ b/src/3rdparty/phonon/includes/Phonon/VideoWidget
@@ -0,0 +1 @@
+#include "../../phonon/videowidget.h"
diff --git a/src/3rdparty/phonon/includes/Phonon/VideoWidgetInterface b/src/3rdparty/phonon/includes/Phonon/VideoWidgetInterface
new file mode 100644
index 0000000000..173dd33e35
--- /dev/null
+++ b/src/3rdparty/phonon/includes/Phonon/VideoWidgetInterface
@@ -0,0 +1 @@
+#include "../../phonon/videowidgetinterface.h"
diff --git a/src/3rdparty/phonon/includes/Phonon/VolumeFaderEffect b/src/3rdparty/phonon/includes/Phonon/VolumeFaderEffect
new file mode 100644
index 0000000000..9e644006e6
--- /dev/null
+++ b/src/3rdparty/phonon/includes/Phonon/VolumeFaderEffect
@@ -0,0 +1 @@
+#include "../../phonon/volumefadereffect.h"
diff --git a/src/3rdparty/phonon/includes/Phonon/VolumeFaderInterface b/src/3rdparty/phonon/includes/Phonon/VolumeFaderInterface
new file mode 100644
index 0000000000..47bfe26a19
--- /dev/null
+++ b/src/3rdparty/phonon/includes/Phonon/VolumeFaderInterface
@@ -0,0 +1 @@
+#include "../../phonon/volumefaderinterface.h"
diff --git a/src/3rdparty/phonon/includes/Phonon/VolumeSlider b/src/3rdparty/phonon/includes/Phonon/VolumeSlider
new file mode 100644
index 0000000000..f4d50f7c1e
--- /dev/null
+++ b/src/3rdparty/phonon/includes/Phonon/VolumeSlider
@@ -0,0 +1 @@
+#include "../../phonon/volumeslider.h"
diff --git a/src/3rdparty/phonon/phonon.pc.cmake b/src/3rdparty/phonon/phonon.pc.cmake
new file mode 100644
index 0000000000..10c3712825
--- /dev/null
+++ b/src/3rdparty/phonon/phonon.pc.cmake
@@ -0,0 +1,11 @@
+prefix=@CMAKE_INSTALL_PREFIX@
+exec_prefix=@EXEC_INSTALL_PREFIX@
+libdir=@LIB_INSTALL_DIR@
+includedir=@INCLUDE_INSTALL_DIR@
+
+Name: Phonon
+Description: Phonon library needed to build applications
+Version: @PHONON_LIB_MAJOR_VERSION@.@PHONON_LIB_MINOR_VERSION@.@PHONON_LIB_PATCH_VERSION@
+Requires: QtCore QtGui QtDBus
+Libs: -L${libdir} -lphonon
+Cflags: -I${includedir}
diff --git a/src/3rdparty/phonon/phonon/.krazy b/src/3rdparty/phonon/phonon/.krazy
new file mode 100644
index 0000000000..f0ab4d57c4
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/.krazy
@@ -0,0 +1,2 @@
+EXCLUDE qclasses
+SKIP /DESIGN/
diff --git a/src/3rdparty/phonon/phonon/BUGS b/src/3rdparty/phonon/phonon/BUGS
new file mode 100644
index 0000000000..fb74e44cfc
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/BUGS
@@ -0,0 +1,9 @@
+When the backend changes there's a drop in the playback. When it's in
+PlayingState it could time how long it takes until the playback resumes and add
+that time to the seek.
+
+When the backend changes the paths are not restored correctly and it crashes
+
+When a new AudioOutput is created with the same name and category it'll still cause
+a notification if a device fallback was necessary. One such notification per
+name/category or even ignoring the name sure is enough.
diff --git a/src/3rdparty/phonon/phonon/CMakeLists.txt b/src/3rdparty/phonon/phonon/CMakeLists.txt
new file mode 100644
index 0000000000..11d7913aee
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/CMakeLists.txt
@@ -0,0 +1,104 @@
+if (PHONON_BUILD_TESTS)
+ add_subdirectory(tests)
+endif (PHONON_BUILD_TESTS)
+
+if (PHONON_BUILD_EXAMPLES)
+ add_subdirectory(examples)
+endif (PHONON_BUILD_EXAMPLES)
+
+add_subdirectory(experimental)
+
+set(phonon_LIB_SRCS
+ objectdescription.cpp
+ objectdescriptionmodel.cpp
+ phononnamespace.cpp
+ mediasource.cpp
+ abstractmediastream.cpp
+ streaminterface.cpp
+ mediaobject.cpp
+ medianode.cpp
+ path.cpp
+ effectparameter.cpp
+ effect.cpp
+ volumefadereffect.cpp
+ abstractaudiooutput.cpp
+ abstractaudiooutput_p.cpp
+ audiooutput.cpp
+ audiooutputinterface.cpp
+ abstractvideooutput.cpp
+ abstractvideooutput_p.cpp
+ backendcapabilities.cpp
+ globalconfig.cpp
+ factory.cpp
+ platform.cpp
+ mediacontroller.cpp
+ videowidget.cpp
+ videoplayer.cpp
+ seekslider.cpp
+ volumeslider.cpp
+ effectwidget.cpp
+ iodevicestream.cpp
+ )
+
+if (QT_QTDBUS_FOUND)
+ list(APPEND phonon_LIB_SRCS
+ audiooutputadaptor.cpp
+ )
+endif (QT_QTDBUS_FOUND)
+
+
+add_definitions(-DPHONON_LIBRARY_PATH="${PLUGIN_INSTALL_DIR}/plugins")
+automoc4_add_library(phonon SHARED ${phonon_LIB_SRCS})
+target_link_libraries(phonon ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY})
+if (QT_QTDBUS_FOUND)
+ target_link_libraries(phonon ${QT_QTDBUS_LIBRARY})
+endif (QT_QTDBUS_FOUND)
+if (${CMAKE_SYSTEM_NAME} MATCHES "SunOS")
+ # We need to explicitly link libm to phonon in Solaris
+ target_link_libraries(phonon m)
+endif (${CMAKE_SYSTEM_NAME} MATCHES "SunOS")
+
+set_target_properties(phonon PROPERTIES
+ VERSION ${PHONON_LIB_VERSION}
+ SOVERSION ${PHONON_LIB_SOVERSION}
+ DEFINE_SYMBOL MAKE_PHONON_LIB
+ )
+install(TARGETS phonon ${INSTALL_TARGETS_DEFAULT_ARGS})
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/phononnamespace.h.in ${CMAKE_CURRENT_BINARY_DIR}/phononnamespace.h)
+
+install(FILES
+ phonon_export.h
+ objectdescription.h
+ objectdescriptionmodel.h
+ ${CMAKE_CURRENT_BINARY_DIR}/phononnamespace.h
+ mediasource.h
+ abstractmediastream.h
+ streaminterface.h
+ mediaobject.h
+ audiooutput.h
+ medianode.h
+ path.h
+ effectparameter.h
+ effect.h
+ effectinterface.h
+ volumefadereffect.h
+ volumefaderinterface.h
+ abstractaudiooutput.h
+ abstractvideooutput.h
+ backendcapabilities.h
+ phonondefs.h
+ backendinterface.h
+ mediaobjectinterface.h
+ audiooutputinterface.h
+ addoninterface.h
+ mediacontroller.h
+ videowidget.h
+ videowidgetinterface.h
+ videoplayer.h
+ seekslider.h
+ volumeslider.h
+ effectwidget.h
+ platformplugin.h
+ DESTINATION ${INCLUDE_INSTALL_DIR}/phonon COMPONENT Devel)
+
+install(FILES org.kde.Phonon.AudioOutput.xml DESTINATION ${DBUS_INTERFACES_INSTALL_DIR})
diff --git a/src/3rdparty/phonon/phonon/IDEAS b/src/3rdparty/phonon/phonon/IDEAS
new file mode 100644
index 0000000000..96fe0567cf
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/IDEAS
@@ -0,0 +1,70 @@
+MediaInfo class
+===============
+
+It might be nice to have a class that gives information about MediaSource
+objects without having to use MediaObject for it. Something like QFileInfo for
+QFile. MediaObject could also return a list of MediaInfo objects for all the
+MediaSource objects in the queue.
+
+Rationale: The app then can get info about length and substreams so that it can
+set up everything correctly for the next "file" in the queue.
+
+
+- on hotplug of a USB audio/video device:
+ 1. If the device is plugged in for the first time
+ Check whether the backend now provides new device selections. If yes, open
+ up central config with the page that allows selection of the default
+ devices. Tell the user what new options are available.
+ Allow the user to set preference of devices: If device USB-Headset is
+ available use that, else use builtin speakers.
+
+ device info persistance
+=========================
+On device selections: should the user be presented with options that are
+currently not available? It might actually be confusing to select a device that
+is not usable at the moment.
+
+Some situations:
+(device A is always available)
+- user plugs device B
+- selects device B as default
+next day: device B unplugged
+- phonon falls back to device A as B is not available and shows a passive popup
+ informing the user about the fallback
+- user opens config dialog
+- device B still shows up as default
+- selects device A, closes dialog
+- opens dialog again
+- device B is gone...
+- user plugs device B
+- device B reappears
+
+The Backend has to provide the information about devices. Those can map directly
+to hardware or a soundserver or some other virtual device. The Backend has to
+have some unique identifier. For example the ALSA devices could be identified
+using the ALSA device names (either hw:0, hw:1 or aliases from asoundrc). OSS
+devices could be identified using /dev/dsp, /dev/dsp1 and so on.
+=> the backend internal uid is a string
+In the Frontend all that is needed is a name and a description of the device
+(both translated to the current locale) and a unique identifier to talk to the
+backend. This identifier could be the same as used internally by the Backend,
+but doesn't have to be.
+
+ "lowlevel" audio I/O
+======================
+ByteStream is a buffered stream, and as therefore completely useless for cases
+where an application wants to write audio data to the soundcard/-system with low
+latency.
+=> PcmInStream and PcmOutStream
+
+
+============================================================================
+= Ideas for "useless but nice" things (until somebody can convince me that =
+= they're useful) =
+============================================================================
+
+ Video Output
+==============
+Add another VideoOutput that can be used directly with QGraphicsView by creating
+a QGraphicsItem subclass.
+
diff --git a/src/3rdparty/phonon/phonon/Messages.sh b/src/3rdparty/phonon/phonon/Messages.sh
new file mode 100644
index 0000000000..c628a048a7
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/Messages.sh
@@ -0,0 +1,6 @@
+#! /usr/bin/env bash
+find ./ -maxdepth 1 -name "*.cpp" -print > files
+find ./ -maxdepth 1 -name "*.h" -print >> files
+#$EXTRACTRC `find $dirs -maxdepth 1 \( -name \*.rc -o -name \*.ui -o -name \*.ui3 -o -name \*.ui4 -o -name \*.kcfg \) ` >> rc.cpp || exit 11
+$XGETTEXT_QT --copyright-holder=This_file_is_part_of_KDE --msgid-bugs-address=http://bugs.kde.org --files-from=files -o $podir/libphonon.pot
+rm files
diff --git a/src/3rdparty/phonon/phonon/TODO b/src/3rdparty/phonon/phonon/TODO
new file mode 100644
index 0000000000..479bbd7c2f
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/TODO
@@ -0,0 +1,31 @@
+- add a metadata function that returns a QVariant instead of a QString - useful for QImage or other binary (QByteArray) content
+
+- QImage VideoWidget::screenshot(): ordinary screenshot doesn't work with XV says Christoph. And VideoDataOutput
+ would be major overkill.
+
+- consider whether to add a signal to notify when the information for
+ availableAudioStreams/availableVideoStreams/availableSubtitleStreams
+ is available
+
+- look at collaboration with other projects, e.g. pavucontrol, gsmartmix
+
+- consider Player dbus interface in MediaObject
+
+- add global setting to pause video when it's not visible
+
+- add a way to request a specific version (>=) from the Backend, so that known to be buggy Backends aren't used
+
+- Video Overlays (OSD) like: show a rectangle as a play symbol, show the position in
+ the file as something like [IIIIIIIII------], and so on
+
+- http://bugs.kde.org/show_bug.cgi?id=147494
+
+- frame/sample precise positioning (cue in/out)
+
+- different timecode support like SMPTE
+
+- Codec interface - at least for audio
+
+- Speed factor for playback (useful mostly for audio - but video still needs to stay in sync)
+
+- tell the platform plugin which backend was loaded (if it doesn't do it itself) so that it can load KDE translations for the backend
diff --git a/src/3rdparty/phonon/phonon/abstractaudiooutput.cpp b/src/3rdparty/phonon/phonon/abstractaudiooutput.cpp
new file mode 100644
index 0000000000..47c5a89777
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/abstractaudiooutput.cpp
@@ -0,0 +1,50 @@
+/* This file is part of the KDE project
+Copyright (C) 2005-2006 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+#include "abstractaudiooutput.h"
+#include "abstractaudiooutput_p.h"
+#include "factory_p.h"
+
+#define PHONON_CLASSNAME AbstractAudioOutput
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+
+ AbstractAudioOutput::AbstractAudioOutput(AbstractAudioOutputPrivate &dd, QObject *parent) : QObject(parent),
+ MediaNode(dd)
+ {
+ }
+
+ AbstractAudioOutput::~AbstractAudioOutput()
+ {
+ }
+
+} //namespace Phonon
+
+QT_END_NAMESPACE
+
+#undef PHONON_CLASSNAME
+
+#include "moc_abstractaudiooutput.cpp"
+
+// vim: sw=4 ts=4 tw=80
diff --git a/src/3rdparty/phonon/phonon/abstractaudiooutput.h b/src/3rdparty/phonon/phonon/abstractaudiooutput.h
new file mode 100644
index 0000000000..a466298f9e
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/abstractaudiooutput.h
@@ -0,0 +1,57 @@
+/* This file is part of the KDE project
+Copyright (C) 2005-2006 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+#ifndef Phonon_ABSTRACTAUDIOOUTPUTBASE_H
+#define Phonon_ABSTRACTAUDIOOUTPUTBASE_H
+
+#include "phonondefs.h"
+#include "phonon_export.h"
+#include "medianode.h"
+#include <QtCore/QObject>
+
+QT_BEGIN_HEADER
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+ class AbstractAudioOutputPrivate;
+
+ /** \class AbstractAudioOutput abstractaudiooutput.h Phonon/AbstractAudioOutput
+ * Common base class for all audio outputs.
+ *
+ * \see AudioOutput
+ */
+ class PHONON_EXPORT AbstractAudioOutput : public QObject, public MediaNode
+ {
+ Q_OBJECT
+ K_DECLARE_PRIVATE(AbstractAudioOutput)
+ protected:
+ AbstractAudioOutput(AbstractAudioOutputPrivate &dd, QObject *parent);
+ public:
+ ~AbstractAudioOutput();
+ };
+} //namespace Phonon
+
+QT_END_NAMESPACE
+QT_END_HEADER
+
+// vim: sw=4 ts=4 tw=80
+#endif // Phonon_ABSTRACTAUDIOOUTPUTBASE_H
diff --git a/src/3rdparty/phonon/phonon/abstractaudiooutput_p.cpp b/src/3rdparty/phonon/phonon/abstractaudiooutput_p.cpp
new file mode 100644
index 0000000000..83ee8b08b6
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/abstractaudiooutput_p.cpp
@@ -0,0 +1,44 @@
+/* This file is part of the KDE project
+ Copyright (C) 2007 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "abstractaudiooutput_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+
+bool AbstractAudioOutputPrivate::aboutToDeleteBackendObject()
+{
+ return true;
+}
+
+void AbstractAudioOutputPrivate::setupBackendObject()
+{
+ Q_ASSERT(m_backendObject);
+
+ // set up attributes
+}
+
+} // namespace Phonon
+
+QT_END_NAMESPACE
diff --git a/src/3rdparty/phonon/phonon/abstractaudiooutput_p.h b/src/3rdparty/phonon/phonon/abstractaudiooutput_p.h
new file mode 100644
index 0000000000..831eb8dc7f
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/abstractaudiooutput_p.h
@@ -0,0 +1,50 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef PHONON_ABSTRACTAUDIOOUTPUT_P_H
+#define PHONON_ABSTRACTAUDIOOUTPUT_P_H
+
+#include "abstractaudiooutput.h"
+#include "medianode_p.h"
+#include "phonondefs_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+class AbstractAudioOutputPrivate : public MediaNodePrivate
+{
+ Q_DECLARE_PUBLIC(AbstractAudioOutput)
+ PHONON_PRIVATEABSTRACTCLASS
+ public:
+ virtual QObject *qObject() { return q_func(); }
+ protected:
+ AbstractAudioOutputPrivate(CastId castId = AbstractAudioOutputPrivateType)
+ : MediaNodePrivate(castId)
+ {
+ }
+};
+} //namespace Phonon
+
+QT_END_NAMESPACE
+
+#endif // PHONON_ABSTRACTAUDIOOUTPUT_P_H
diff --git a/src/3rdparty/phonon/phonon/abstractmediastream.cpp b/src/3rdparty/phonon/phonon/abstractmediastream.cpp
new file mode 100644
index 0000000000..a661702186
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/abstractmediastream.cpp
@@ -0,0 +1,198 @@
+/* This file is part of the KDE project
+ Copyright (C) 2007 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "abstractmediastream.h"
+#include "abstractmediastream_p.h"
+#include "mediaobjectinterface.h"
+#include "mediaobject_p.h"
+#include "streaminterface_p.h"
+
+#ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+
+AbstractMediaStream::AbstractMediaStream(QObject *parent)
+ : QObject(parent),
+ d_ptr(new AbstractMediaStreamPrivate)
+{
+ d_ptr->q_ptr = this;
+}
+
+AbstractMediaStream::AbstractMediaStream(AbstractMediaStreamPrivate &dd, QObject *parent)
+ : QObject(parent),
+ d_ptr(&dd)
+{
+ d_ptr->q_ptr = this;
+}
+
+AbstractMediaStream::~AbstractMediaStream()
+{
+ delete d_ptr;
+}
+
+qint64 AbstractMediaStream::streamSize() const
+{
+ return d_ptr->streamSize;
+}
+
+void AbstractMediaStream::setStreamSize(qint64 newSize)
+{
+ d_ptr->setStreamSize(newSize);
+}
+
+void AbstractMediaStreamPrivate::setStreamSize(qint64 newSize)
+{
+ streamSize = newSize;
+ if (streamInterface) {
+ streamInterface->setStreamSize(newSize);
+ }
+}
+
+bool AbstractMediaStream::streamSeekable() const
+{
+ return d_ptr->streamSeekable;
+}
+
+void AbstractMediaStream::setStreamSeekable(bool s)
+{
+ d_ptr->setStreamSeekable(s);
+}
+
+void AbstractMediaStreamPrivate::setStreamSeekable(bool s)
+{
+ streamSeekable = s;
+ if (streamInterface) {
+ streamInterface->setStreamSeekable(s);
+ }
+}
+
+void AbstractMediaStream::writeData(const QByteArray &data)
+{
+ d_ptr->writeData(data);
+}
+
+void AbstractMediaStreamPrivate::writeData(const QByteArray &data)
+{
+ if (ignoreWrites) {
+ return;
+ }
+ Q_ASSERT(streamInterface);
+ streamInterface->writeData(data);
+}
+
+void AbstractMediaStream::endOfData()
+{
+ d_ptr->endOfData();
+}
+
+void AbstractMediaStreamPrivate::endOfData()
+{
+ if (streamInterface) {
+ streamInterface->endOfData();
+ }
+}
+
+void AbstractMediaStream::error(Phonon::ErrorType type, const QString &text)
+{
+ Q_D(AbstractMediaStream);
+ d->errorType = type;
+ d->errorText = text;
+ if (d->mediaObjectPrivate) {
+ // TODO: MediaObject might be in a different thread
+ d->mediaObjectPrivate->streamError(type, text);
+ }
+}
+
+void AbstractMediaStream::enoughData()
+{
+}
+
+void AbstractMediaStream::seekStream(qint64)
+{
+ Q_ASSERT(!d_ptr->streamSeekable);
+}
+
+AbstractMediaStreamPrivate::~AbstractMediaStreamPrivate()
+{
+ if (mediaObjectPrivate) {
+ // TODO: MediaObject might be in a different thread
+ mediaObjectPrivate->removeDestructionHandler(this);
+ }
+ if (streamInterface) {
+ // TODO: StreamInterface might be in a different thread
+ streamInterface->d->disconnectMediaStream();
+ }
+}
+
+void AbstractMediaStreamPrivate::setStreamInterface(StreamInterface *iface)
+{
+ Q_Q(AbstractMediaStream);
+ streamInterface = iface;
+ if (!iface) {
+ // our subclass might be just about to call writeData, so tell it we have enoughData and
+ // ignore the next writeData calls
+ q->enoughData();
+ ignoreWrites = true;
+ return;
+ }
+ if (ignoreWrites) {
+ ignoreWrites = false;
+ // we had a StreamInterface before. The new StreamInterface expects us to start reading from
+ // position 0
+ q->reset();
+ } else {
+ iface->setStreamSize(streamSize);
+ iface->setStreamSeekable(streamSeekable);
+ }
+}
+
+void AbstractMediaStreamPrivate::setMediaObjectPrivate(MediaObjectPrivate *mop)
+{
+ // TODO: MediaObject might be in a different thread
+ mediaObjectPrivate = mop;
+ mediaObjectPrivate->addDestructionHandler(this);
+ if (!errorText.isEmpty()) {
+ mediaObjectPrivate->streamError(errorType, errorText);
+ }
+}
+
+void AbstractMediaStreamPrivate::phononObjectDestroyed(MediaNodePrivate *bp)
+{
+ // TODO: MediaObject might be in a different thread
+ Q_ASSERT(bp == mediaObjectPrivate);
+ Q_UNUSED(bp);
+ mediaObjectPrivate = 0;
+}
+
+} // namespace Phonon
+
+
+QT_END_NAMESPACE
+
+#include "moc_abstractmediastream.cpp"
+
+#endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
+
+// vim: sw=4 sts=4 et tw=100
diff --git a/src/3rdparty/phonon/phonon/abstractmediastream.h b/src/3rdparty/phonon/phonon/abstractmediastream.h
new file mode 100644
index 0000000000..0daa92ab53
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/abstractmediastream.h
@@ -0,0 +1,227 @@
+/* This file is part of the KDE project
+ Copyright (C) 2007 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef PHONON_ABSTRACTMEDIASTREAM_H
+#define PHONON_ABSTRACTMEDIASTREAM_H
+
+#include "phonon_export.h"
+#include "phononnamespace.h"
+#include <QtCore/QObject>
+
+QT_BEGIN_HEADER
+QT_BEGIN_NAMESPACE
+
+class QByteArray;
+
+#ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
+
+namespace Phonon
+{
+class MediaObject;
+class AbstractMediaStreamPrivate;
+
+/** \class AbstractMediaStream abstractmediastream.h Phonon/AbstractMediaStream
+ * \brief Base class for custom media data streams.
+ *
+ * Implement this class to provide a custom data stream to the backend. The class supports both, the
+ * push and the pull model.
+ *
+ * Push:
+ * \code
+ * PushStream::PushStream(QObject *parent)
+ * : AbstractMediaStream(parent), m_timer(new QTimer(this))
+ * {
+ * setStreamSize(getMediaStreamSize());
+ *
+ * connect(m_timer, SIGNAL(timeout()), SLOT(moreData()));
+ * m_timer->setInterval(0);
+ * }
+ *
+ * void PushStream::moreData()
+ * {
+ * const QByteArray data = getMediaData();
+ * if (data.isEmpty()) {
+ * endOfData();
+ * } else {
+ * writeData(data);
+ * }
+ * }
+ *
+ * void PushStream::needData()
+ * {
+ * m_timer->start();
+ * moreData();
+ * }
+ *
+ * void PushStream::enoughData()
+ * {
+ * m_timer->stop();
+ * }
+ * \endcode
+ *
+ * Pull:
+ * \code
+ * PullStream::PullStream(QObject *parent)
+ * : AbstractMediaStream(parent)
+ * {
+ * setStreamSize(getMediaStreamSize());
+ * }
+ *
+ * void PullStream::needData()
+ * {
+ * const QByteArray data = getMediaData();
+ * if (data.isEmpty()) {
+ * endOfData();
+ * } else {
+ * writeData(data);
+ * }
+ * }
+ * \endcode
+ *
+ * \ingroup Playback
+ * \author Matthias Kretz <kretz@kde.org>
+ */
+class PHONON_EXPORT AbstractMediaStream : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(AbstractMediaStream)
+ friend class MediaObject;
+ friend class MediaObjectPrivate;
+ friend class StreamInterface;
+ public:
+ virtual ~AbstractMediaStream();
+
+ protected:
+ /**
+ * Constructs an AbstractMediaStream object with a \p parent.
+ */
+ explicit AbstractMediaStream(QObject *parent = 0);
+
+ /**
+ * Returns the stream size that was set with \ref setStreamSize.
+ *
+ * A negative value means that the length of the stream cannot be known.
+ *
+ * Defaults to \c 0.
+ */
+ qint64 streamSize() const;
+
+ /**
+ * Sets the size of the stream in number of bytes.
+ *
+ * A negative value means that the length of the stream cannot be known.
+ *
+ * Defaults to 0.
+ *
+ * This function has to be called. A backend will not call \ref needData() until the
+ * stream size is set.
+ */
+ void setStreamSize(qint64);
+
+ /**
+ * Returns whether your data stream is set as seekable.
+ *
+ * Defaults to \c false.
+ */
+ bool streamSeekable() const;
+
+ /**
+ * Sets whether your data stream is seekable.
+ *
+ * Defaults to \c false.
+ *
+ * If you set this to \c true you have to implement the \ref seekStream function.
+ */
+ void setStreamSeekable(bool);
+
+ /**
+ * Sends the media \p data to the backend for decoding.
+ *
+ * \warning Don't call this function before the first needData() is emitted.
+ */
+ void writeData(const QByteArray &data);
+
+ /**
+ * Tells the backend that the media data stream is at its end.
+ *
+ * \warning Don't call this function before the first needData() is emitted.
+ */
+ void endOfData();
+
+ /**
+ * If an I/O error occurs you should call this function to make MediaObject go into
+ * ErrorState.
+ *
+ * \see MediaObject::errorType()
+ * \see MediaObject::errorString()
+ */
+ void error(Phonon::ErrorType errorType, const QString &errorString);
+
+ /**
+ * Reimplement this function to reset the stream. Subsequent calls to writeData should start
+ * from the first position of the data unless a seek is requested.
+ *
+ * The function is necessary for the case where a non-seekable MediaStream is
+ * played more than once. For a seekable stream the implementation can simply call
+ * \code
+ * seekStream(0);
+ * \endcode.
+ */
+ virtual void reset() = 0;
+
+ /**
+ * Reimplement this function to be notified when the backend needs data.
+ *
+ * When this function is called you should try to call writeData or endOfData before
+ * returning.
+ */
+ virtual void needData() = 0;
+
+ /**
+ * Reimplement this function to be notified when the backend has enough data and your stream
+ * object may take a break. This method is important for pushing data to the backend in
+ * order to not fill the backend buffer unnecessarily.
+ */
+ virtual void enoughData();
+
+ /**
+ * Reimplement this function if your stream is seekable.
+ *
+ * When this function is called the next call to writeData has to be at the requested \p
+ * offset.
+ *
+ * \warning Do not call the parent implementation.
+ */
+ virtual void seekStream(qint64 offset);
+
+ AbstractMediaStream(AbstractMediaStreamPrivate &dd, QObject *parent);
+ AbstractMediaStreamPrivate *d_ptr;
+};
+
+} // namespace Phonon
+
+#endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
+
+QT_END_NAMESPACE
+QT_END_HEADER
+
+#endif // PHONON_ABSTRACTMEDIASTREAM_H
diff --git a/src/3rdparty/phonon/phonon/abstractmediastream_p.h b/src/3rdparty/phonon/phonon/abstractmediastream_p.h
new file mode 100644
index 0000000000..a9d64894fb
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/abstractmediastream_p.h
@@ -0,0 +1,83 @@
+/* This file is part of the KDE project
+ Copyright (C) 2007 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef ABSTRACTMEDIASTREAM_P_H
+#define ABSTRACTMEDIASTREAM_P_H
+
+#include "phonon_export.h"
+#include "abstractmediastream.h"
+#include "mediaobject_p.h"
+#include "streaminterface.h"
+
+#include "medianodedestructionhandler_p.h"
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
+
+class MediaObjectPrivate;
+
+namespace Phonon
+{
+class PHONON_EXPORT AbstractMediaStreamPrivate : private MediaNodeDestructionHandler
+{
+ friend class MediaObject;
+ Q_DECLARE_PUBLIC(AbstractMediaStream)
+ public:
+ void setStreamInterface(StreamInterface *);
+ void setMediaObjectPrivate(MediaObjectPrivate *);
+
+ protected:
+ AbstractMediaStreamPrivate()
+ : streamSize(0),
+ streamSeekable(false),
+ ignoreWrites(false),
+ streamInterface(0),
+ mediaObjectPrivate(0),
+ errorType(NoError)
+ {
+ }
+ ~AbstractMediaStreamPrivate();
+
+ virtual void setStreamSize(qint64 newSize);
+ virtual void setStreamSeekable(bool s);
+ virtual void writeData(const QByteArray &data);
+ virtual void endOfData();
+ void phononObjectDestroyed(MediaNodePrivate *);
+
+ AbstractMediaStream *q_ptr;
+ qint64 streamSize;
+ bool streamSeekable;
+ bool ignoreWrites;
+ StreamInterface *streamInterface;
+ MediaObjectPrivate *mediaObjectPrivate;
+ Phonon::ErrorType errorType;
+ QString errorText;
+};
+} // namespace Phonon
+
+#endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
+
+QT_END_NAMESPACE
+
+#endif // ABSTRACTMEDIASTREAM_P_H
+// vim: sw=4 sts=4 et tw=100
diff --git a/src/3rdparty/phonon/phonon/abstractvideooutput.cpp b/src/3rdparty/phonon/phonon/abstractvideooutput.cpp
new file mode 100644
index 0000000000..30dde14373
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/abstractvideooutput.cpp
@@ -0,0 +1,41 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+#include "abstractvideooutput.h"
+#include "abstractvideooutput_p.h"
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_PHONON_VIDEO
+
+namespace Phonon
+{
+
+AbstractVideoOutput::AbstractVideoOutput(AbstractVideoOutputPrivate &d)
+ : MediaNode(d)
+{
+}
+
+} // namespace Phonon
+
+#endif //QT_NO_PHONON_VIDEO
+
+QT_END_NAMESPACE
diff --git a/src/3rdparty/phonon/phonon/abstractvideooutput.h b/src/3rdparty/phonon/phonon/abstractvideooutput.h
new file mode 100644
index 0000000000..04cfdf0e08
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/abstractvideooutput.h
@@ -0,0 +1,74 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005-2006 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+#ifndef Phonon_ABSTRACTVIDEOOUTPUTBASE_H
+#define Phonon_ABSTRACTVIDEOOUTPUTBASE_H
+
+#include "phonondefs.h"
+#include "phonon_export.h"
+#include "medianode.h"
+#include <QtCore/QObject>
+
+QT_BEGIN_HEADER
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_PHONON_VIDEO
+
+class QString;
+
+namespace Phonon
+{
+
+namespace Experimental
+{
+ class Visualization;
+ class VisualizationPrivate;
+} // namespace Experimental
+
+ class AbstractVideoOutputPrivate;
+
+ /** \class AbstractVideoOutput abstractvideooutput.h Phonon/AbstractVideoOutput
+ * \brief Common base class for all video outputs.
+ *
+ * \see VideoWidget
+ */
+ class PHONON_EXPORT AbstractVideoOutput : public MediaNode
+ {
+ friend class Experimental::Visualization;
+ friend class Experimental::VisualizationPrivate;
+ K_DECLARE_PRIVATE(AbstractVideoOutput)
+ protected:
+ /**
+ * \internal
+ * Constructor that is called from derived classes.
+ *
+ * \param d the private object
+ */
+ AbstractVideoOutput(AbstractVideoOutputPrivate &d);
+ };
+} //namespace Phonon
+
+#endif //QT_NO_PHONON_VIDEO
+
+QT_END_NAMESPACE
+QT_END_HEADER
+
+#endif // Phonon_ABSTRACTVIDEOOUTPUTBASE_H
diff --git a/src/3rdparty/phonon/phonon/abstractvideooutput_p.cpp b/src/3rdparty/phonon/phonon/abstractvideooutput_p.cpp
new file mode 100644
index 0000000000..83d06507ca
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/abstractvideooutput_p.cpp
@@ -0,0 +1,41 @@
+/* This file is part of the KDE project
+ Copyright (C) 2007 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "abstractvideooutput_p.h"
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_PHONON_VIDEO
+
+namespace Phonon
+{
+
+bool AbstractVideoOutputPrivate::aboutToDeleteBackendObject()
+{
+ return true;
+}
+
+} //namespace Phonon
+
+#endif //QT_NO_PHONON_VIDEO
+
+QT_END_NAMESPACE
diff --git a/src/3rdparty/phonon/phonon/abstractvideooutput_p.h b/src/3rdparty/phonon/phonon/abstractvideooutput_p.h
new file mode 100644
index 0000000000..d0e81578b0
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/abstractvideooutput_p.h
@@ -0,0 +1,48 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef ABSTRACTVIDEOOUTPUT_P_H
+#define ABSTRACTVIDEOOUTPUT_P_H
+
+#include "abstractvideooutput.h"
+#include "medianode_p.h"
+#include "phonondefs_p.h"
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_PHONON_VIDEO
+
+namespace Phonon
+{
+class AbstractVideoOutputPrivate : public MediaNodePrivate
+{
+ Q_DECLARE_PUBLIC(AbstractVideoOutput)
+ PHONON_PRIVATEABSTRACTCLASS
+};
+} //namespace Phonon
+
+#endif //QT_NO_PHONON_VIDEO
+
+QT_END_NAMESPACE
+
+#endif // ABSTRACTVIDEOOUTPUT_P_H
+// vim: sw=4 ts=4 tw=80
diff --git a/src/3rdparty/phonon/phonon/addoninterface.h b/src/3rdparty/phonon/phonon/addoninterface.h
new file mode 100644
index 0000000000..f400523195
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/addoninterface.h
@@ -0,0 +1,103 @@
+/* This file is part of the KDE project
+ Copyright (C) 2007-2008 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef PHONON_ADDONINTERFACE_H
+#define PHONON_ADDONINTERFACE_H
+
+#include "phononnamespace.h"
+
+#include <QtCore/QList>
+#include <QtCore/QVariant>
+
+QT_BEGIN_HEADER
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_PHONON_MEDIACONTROLLER
+
+namespace Phonon
+{
+/** \class AddonInterface addoninterface.h Phonon/AddonInterface
+ * \short Interface for Menu, Chapter, Angle and Title/Track control.
+ *
+ * \author Matthias Kretz <kretz@kde.org>
+ */
+class AddonInterface
+{
+ public:
+ virtual ~AddonInterface() {}
+
+ enum Interface {
+ NavigationInterface = 1,
+ ChapterInterface = 2,
+ AngleInterface = 3,
+ TitleInterface = 4,
+ SubtitleInterface = 5,
+ AudioChannelInterface = 6
+ };
+
+ enum NavigationCommand {
+ Menu1Button
+ };
+ enum ChapterCommand {
+ availableChapters,
+ chapter,
+ setChapter
+ };
+ enum AngleCommand {
+ availableAngles,
+ angle,
+ setAngle
+ };
+ enum TitleCommand {
+ availableTitles,
+ title,
+ setTitle,
+ autoplayTitles,
+ setAutoplayTitles
+ };
+ enum SubtitleCommand {
+ availableSubtitles,
+ currentSubtitle,
+ setCurrentSubtitle
+ };
+ enum AudioChannelCommand {
+ availableAudioChannels,
+ currentAudioChannel,
+ setCurrentAudioChannel
+ };
+
+ virtual bool hasInterface(Interface iface) const = 0;
+
+ virtual QVariant interfaceCall(Interface iface, int command,
+ const QList<QVariant> &arguments = QList<QVariant>()) = 0;
+};
+
+} // namespace Phonon
+
+Q_DECLARE_INTERFACE(Phonon::AddonInterface, "AddonInterface0.2.phonon.kde.org")
+
+#endif //QT_NO_PHONON_MEDIACONTROLLER
+
+QT_END_NAMESPACE
+QT_END_HEADER
+
+#endif // PHONON_ADDONINTERFACE_H
diff --git a/src/3rdparty/phonon/phonon/audiooutput.cpp b/src/3rdparty/phonon/phonon/audiooutput.cpp
new file mode 100644
index 0000000000..752580a156
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/audiooutput.cpp
@@ -0,0 +1,418 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005-2006 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+#include "audiooutput.h"
+#include "audiooutput_p.h"
+#include "factory_p.h"
+#include "objectdescription.h"
+#include "audiooutputadaptor_p.h"
+#include "globalconfig_p.h"
+#include "audiooutputinterface.h"
+#include "phononnamespace_p.h"
+#include "platform_p.h"
+
+#include <qmath.h>
+
+#define PHONON_CLASSNAME AudioOutput
+#define IFACES2 AudioOutputInterface42
+#define IFACES1 IFACES2
+#define IFACES0 AudioOutputInterface40, IFACES1
+#define PHONON_INTERFACENAME IFACES0
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+
+static inline bool callSetOutputDevice(MediaNodePrivate *const d, int index)
+{
+ Iface<IFACES2> iface(d);
+ if (iface) {
+ return iface->setOutputDevice(AudioOutputDevice::fromIndex(index));
+ }
+ return Iface<IFACES0>::cast(d)->setOutputDevice(index);
+}
+
+static inline bool callSetOutputDevice(MediaNodePrivate *const d, const AudioOutputDevice &dev)
+{
+ Iface<IFACES2> iface(d);
+ if (iface) {
+ return iface->setOutputDevice(dev);
+ }
+ return Iface<IFACES0>::cast(d)->setOutputDevice(dev.index());
+}
+
+AudioOutput::AudioOutput(Phonon::Category category, QObject *parent)
+ : AbstractAudioOutput(*new AudioOutputPrivate, parent)
+{
+ K_D(AudioOutput);
+ d->init(category);
+}
+
+AudioOutput::AudioOutput(QObject *parent)
+ : AbstractAudioOutput(*new AudioOutputPrivate, parent)
+{
+ K_D(AudioOutput);
+ d->init(NoCategory);
+}
+
+void AudioOutputPrivate::init(Phonon::Category c)
+{
+ Q_Q(AudioOutput);
+#ifndef QT_NO_DBUS
+ adaptor = new AudioOutputAdaptor(q);
+ static unsigned int number = 0;
+ const QString &path = QLatin1String("/AudioOutputs/") + QString::number(number++);
+ QDBusConnection con = QDBusConnection::sessionBus();
+ con.registerObject(path, q);
+ emit adaptor->newOutputAvailable(con.baseService(), path);
+ q->connect(q, SIGNAL(volumeChanged(qreal)), adaptor, SIGNAL(volumeChanged(qreal)));
+ q->connect(q, SIGNAL(mutedChanged(bool)), adaptor, SIGNAL(mutedChanged(bool)));
+#endif
+
+ category = c;
+
+ // select hardware device according to the category
+ device = AudioOutputDevice::fromIndex(GlobalConfig().audioOutputDeviceFor(category, GlobalConfig::AdvancedDevicesFromSettings | GlobalConfig::HideUnavailableDevices));
+
+ createBackendObject();
+
+ q->connect(Factory::sender(), SIGNAL(availableAudioOutputDevicesChanged()), SLOT(_k_deviceListChanged()));
+}
+
+
+
+void AudioOutputPrivate::createBackendObject()
+{
+ if (m_backendObject)
+ return;
+ Q_Q(AudioOutput);
+ m_backendObject = Factory::createAudioOutput(q);
+ if (m_backendObject) {
+ setupBackendObject();
+ }
+}
+
+QString AudioOutput::name() const
+{
+ K_D(const AudioOutput);
+ return d->name;
+}
+
+void AudioOutput::setName(const QString &newName)
+{
+ K_D(AudioOutput);
+ if (d->name == newName) {
+ return;
+ }
+ d->name = newName;
+ setVolume(Platform::loadVolume(newName));
+#ifndef QT_NO_DBUS
+ emit d->adaptor->nameChanged(newName);
+#endif
+}
+
+static const qreal LOUDNESS_TO_VOLTAGE_EXPONENT = qreal(0.67);
+static const qreal VOLTAGE_TO_LOUDNESS_EXPONENT = qreal(1.0/LOUDNESS_TO_VOLTAGE_EXPONENT);
+
+void AudioOutput::setVolume(qreal volume)
+{
+ K_D(AudioOutput);
+ d->volume = volume;
+ if (k_ptr->backendObject() && !d->muted) {
+ // using Stevens' power law loudness is proportional to (sound pressure)^0.67
+ // sound pressure is proportional to voltage:
+ // p² \prop P \prop V²
+ // => if a factor for loudness of x is requested
+ INTERFACE_CALL(setVolume(pow(volume, VOLTAGE_TO_LOUDNESS_EXPONENT)));
+ } else {
+ emit volumeChanged(volume);
+ }
+ Platform::saveVolume(d->name, volume);
+}
+
+qreal AudioOutput::volume() const
+{
+ K_D(const AudioOutput);
+ if (d->muted || !d->m_backendObject) {
+ return d->volume;
+ }
+ return pow(INTERFACE_CALL(volume()), LOUDNESS_TO_VOLTAGE_EXPONENT);
+}
+
+#ifndef PHONON_LOG10OVER20
+#define PHONON_LOG10OVER20
+static const qreal log10over20 = qreal(0.1151292546497022842); // ln(10) / 20
+#endif // PHONON_LOG10OVER20
+
+qreal AudioOutput::volumeDecibel() const
+{
+ K_D(const AudioOutput);
+ if (d->muted || !d->m_backendObject) {
+ return log(d->volume) / log10over20;
+ }
+ return 0.67 * log(INTERFACE_CALL(volume())) / log10over20;
+}
+
+void AudioOutput::setVolumeDecibel(qreal newVolumeDecibel)
+{
+ setVolume(exp(newVolumeDecibel * log10over20));
+}
+
+bool AudioOutput::isMuted() const
+{
+ K_D(const AudioOutput);
+ return d->muted;
+}
+
+void AudioOutput::setMuted(bool mute)
+{
+ K_D(AudioOutput);
+ if (d->muted != mute) {
+ if (mute) {
+ d->muted = mute;
+ if (k_ptr->backendObject()) {
+ INTERFACE_CALL(setVolume(0.0));
+ }
+ } else {
+ if (k_ptr->backendObject()) {
+ INTERFACE_CALL(setVolume(pow(d->volume, VOLTAGE_TO_LOUDNESS_EXPONENT)));
+ }
+ d->muted = mute;
+ }
+ emit mutedChanged(mute);
+ }
+}
+
+Category AudioOutput::category() const
+{
+ K_D(const AudioOutput);
+ return d->category;
+}
+
+AudioOutputDevice AudioOutput::outputDevice() const
+{
+ K_D(const AudioOutput);
+ return d->device;
+}
+
+bool AudioOutput::setOutputDevice(const AudioOutputDevice &newAudioOutputDevice)
+{
+ K_D(AudioOutput);
+ if (!newAudioOutputDevice.isValid()) {
+ d->outputDeviceOverridden = false;
+ const int newIndex = GlobalConfig().audioOutputDeviceFor(d->category);
+ if (newIndex == d->device.index()) {
+ return true;
+ }
+ d->device = AudioOutputDevice::fromIndex(newIndex);
+ } else {
+ d->outputDeviceOverridden = true;
+ if (d->device == newAudioOutputDevice) {
+ return true;
+ }
+ d->device = newAudioOutputDevice;
+ }
+ if (k_ptr->backendObject()) {
+ return callSetOutputDevice(k_ptr, d->device.index());
+ }
+ return true;
+}
+
+bool AudioOutputPrivate::aboutToDeleteBackendObject()
+{
+ if (m_backendObject) {
+ volume = pINTERFACE_CALL(volume());
+ }
+ return AbstractAudioOutputPrivate::aboutToDeleteBackendObject();
+}
+
+void AudioOutputPrivate::setupBackendObject()
+{
+ Q_Q(AudioOutput);
+ Q_ASSERT(m_backendObject);
+ AbstractAudioOutputPrivate::setupBackendObject();
+
+ QObject::connect(m_backendObject, SIGNAL(volumeChanged(qreal)), q, SLOT(_k_volumeChanged(qreal)));
+ QObject::connect(m_backendObject, SIGNAL(audioDeviceFailed()), q, SLOT(_k_audioDeviceFailed()));
+
+ // set up attributes
+ pINTERFACE_CALL(setVolume(pow(volume, VOLTAGE_TO_LOUDNESS_EXPONENT)));
+
+ // if the output device is not available and the device was not explicitly set
+ if (!callSetOutputDevice(this, device) && !outputDeviceOverridden) {
+ // fall back in the preference list of output devices
+ QList<int> deviceList = GlobalConfig().audioOutputDeviceListFor(category, GlobalConfig::AdvancedDevicesFromSettings | GlobalConfig::HideUnavailableDevices);
+ if (deviceList.isEmpty()) {
+ return;
+ }
+ foreach (int devIndex, deviceList) {
+ const AudioOutputDevice &dev = AudioOutputDevice::fromIndex(devIndex);
+ if (callSetOutputDevice(this, dev)) {
+ handleAutomaticDeviceChange(dev, AudioOutputPrivate::FallbackChange);
+ return; // found one that works
+ }
+ }
+ // if we get here there is no working output device. Tell the backend.
+ const AudioOutputDevice none;
+ callSetOutputDevice(this, none);
+ handleAutomaticDeviceChange(none, FallbackChange);
+ }
+}
+
+void AudioOutputPrivate::_k_volumeChanged(qreal newVolume)
+{
+ if (!muted) {
+ Q_Q(AudioOutput);
+ emit q->volumeChanged(pow(newVolume, qreal(0.67)));
+ }
+}
+
+void AudioOutputPrivate::_k_revertFallback()
+{
+ if (deviceBeforeFallback == -1) {
+ return;
+ }
+ device = AudioOutputDevice::fromIndex(deviceBeforeFallback);
+ callSetOutputDevice(this, device);
+ Q_Q(AudioOutput);
+ emit q->outputDeviceChanged(device);
+#ifndef QT_NO_DBUS
+ emit adaptor->outputDeviceIndexChanged(device.index());
+#endif
+}
+
+void AudioOutputPrivate::_k_audioDeviceFailed()
+{
+ pDebug() << Q_FUNC_INFO;
+ // outputDeviceIndex identifies a failing device
+ // fall back in the preference list of output devices
+ QList<int> deviceList = GlobalConfig().audioOutputDeviceListFor(category, GlobalConfig::AdvancedDevicesFromSettings | GlobalConfig::HideUnavailableDevices);
+ foreach (int devIndex, deviceList) {
+ // if it's the same device as the one that failed, ignore it
+ if (device.index() != devIndex) {
+ const AudioOutputDevice &info = AudioOutputDevice::fromIndex(devIndex);
+ if (callSetOutputDevice(this, info)) {
+ handleAutomaticDeviceChange(info, FallbackChange);
+ return; // found one that works
+ }
+ }
+ }
+ // if we get here there is no working output device. Tell the backend.
+ const AudioOutputDevice none;
+ callSetOutputDevice(this, none);
+ handleAutomaticDeviceChange(none, FallbackChange);
+}
+
+void AudioOutputPrivate::_k_deviceListChanged()
+{
+ pDebug() << Q_FUNC_INFO;
+ // let's see if there's a usable device higher in the preference list
+ QList<int> deviceList = GlobalConfig().audioOutputDeviceListFor(category, GlobalConfig::AdvancedDevicesFromSettings);
+ DeviceChangeType changeType = HigherPreferenceChange;
+ foreach (int devIndex, deviceList) {
+ const AudioOutputDevice &info = AudioOutputDevice::fromIndex(devIndex);
+ if (!info.property("available").toBool()) {
+ if (device.index() == devIndex) {
+ // we've reached the currently used device and it's not available anymore, so we
+ // fallback to the next available device
+ changeType = FallbackChange;
+ }
+ pDebug() << devIndex << "is not available";
+ continue;
+ }
+ pDebug() << devIndex << "is available";
+ if (device.index() == devIndex) {
+ // we've reached the currently used device, nothing to change
+ break;
+ }
+ if (callSetOutputDevice(this, info)) {
+ handleAutomaticDeviceChange(info, changeType);
+ break; // found one with higher preference that works
+ }
+ }
+}
+
+static struct
+{
+ int first;
+ int second;
+} g_lastFallback = { 0, 0 };
+
+void AudioOutputPrivate::handleAutomaticDeviceChange(const AudioOutputDevice &device2, DeviceChangeType type)
+{
+ Q_Q(AudioOutput);
+ deviceBeforeFallback = device.index();
+ device = device2;
+ emit q->outputDeviceChanged(device2);
+#ifndef QT_NO_DBUS
+ emit adaptor->outputDeviceIndexChanged(device.index());
+#endif
+ const AudioOutputDevice &device1 = AudioOutputDevice::fromIndex(deviceBeforeFallback);
+ switch (type) {
+ case FallbackChange:
+ if (g_lastFallback.first != device1.index() || g_lastFallback.second != device2.index()) {
+#ifndef QT_NO_PHONON_PLATFORMPLUGIN
+ const QString &text = //device2.isValid() ?
+ AudioOutput::tr("<html>The audio playback device <b>%1</b> does not work.<br/>"
+ "Falling back to <b>%2</b>.</html>").arg(device1.name()).arg(device2.name()) /*:
+ AudioOutput::tr("<html>The audio playback device <b>%1</b> does not work.<br/>"
+ "No other device available.</html>").arg(device1.name())*/;
+ Platform::notification("AudioDeviceFallback", text);
+#endif //QT_NO_PHONON_PLATFORMPLUGIN
+ g_lastFallback.first = device1.index();
+ g_lastFallback.second = device2.index();
+ }
+ break;
+ case HigherPreferenceChange:
+ {
+#ifndef QT_NO_PHONON_PLATFORMPLUGIN
+ const QString text = AudioOutput::tr("<html>Switching to the audio playback device <b>%1</b><br/>"
+ "which just became available and has higher preference.</html>").arg(device2.name());
+ Platform::notification("AudioDeviceFallback", text,
+ QStringList(AudioOutput::tr("Revert back to device '%1'").arg(device1.name())),
+ q, SLOT(_k_revertFallback()));
+#endif //QT_NO_PHONON_PLATFORMPLUGIN
+ g_lastFallback.first = 0;
+ g_lastFallback.second = 0;
+ }
+ break;
+ }
+}
+
+AudioOutputPrivate::~AudioOutputPrivate()
+{
+#ifndef QT_NO_DBUS
+ emit adaptor->outputDestroyed();
+#endif
+}
+
+} //namespace Phonon
+
+QT_END_NAMESPACE
+
+#include "moc_audiooutput.cpp"
+
+#undef PHONON_CLASSNAME
+#undef PHONON_INTERFACENAME
+#undef IFACES2
+#undef IFACES1
+#undef IFACES0
diff --git a/src/3rdparty/phonon/phonon/audiooutput.h b/src/3rdparty/phonon/phonon/audiooutput.h
new file mode 100644
index 0000000000..54bb389383
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/audiooutput.h
@@ -0,0 +1,179 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005-2006 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+#ifndef Phonon_AUDIOOUTPUT_H
+#define Phonon_AUDIOOUTPUT_H
+
+#include "phonon_export.h"
+#include "abstractaudiooutput.h"
+#include "phonondefs.h"
+#include "phononnamespace.h"
+#include "objectdescription.h"
+
+QT_BEGIN_HEADER
+QT_BEGIN_NAMESPACE
+
+class QString;
+
+class AudioOutputAdaptor;
+namespace Phonon
+{
+ class AudioOutputPrivate;
+
+ /** \class AudioOutput audiooutput.h Phonon/AudioOutput
+ * \short Class for audio output to the soundcard.
+ *
+ * Use this class to define the audio output.
+ *
+ * \ingroup Frontend
+ * \author Matthias Kretz <kretz@kde.org>
+ * \see Phonon::Ui::VolumeSlider
+ */
+ class PHONON_EXPORT AudioOutput : public AbstractAudioOutput
+ {
+ friend class FactoryPrivate;
+ friend class ::AudioOutputAdaptor;
+ Q_OBJECT
+ K_DECLARE_PRIVATE(AudioOutput)
+ /**
+ * This is the name that appears in Mixer applications that control
+ * the volume of this output.
+ *
+ * \see category
+ */
+ Q_PROPERTY(QString name READ name WRITE setName)
+ /**
+ * This is the current loudness of the output (it is using Stevens' law
+ * to calculate the change in voltage internally).
+ *
+ * \see volumeDecibel
+ */
+ Q_PROPERTY(qreal volume READ volume WRITE setVolume NOTIFY volumeChanged)
+ /**
+ * This is the current volume of the output in decibel.
+ *
+ * 0 dB means no change in volume, -6dB means an attenuation of the
+ * voltage to 50% and an attenuation of the power to 25%, -inf dB means
+ * silence.
+ *
+ * \see volume
+ */
+ Q_PROPERTY(qreal volumeDecibel READ volumeDecibel WRITE setVolumeDecibel)
+ /**
+ * This property holds the (hardware) destination for the output.
+ *
+ * The default device is determined by the category and the global
+ * configuration for that category of outputs. Normally you don't need
+ * to override this setting - letting the user change the global
+ * configuration is the right choice. You can still override the
+ * device though, if you have good reasons to do so.
+ *
+ * \see outputDeviceChanged
+ */
+ Q_PROPERTY(AudioOutputDevice outputDevice READ outputDevice WRITE setOutputDevice)
+
+ /**
+ * This property tells whether the output is muted.
+ *
+ * Muting the output has the same effect as calling setVolume(0.0).
+ */
+ Q_PROPERTY(bool muted READ isMuted WRITE setMuted NOTIFY mutedChanged)
+ public:
+ /**
+ * Creates a new AudioOutput that defines output to a physical
+ * device.
+ *
+ * \param category The category can be used by mixer applications to group volume
+ * controls of applications into categories. That makes it easier for
+ * the user to identify the programs.
+ * The category is also used for the default output device that is
+ * configured centrally. As an example: often users want to have the
+ * audio signal of a VoIP application go to their USB headset while
+ * all other sounds should go to the internal soundcard.
+ *
+ * \param parent QObject parent
+ *
+ * \see Phonon::categoryToString
+ * \see outputDevice
+ */
+ explicit AudioOutput(Phonon::Category category, QObject *parent = 0);
+ explicit AudioOutput(QObject *parent = 0);
+
+ QString name() const;
+ qreal volume() const;
+ qreal volumeDecibel() const;
+
+ /**
+ * Returns the category of this output.
+ *
+ * \see AudioOutput(Phonon::Category, QObject *)
+ */
+ Phonon::Category category() const;
+ AudioOutputDevice outputDevice() const;
+ bool isMuted() const;
+
+ public Q_SLOTS:
+ void setName(const QString &newName);
+ void setVolume(qreal newVolume);
+ void setVolumeDecibel(qreal newVolumeDecibel);
+ bool setOutputDevice(const Phonon::AudioOutputDevice &newAudioOutputDevice);
+ void setMuted(bool mute);
+
+ Q_SIGNALS:
+ /**
+ * This signal is emitted whenever the volume has changed. As the
+ * volume can change without a call to setVolume (calls over dbus)
+ * this is important
+ * to keep a widget showing the current volume up to date.
+ */
+ void volumeChanged(qreal newVolume);
+
+ /**
+ * This signal is emitted when the muted property has changed. As
+ * this property can change by IPC (DBus) calls a UI element showing
+ * the muted property should listen to this signal.
+ */
+ void mutedChanged(bool);
+
+ /**
+ * This signal is emitted when the (hardware) device for the output
+ * has changed.
+ *
+ * The change can happen either through setOutputDevice or if the
+ * global configuration for the used category has changed.
+ *
+ * \see outputDevice
+ */
+ void outputDeviceChanged(const Phonon::AudioOutputDevice &newAudioOutputDevice);
+
+ private:
+ Q_PRIVATE_SLOT(k_func(), void _k_volumeChanged(qreal))
+ Q_PRIVATE_SLOT(k_func(), void _k_revertFallback())
+ Q_PRIVATE_SLOT(k_func(), void _k_audioDeviceFailed())
+ Q_PRIVATE_SLOT(k_func(), void _k_deviceListChanged())
+ };
+} //namespace Phonon
+
+QT_END_NAMESPACE
+QT_END_HEADER
+
+// vim: sw=4 ts=4 tw=80
+#endif // Phonon_AUDIOOUTPUT_H
diff --git a/src/3rdparty/phonon/phonon/audiooutput_p.h b/src/3rdparty/phonon/phonon/audiooutput_p.h
new file mode 100644
index 0000000000..459b491a69
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/audiooutput_p.h
@@ -0,0 +1,95 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef AUDIOOUTPUT_P_H
+#define AUDIOOUTPUT_P_H
+
+#include "audiooutput.h"
+#include "abstractaudiooutput_p.h"
+#include "platform_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+class AudioOutputAdaptor;
+
+class AudioOutputPrivate : public AbstractAudioOutputPrivate
+{
+ Q_DECLARE_PUBLIC(AudioOutput)
+ PHONON_PRIVATECLASS
+ public:
+ inline static AudioOutputPrivate *cast(MediaNodePrivate *x)
+ {
+ if (x && x->castId == MediaNodePrivate::AudioOutputType) {
+ return static_cast<AudioOutputPrivate *>(x);
+ }
+ return 0;
+ }
+ void init(Phonon::Category c);
+
+
+ protected:
+ AudioOutputPrivate(CastId castId = MediaNodePrivate::AudioOutputType)
+ : AbstractAudioOutputPrivate(castId),
+ name(Platform::applicationName()),
+ volume(Platform::loadVolume(name)),
+#ifndef QT_NO_DBUS
+ adaptor(0),
+#endif
+ deviceBeforeFallback(-1),
+ outputDeviceOverridden(false),
+ muted(false)
+ {
+ }
+
+ ~AudioOutputPrivate();
+
+ enum DeviceChangeType {
+ FallbackChange,
+ HigherPreferenceChange
+ };
+ void handleAutomaticDeviceChange(const AudioOutputDevice &newDev, DeviceChangeType type);
+
+ void _k_volumeChanged(qreal);
+ void _k_revertFallback();
+ void _k_audioDeviceFailed();
+ void _k_deviceListChanged();
+
+ private:
+ QString name;
+ Phonon::AudioOutputDevice device;
+ qreal volume;
+#ifndef QT_NO_DBUS
+ Phonon::AudioOutputAdaptor *adaptor;
+#endif
+ Category category;
+ int deviceBeforeFallback;
+ bool outputDeviceOverridden;
+ bool muted;
+};
+} //namespace Phonon
+
+QT_END_NAMESPACE
+
+#endif // AUDIOOUTPUT_P_H
+// vim: sw=4 ts=4 tw=80
diff --git a/src/3rdparty/phonon/phonon/audiooutputadaptor.cpp b/src/3rdparty/phonon/phonon/audiooutputadaptor.cpp
new file mode 100644
index 0000000000..2c01773754
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/audiooutputadaptor.cpp
@@ -0,0 +1,101 @@
+/*
+ * This file was generated by dbusidl2cpp version 0.4
+ * when processing input file org.kde.Phonon.AudioOutput.xml
+ *
+ * dbusidl2cpp is Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * This is an auto-generated file. This file has been hand-edited.
+ */
+
+#include "audiooutputadaptor_p.h"
+#include "audiooutput.h"
+#include <QtCore/QArgument>
+#include <QtCore/QByteRef>
+#include <QtCore/QList>
+#include <QtCore/QMap>
+#include <QtCore/QString>
+#include <QtCore/QStringList>
+#include <QtCore/QVariant>
+#include "phononnamespace_p.h"
+#include "objectdescription.h"
+
+#ifndef QT_NO_DBUS
+
+/*
+ * Implementation of adaptor class AudioOutputAdaptor
+ */
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+
+AudioOutputAdaptor::AudioOutputAdaptor(QObject *parent)
+ : QDBusAbstractAdaptor(parent)
+{
+ // constructor
+ setAutoRelaySignals(true);
+}
+
+AudioOutputAdaptor::~AudioOutputAdaptor()
+{
+ // destructor
+}
+
+double AudioOutputAdaptor::volume() const
+{
+ // get the value of property volume
+ return qvariant_cast<qreal>(parent()->property("volume"));
+}
+
+void AudioOutputAdaptor::setVolume(double value)
+{
+ // set the value of property volume
+ parent()->setProperty("volume", QVariant::fromValue(static_cast<qreal>(value)));
+}
+
+bool AudioOutputAdaptor::muted() const
+{
+ return parent()->property("muted").toBool();
+}
+
+void AudioOutputAdaptor::setMuted(bool value)
+{
+ parent()->setProperty("muted", value);
+}
+
+QString AudioOutputAdaptor::category()
+{
+ // handle method call org.kde.Phonon.AudioOutput.category
+ return Phonon::categoryToString(static_cast<Phonon::AudioOutput *>(parent())->category());
+}
+
+QString AudioOutputAdaptor::name()
+{
+ // handle method call org.kde.Phonon.AudioOutput.name
+ QString name;
+ //QMetaObject::invokeMethod(parent(), "name", Q_RETURN_ARG(QString, name));
+
+ // Alternative:
+ name = static_cast<Phonon::AudioOutput *>(parent())->name();
+ return name;
+}
+
+int AudioOutputAdaptor::outputDeviceIndex() const
+{
+ return static_cast<Phonon::AudioOutput *>(parent())->outputDevice().index();
+}
+
+void AudioOutputAdaptor::setOutputDeviceIndex(int newAudioOutputDeviceIndex)
+{
+ static_cast<Phonon::AudioOutput *>(parent())
+ ->setOutputDevice(Phonon::AudioOutputDevice::fromIndex(newAudioOutputDeviceIndex));
+}
+
+} // namespace Phonon
+
+QT_END_NAMESPACE
+
+#include "moc_audiooutputadaptor_p.cpp"
+
+#endif
diff --git a/src/3rdparty/phonon/phonon/audiooutputadaptor_p.h b/src/3rdparty/phonon/phonon/audiooutputadaptor_p.h
new file mode 100644
index 0000000000..7178e9b12e
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/audiooutputadaptor_p.h
@@ -0,0 +1,109 @@
+/*
+ * This file was generated by dbusidl2cpp version 0.4
+ * when processing input file org.kde.Phonon.AudioOutput.xml
+ *
+ * dbusidl2cpp is Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * This is an auto-generated file. This file has been hand-edited.
+ */
+
+#ifndef AUDIOOUTPUTADAPTOR_P_H
+#define AUDIOOUTPUTADAPTOR_P_H
+
+#include <QtCore/QObject>
+
+#ifndef QT_NO_DBUS
+#include <QtDBus/QtDBus>
+
+QT_BEGIN_HEADER
+QT_BEGIN_NAMESPACE
+
+class QByteArray;
+template<class T> class QList;
+template<class Key, class Value> class QMap;
+class QString;
+class QStringList;
+class QVariant;
+
+namespace Phonon
+{
+ class AudioOutputPrivate;
+ class AudioOutput;
+
+/*
+ * Adaptor class for interface org.kde.Phonon.AudioOutput
+ */
+class AudioOutputAdaptor: public QDBusAbstractAdaptor
+{
+ friend class Phonon::AudioOutputPrivate;
+ friend class Phonon::AudioOutput;
+ Q_OBJECT
+ Q_CLASSINFO("D-Bus Interface", "org.kde.Phonon.AudioOutput")
+ Q_CLASSINFO("D-Bus Introspection", ""
+" <interface name=\"org.kde.Phonon.AudioOutput\" >\n"
+" <property access=\"readwrite\" type=\"d\" name=\"volume\" />\n"
+" <property access=\"readwrite\" type=\"b\" name=\"muted\" />\n"
+" <property access=\"readwrite\" type=\"i\" name=\"outputDeviceIndex\" />\n"
+" <signal name=\"volumeChanged\" >\n"
+" <arg direction=\"out\" type=\"d\" />\n"
+" </signal>\n"
+" <signal name=\"mutedChanged\" >\n"
+" <arg direction=\"out\" type=\"b\" />\n"
+" </signal>\n"
+" <signal name=\"outputDeviceIndexChanged\" >\n"
+" <arg direction=\"out\" type=\"i\" />\n"
+" </signal>\n"
+" <signal name=\"nameChanged\" >\n"
+" <arg direction=\"out\" type=\"s\" name=\"newName\" />\n"
+" </signal>\n"
+" <signal name=\"newOutputAvailable\" >\n"
+" <arg direction=\"out\" type=\"s\" name=\"service\" />\n"
+" <arg direction=\"out\" type=\"s\" name=\"path\" />\n"
+" </signal>\n"
+" <signal name=\"outputDestroyed\" >\n"
+" </signal>\n"
+" <method name=\"category\" >\n"
+" <arg direction=\"out\" type=\"s\" />\n"
+" </method>\n"
+" <method name=\"name\" >\n"
+" <arg direction=\"out\" type=\"s\" />\n"
+" </method>\n"
+" </interface>\n"
+ "")
+public:
+ AudioOutputAdaptor(QObject *parent);
+ virtual ~AudioOutputAdaptor();
+
+public: // PROPERTIES
+ Q_PROPERTY(bool muted READ muted WRITE setMuted)
+ bool muted() const;
+ void setMuted(bool value);
+
+ Q_PROPERTY(int outputDeviceIndex READ outputDeviceIndex WRITE setOutputDeviceIndex)
+ int outputDeviceIndex() const;
+ void setOutputDeviceIndex(int value);
+
+ Q_PROPERTY(double volume READ volume WRITE setVolume)
+ double volume() const;
+ void setVolume(double value);
+
+public Q_SLOTS: // METHODS
+ QString category();
+ QString name();
+Q_SIGNALS: // SIGNALS
+ void mutedChanged(bool in0);
+ void nameChanged(const QString &newName);
+ void newOutputAvailable(const QString &service, const QString &path);
+ void outputDestroyed();
+ void outputDeviceIndexChanged(int in0);
+ void volumeChanged(qreal in0);
+};
+
+} // namespace Phonon
+
+QT_END_NAMESPACE
+QT_END_HEADER
+
+#endif // QT_NO_DBUS
+
+#endif // AUDIOOUTPUTADAPTOR_P_H
diff --git a/src/3rdparty/phonon/phonon/audiooutputinterface.cpp b/src/3rdparty/phonon/phonon/audiooutputinterface.cpp
new file mode 100644
index 0000000000..be2780d835
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/audiooutputinterface.cpp
@@ -0,0 +1,40 @@
+/* This file is part of the KDE project
+ Copyright (C) 2008 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+#include "audiooutputinterface.h"
+#include <QtCore/QList>
+#include <QtCore/QStringList>
+#include <QtCore/QPair>
+#include "platform_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+
+QList<QPair<QByteArray, QString> > AudioOutputInterface42::deviceAccessListFor(const Phonon::AudioOutputDevice &deviceDesc) const
+{
+ return Platform::deviceAccessListFor(deviceDesc);
+}
+
+} // namespace Phonon
+
+QT_END_NAMESPACE
diff --git a/src/3rdparty/phonon/phonon/audiooutputinterface.h b/src/3rdparty/phonon/phonon/audiooutputinterface.h
new file mode 100644
index 0000000000..1511e02961
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/audiooutputinterface.h
@@ -0,0 +1,151 @@
+/* This file is part of the KDE project
+ Copyright (C) 2007-2008 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef PHONON_AUDIOOUTPUTINTERFACE_H
+#define PHONON_AUDIOOUTPUTINTERFACE_H
+
+#include "phononnamespace.h"
+#include "objectdescription.h"
+#include "phonondefs.h"
+#include <QtCore/QtGlobal>
+
+QT_BEGIN_HEADER
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+/** \class AudioOutputInterface audiooutputinterface.h Phonon/AudioOutputInterface
+ * \short Interface for AudioOutput objects
+ *
+ * The implementation can make use of the signals
+ * \code
+ void volumeChanged(qreal newVolume);
+ void audioDeviceFailed();
+ * \endcode
+ * to notify the frontend whenever the volume has changed or when an audioDeviceFailed (e.g. USB
+ * unplug or sound server failure).
+ *
+ * \author Matthias Kretz <kretz@kde.org>
+ */
+class AudioOutputInterface40
+{
+ public:
+ virtual ~AudioOutputInterface40() {}
+
+ /**
+ * Returns the current software volume.
+ *
+ * A value of 0.0 means muted, 1.0 means unchanged, 2.0 means double voltage (i.e. all
+ * samples are multiplied by 2).
+ */
+ virtual qreal volume() const = 0;
+ /**
+ * Sets the new current software volume.
+ *
+ * A value of 0.0 means muted, 1.0 means unchanged, 2.0 means double voltage (i.e. all
+ * samples are multiplied by 2).
+ *
+ * Everytime the volume in the backend changes it should emit volumeChanged(qreal), also
+ * inside this function.
+ */
+ virtual void setVolume(qreal) = 0;
+
+ /**
+ * Returns the index of the device that is used. The index is the number returned from
+ * BackendInterface::objectDescriptionIndexes(AudioOutputDeviceType).
+ */
+ virtual int outputDevice() const = 0;
+ /**
+ * \deprecated
+ *
+ * Requests to change the current output device to the one identified by the passed index.
+ *
+ * The index is the number returned from
+ * BackendInterface::objectDescriptionIndexes(AudioOutputDeviceType).
+ *
+ * \returns \c true if the requested device works and is used after this call.
+ * \returns \c false if something failed and the device is not used after this call.
+ */
+ virtual bool setOutputDevice(int) = 0;
+};
+
+class AudioOutputInterface42 : public AudioOutputInterface40
+{
+ public:
+ /**
+ * Requests to change the current output device.
+ *
+ * \returns \c true if the requested device works and is used after this call.
+ * \returns \c false if something failed and the device is not used after this call.
+ */
+ virtual bool setOutputDevice(const Phonon::AudioOutputDevice &) = 0;
+
+ using AudioOutputInterface40::setOutputDevice;
+
+ /**
+ * Helper function for backends to get a list of (driver, handle) pairs for
+ * AudioOutputDevice objects that are listed by the platform plugin.
+ *
+ * Example:
+ * \code
+ typedef QPair<QByteArray, QString> PhononDeviceAccess;
+ const QList<PhononDeviceAccess> &deviceAccessList = deviceAccessListFor(deviceDesc);
+ foreach (const PhononDeviceAccess &access, deviceAccessList) {
+ const QByteArray &driver = access.first;
+ const QString &handle = access.second;
+ if (openDevice(driver, handle)) {
+ // we found the first pair in the list that works. done.
+ return;
+ }
+ // continue trying the other (driver, handle) pairs
+ }
+ // none of the (driver, handle) pairs worked, that means the whole AudioOutputDevice is
+ // inaccessible and the frontend needs to know (either by emitting audioDeviceFailed or
+ // returning false when called from setOutputDevice)
+ * \endcode
+ *
+ * At the time of this writing the following driver strings are known to be in use:
+ * \li \c alsa: The handle is the string to pass to snd_pcm_open (e.g. "dmix:CARD=0,DEV=1")
+ * \li \c oss: The handle is the device file (e.g. "/dev/dsp")
+ * \li \c pulseaudio: The handle contains the server string and the sink/source name
+ * separated by a newline character.
+ * (e.g. unix:/tmp/pulse-mkretz/native\nalsa_output.pci_8086_293e_sound_card_0_alsa_playback_0)
+ */
+ PHONON_EXPORT QList<QPair<QByteArray, QString> > deviceAccessListFor(const Phonon::AudioOutputDevice &) const;
+};
+
+} // namespace Phonon
+
+#ifdef PHONON_BACKEND_VERSION_4_2
+namespace Phonon { typedef AudioOutputInterface42 AudioOutputInterface; }
+Q_DECLARE_INTERFACE(Phonon::AudioOutputInterface40, "AudioOutputInterface2.phonon.kde.org")
+Q_DECLARE_INTERFACE(Phonon::AudioOutputInterface, "3AudioOutputInterface.phonon.kde.org")
+#else
+namespace Phonon { typedef AudioOutputInterface40 AudioOutputInterface; }
+Q_DECLARE_INTERFACE(Phonon::AudioOutputInterface, "AudioOutputInterface2.phonon.kde.org")
+Q_DECLARE_INTERFACE(Phonon::AudioOutputInterface42, "3AudioOutputInterface.phonon.kde.org")
+#endif
+
+QT_END_NAMESPACE
+QT_END_HEADER
+
+#endif // PHONON_AUDIOOUTPUTINTERFACE_H
diff --git a/src/3rdparty/phonon/phonon/backend.dox b/src/3rdparty/phonon/phonon/backend.dox
new file mode 100644
index 0000000000..8a9c5b2529
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/backend.dox
@@ -0,0 +1,107 @@
+/**
+\page phonon_Backend The Backend Class
+\ingroup Backend
+
+\section phonon_Backend_requiredfunctions Required Functions
+\li bool \ref phonon_Backend_supportsOSD "supportsOSD()"
+\li bool \ref phonon_Backend_supportsFourcc "supportsFourcc( quint32 )"
+\li bool \ref phonon_Backend_supportsSubtitles "supportsSubtitles()"
+\li bool \ref phonon_Backend_supportsVideo "supportsVideo()"
+\li QStringList \ref phonon_Backend_availableMimeTypes "availableMimeTypes()"
+
+\section Member Function Documentation
+
+\subsection phonon_Backend_supportsFourcc bool supportsFourcc( quint32 fourcc )
+Tells whether the FOURCC (four character code) is supported for
+the \ref phonon_VideoDataOutput "VideoDataOutput" interface. If you return \c true, you have to be
+able to return VideoFrame objects accordingly from
+\ref phonon_VideoDataOutput "VideoDataOutput".
+\param fourcc A four character code defining a video frame format.
+\returns \c true if your \ref phonon_VideoDataOutput "VideoDataOutput" can
+output video frames in the requested format.
+\returns \c false if the video frames can not be converted into the requested
+format.
+
+\subsection phonon_Backend_availableMimeTypes QStringList availableMimeTypes()
+Lists the MIME types the backend can read and decode.
+
+\subsection phonon_Backend_xIndexes QSet<int> <device/codec/effect/...>Indexes()
+ Returns a set of indexes that identify the devices/codecs/effects/... the
+ backend supports. This list needs to be compiled from looking at
+ available hardware and virtual devices/plugins/... . The implementation
+ should use cached information, but you need to invalidate the cache
+ whenever the hardware configuration changes or new virtual devices come
+ available/new plugins are installed/... .
+
+ \return The indexes of the available devices/codecs/effects/...
+
+ \see \ref phonon_Backend_xName
+ \see \ref phonon_Backend_xDescription
+
+\subsection phonon_Backend_xName QString <device/codec/effect/...>Name( int index )
+ Returns the name of the given device/codec/effect/...
+
+ \param index The index of one device/codec/effect/... this is one index
+ out of \ref phonon_Backend_xIndexes
+
+ \returns A translated user visible string to name the device.
+
+ \see \ref phonon_Backend_xIndexes
+ \see \ref phonon_Backend_xDescription
+\subsection phonon_Backend_xDescription QString <device/codec/effect/...>Description( int index )
+ Returns the description of the given device/codec/effect/...
+
+ \param index The index of one device/codec/effect/... this is one index
+ out of \ref phonon_Backend_xIndexes
+
+ \returns A translated user visible string to describe the device.
+
+ \see \ref phonon_Backend_xIndexes
+ \see \ref phonon_Backend_xName
+
+\subsection phonon_Backend_audioCaptureDeviceVideoIndex qint32 audioCaptureDeviceVideoIndex( int index )
+ \param index The index of the device. This is one of the indexes the backend
+ returned via \ref phonon_Backend_xIndexes
+ \returns An index of a video capture device that is associated with the given
+ audio capture device. For example a webcam might have both a video and an audio
+ capture device, and in order give the user a hint that the audio and video
+ capture devices belong together this index is used.
+ \returns If there is no associated video capture device return -1.
+
+\subsection phonon_Backend_videoCaptureDeviceAudioIndex qint32 videoCaptureDeviceAudioIndex( int index )
+ \param index The index of the device. This is one of the indexes the backend
+ returned via \ref phonon_Backend_xIndexes
+ \returns An index of a audio capture device that is associated with the given
+ video capture device. For example a webcam might have both a audio and an video
+ capture device, and in order give the user a hint that the video and audio
+ capture devices belong together this index is used.
+ \returns If there is no associated audio capture device return -1.
+
+\page phonon_AudioDataOutput The AudioDataOutput Class
+\ingroup Backend
+
+\page phonon_AudioOutput The AudioOutput Class
+\ingroup Backend
+
+\page phonon_VideoDataOutput The VideoDataOutput Class
+\ingroup Backend
+
+\page phonon_VideoWidget The VideoWidget Class
+\ingroup Backend
+
+\page phonon_Effect The Effect Class
+\ingroup Backend
+
+\page phonon_BrightnessControl The BrightnessControl Class
+\ingroup Backend
+
+\page phonon_VideoEffect The VideoEffect Class
+\ingroup Backend
+
+\page phonon_Visualization The Visualization Class
+\ingroup Backend
+
+\page phonon_VolumeFaderEffect The VolumeFaderEffect Class
+\ingroup Backend
+
+*/
diff --git a/src/3rdparty/phonon/phonon/backendcapabilities.cpp b/src/3rdparty/phonon/phonon/backendcapabilities.cpp
new file mode 100644
index 0000000000..5dee6a0351
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/backendcapabilities.cpp
@@ -0,0 +1,121 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005-2006 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "backendcapabilities.h"
+#include "backendcapabilities_p.h"
+
+#include "phonondefs_p.h"
+#include "backendinterface.h"
+#include "factory_p.h"
+#include "globalconfig_p.h"
+#include "globalstatic_p.h"
+#include "objectdescription.h"
+
+#include <QtCore/QList>
+#include <QtCore/QSet>
+#include <QtCore/QStringList>
+
+QT_BEGIN_NAMESPACE
+
+PHONON_GLOBAL_STATIC(Phonon::BackendCapabilitiesPrivate, globalBCPrivate)
+
+namespace Phonon
+{
+
+BackendCapabilities::Notifier *BackendCapabilities::notifier()
+{
+ return globalBCPrivate;
+}
+
+QStringList BackendCapabilities::availableMimeTypes()
+{
+ if (BackendInterface *backendIface = qobject_cast<BackendInterface *>(Factory::backend()))
+ return backendIface->availableMimeTypes();
+ else
+ return QStringList();
+}
+
+bool BackendCapabilities::isMimeTypeAvailable(const QString &mimeType)
+{
+ QObject *m_backendObject = Factory::backend(false);
+ if (!m_backendObject) {
+ if (!Factory::isMimeTypeAvailable(mimeType)) {
+ return false;
+ }
+ // without loading the backend we found out that the MIME type might be supported, now we
+ // want to know for certain. For that we need to load the backend.
+ m_backendObject = Factory::backend(true);
+ }
+ if (!m_backendObject) {
+ // no backend == no MIME type supported at all
+ return false;
+ }
+ return availableMimeTypes().contains(mimeType);
+}
+
+QList<AudioOutputDevice> BackendCapabilities::availableAudioOutputDevices()
+{
+ QList<AudioOutputDevice> ret;
+ const QList<int> deviceIndexes = GlobalConfig().audioOutputDeviceListFor(Phonon::NoCategory);
+ foreach (int i, deviceIndexes) {
+ ret.append(AudioOutputDevice::fromIndex(i));
+ }
+ return ret;
+}
+
+
+#ifndef QT_NO_PHONON_AUDIOCAPTURE
+QList<AudioCaptureDevice> BackendCapabilities::availableAudioCaptureDevices()
+{
+ QList<AudioCaptureDevice> ret;
+ const QList<int> deviceIndexes = GlobalConfig().audioCaptureDeviceListFor(Phonon::NoCategory);
+ foreach (int i, deviceIndexes) {
+ ret.append(AudioCaptureDevice::fromIndex(i));
+ }
+ return ret;
+}
+#endif //QT_NO_PHONON_AUDIOCAPTURE
+
+#ifndef QT_NO_PHONON_EFFECT
+QList<EffectDescription> BackendCapabilities::availableAudioEffects()
+{
+ BackendInterface *backendIface = qobject_cast<BackendInterface *>(Factory::backend());
+ QList<EffectDescription> ret;
+ if (backendIface) {
+ QList<int> deviceIndexes = backendIface->objectDescriptionIndexes(Phonon::EffectType);
+ foreach (int i, deviceIndexes) {
+ ret.append(EffectDescription::fromIndex(i));
+ }
+ }
+ return ret;
+}
+#endif //QT_NO_PHONON_EFFECT
+
+} // namespace Phonon
+
+QT_END_NAMESPACE
+
+#include "moc_backendcapabilities.cpp"
+
+// vim: sw=4 ts=4
+
+
diff --git a/src/3rdparty/phonon/phonon/backendcapabilities.h b/src/3rdparty/phonon/phonon/backendcapabilities.h
new file mode 100644
index 0000000000..65b2830056
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/backendcapabilities.h
@@ -0,0 +1,213 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005-2006 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef Phonon_BACKENDCAPABILITIES_H
+#define Phonon_BACKENDCAPABILITIES_H
+
+#include "phonon_export.h"
+#include "objectdescription.h"
+
+#include <QtCore/QObject>
+
+QT_BEGIN_HEADER
+QT_BEGIN_NAMESPACE
+
+#ifdef __QT_SYNCQT__
+// Tell syncqt that the BackendCapabilities namespace should be treated like a class
+#pragma qt_class(Phonon::BackendCapabilities)
+#pragma qt_sync_stop_processing
+#endif
+
+template<class T> class QList;
+class QStringList;
+
+namespace Phonon
+{
+
+/**
+ * Collection of functions describing the capabilities of the Backend.
+ *
+ * \ingroup BackendInformation
+ * \author Matthias Kretz <kretz@kde.org>
+ */
+namespace BackendCapabilities
+{
+ /** \class Notifier backendcapabilities.h Phonon/BackendCapabilities
+ * Notifications about backend capabilities.
+ *
+ * \ingroup BackendInformation
+ */
+ class Notifier : public QObject
+ {
+ Q_OBJECT
+ Q_SIGNALS:
+ /**
+ * This signal is emitted if the capabilities have changed. This can
+ * happen if the user has requested a backend change.
+ */
+ void capabilitiesChanged();
+
+ /**
+ * This signal is emitted when audio output devices were plugged or
+ * unplugged.
+ *
+ * Check BackendCapabilities::availableAudioOutputDevices to get the
+ * current list of available devices.
+ */
+ void availableAudioOutputDevicesChanged();
+
+ /**
+ * This signal is emitted when audio capture devices were plugged or
+ * unplugged.
+ *
+ * Check BackendCapabilities::availableAudioCaptureDevices to get the
+ * current list of available devices.
+ */
+#ifndef QT_NO_PHONON_AUDIOCAPTURE
+ void availableAudioCaptureDevicesChanged();
+#endif //QT_NO_PHONON_AUDIOCAPTURE
+ };
+
+ /**
+ * Use this function to get a QObject pointer to connect to the capabilitiesChanged signal.
+ *
+ * \return a pointer to a QObject.
+ *
+ * The capabilitiesChanged signal is emitted if the capabilities have changed. This can
+ * happen if the user has requested a backend change.
+ *
+ * To connect to this signal do the following:
+ * \code
+ * QObject::connect(BackendCapabilities::notifier(), SIGNAL(capabilitiesChanged()), ...
+ * \endcode
+ *
+ * \see Notifier::capabilitiesChanged()
+ */
+ PHONON_EXPORT Notifier *notifier();
+
+ /**
+ * Returns a list of mime types that the Backend can decode.
+ *
+ * \see isMimeTypeAvailable()
+ */
+ PHONON_EXPORT QStringList availableMimeTypes();
+
+ /**
+ * Often all you want to know is whether one given MIME type can be
+ * decoded by the backend. Use this method in favor of availableMimeTypes()
+ * as it can give you a negative answer without having a backend loaded.
+ *
+ * \see availableMimeTypes();
+ */
+ PHONON_EXPORT bool isMimeTypeAvailable(const QString &mimeType);
+
+ /**
+ * Returns the audio output devices the backend supports.
+ *
+ * \return A list of AudioOutputDevice objects that give a name and
+ * description for every supported audio output device.
+ */
+ PHONON_EXPORT QList<AudioOutputDevice> availableAudioOutputDevices();
+
+ /**
+ * Returns the audio capture devices the backend supports.
+ *
+ * \return A list of AudioCaptureDevice objects that give a name and
+ * description for every supported audio capture device.
+ */
+#ifndef QT_NO_PHONON_AUDIOCAPTURE
+ PHONON_EXPORT QList<AudioCaptureDevice> availableAudioCaptureDevices();
+#endif //QT_NO_PHONON_AUDIOCAPTURE
+
+ /**
+ * Returns the video output devices the backend supports.
+ *
+ * \return A list of VideoOutputDevice objects that give a name and
+ * description for every supported video output device.
+ */
+// PHONON_EXPORT QList<VideoOutputDevice> availableVideoOutputDevices();
+
+ /**
+ * Returns the video capture devices the backend supports.
+ *
+ * \return A list of VideoCaptureDevice objects that give a name and
+ * description for every supported video capture device.
+ */
+// PHONON_EXPORT QList<VideoCaptureDevice> availableVideoCaptureDevices();
+
+ /**
+ * Returns the visualization effects the backend supports.
+ *
+ * \return A list of VisualizationEffect objects that give a name and
+ * description for every supported visualization effect.
+ */
+// PHONON_EXPORT QList<VisualizationDescription> availableVisualizations();
+
+ /**
+ * Returns descriptions for the audio effects the backend supports.
+ *
+ * \return A list of AudioEffectDescription objects that give a name and
+ * description for every supported audio effect.
+ */
+#ifndef QT_NO_PHONON_EFFECT
+ PHONON_EXPORT QList<EffectDescription> availableAudioEffects();
+#endif //QT_NO_PHONON_EFFECT
+
+//X /**
+//X * Returns descriptions for the video effects the backend supports.
+//X *
+//X * \return A list of VideoEffectDescription objects that give a name and
+//X * description for every supported video effect.
+//X */
+//X PHONON_EXPORT QList<EffectDescription> availableVideoEffects();
+
+ /**
+ * Returns descriptions for the audio codecs the backend supports.
+ *
+ * \return A list of AudioCodec objects that give a name and
+ * description for every supported audio codec.
+ */
+// PHONON_EXPORT QList<AudioCodecDescription> availableAudioCodecs();
+
+ /**
+ * Returns descriptions for the video codecs the backend supports.
+ *
+ * \return A list of VideoCodec objects that give a name and
+ * description for every supported video codec.
+ */
+// PHONON_EXPORT QList<VideoCodecDescription> availableVideoCodecs();
+
+ /**
+ * Returns descriptions for the container formats the backend supports.
+ *
+ * \return A list of ContainerFormat objects that give a name and
+ * description for every supported container format.
+ */
+// PHONON_EXPORT QList<ContainerFormatDescription> availableContainerFormats();
+} // namespace BackendCapabilities
+} // namespace Phonon
+
+QT_END_NAMESPACE
+QT_END_HEADER
+
+#endif // Phonon_BACKENDCAPABILITIES_H
+// vim: sw=4 ts=4 tw=80
diff --git a/src/3rdparty/phonon/phonon/backendcapabilities_p.h b/src/3rdparty/phonon/phonon/backendcapabilities_p.h
new file mode 100644
index 0000000000..c17f24f537
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/backendcapabilities_p.h
@@ -0,0 +1,50 @@
+/* This file is part of the KDE project
+ Copyright (C) 2007 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef PHONON_BACKENDCAPABILITIES_P_H
+#define PHONON_BACKENDCAPABILITIES_P_H
+
+#include "backendcapabilities.h"
+#include <QtCore/QObject>
+#include "factory_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+class BackendCapabilitiesPrivate : public BackendCapabilities::Notifier
+{
+ public:
+ BackendCapabilitiesPrivate()
+ {
+ connect(Factory::sender(), SIGNAL(backendChanged()), SIGNAL(capabilitiesChanged()));
+ connect(Factory::sender(), SIGNAL(availableAudioOutputDevicesChanged()), SIGNAL(availableAudioOutputDevicesChanged()));
+ connect(Factory::sender(), SIGNAL(availableAudioCaptureDevicesChanged()), SIGNAL(availableAudioCaptureDevicesChanged()));
+ }
+};
+
+} // namespace Phonon
+
+QT_END_NAMESPACE
+
+#endif // PHONON_BACKENDCAPABILITIES_P_H
+// vim: sw=4 sts=4 et tw=100
diff --git a/src/3rdparty/phonon/phonon/backendinterface.h b/src/3rdparty/phonon/phonon/backendinterface.h
new file mode 100644
index 0000000000..e1f11dab46
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/backendinterface.h
@@ -0,0 +1,287 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006-2007 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef PHONON_BACKENDINTERFACE_H
+#define PHONON_BACKENDINTERFACE_H
+
+#include "phonon_export.h"
+#include "objectdescription.h"
+
+#include <QtCore/QtGlobal>
+#include <QtCore/QSet>
+
+QT_BEGIN_HEADER
+QT_BEGIN_NAMESPACE
+
+class QVariant;
+
+namespace Phonon
+{
+
+/** \class BackendInterface backendinterface.h Phonon/BackendInterface
+ * \short Main Backend class interface
+ *
+ * This interface defines the main factory of the backend. The createObject function creates all the
+ * objects needed by the frontend.
+ *
+ * The objectDescriptionIndexes and objectDescriptionProperties functions return information about
+ * available devices, effects and codecs.
+ *
+ * An implementation could look like this:
+ * \code
+ * QObject *Backend::createObject(BackendInterface::Class c, QObject *parent, const QList<QVariant> &args)
+ * {
+ * switch (c) {
+ * case MediaObjectClass:
+ * return new MediaObject(parent);
+ * case VolumeFaderEffectClass:
+ * return new VolumeFaderEffect(parent);
+ * case AudioOutputClass:
+ * return new AudioOutput(parent);
+ * case AudioDataOutputClass:
+ * return new AudioDataOutput(parent);
+ * case VisualizationClass:
+ * return new Visualization(parent);
+ * case VideoDataOutputClass:
+ * return new VideoDataOutput(parent);
+ * case EffectClass:
+ * return new Effect(args[0].toInt(), parent);
+ * case VideoWidgetClass:
+ * return new VideoWidget(qobject_cast<QWidget *>(parent));
+ * }
+ * return 0;
+ * }
+ *
+ * QSet<int> Backend::objectDescriptionIndexes(ObjectDescriptionType type) const
+ * {
+ * QSet<int> set;
+ * switch(type)
+ * {
+ * case Phonon::AudioOutputDeviceType:
+ * // use AudioDeviceEnumerator to list ALSA and OSS devices
+ * set << 10000 << 10001;
+ * break;
+ * case Phonon::AudioCaptureDeviceType:
+ * set << 20000 << 20001;
+ * break;
+ * case Phonon::VideoOutputDeviceType:
+ * break;
+ * case Phonon::VideoCaptureDeviceType:
+ * set << 30000 << 30001;
+ * break;
+ * case Phonon::VisualizationType:
+ * case Phonon::AudioCodecType:
+ * case Phonon::VideoCodecType:
+ * case Phonon::ContainerFormatType:
+ * break;
+ * case Phonon::EffectType:
+ * set << 0x7F000001;
+ * break;
+ * }
+ * return set;
+ * }
+ *
+ * QHash<QByteArray, QVariant> Backend::objectDescriptionProperties(ObjectDescriptionType type, int index) const
+ * {
+ * QHash<QByteArray, QVariant> ret;
+ * switch (type) {
+ * case Phonon::AudioOutputDeviceType:
+ * switch (index) {
+ * case 10000:
+ * ret.insert("name", QLatin1String("internal Soundcard"));
+ * break;
+ * case 10001:
+ * ret.insert("name", QLatin1String("USB Headset"));
+ * ret.insert("icon", KIcon("usb-headset"));
+ * ret.insert("available", false);
+ * break;
+ * }
+ * break;
+ * case Phonon::AudioCaptureDeviceType:
+ * switch (index) {
+ * case 20000:
+ * ret.insert("name", QLatin1String("Soundcard"));
+ * ret.insert("description", QLatin1String("first description"));
+ * break;
+ * case 20001:
+ * ret.insert("name", QLatin1String("DV"));
+ * ret.insert("description", QLatin1String("second description"));
+ * break;
+ * }
+ * break;
+ * case Phonon::VideoOutputDeviceType:
+ * break;
+ * case Phonon::VideoCaptureDeviceType:
+ * switch (index) {
+ * case 30000:
+ * ret.insert("name", QLatin1String("USB Webcam"));
+ * ret.insert("description", QLatin1String("first description"));
+ * break;
+ * case 30001:
+ * ret.insert("name", QLatin1String("DV"));
+ * ret.insert("description", QLatin1String("second description"));
+ * break;
+ * }
+ * break;
+ * case Phonon::VisualizationType:
+ * break;
+ * case Phonon::AudioCodecType:
+ * break;
+ * case Phonon::VideoCodecType:
+ * break;
+ * case Phonon::ContainerFormatType:
+ * break;
+ * case Phonon::EffectType:
+ * switch (index) {
+ * case 0x7F000001:
+ * ret.insert("name", QLatin1String("Delay"));
+ * ret.insert("description", QLatin1String("Simple delay effect with time, feedback and level controls."));
+ * break;
+ * }
+ * break;
+ * }
+ * return ret;
+ * }
+ * \endcode
+ *
+ * \author Matthias Kretz <kretz@kde.org>
+ */
+class BackendInterface
+{
+ public:
+ /**
+ * \internal
+ *
+ * Silence gcc's warning.
+ */
+ virtual ~BackendInterface() {}
+
+ /**
+ * Classes that the createObject function has to handle.
+ */
+ enum Class {
+ /**
+ * Request to return a %MediaObject object.
+ */
+ MediaObjectClass,
+ /**
+ * Request to return a %VolumeFaderEffect object.
+ */
+ VolumeFaderEffectClass,
+ /**
+ * Request to return a %AudioOutput object.
+ */
+ AudioOutputClass,
+ /**
+ * Request to return a %AudioDataOutput object.
+ */
+ AudioDataOutputClass,
+ /**
+ * Request to return a %Visualization object.
+ */
+ VisualizationClass,
+ /**
+ * Request to return a %VideoDataOutput object.
+ */
+ VideoDataOutputClass,
+ /**
+ * Request to return a %Effect object.
+ *
+ * Takes an additional int that specifies the effect Id.
+ */
+ EffectClass,
+ /**
+ * Request to return a %VideoWidget object.
+ */
+ VideoWidgetClass
+ };
+
+ /**
+ * Returns a new instance of the requested class.
+ *
+ * \param c The requested class.
+ * \param parent The parent object.
+ * \param args Additional arguments (documented in \ref Class).
+ */
+ virtual QObject *createObject(Class c, QObject *parent, const QList<QVariant> &args = QList<QVariant>()) = 0;
+
+ /**
+ * Returns the unique identifiers for the devices/effects/codecs of the given \p type.
+ *
+ * \param type see \ref ObjectDescriptionType
+ */
+ virtual QList<int> objectDescriptionIndexes(ObjectDescriptionType type) const = 0;
+
+ /**
+ * Given a unique identifier that was returned from objectDescriptionIndexes this function
+ * returns a hash mapping property names to values.
+ *
+ * The property "name" must always be present. All other properties are optional.
+ *
+ * List of possible properties:
+ * \li \c \b name: The name of the device/effect/codec/...
+ * \li \c \b description: A text explaining what this device/effect/codec/... is/can do
+ * \li \c \b icon: An icon name (using the freedesktop naming scheme) or a QIcon for this
+ * device/effect/codec/...
+ * \li \c \b available: A bool telling whether the device is present or unplugged.
+ *
+ * \param type see \ref ObjectDescriptionType
+ * \param index The unique identifier that is returned from objectDescriptionIndexes
+ */
+ virtual QHash<QByteArray, QVariant> objectDescriptionProperties(ObjectDescriptionType type, int index) const = 0;
+
+ /**
+ * When this function is called the nodes given in the parameter list should not lose any
+ * signal data when connections are changed.
+ */
+ virtual bool startConnectionChange(QSet<QObject *>) = 0;
+
+ /**
+ * Defines a signal connection between the two given nodes.
+ */
+ virtual bool connectNodes(QObject *, QObject *) = 0;
+
+ /**
+ * Cuts a signal connection between the two given nodes.
+ */
+ virtual bool disconnectNodes(QObject *, QObject *) = 0;
+
+ /**
+ * When this function is called the nodes given in the parameter list may lose
+ * signal data when a port is not connected.
+ */
+ virtual bool endConnectionChange(QSet<QObject *>) = 0;
+
+ /**
+ * gets all available mime types
+ */
+ virtual QStringList availableMimeTypes() const = 0;
+
+};
+} // namespace Phonon
+
+Q_DECLARE_INTERFACE(Phonon::BackendInterface, "BackendInterface3.phonon.kde.org")
+
+QT_END_NAMESPACE
+QT_END_HEADER
+
+#endif // PHONON_BACKENDINTERFACE_H
diff --git a/src/3rdparty/phonon/phonon/effect.cpp b/src/3rdparty/phonon/phonon/effect.cpp
new file mode 100644
index 0000000000..c12523200b
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/effect.cpp
@@ -0,0 +1,136 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005-2007 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+#include "effect.h"
+#include "effect_p.h"
+#include "effectparameter.h"
+#include "effectinterface.h"
+#include "factory_p.h"
+
+#define PHONON_INTERFACENAME EffectInterface
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_PHONON_EFFECT
+
+namespace Phonon
+{
+Effect::~Effect()
+{
+}
+
+Effect::Effect(const EffectDescription &description, QObject *parent)
+ : QObject(parent), MediaNode(*new EffectPrivate)
+{
+ K_D(Effect);
+ d->description = description;
+ d->createBackendObject();
+}
+
+Effect::Effect(EffectPrivate &dd, QObject *parent)
+ : QObject(parent), MediaNode(dd)
+{
+}
+
+void EffectPrivate::createBackendObject()
+{
+ if (m_backendObject)
+ return;
+ Q_Q(Effect);
+ m_backendObject = Factory::createEffect(description.index(), q);
+ if (m_backendObject) {
+ setupBackendObject();
+ }
+}
+
+//X Effect::Type Effect::type() const
+//X {
+//X K_D(const Effect);
+//X return d->type;
+//X }
+//X
+EffectDescription Effect::description() const
+{
+ K_D(const Effect);
+ return d->description;
+}
+
+QList<EffectParameter> Effect::parameters() const
+{
+ K_D(const Effect);
+ // there should be an iface object, but better be safe for those backend
+ // switching corner-cases: when the backend switches the new backend might
+ // not support this effect -> no iface object
+ if (d->m_backendObject) {
+ return INTERFACE_CALL(parameters());
+ }
+ return QList<EffectParameter>();
+}
+
+QVariant Effect::parameterValue(const EffectParameter &param) const
+{
+ K_D(const Effect);
+ if (!d->m_backendObject) {
+ return d->parameterValues[param];
+ }
+ return INTERFACE_CALL(parameterValue(param));
+}
+
+void Effect::setParameterValue(const EffectParameter &param, const QVariant &newValue)
+{
+ K_D(Effect);
+ d->parameterValues[param] = newValue;
+ if (d->backendObject()) {
+ INTERFACE_CALL(setParameterValue(param, newValue));
+ }
+}
+
+bool EffectPrivate::aboutToDeleteBackendObject()
+{
+ if (m_backendObject) {
+ const QList<EffectParameter> parameters = pINTERFACE_CALL(parameters());
+ foreach (const EffectParameter &p, parameters) {
+ parameterValues[p] = pINTERFACE_CALL(parameterValue(p));
+ }
+ }
+ return true;
+}
+
+void EffectPrivate::setupBackendObject()
+{
+ Q_ASSERT(m_backendObject);
+
+ // set up attributes
+ const QList<EffectParameter> parameters = pINTERFACE_CALL(parameters());
+ foreach (const EffectParameter &p, parameters) {
+ pINTERFACE_CALL(setParameterValue(p, parameterValues[p]));
+ }
+}
+
+} //namespace Phonon
+
+#endif //QT_NO_PHONON_EFFECT
+
+QT_END_NAMESPACE
+
+#include "moc_effect.cpp"
+
+// vim: sw=4 ts=4 tw=80
diff --git a/src/3rdparty/phonon/phonon/effect.h b/src/3rdparty/phonon/phonon/effect.h
new file mode 100644
index 0000000000..b3a7975e6a
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/effect.h
@@ -0,0 +1,119 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005-2007 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+
+#ifndef PHONON_EFFECT_H
+#define PHONON_EFFECT_H
+
+#include "phonondefs.h"
+#include <QtCore/QObject>
+#include "objectdescription.h"
+#include "medianode.h"
+
+QT_BEGIN_HEADER
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_PHONON_EFFECT
+
+class QString;
+template<class T> class QList;
+
+namespace Phonon
+{
+ class EffectParameter;
+ class EffectPrivate;
+
+ /** \class Effect effect.h Phonon/Effect
+ * \short Effects that can be inserted into a Path.
+ * An effect is a special object which can perform
+ * transformations on the specified path. Examples may include simple
+ * modifiers such as fading or pitch shifting, or more complex mathematical
+ * transformations.
+ *
+ * In order to use an effect, insert it into the path as follows:
+ * \code
+ * Path path = Phonon::createPath(...);
+ * Effect *effect = new Effect(this);
+ * path.insertEffect(effect);
+ * \endcode
+ *
+ * The effect will immediately begin applying it's transformations on
+ * the path. To stop it, remove the Effect from the path.
+ *
+ * \ingroup PhononEffects
+ * \author Matthias Kretz <kretz@kde.org>
+ */
+ class PHONON_EXPORT Effect : public QObject, public MediaNode
+ {
+ Q_OBJECT
+ K_DECLARE_PRIVATE(Effect)
+
+ public:
+ ~Effect();
+
+//X enum Type {
+//X AudioEffect,
+//X VideoEffect
+//X };
+
+ /**
+ * QObject constructor.
+ *
+ * \param description An EffectDescription object to determine the
+ * type of effect. See BackendCapabilities::availableAudioEffects().
+ * \param parent QObject parent
+ */
+ explicit Effect(const EffectDescription &description, QObject *parent = 0);
+
+//X Type type() const;
+
+ /**
+ * Returns the description of this effect. This is the same type as was
+ * passed to the constructor.
+ */
+ EffectDescription description() const;
+
+ /**
+ * Returns a list of parameters that this effect provides to control
+ * its behaviour.
+ *
+ * \see EffectParameter
+ * \see EffectWidget
+ */
+ QList<EffectParameter> parameters() const;
+
+ QVariant parameterValue(const EffectParameter&) const;
+ void setParameterValue(const EffectParameter&, const QVariant &value);
+
+ protected:
+ Effect(EffectPrivate &dd, QObject *parent);
+ };
+} //namespace Phonon
+
+#endif // QT_NO_EFFECT
+
+QT_END_NAMESPACE
+QT_END_HEADER
+
+// vim: sw=4 ts=4 tw=80
+#endif // PHONON_EFFECT_H
+
diff --git a/src/3rdparty/phonon/phonon/effect_p.h b/src/3rdparty/phonon/phonon/effect_p.h
new file mode 100644
index 0000000000..586812af41
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/effect_p.h
@@ -0,0 +1,61 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006-2007 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef EFFECT_P_H
+#define EFFECT_P_H
+
+#include "effect.h"
+#include "effectparameter.h"
+#include "medianode_p.h"
+#include <QtCore/QHash>
+#include <QtCore/QVariant>
+#include "phonondefs_p.h"
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_PHONON_EFFECT
+
+namespace Phonon
+{
+class EffectPrivate : public MediaNodePrivate
+{
+ Q_DECLARE_PUBLIC(Effect)
+ PHONON_PRIVATECLASS
+ public:
+ virtual QObject *qObject() { return q_func(); }
+ protected:
+ EffectPrivate()
+ {
+ }
+
+//X Effect::Type type;
+ EffectDescription description;
+ QHash<EffectParameter, QVariant> parameterValues;
+};
+} //namespace Phonon
+
+QT_END_NAMESPACE
+
+#endif //QT_NO_PHONON_EFFECT
+
+#endif // EFFECT_P_H
+// vim: sw=4 ts=4 tw=80
diff --git a/src/3rdparty/phonon/phonon/effectinterface.h b/src/3rdparty/phonon/phonon/effectinterface.h
new file mode 100644
index 0000000000..f535105e27
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/effectinterface.h
@@ -0,0 +1,68 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006-2008 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef PHONON_EFFECTINTERFACE_H
+#define PHONON_EFFECTINTERFACE_H
+
+#include "phononnamespace.h"
+#include <QtCore/QVariant>
+
+QT_BEGIN_HEADER
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_PHONON_EFFECT
+
+namespace Phonon
+{
+ class EffectParameter;
+ /** \class EffectInterface effectinterface.h Phonon/EffectInterface
+ * \short Interface for Effect objects
+ *
+ * \author Matthias Kretz <kretz@kde.org>
+ */
+ class EffectInterface
+ {
+ public:
+ virtual ~EffectInterface() {}
+ /**
+ * Returns the EffectParameter objects to describe the parameters of this effect.
+ */
+ virtual QList<EffectParameter> parameters() const = 0;
+ /**
+ * Returns the value for the selected parameter.
+ */
+ virtual QVariant parameterValue(const EffectParameter &) const = 0;
+ /**
+ * Sets the value for the selected parameter.
+ */
+ virtual void setParameterValue(const EffectParameter &, const QVariant &newValue) = 0;
+ };
+} //namespace Phonon
+
+Q_DECLARE_INTERFACE(Phonon::EffectInterface, "EffectInterface0.phonon.kde.org")
+
+#endif //QT_NO_PHONON_EFFECT
+
+QT_END_NAMESPACE
+QT_END_HEADER
+
+#endif // PHONON_EFFECTINTERFACE_H
diff --git a/src/3rdparty/phonon/phonon/effectparameter.cpp b/src/3rdparty/phonon/phonon/effectparameter.cpp
new file mode 100644
index 0000000000..6030b6ece8
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/effectparameter.cpp
@@ -0,0 +1,142 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "effectparameter.h"
+#include "effectparameter_p.h"
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_PHONON_EFFECT
+
+namespace Phonon
+{
+
+uint qHash(const Phonon::EffectParameter &param)
+{
+ return param.id();
+}
+
+EffectParameter::EffectParameter()
+ : d(new EffectParameterPrivate)
+{
+}
+
+EffectParameter::EffectParameter(int parameterId, const QString &name, Hints hints,
+ const QVariant &defaultValue, const QVariant &min, const QVariant &max,
+ const QVariantList &values, const QString &description)
+ : d(new EffectParameterPrivate)
+{
+ d->parameterId = parameterId;
+ d->min = min;
+ d->max = max;
+ d->defaultValue = defaultValue;
+ d->name = name;
+ d->possibleValues = values;
+ d->description = description;
+ d->hints = hints;
+}
+
+EffectParameter::~EffectParameter()
+{
+}
+
+EffectParameter::EffectParameter(const EffectParameter &rhs)
+ : d(rhs.d)
+{
+}
+
+EffectParameter &EffectParameter::operator=(const EffectParameter &rhs)
+{
+ d = rhs.d;
+ return *this;
+}
+
+bool EffectParameter::operator<(const EffectParameter &rhs) const
+{
+ return d->parameterId < rhs.d->parameterId;
+}
+
+bool EffectParameter::operator==(const EffectParameter &rhs) const
+{
+ return d->parameterId == rhs.d->parameterId;
+}
+
+bool EffectParameter::operator>(const EffectParameter &rhs) const
+{
+ return d->parameterId > rhs.d->parameterId;
+}
+
+const QString &EffectParameter::name() const
+{
+ return d->name;
+}
+
+const QString &EffectParameter::description() const
+{
+ return d->description;
+}
+
+bool EffectParameter::isLogarithmicControl() const
+{
+ return d->hints & LogarithmicHint;
+}
+
+QVariant::Type EffectParameter::type() const
+{
+ if (d->possibleValues.isEmpty()) {
+ return d->defaultValue.type();
+ }
+ return QVariant::String;
+}
+
+QVariantList EffectParameter::possibleValues() const
+{
+ return d->possibleValues;
+}
+
+QVariant EffectParameter::minimumValue() const
+{
+ return d->min;
+}
+
+QVariant EffectParameter::maximumValue() const
+{
+ return d->max;
+}
+
+QVariant EffectParameter::defaultValue() const
+{
+ return d->defaultValue;
+}
+
+int EffectParameter::id() const
+{
+ return d->parameterId;
+}
+
+}
+
+#endif //QT_NO_PHONON_EFFECT
+
+QT_END_NAMESPACE
+
+// vim: sw=4 ts=4
diff --git a/src/3rdparty/phonon/phonon/effectparameter.h b/src/3rdparty/phonon/phonon/effectparameter.h
new file mode 100644
index 0000000000..55c70495e7
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/effectparameter.h
@@ -0,0 +1,237 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef PHONON_EFFECTPARAMETER_H
+#define PHONON_EFFECTPARAMETER_H
+
+#include "phonon_export.h"
+
+#include <QtCore/QExplicitlySharedDataPointer>
+#include <QtCore/QVariant>
+
+QT_BEGIN_HEADER
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_PHONON_EFFECT
+
+namespace Phonon
+{
+
+class Effect;
+class EffectParameterPrivate;
+
+/** \class EffectParameter effectparameter.h Phonon/EffectParameter
+ * \brief This class describes one parameter of an effect.
+ *
+ * \ingroup PhononEffects
+ * \author Matthias Kretz <kretz@kde.org>
+ * \see Effect
+ */
+class PHONON_EXPORT EffectParameter
+{
+ friend class BrightnessControl;
+ public:
+ /**
+ * \internal
+ *
+ * Creates an invalid effect parameter.
+ */
+ EffectParameter();
+
+ /**
+ * The name of the parameter. Can be used as the label.
+ *
+ * \return A label for the parameter.
+ */
+ const QString &name() const;
+
+ /**
+ * The parameter may come with a description (LADSPA doesn't have a
+ * field for this, so don't expect many effects to provide a
+ * description).
+ *
+ * The description can be used for a tooltip or WhatsThis help.
+ *
+ * \return A text describing the parameter.
+ */
+ const QString &description() const;
+
+ /**
+ * Returns the parameter type.
+ *
+ * Common types are QVariant::Int, QVariant::Double, QVariant::Bool and QVariant::String. When
+ * QVariant::String is returned you get the possible values from possibleValues.
+ */
+ QVariant::Type type() const;
+
+ /**
+ * Returns whether the parameter should be
+ * displayed using a logarithmic scale. This is particularly useful for
+ * frequencies and gains.
+ */
+ bool isLogarithmicControl() const;
+
+ /**
+ * The minimum value to be used for the control to edit the parameter.
+ *
+ * If the returned QVariant is invalid the value is not bounded from
+ * below.
+ */
+ QVariant minimumValue() const;
+
+ /**
+ * The maximum value to be used for the control to edit the parameter.
+ *
+ * If the returned QVariant is invalid the value is not bounded from
+ * above.
+ */
+ QVariant maximumValue() const;
+
+ /**
+ * The default value.
+ */
+ QVariant defaultValue() const;
+
+ /**
+ * The possible values to be used for the control to edit the parameter.
+ *
+ * if the value of this parameter is to be picked from predefined values
+ * this returns the list (otherwise it returns an empty QVariantList).
+ */
+ QVariantList possibleValues() const;
+
+ /**
+ * \internal
+ * compares the ids of the parameters
+ */
+ bool operator<(const EffectParameter &rhs) const;
+
+ /**
+ * \internal
+ * compares the ids of the parameters
+ */
+ bool operator>(const EffectParameter &rhs) const;
+
+ /**
+ * \internal
+ * compares the ids of the parameters
+ */
+ bool operator==(const EffectParameter &rhs) const;
+
+ /* dtor, cctor and operator= for forward decl of EffectParameterPrivate */
+ ~EffectParameter();
+ EffectParameter(const EffectParameter &rhs);
+ EffectParameter &operator=(const EffectParameter &rhs);
+
+ /**
+ * Only for backend developers:
+ *
+ * Flags to set the return values of isToggleControl(),
+ * isLogarithmicControl(), isIntegerControl(), isBoundedBelow() and
+ * isBoundedAbove(). The values of the flags correspond to the values
+ * used for LADSPA effects.
+ */
+ enum Hint {
+ /**
+ * If this hint is set it means that
+ * the the control has only two states: zero and non-zero.
+ *
+ * \see isToggleControl()
+ */
+ ToggledHint = 0x04,
+
+ /* LADSPA's SAMPLE_RATE hint needs to be translated by the backend
+ * to normal bounds, as the backend knows the sample rate - and the
+ * frontend doesn't */
+
+ /**
+ * \see isLogarithmicControl()
+ */
+ LogarithmicHint = 0x10,
+ /**
+ * \see isIntegerControl
+ */
+ IntegerHint = 0x20
+ };
+ Q_DECLARE_FLAGS(Hints, Hint)
+
+ /**
+ * Only to be used by backend implementations:
+ *
+ * Creates a new effect parameter.
+ *
+ * \param parameterId This is a number to uniquely identify the
+ * parameter. The id is used for value() and setValue().
+ *
+ * \param name The name/label for this parameter.
+ *
+ * \param hints Sets the hints for the type of parameter.
+ *
+ * \param defaultValue The value that should be used as a default.
+ *
+ * \param min The minimum value allowed for this parameter. You only
+ * need to set this if the BoundedBelowHint is set.
+ *
+ * \param max The maximum value allowed for this parameter. You only
+ * need to set this if the BoundedAboveHint is set.
+ *
+ * \param description A descriptive text for the parameter
+ * (explaining what it controls) to be used as a tooltip or
+ * WhatsThis help.
+ */
+ EffectParameter(int parameterId, const QString &name, Hints hints,
+ const QVariant &defaultValue, const QVariant &min = QVariant(),
+ const QVariant &max = QVariant(), const QVariantList &values = QVariantList(),
+ const QString &description = QString());
+
+ /**
+ * \internal
+ *
+ * Returns the parameter's id.
+ */
+ int id() const;
+
+ protected:
+ /**
+ * The data is implicitly shared.
+ */
+ QExplicitlySharedDataPointer<EffectParameterPrivate> d;
+};
+
+uint PHONON_EXPORT qHash(const Phonon::EffectParameter &param);
+
+} // namespace Phonon
+
+#if defined(Q_CC_MSVC) && _MSC_VER <= 1300
+//this ensures that code outside Phonon can use the hash function
+//it also a workaround for some compilers
+inline uint qHash(const Phonon::EffectParameter &param) { return Phonon::qHash(param); } //krazy:exclude=inline
+#endif
+Q_DECLARE_OPERATORS_FOR_FLAGS(Phonon::EffectParameter::Hints)
+
+#endif //QT_NO_PHONON_EFFECT
+
+QT_END_NAMESPACE
+QT_END_HEADER
+
+#endif // PHONON_EFFECTPARAMETER_H
+// vim: sw=4 ts=4 tw=80
diff --git a/src/3rdparty/phonon/phonon/effectparameter_p.h b/src/3rdparty/phonon/phonon/effectparameter_p.h
new file mode 100644
index 0000000000..0fc387ac47
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/effectparameter_p.h
@@ -0,0 +1,56 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef EFFECTPARAMETER_P_H
+#define EFFECTPARAMETER_P_H
+
+#include "effectparameter.h"
+#include <QtCore/QSharedData>
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_PHONON_EFFECT
+
+namespace Phonon
+{
+
+class EffectParameterPrivate : public QSharedData
+{
+ public:
+ int parameterId;
+ QVariant min;
+ QVariant max;
+ QVariant defaultValue;
+ QString name;
+ QString description;
+ QVariantList possibleValues;
+ EffectParameter::Hints hints;
+};
+
+} // namespace Phonon
+
+#endif //QT_NO_PHONON_EFFECT
+
+QT_END_NAMESPACE
+
+#endif // EFFECTPARAMETER_P_H
+// vim: sw=4 ts=4 tw=80
diff --git a/src/3rdparty/phonon/phonon/effectwidget.cpp b/src/3rdparty/phonon/phonon/effectwidget.cpp
new file mode 100644
index 0000000000..da5a51a469
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/effectwidget.cpp
@@ -0,0 +1,254 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006-2007 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "effectwidget.h"
+#include "effectwidget_p.h"
+
+#include <QtCore/QtAlgorithms>
+#include <QtCore/QList>
+
+#include "effect.h"
+#include "effectparameter.h"
+#include "phonondefs_p.h"
+#include <QtGui/QBoxLayout>
+#include <QtGui/QLabel>
+#include <QtGui/QSpinBox>
+#include <QtGui/QCheckBox>
+#include <QtGui/QComboBox>
+#include <QtGui/QSlider>
+#include <limits>
+
+#ifdef min
+#undef min
+#endif
+#ifdef max
+#undef max
+#endif
+static const qreal DEFAULT_MIN = std::numeric_limits<qreal>::min();
+static const qreal DEFAULT_MAX = std::numeric_limits<qreal>::max();
+static const int DEFAULT_MIN_INT = std::numeric_limits<int>::min();
+static const int DEFAULT_MAX_INT = std::numeric_limits<int>::max();
+static const int SLIDER_RANGE = 8;
+static const int TICKINTERVAL = 4;
+
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_PHONON_EFFECTWIDGET
+
+namespace Phonon
+{
+
+EffectWidget::EffectWidget(Effect *effect, QWidget *parent)
+ : QWidget(parent),
+ k_ptr(new EffectWidgetPrivate(effect))
+{
+ K_D(EffectWidget);
+ d->q_ptr = this;
+ d->autogenerateUi();
+}
+
+EffectWidget::~EffectWidget()
+{
+ delete k_ptr;
+}
+
+/*
+EffectWidget::EffectWidget(EffectWidgetPrivate &dd, QWidget *parent)
+ : QWidget(parent)
+ , k_ptr(&dd)
+{
+ K_D(EffectWidget);
+ d->q_ptr = this;
+ d->autogenerateUi();
+}
+*/
+
+EffectWidgetPrivate::EffectWidgetPrivate(Effect *e)
+ : effect(e)
+{
+ //TODO: look up whether there is a specialized widget for this effect. This
+ //could be a DSO or a Designer ui file found via KTrader.
+ //
+ //if no specialized widget is available:
+}
+
+void EffectWidgetPrivate::autogenerateUi()
+{
+ Q_Q(EffectWidget);
+ QVBoxLayout *mainLayout = new QVBoxLayout(q);
+ mainLayout->setMargin(0);
+ foreach (const EffectParameter &para, effect->parameters()) {
+ QVariant value = effect->parameterValue(para);
+ QHBoxLayout *pLayout = new QHBoxLayout;
+ mainLayout->addLayout(pLayout);
+
+ QLabel *label = new QLabel(q);
+ pLayout->addWidget(label);
+ label->setText(para.name());
+#ifndef QT_NO_TOOLTIP
+ label->setToolTip(para.description());
+#endif
+
+ QWidget *control = 0;
+ switch (para.type()) {
+ case QVariant::String:
+ {
+ QComboBox *cb = new QComboBox(q);
+ control = cb;
+ if (value.type() == QVariant::Int) {
+ //value just defines the item index
+ foreach (const QVariant &item, para.possibleValues()) {
+ cb->addItem(item.toString());
+ }
+ cb->setCurrentIndex(value.toInt());
+ QObject::connect(cb, SIGNAL(currentIndexChanged(int)), q, SLOT(_k_setIntParameter(int)));
+ } else {
+ foreach (const QVariant &item, para.possibleValues()) {
+ cb->addItem(item.toString());
+ if (item == value) {
+ cb->setCurrentIndex(cb->count() - 1);
+ }
+ }
+ QObject::connect(cb, SIGNAL(currentIndexChanged(QString)), q, SLOT(_k_setStringParameter(QString)));
+ }
+ }
+ break;
+ case QVariant::Bool:
+ {
+ QCheckBox *cb = new QCheckBox(q);
+ control = cb;
+ cb->setChecked(value.toBool());
+ QObject::connect(cb, SIGNAL(toggled(bool)), q, SLOT(_k_setToggleParameter(bool)));
+ }
+ break;
+ case QVariant::Int:
+ {
+ QSpinBox *sb = new QSpinBox(q);
+ control = sb;
+ bool minValueOk = false;
+ bool maxValueOk = false;
+ const int minValue = para.minimumValue().toInt(&minValueOk);
+ const int maxValue = para.minimumValue().toInt(&maxValueOk);
+
+ sb->setRange(minValueOk ? minValue : DEFAULT_MIN_INT, maxValueOk ? maxValue : DEFAULT_MAX_INT);
+ sb->setValue(value.toInt());
+ QObject::connect(sb, SIGNAL(valueChanged(int)), q, SLOT(_k_setIntParameter(int)));
+ }
+ break;
+ case QVariant::Double:
+ {
+ const double minValue = (para.minimumValue().type() == QVariant::Double ?
+ para.minimumValue().toDouble() : DEFAULT_MIN);
+ const double maxValue = (para.maximumValue().type() == QVariant::Double ?
+ para.maximumValue().toDouble() : DEFAULT_MAX);
+
+ if (minValue == -1. && maxValue == 1.) {
+ //Special case values between -1 and 1.0 to use a slider for improved usability
+ QSlider *slider = new QSlider(Qt::Horizontal, q);
+ slider->setRange(-SLIDER_RANGE, +SLIDER_RANGE);
+ slider->setValue(int(SLIDER_RANGE * value.toDouble()));
+ slider->setTickPosition(QSlider::TicksBelow);
+ slider->setTickInterval(TICKINTERVAL);
+ QObject::connect(slider, SIGNAL(valueChanged(int)), q, SLOT(_k_setSliderParameter(int)));
+ } else {
+ double step = 0.1;
+ if (qAbs(maxValue - minValue) > 50)
+ step = 1.0;
+ QDoubleSpinBox *sb = new QDoubleSpinBox(q);
+ control = sb;
+ sb->setRange(minValue, maxValue);
+ sb->setValue(value.toDouble());
+ sb->setSingleStep(step);
+ QObject::connect(sb, SIGNAL(valueChanged(double)), q,
+ SLOT(_k_setDoubleParameter(double)));
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+#ifndef QT_NO_TOOLTIP
+ control->setToolTip(para.description());
+#endif
+ if (control) {
+#ifndef QT_NO_SHORTCUT
+ label->setBuddy(control);
+#endif
+ pLayout->addWidget(control);
+ parameterForObject.insert(control, para);
+ }
+ }
+}
+
+void EffectWidgetPrivate::_k_setToggleParameter(bool checked)
+{
+ Q_Q(EffectWidget);
+ if (parameterForObject.contains(q->sender())) {
+ effect->setParameterValue(parameterForObject[q->sender()], checked);
+ }
+}
+
+void EffectWidgetPrivate::_k_setIntParameter(int value)
+{
+ Q_Q(EffectWidget);
+ if (parameterForObject.contains(q->sender())) {
+ effect->setParameterValue(parameterForObject[q->sender()], value);
+ }
+}
+
+void EffectWidgetPrivate::_k_setDoubleParameter(double value)
+{
+ Q_Q(EffectWidget);
+ if (parameterForObject.contains(q->sender())) {
+ effect->setParameterValue(parameterForObject[q->sender()], value);
+ }
+}
+
+void EffectWidgetPrivate::_k_setStringParameter(const QString &value)
+{
+ Q_Q(EffectWidget);
+ if (parameterForObject.contains(q->sender())) {
+ effect->setParameterValue(parameterForObject[q->sender()], value);
+ }
+}
+
+void EffectWidgetPrivate::_k_setSliderParameter(int value)
+{
+ Q_Q(EffectWidget);
+ if (parameterForObject.contains(q->sender())) {
+ effect->setParameterValue(parameterForObject[q->sender()], double(value) / double(SLIDER_RANGE));
+ }
+}
+
+
+} // namespace Phonon
+
+
+#endif // QT_NO_PHONON_EFFECTWIDGET
+
+QT_END_NAMESPACE
+
+#include "moc_effectwidget.cpp"
+
+// vim: sw=4 ts=4
diff --git a/src/3rdparty/phonon/phonon/effectwidget.h b/src/3rdparty/phonon/phonon/effectwidget.h
new file mode 100644
index 0000000000..340b2e3feb
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/effectwidget.h
@@ -0,0 +1,76 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006-2007 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef PHONON_UI_EFFECTWIDGET_H
+#define PHONON_UI_EFFECTWIDGET_H
+
+#include "phonon_export.h"
+#include "phonondefs.h"
+#include <QtGui/QWidget>
+
+QT_BEGIN_HEADER
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_PHONON_EFFECTWIDGET
+
+namespace Phonon
+{
+class Effect;
+
+ class EffectWidgetPrivate;
+
+ /** \class EffectWidget effectwidget.h Phonon/EffectWidget
+ * \brief Widget to control the parameters of an \ref Effect.
+ *
+ * \ingroup PhononWidgets
+ * \ingroup PhononEffects
+ * \author Matthias Kretz <kretz@kde.org>
+ */
+ class PHONON_EXPORT EffectWidget : public QWidget
+ {
+ Q_OBJECT
+ K_DECLARE_PRIVATE(EffectWidget)
+ public:
+ explicit EffectWidget(Effect *effect, QWidget *parent = 0);
+ ~EffectWidget();
+
+ protected:
+ //EffectWidget(EffectWidgetPrivate &dd, QWidget *parent);
+ EffectWidgetPrivate *const k_ptr;
+
+ private:
+ Q_PRIVATE_SLOT(k_func(), void _k_setToggleParameter(bool checked))
+ Q_PRIVATE_SLOT(k_func(), void _k_setIntParameter(int value))
+ Q_PRIVATE_SLOT(k_func(), void _k_setDoubleParameter(double value))
+ Q_PRIVATE_SLOT(k_func(), void _k_setStringParameter(const QString &))
+ Q_PRIVATE_SLOT(k_func(), void _k_setSliderParameter(int))
+ };
+} // namespace Phonon
+
+#endif //QT_NO_PHONON_EFFECTWIDGET
+
+QT_END_NAMESPACE
+QT_END_HEADER
+
+#endif // PHONON_UI_EFFECTWIDGET_H
+
+// vim: sw=4 ts=4 tw=100
diff --git a/src/3rdparty/phonon/phonon/effectwidget_p.h b/src/3rdparty/phonon/phonon/effectwidget_p.h
new file mode 100644
index 0000000000..6ce44bfe3e
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/effectwidget_p.h
@@ -0,0 +1,64 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006-2007 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef PHONON_UI_EFFECTWIDGET_P_H
+#define PHONON_UI_EFFECTWIDGET_P_H
+
+#include "effectwidget.h"
+#include "effectparameter.h"
+#include <QtCore/QHash>
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_PHONON_EFFECTWIDGET
+
+namespace Phonon
+{
+ class EffectWidgetPrivate
+ {
+ Q_DECLARE_PUBLIC(EffectWidget)
+ protected:
+ EffectWidgetPrivate(Effect *effect);
+
+ EffectWidget *q_ptr;
+
+ private:
+ Effect *effect;
+ QHash<QObject *, EffectParameter> parameterForObject;
+
+ void _k_setToggleParameter(bool checked);
+ void _k_setIntParameter(int value);
+ void _k_setDoubleParameter(double value);
+ void _k_setStringParameter(const QString &);
+ void _k_setSliderParameter(int);
+
+ void autogenerateUi();
+ };
+} // namespace Phonon
+
+#endif //QT_NO_PHONON_EFFECTWIDGET
+
+QT_END_NAMESPACE
+
+#endif // PHONON_UI_EFFECTWIDGET_P_H
+
+// vim: sw=4 ts=4 tw=80
diff --git a/src/3rdparty/phonon/phonon/extractmethodcalls.rb b/src/3rdparty/phonon/phonon/extractmethodcalls.rb
new file mode 100755
index 0000000000..910048969e
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/extractmethodcalls.rb
@@ -0,0 +1,527 @@
+#!/usr/bin/ruby
+
+class MethodDef
+ def initialize(returnType, signature, optional)
+ @returnType = returnType
+ @signature = signature
+ @optional = optional
+ end
+
+ attr_reader :returnType, :signature, :optional
+ attr_writer :optional
+end
+
+class SignalDef
+ def initialize(signature)
+ @signature = signature
+ end
+
+ attr_reader :signature
+end
+
+class Parser
+ def initialize(filename)
+ @file = File.new filename, "r"
+ @signatures = Hash.new
+ parse
+ end
+
+ attr_reader :signatures
+
+ private
+ def addSignal(signature)
+ unless @signatures.include? signature
+ @signatures[signature] = SignalDef.new(signature)
+ end
+ end
+
+ def addMethod(returnType, signature, optional)
+ if @signatures.include? signature
+ if returnType != ''
+ if @signatures[signature].returnType == ''
+ optional = false if @signatures[signature].optional == false
+ @signatures[signature] = MethodDef.new(returnType, signature, optional)
+ elsif @signatures[signature].returnType != returnType
+ fail "same signature '#{signature}' but differing return types: #{returnType} and #{@signatures[signature].returnType}"
+ end
+ elsif not optional and @signatures[signature].optional
+ @signatures[signature].optional = false
+ end
+ else
+ @signatures[signature] = MethodDef.new(returnType, signature, optional)
+ end
+ end
+
+ PARSER_RETURN_TYPE = 0
+ PARSER_RETURN_VAR = 1
+ PARSER_METHOD_NAME = 2
+ PARSER_ARGUMENT_TYPE = 3
+ PARSER_ARGUMENT_VAR = 4
+
+ PARSER2_CLASSNAME = 0
+ PARSER2_METHODPREFIX = 1
+
+ PARSER3_QMETAOBJECT = 0
+ PARSER3_SCOPEDELIMIT = 1
+ PARSER3_INVOKEMETHOD = 2
+ PARSER3_OPENPARENTH = 3
+ PARSER3_BACKENDOBJ = 4
+ PARSER3_METHODNAME = 5
+ PARSER3_CONNECTION = 6
+ PARSER3_RET_OR_ARG = 7
+ PARSER3_RET_OPEN = 8
+ PARSER3_RET_TYPE = 9
+ PARSER3_RET_NAME = 10
+ PARSER3_RET_CLOSE = 11
+ PARSER3_ARG = 12
+ PARSER3_ARG_OPEN = 13
+ PARSER3_ARG_TYPE = 14
+ PARSER3_ARG_NAME = 15
+ PARSER3_ARG_CLOSE = 16
+ PARSER3_CLOSE = 17
+ PARSER3_DONE = 18
+
+ PARSER4_OPENING_PAREN = 0
+ PARSER4_SENDER = 1
+ PARSER4_PRIVATE_SENDER = 2
+ PARSER4_COMMA_1 = 3
+ PARSER4_SIGNAL_MACRO = 4
+ PARSER4_SIGNAL_OPENING_PAREN = 5
+ PARSER4_SIGNAL_SIGNATURE = 6
+ PARSER4_SIGNAL_SIGNATURE_OPENING_PAREN = 7
+ PARSER4_SIGNAL_SIGNATURE_CONST = 8
+ PARSER4_SIGNAL_SIGNATURE_TYPE1 = 9
+ PARSER4_SIGNAL_SIGNATURE_TYPE2_1 = 10
+ PARSER4_SIGNAL_SIGNATURE_TYPE2_2 = 11
+ PARSER4_SIGNAL_CLOSING_PAREN = 12
+
+ def parse
+ inbackendcall = false
+ innamedescriptioncall = false
+ ininvokemethodcall = false
+ invokemethodcallOnBackendObject = false
+ inconnect = false
+ optionalmethod = false
+ lasttoken = ';'
+ thistoken = ';'
+ returnType = String.new
+ signature = String.new
+ parserstate = PARSER_RETURN_TYPE
+ depth = 0
+ tokenize do |token|
+ #STDERR.puts token
+ lasttoken = thistoken
+ thistoken = token
+ token = token[1..-1] if token[0,9] == "pBACKEND_"
+ if token[0,8] == "BACKEND_"
+ fail if innamedescriptioncall
+ fail if inbackendcall
+ fail if ininvokemethodcall
+ fail if inconnect
+ inbackendcall = true
+ if token[8,3] != "GET" # skip return arg
+ parserstate = PARSER_METHOD_NAME
+ returnType = ''
+ else
+ parserstate = PARSER_RETURN_TYPE
+ end
+ elsif token == 'NAMEDESCRIPTIONFROMINDEX'
+ fail if innamedescriptioncall
+ fail if inbackendcall
+ fail if ininvokemethodcall
+ fail if inconnect
+ innamedescriptioncall = true
+ parserstate = PARSER2_CLASSNAME
+ elsif token == 'QMetaObject'
+ fail if innamedescriptioncall
+ fail if inbackendcall
+ fail if ininvokemethodcall
+ fail if inconnect
+ ininvokemethodcall = true
+ parserstate = PARSER3_SCOPEDELIMIT
+ optionalmethod = (lasttoken[-1,1] == '=' or lasttoken == '(' or lasttoken == '!') ? true : false
+ elsif token == 'connect'
+ fail if innamedescriptioncall
+ fail if inbackendcall
+ fail if ininvokemethodcall
+ fail if inconnect
+ inconnect = true
+ parserstate = PARSER4_OPENING_PAREN
+ elsif inconnect
+ #puts "state = #{parserstate}, token = #{token}"
+ lastparserstate = parserstate
+ case parserstate
+ when PARSER4_OPENING_PAREN
+ parserstate = PARSER4_SENDER if token == '('
+ when PARSER4_SENDER
+ # d->m_backendObject or only m_backendObject
+ parserstate = PARSER4_COMMA_1 if token == 'm_backendObject'
+ parserstate = PARSER4_PRIVATE_SENDER if token == 'd'
+ when PARSER4_PRIVATE_SENDER
+ parserstate = PARSER4_SENDER if token == '->'
+ when PARSER4_COMMA_1
+ parserstate = PARSER4_SIGNAL_MACRO if token == ','
+ when PARSER4_SIGNAL_MACRO
+ parserstate = PARSER4_SIGNAL_OPENING_PAREN if token == 'SIGNAL'
+ when PARSER4_SIGNAL_OPENING_PAREN
+ parserstate = PARSER4_SIGNAL_SIGNATURE if token == '('
+ when PARSER4_SIGNAL_SIGNATURE
+ signature = token
+ parserstate = PARSER4_SIGNAL_SIGNATURE_OPENING_PAREN
+ when PARSER4_SIGNAL_SIGNATURE_OPENING_PAREN
+ case token
+ when '('
+ signature += '('
+ parserstate = PARSER4_SIGNAL_SIGNATURE_CONST
+ when '()'
+ signature += '()'
+ parserstate = PARSER4_SIGNAL_CLOSING_PAREN
+ end
+ when PARSER4_SIGNAL_SIGNATURE_CONST
+ case token
+ when 'const'
+ signature += 'const '
+ parserstate = PARSER4_SIGNAL_SIGNATURE_TYPE1
+ when ')'
+ signature += ')'
+ parserstate = PARSER4_SIGNAL_CLOSING_PAREN
+ else
+ signature += token
+ parserstate = PARSER4_SIGNAL_SIGNATURE_TYPE2_1
+ end
+ when PARSER4_SIGNAL_SIGNATURE_TYPE1
+ case token
+ when 'const'
+ when ')'
+ else
+ signature += token
+ parserstate = PARSER4_SIGNAL_SIGNATURE_TYPE2_1
+ end
+ when PARSER4_SIGNAL_SIGNATURE_TYPE2_1
+ case token
+ when ','
+ signature += ', '
+ parserstate = PARSER4_SIGNAL_SIGNATURE_TYPE1
+ when ')'
+ signature += ')'
+ parserstate = PARSER4_SIGNAL_CLOSING_PAREN
+ else
+ signature += token
+ parserstate = PARSER4_SIGNAL_SIGNATURE_TYPE2_2
+ end
+ when PARSER4_SIGNAL_SIGNATURE_TYPE2_2
+ case token
+ when ','
+ signature += ', '
+ parserstate = PARSER4_SIGNAL_SIGNATURE_TYPE1
+ when ')'
+ signature += ')'
+ parserstate = PARSER4_SIGNAL_CLOSING_PAREN
+ else
+ signature += token
+ parserstate = PARSER4_SIGNAL_SIGNATURE_TYPE2_1
+ end
+ when PARSER4_SIGNAL_CLOSING_PAREN
+ addSignal(signature) if token == ')'
+ end
+ if parserstate == lastparserstate
+ inconnect = false
+ signature = String.new
+ end
+ elsif ininvokemethodcall
+ case parserstate
+ when PARSER3_BACKENDOBJ
+ if token == ','
+ if invokemethodcallOnBackendObject
+ parserstate += 1
+ else
+ ininvokemethodcall = false
+ end
+ elsif token =~ /backendObject/
+ invokemethodcallOnBackendObject = true
+ end
+ when PARSER3_SCOPEDELIMIT
+ if token == '::'
+ parserstate += 1
+ else
+ ininvokemethodcall = false
+ end
+ when PARSER3_INVOKEMETHOD
+ if token == 'invokeMethod'
+ parserstate += 1
+ else
+ ininvokemethodcall = false
+ end
+ when PARSER3_OPENPARENTH
+ fail if token != '('
+ parserstate += 1
+ invokemethodcallOnBackendObject = false
+ when PARSER3_METHODNAME
+ case token
+ when ','
+ signature += '('
+ parserstate = PARSER3_CONNECTION
+ else
+ fail if signature.length > 0
+ signature = token[1..-2]
+ end
+ when PARSER3_CONNECTION
+ case token
+ when ','
+ parserstate = PARSER3_RET_OR_ARG
+ when ')'
+ parserstate = PARSER3_CLOSE
+# the connection is optional
+ when 'Q_RETURN_ARG'
+ parserstate = PARSER3_RET_OPEN
+ when 'Q_ARG'
+ returnType = ''
+ parserstate = PARSER3_ARG_OPEN
+ end
+ when PARSER3_RET_OR_ARG
+ if token == 'Q_RETURN_ARG'
+ parserstate = PARSER3_RET_OPEN
+ elsif token == 'Q_ARG'
+ returnType = ''
+ parserstate = PARSER3_ARG_OPEN
+ else
+ fail "unexpected token '#{token}"
+ end
+ when PARSER3_RET_TYPE
+ if token == ','
+ parserstate += 1
+ else
+ if token == '*' or token == '&' or token == '<' or token == '>' or token == '::' or returnType.empty? or returnType[-1,1] == '<' or returnType[-2,2] == '::'
+ returnType += token
+ else
+ returnType += ' ' + token
+ end
+ end
+ when PARSER3_RET_NAME
+ parserstate = PARSER3_RET_CLOSE if token == ')'
+ when PARSER3_RET_CLOSE
+ case token
+ when ')'
+ parserstate = PARSER3_CLOSE
+ when ','
+ parserstate = PARSER3_ARG
+ end
+ when PARSER3_ARG
+ if token == 'Q_ARG'
+ parserstate = PARSER3_ARG_OPEN
+ else
+ fail "unexpected token '#{token}"
+ end
+ when PARSER3_ARG_TYPE
+ if token == ','
+ parserstate += 1
+ else
+ signature += ' ' if signature[-1,1] =~ /\w/ and token[0,1] =~ /\w/
+ signature += token
+ end
+ when PARSER3_ARG_NAME
+ case token
+ when '('
+ depth += 1
+ when ')'
+ if depth == 0
+ parserstate = PARSER3_ARG_CLOSE
+ else
+ depth -= 1
+ end
+ end
+ when PARSER3_ARG_CLOSE
+ case token
+ when ','
+ signature += ','
+ parserstate = PARSER3_ARG
+ when ')'
+ parserstate = PARSER3_CLOSE
+ else
+ fail
+ end
+ when PARSER3_ARG_OPEN, PARSER3_RET_OPEN
+ fail if token != '('
+ parserstate += 1
+ when PARSER3_CLOSE
+ signature += ')'
+ addMethod returnType, signature, optionalmethod
+ ininvokemethodcall = false
+ returnType = String.new
+ signature = String.new
+ end
+ elsif innamedescriptioncall
+ case parserstate
+ when PARSER2_CLASSNAME
+ parserstate = PARSER2_METHODPREFIX if token == ','
+ when PARSER2_METHODPREFIX
+ addMethod 'QSet<int>', token + 'Indexes()', false
+ addMethod 'int', token + 'Name()', false
+ addMethod 'int', token + 'Description()', false
+ innamedescriptioncall = false
+ end
+ elsif inbackendcall
+ next if token == '(' # skip (
+ if token == ';'
+ if signature.length > 0
+ signature += ')'
+ addMethod returnType, signature, false
+ signature = String.new
+ returnType = String.new
+ end
+ inbackendcall = false
+ else
+ if token == ','
+ if parserstate == PARSER_ARGUMENT_VAR
+ signature += ','
+ parserstate = PARSER_ARGUMENT_TYPE
+ else
+ parserstate += 1
+ end
+ next
+ end
+ case parserstate
+ when PARSER_RETURN_TYPE
+ returnType += token
+ when PARSER_RETURN_VAR
+ when PARSER_METHOD_NAME
+ next if token == ')'
+ fail if token[0,1] != '"' or token[-1,1] != '"'
+ fail if signature.length > 0
+ signature = token[1..-2] + '('
+ when PARSER_ARGUMENT_TYPE
+ signature += token
+ end
+ end
+ end
+ end
+ end
+
+ def tokenize
+ incomment = false
+ instring = false
+ laststring = ''
+ linenum = 0
+ @file.each_line do |line|
+ linenum += 1
+ line.strip!
+ next if line[0..1] == "//"
+ next if line[0,1] == "#" # ignore preprocessor statements
+ line.split(/(\b|\s+)/).each do |token|
+ #STDERR.puts "string: #{instring} comment: #{incomment} token: '#{token}'"
+ if instring
+ indexOfEscapedQuote = token.index '\\"'
+ if indexOfEscapedQuote != nil
+ laststring += token
+ next
+ end
+ indexOfQuote = token.index '"'
+ if indexOfQuote and indexOfQuote > 0
+ fail if token[indexOfQuote-1,1] == '\\'
+ laststring += token[0..indexOfQuote-1]
+ token = token[indexOfQuote..-1]
+ end
+ if token[0,2] == '""'
+ laststring += token[2..-1]
+ next
+ elsif token[0,1] == '"'
+ if laststring[-1,1] == '\\'
+ laststring[-1,1] = '"'
+ laststring += token[1..-1]
+ next
+ end
+ instring = false
+ yield laststring + '"'
+ token = token[1..-1]
+ else
+ laststring += token
+ next
+ end
+ end
+ token.strip!
+ next if token.empty?
+ if incomment
+ incomment = false if token[0..1] == "*/"
+ next
+ else
+ if token[0..1] == "/*"
+ incomment = true
+ next
+ end
+ break if token == "//"
+ end
+ doublequote = token.index '""'
+ if doublequote != nil
+ if doublequote > 0
+ yield token[0,doublequote]
+ end
+ yield '""'
+ if token.length > doublequote+2
+ token = token[doublequote+2..-1]
+ else
+ next
+ end
+ end
+ quote = token.index '"'
+ if quote != nil
+ laststring = token[quote..-1]
+ instring = true
+ if quote > 0
+ token = token[0,quote]
+ else
+ next
+ end
+ end
+ semicolon = token.index ';'
+ if not semicolon
+ tokenize2(token) { |i| yield i }
+ elsif semicolon > 0
+ tokenize2(token[0..semicolon-1]) { |i| yield i }
+ yield ';'
+ if token.length > semicolon + 1
+ tokenize2(token[semicolon+1..-1]) { |i| yield i }
+ end
+ elsif (semicolon == 0 and token.length > 1)
+ yield ';'
+ tokenize2(token[1..-1]) { |i| yield i }
+ else
+ yield token # a single ;
+ end
+ end
+ end
+ end
+
+ def tokenize2(token)
+ if token.length > 1
+ #STDERR.puts "long token: #{token}"
+ while token[0,1] == '(' or token[0,1] == ')' or token[0,1] == "'" or token[0,1] == '&'
+ yield token[0,1]
+ token = token[1..-1]
+ #STDERR.puts "less long token: #{token}"
+ end
+ return if token.empty?
+ if token.length == 1
+ yield token
+ return
+ elsif token[-1,1] == ',' or token[-1,1] == "'"
+ yield token[0..-2]
+ yield token[-1,1]
+ return
+ end
+ end
+ yield token
+ end
+end
+
+p = Parser.new ARGV[0]
+p.signatures.each do |signature,method|
+ if method.class == SignalDef
+ puts "addSignal(\"#{signature}\");"
+ else
+ if method.optional
+ puts "addMethod(\"#{method.returnType}\", \"#{signature}\", true);"
+ else
+ puts "addMethod(\"#{method.returnType}\", \"#{signature}\");"
+ end
+ end
+end
diff --git a/src/3rdparty/phonon/phonon/factory.cpp b/src/3rdparty/phonon/phonon/factory.cpp
new file mode 100644
index 0000000000..43c45ee8b2
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/factory.cpp
@@ -0,0 +1,457 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004-2007 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "factory_p.h"
+
+#include "backendinterface.h"
+#include "medianode_p.h"
+#include "mediaobject.h"
+#include "audiooutput.h"
+#include "globalstatic_p.h"
+#include "objectdescription.h"
+#include "platformplugin.h"
+#include "phononnamespace_p.h"
+
+#include <QtCore/QCoreApplication>
+#include <QtCore/QDir>
+#include <QtCore/QList>
+#include <QtCore/QPluginLoader>
+#include <QtCore/QPointer>
+#ifndef QT_NO_DBUS
+#include <QtDBus/QtDBus>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+
+class PlatformPlugin;
+class FactoryPrivate : public Phonon::Factory::Sender
+{
+ friend QObject *Factory::backend(bool);
+ Q_OBJECT
+ public:
+ FactoryPrivate();
+ ~FactoryPrivate();
+ bool createBackend();
+#ifndef QT_NO_PHONON_PLATFORMPLUGIN
+ PlatformPlugin *platformPlugin();
+
+ PlatformPlugin *m_platformPlugin;
+ bool m_noPlatformPlugin;
+#endif //QT_NO_PHONON_PLATFORMPLUGIN
+ QPointer<QObject> m_backendObject;
+
+ QList<QObject *> objects;
+ QList<MediaNodePrivate *> mediaNodePrivateList;
+
+ private Q_SLOTS:
+ /**
+ * This is called via DBUS when the user changes the Phonon Backend.
+ */
+#ifndef QT_NO_DBUS
+ void phononBackendChanged();
+#endif //QT_NO_DBUS
+
+ /**
+ * unregisters the backend object
+ */
+ void objectDestroyed(QObject *);
+
+ void objectDescriptionChanged(ObjectDescriptionType);
+};
+
+PHONON_GLOBAL_STATIC(Phonon::FactoryPrivate, globalFactory)
+
+static inline void ensureLibraryPathSet()
+{
+#ifdef PHONON_LIBRARY_PATH
+ static bool done = false;
+ if (!done) {
+ done = true;
+ QCoreApplication::addLibraryPath(QLatin1String(PHONON_LIBRARY_PATH));
+ }
+#endif // PHONON_LIBRARY_PATH
+}
+
+void Factory::setBackend(QObject *b)
+{
+ Q_ASSERT(globalFactory->m_backendObject == 0);
+ globalFactory->m_backendObject = b;
+}
+
+/*void Factory::createBackend(const QString &library, const QString &version)
+{
+ Q_ASSERT(globalFactory->m_backendObject == 0);
+ PlatformPlugin *f = globalFactory->platformPlugin();
+ if (f) {
+ globalFactory->m_backendObject = f->createBackend(library, version);
+ }
+}*/
+
+bool FactoryPrivate::createBackend()
+{
+ Q_ASSERT(m_backendObject == 0);
+#ifndef QT_NO_PHONON_PLATFORMPLUGIN
+ PlatformPlugin *f = globalFactory->platformPlugin();
+ if (f) {
+ m_backendObject = f->createBackend();
+ }
+#endif //QT_NO_PHONON_PLATFORMPLUGIN
+ if (!m_backendObject) {
+ ensureLibraryPathSet();
+
+ // could not load a backend through the platform plugin. Falling back to the default
+ // (finding the first loadable backend).
+ const QLatin1String suffix("/phonon_backend/");
+ foreach (QString libPath, QCoreApplication::libraryPaths()) {
+ libPath += suffix;
+ const QDir dir(libPath);
+ if (!dir.exists()) {
+ pDebug() << Q_FUNC_INFO << dir.absolutePath() << "does not exist";
+ continue;
+ }
+ foreach (const QString &pluginName, dir.entryList(QDir::Files)) {
+ QPluginLoader pluginLoader(libPath + pluginName);
+ if (!pluginLoader.load()) {
+ pDebug() << Q_FUNC_INFO << " load failed:"
+ << pluginLoader.errorString();
+ continue;
+ }
+ pDebug() << pluginLoader.instance();
+ m_backendObject = pluginLoader.instance();
+ if (m_backendObject) {
+ break;
+ }
+
+ // no backend found, don't leave an unused plugin in memory
+ pluginLoader.unload();
+ }
+
+ if (m_backendObject) {
+ break;
+ }
+ }
+ if (!m_backendObject) {
+ pWarning() << Q_FUNC_INFO << "phonon backend plugin could not be loaded";
+ return false;
+ }
+ }
+
+ connect(m_backendObject, SIGNAL(objectDescriptionChanged(ObjectDescriptionType)),
+ SLOT(objectDescriptionChanged(ObjectDescriptionType)));
+
+ return true;
+}
+
+FactoryPrivate::FactoryPrivate()
+#ifndef QT_NO_PHONON_PLATFORMPLUGIN
+ : m_platformPlugin(0),
+ m_noPlatformPlugin(false)
+#endif //QT_NO_PHONON_PLATFORMPLUGIN
+ , m_backendObject(0)
+{
+ // Add the post routine to make sure that all other global statics (especially the ones from Qt)
+ // are still available. If the FactoryPrivate dtor is called too late many bad things can happen
+ // as the whole backend might still be alive.
+ qAddPostRoutine(globalFactory.destroy);
+#ifndef QT_NO_DBUS
+ QDBusConnection::sessionBus().connect(QString(), QString(), QLatin1String("org.kde.Phonon.Factory"),
+ QLatin1String("phononBackendChanged"), this, SLOT(phononBackendChanged()));
+#endif
+}
+
+FactoryPrivate::~FactoryPrivate()
+{
+ foreach (QObject *o, objects) {
+ MediaObject *m = qobject_cast<MediaObject *>(o);
+ if (m) {
+ m->stop();
+ }
+ }
+ foreach (MediaNodePrivate *bp, mediaNodePrivateList) {
+ bp->deleteBackendObject();
+ }
+ if (objects.size() > 0) {
+ pError() << "The backend objects are not deleted as was requested.";
+ qDeleteAll(objects);
+ }
+ delete m_backendObject;
+#ifndef QT_NO_PHONON_PLATFORMPLUGIN
+ delete m_platformPlugin;
+#endif //QT_NO_PHONON_PLATFORMPLUGIN
+}
+
+void FactoryPrivate::objectDescriptionChanged(ObjectDescriptionType type)
+{
+#ifdef PHONON_METHODTEST
+ Q_UNUSED(type);
+#else
+ pDebug() << Q_FUNC_INFO << type;
+ switch (type) {
+ case AudioOutputDeviceType:
+ emit availableAudioOutputDevicesChanged();
+ break;
+ case AudioCaptureDeviceType:
+ emit availableAudioCaptureDevicesChanged();
+ break;
+ default:
+ break;
+ }
+ //emit capabilitiesChanged();
+#endif // PHONON_METHODTEST
+}
+
+Factory::Sender *Factory::sender()
+{
+ return globalFactory;
+}
+
+bool Factory::isMimeTypeAvailable(const QString &mimeType)
+{
+#ifndef QT_NO_PHONON_PLATFORMPLUGIN
+ PlatformPlugin *f = globalFactory->platformPlugin();
+ if (f) {
+ return f->isMimeTypeAvailable(mimeType);
+ }
+#else
+ Q_UNUSED(mimeType);
+#endif //QT_NO_PHONON_PLATFORMPLUGIN
+ return true; // the MIME type might be supported, let BackendCapabilities find out
+}
+
+void Factory::registerFrontendObject(MediaNodePrivate *bp)
+{
+ globalFactory->mediaNodePrivateList.prepend(bp); // inserted last => deleted first
+}
+
+void Factory::deregisterFrontendObject(MediaNodePrivate *bp)
+{
+ // The Factory can already be cleaned up while there are other frontend objects still alive.
+ // When those are deleted they'll call deregisterFrontendObject through ~BasePrivate
+ if (!globalFactory.isDestroyed()) {
+ globalFactory->mediaNodePrivateList.removeAll(bp);
+ }
+}
+
+#ifndef QT_NO_DBUS
+void FactoryPrivate::phononBackendChanged()
+{
+ if (m_backendObject) {
+ foreach (MediaNodePrivate *bp, mediaNodePrivateList) {
+ bp->deleteBackendObject();
+ }
+ if (objects.size() > 0) {
+ pDebug() << "WARNING: we were asked to change the backend but the application did\n"
+ "not free all references to objects created by the factory. Therefore we can not\n"
+ "change the backend without crashing. Now we have to wait for a restart to make\n"
+ "backendswitching possible.";
+ // in case there were objects deleted give 'em a chance to recreate
+ // them now
+ foreach (MediaNodePrivate *bp, mediaNodePrivateList) {
+ bp->createBackendObject();
+ }
+ return;
+ }
+ delete m_backendObject;
+ m_backendObject = 0;
+ }
+ createBackend();
+ foreach (MediaNodePrivate *bp, mediaNodePrivateList) {
+ bp->createBackendObject();
+ }
+ emit backendChanged();
+}
+#endif //QT_NO_DBUS
+
+//X void Factory::freeSoundcardDevices()
+//X {
+//X if (globalFactory->backend) {
+//X globalFactory->backend->freeSoundcardDevices();
+//X }
+//X }
+
+void FactoryPrivate::objectDestroyed(QObject * obj)
+{
+ //pDebug() << Q_FUNC_INFO << obj;
+ objects.removeAll(obj);
+}
+
+#define FACTORY_IMPL(classname) \
+QObject *Factory::create ## classname(QObject *parent) \
+{ \
+ if (backend()) { \
+ return registerQObject(qobject_cast<BackendInterface *>(backend())->createObject(BackendInterface::classname##Class, parent)); \
+ } \
+ return 0; \
+}
+#define FACTORY_IMPL_1ARG(classname) \
+QObject *Factory::create ## classname(int arg1, QObject *parent) \
+{ \
+ if (backend()) { \
+ return registerQObject(qobject_cast<BackendInterface *>(backend())->createObject(BackendInterface::classname##Class, parent, QList<QVariant>() << arg1)); \
+ } \
+ return 0; \
+}
+
+FACTORY_IMPL(MediaObject)
+#ifndef QT_NO_PHONON_EFFECT
+FACTORY_IMPL_1ARG(Effect)
+#endif //QT_NO_PHONON_EFFECT
+#ifndef QT_NO_PHONON_VOLUMEFADEREFFECT
+FACTORY_IMPL(VolumeFaderEffect)
+#endif //QT_NO_PHONON_VOLUMEFADEREFFECT
+FACTORY_IMPL(AudioOutput)
+#ifndef QT_NO_PHONON_VIDEO
+FACTORY_IMPL(VideoWidget)
+#endif //QT_NO_PHONON_VIDEO
+
+#undef FACTORY_IMPL
+
+#ifndef QT_NO_PHONON_PLATFORMPLUGIN
+PlatformPlugin *FactoryPrivate::platformPlugin()
+{
+ if (m_platformPlugin) {
+ return m_platformPlugin;
+ }
+ if (m_noPlatformPlugin) {
+ return 0;
+ }
+#ifndef QT_NO_DBUS
+ if (!QCoreApplication::instance() || QCoreApplication::applicationName().isEmpty()) {
+ pWarning() << "Phonon needs QCoreApplication::applicationName to be set to export audio output names through the DBUS interface";
+ }
+#endif
+ Q_ASSERT(QCoreApplication::instance());
+ const QByteArray platform_plugin_env = qgetenv("PHONON_PLATFORMPLUGIN");
+ if (!platform_plugin_env.isEmpty()) {
+ QPluginLoader pluginLoader(QString::fromLocal8Bit(platform_plugin_env.constData()));
+ if (pluginLoader.load()) {
+ m_platformPlugin = qobject_cast<PlatformPlugin *>(pluginLoader.instance());
+ if (m_platformPlugin) {
+ return m_platformPlugin;
+ }
+ }
+ }
+ const QString suffix(QLatin1String("/phonon_platform/"));
+ ensureLibraryPathSet();
+ QDir dir;
+ dir.setNameFilters(
+ !qgetenv("KDE_FULL_SESSION").isEmpty() ? QStringList(QLatin1String("kde.*")) :
+ (!qgetenv("GNOME_DESKTOP_SESSION_ID").isEmpty() ? QStringList(QLatin1String("gnome.*")) :
+ QStringList())
+ );
+ dir.setFilter(QDir::Files);
+ forever {
+ foreach (QString libPath, QCoreApplication::libraryPaths()) {
+ libPath += suffix;
+ dir.setPath(libPath);
+ if (!dir.exists()) {
+ continue;
+ }
+ foreach (const QString &pluginName, dir.entryList()) {
+ QPluginLoader pluginLoader(libPath + pluginName);
+ if (!pluginLoader.load()) {
+ pDebug() << Q_FUNC_INFO << " platform plugin load failed:"
+ << pluginLoader.errorString();
+ continue;
+ }
+ pDebug() << pluginLoader.instance();
+ QObject *qobj = pluginLoader.instance();
+ m_platformPlugin = qobject_cast<PlatformPlugin *>(qobj);
+ pDebug() << m_platformPlugin;
+ if (m_platformPlugin) {
+ connect(qobj, SIGNAL(objectDescriptionChanged(ObjectDescriptionType)),
+ SLOT(objectDescriptionChanged(ObjectDescriptionType)));
+ return m_platformPlugin;
+ } else {
+ delete qobj;
+ pDebug() << Q_FUNC_INFO << dir.absolutePath() << "exists but the platform plugin was not loadable:" << pluginLoader.errorString();
+ pluginLoader.unload();
+ }
+ }
+ }
+ if (dir.nameFilters().isEmpty()) {
+ break;
+ }
+ dir.setNameFilters(QStringList());
+ }
+ pDebug() << Q_FUNC_INFO << "platform plugin could not be loaded";
+ m_noPlatformPlugin = true;
+ return 0;
+}
+
+PlatformPlugin *Factory::platformPlugin()
+{
+ return globalFactory->platformPlugin();
+}
+#endif // QT_NO_PHONON_PLATFORMPLUGIN
+
+QObject *Factory::backend(bool createWhenNull)
+{
+ if (globalFactory.isDestroyed()) {
+ return 0;
+ }
+ if (createWhenNull && globalFactory->m_backendObject == 0) {
+ globalFactory->createBackend();
+ // XXX: might create "reentrancy" problems:
+ // a method calls this method and is called again because the
+ // backendChanged signal is emitted
+ emit globalFactory->backendChanged();
+ }
+ return globalFactory->m_backendObject;
+}
+
+#define GET_STRING_PROPERTY(name) \
+QString Factory::name() \
+{ \
+ if (globalFactory->m_backendObject) { \
+ return globalFactory->m_backendObject->property(#name).toString(); \
+ } \
+ return QString(); \
+} \
+
+GET_STRING_PROPERTY(identifier)
+GET_STRING_PROPERTY(backendName)
+GET_STRING_PROPERTY(backendComment)
+GET_STRING_PROPERTY(backendVersion)
+GET_STRING_PROPERTY(backendIcon)
+GET_STRING_PROPERTY(backendWebsite)
+
+QObject *Factory::registerQObject(QObject *o)
+{
+ if (o) {
+ QObject::connect(o, SIGNAL(destroyed(QObject *)), globalFactory, SLOT(objectDestroyed(QObject *)), Qt::DirectConnection);
+ globalFactory->objects.append(o);
+ }
+ return o;
+}
+
+} //namespace Phonon
+
+QT_END_NAMESPACE
+
+#include "factory.moc"
+#include "moc_factory_p.cpp"
+
+// vim: sw=4 ts=4
diff --git a/src/3rdparty/phonon/phonon/factory_p.h b/src/3rdparty/phonon/phonon/factory_p.h
new file mode 100644
index 0000000000..de059f88eb
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/factory_p.h
@@ -0,0 +1,196 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004-2007 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef PHONON_FACTORY_P_H
+#define PHONON_FACTORY_P_H
+
+#include "phonon_export.h"
+
+#include <QtCore/QObject>
+#include <QtCore/QStringList>
+
+QT_BEGIN_HEADER
+QT_BEGIN_NAMESPACE
+
+class QUrl;
+class QIcon;
+
+namespace Phonon
+{
+ class PlatformPlugin;
+ class MediaNodePrivate;
+ class AbstractMediaStream;
+
+/**
+ * \internal
+ * \brief Factory to access the preferred Backend.
+ *
+ * This class is used internally to get the backend's implementation.
+ * It keeps track of the objects that were created. When a
+ * request for a backend change comes, it asks all frontend objects to delete
+ * their backend objects and then checks whether they were all deleted. Only
+ * then the old backend is unloaded and the new backend is loaded.
+ *
+ * \author Matthias Kretz <kretz@kde.org>
+ */
+namespace Factory
+{
+ /**
+ * Emits signals for Phonon::Factory.
+ */
+ class Sender : public QObject
+ {
+ Q_OBJECT
+ Q_SIGNALS:
+ /**
+ * Emitted after the backend has successfully been changed.
+ */
+ void backendChanged();
+
+ /**
+ * \copydoc BackendCapabilities::Notifier::availableAudioOutputDevicesChanged
+ */
+ void availableAudioOutputDevicesChanged();
+
+ /**
+ * \copydoc BackendCapabilities::Notifier::availableAudioCaptureDevicesChanged
+ */
+ void availableAudioCaptureDevicesChanged();
+ };
+
+ /**
+ * Returns a pointer to the object emitting the signals.
+ *
+ * \see Sender::backendChanged()
+ */
+ PHONON_EXPORT Sender *sender();
+
+ /**
+ * Create a new backend object for a MediaObject.
+ *
+ * \return a pointer to the MediaObject the backend provides.
+ */
+ QObject *createMediaObject(QObject *parent = 0);
+ /**
+ * Create a new backend object for a Effect.
+ *
+ * \return a pointer to the Effect the backend provides.
+ */
+#ifndef QT_NO_PHONON_EFFECT
+ QObject *createEffect(int effectId, QObject *parent = 0);
+#endif //QT_NO_PHONON_EFFECT
+ /**
+ * Create a new backend object for a VolumeFaderEffect.
+ *
+ * \return a pointer to the VolumeFaderEffect the backend provides.
+ */
+#ifndef QT_NO_PHONON_VOLUMEFADEREFFECT
+ QObject *createVolumeFaderEffect(QObject *parent = 0);
+#endif //QT_NO_PHONON_VOLUMEFADEREFFECT
+ /**
+ * Create a new backend object for a AudioOutput.
+ *
+ * \return a pointer to the AudioOutput the backend provides.
+ */
+ QObject *createAudioOutput(QObject *parent = 0);
+ /**
+ * Create a new backend object for a VideoWidget.
+ *
+ * \return a pointer to the VideoWidget the backend provides.
+ */
+#ifndef QT_NO_PHONON_VIDEO
+ QObject *createVideoWidget(QObject *parent = 0);
+#endif //QT_NO_PHONON_VIDEO
+
+ /**
+ * \return a pointer to the backend interface.
+ */
+ PHONON_EXPORT QObject *backend(bool createWhenNull = true);
+
+ /**
+ * Unique identifier for the Backend. Can be used in configuration files
+ * for example.
+ */
+ QString identifier();
+
+ /**
+ * Get the name of the Backend. It's the name from the .desktop file.
+ */
+ PHONON_EXPORT QString backendName();
+
+ /**
+ * Get the comment of the Backend. It's the comment from the .desktop file.
+ */
+ QString backendComment();
+
+ /**
+ * Get the version of the Backend. It's the version from the .desktop file.
+ *
+ * The version is especially interesting if there are several versions
+ * available for binary incompatible versions of the backend's media
+ * framework.
+ */
+ QString backendVersion();
+
+ /**
+ * Get the icon (name) of the Backend. It's the icon from the .desktop file.
+ */
+ QString backendIcon();
+
+ /**
+ * Get the website of the Backend. It's the website from the .desktop file.
+ */
+ QString backendWebsite();
+
+ /**
+ * registers the backend object
+ */
+ PHONON_EXPORT QObject *registerQObject(QObject *o);
+
+ bool isMimeTypeAvailable(const QString &mimeType);
+
+ PHONON_EXPORT void registerFrontendObject(MediaNodePrivate *);
+ PHONON_EXPORT void deregisterFrontendObject(MediaNodePrivate *);
+
+ PHONON_EXPORT void setBackend(QObject *);
+ //PHONON_EXPORT void createBackend(const QString &library, const QString &version = QString());
+
+ PHONON_EXPORT PlatformPlugin *platformPlugin();
+
+//X It is probably better if we can get away with internal handling of
+//X freeing the soundcard device when it's not needed anymore and
+//X providing an IPC method to stop all MediaObjects -> free all
+//X devices
+//X /**
+//X * \internal
+//X * This is called when the application needs to free the soundcard
+//X * device(s).
+//X */
+//X void freeSoundcardDevices();
+} // namespace Factory
+} // namespace Phonon
+
+QT_END_NAMESPACE
+QT_END_HEADER
+
+#endif // PHONON_FACTORY_P_H
+// vim: sw=4 ts=4
diff --git a/src/3rdparty/phonon/phonon/frontendinterface_p.h b/src/3rdparty/phonon/phonon/frontendinterface_p.h
new file mode 100644
index 0000000000..b6c76ceffa
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/frontendinterface_p.h
@@ -0,0 +1,68 @@
+/* This file is part of the KDE project
+ Copyright (C) 2007 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef PHONON_FRONTENDINTERFACEPRIVATE_H
+#define PHONON_FRONTENDINTERFACEPRIVATE_H
+
+#include "addoninterface.h"
+#include "mediaobject_p.h"
+#include "phononnamespace_p.h"
+#include <QtCore/QPointer>
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_PHONON_MEDIACONTROLLER
+
+namespace Phonon
+{
+class FrontendInterfacePrivate
+{
+ public:
+ FrontendInterfacePrivate(MediaObject *mp) : media(mp) {
+ Q_ASSERT(media);
+ MediaObjectPrivate *d = media->k_func();
+ d->interfaceList << this;
+ }
+ virtual ~FrontendInterfacePrivate() {
+ if (media) {
+ MediaObjectPrivate *d = media->k_func();
+ d->interfaceList << this;
+ }
+ }
+ virtual void backendObjectChanged(QObject *iface) = 0;
+ void _backendObjectChanged() {
+ pDebug() << Q_FUNC_INFO;
+ QObject *x = media->k_ptr->backendObject();
+ if (x) {
+ backendObjectChanged(x);
+ }
+ }
+ AddonInterface *iface() { return qobject_cast<AddonInterface *>(media->k_ptr->backendObject()); }
+ QPointer<MediaObject> media;
+};
+} // namespace Phonon
+
+#endif //QT_NO_PHONON_MEDIACONTROLLER
+
+QT_END_NAMESPACE
+
+#endif // PHONON_FRONTENDINTERFACEPRIVATE_H
diff --git a/src/3rdparty/phonon/phonon/globalconfig.cpp b/src/3rdparty/phonon/phonon/globalconfig.cpp
new file mode 100644
index 0000000000..d13e491de4
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/globalconfig.cpp
@@ -0,0 +1,243 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006-2008 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "globalconfig_p.h"
+
+#include "factory_p.h"
+#include "objectdescription.h"
+#include "phonondefs_p.h"
+#include "platformplugin.h"
+#include "backendinterface.h"
+#include "qsettingsgroup_p.h"
+#include "phononnamespace_p.h"
+
+#include <QtCore/QList>
+#include <QtCore/QVariant>
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+
+GlobalConfig::GlobalConfig() : m_config(QLatin1String("kde.org"), QLatin1String("libphonon"))
+{
+}
+
+GlobalConfig::~GlobalConfig()
+{
+}
+
+enum WhatToFilter {
+ FilterAdvancedDevices = 1,
+ FilterHardwareDevices = 2,
+ FilterUnavailableDevices = 4
+};
+
+static void filter(ObjectDescriptionType type, BackendInterface *backendIface, QList<int> *list, int whatToFilter)
+{
+ QMutableListIterator<int> it(*list);
+ while (it.hasNext()) {
+ const QHash<QByteArray, QVariant> properties = backendIface->objectDescriptionProperties(type, it.next());
+ QVariant var;
+ if (whatToFilter & FilterAdvancedDevices) {
+ var = properties.value("isAdvanced");
+ if (var.isValid() && var.toBool()) {
+ it.remove();
+ continue;
+ }
+ }
+ if (whatToFilter & FilterHardwareDevices) {
+ var = properties.value("isHardwareDevice");
+ if (var.isValid() && var.toBool()) {
+ it.remove();
+ continue;
+ }
+ }
+ if (whatToFilter & FilterUnavailableDevices) {
+ var = properties.value("available");
+ if (var.isValid() && !var.toBool()) {
+ it.remove();
+ continue;
+ }
+ }
+ }
+}
+
+static QList<int> listSortedByConfig(const QSettingsGroup &backendConfig, Phonon::Category category, QList<int> &defaultList)
+{
+ if (defaultList.size() <= 1) {
+ // nothing to sort
+ return defaultList;
+ } else {
+ // make entries unique
+ QSet<int> seen;
+ QMutableListIterator<int> it(defaultList);
+ while (it.hasNext()) {
+ if (seen.contains(it.next())) {
+ it.remove();
+ } else {
+ seen.insert(it.value());
+ }
+ }
+ }
+
+ QString categoryKey = QLatin1String("Category_") + QString::number(static_cast<int>(category));
+ if (!backendConfig.hasKey(categoryKey)) {
+ // no list in config for the given category
+ categoryKey = QLatin1String("Category_") + QString::number(static_cast<int>(Phonon::NoCategory));
+ if (!backendConfig.hasKey(categoryKey)) {
+ // no list in config for NoCategory
+ return defaultList;
+ }
+ }
+
+ //Now the list from m_config
+ QList<int> deviceList = backendConfig.value(categoryKey, QList<int>());
+
+ //if there are devices in m_config that the backend doesn't report, remove them from the list
+ QMutableListIterator<int> i(deviceList);
+ while (i.hasNext()) {
+ if (0 == defaultList.removeAll(i.next())) {
+ i.remove();
+ }
+ }
+
+ //if the backend reports more devices that are not in m_config append them to the list
+ deviceList += defaultList;
+
+ return deviceList;
+}
+
+QList<int> GlobalConfig::audioOutputDeviceListFor(Phonon::Category category, int override) const
+{
+ //The devices need to be stored independently for every backend
+ const QSettingsGroup backendConfig(&m_config, QLatin1String("AudioOutputDevice")); // + Factory::identifier());
+ const QSettingsGroup generalGroup(&m_config, QLatin1String("General"));
+ const bool hideAdvancedDevices = ((override & AdvancedDevicesFromSettings)
+ ? generalGroup.value(QLatin1String("HideAdvancedDevices"), true)
+ : static_cast<bool>(override & HideAdvancedDevices));
+
+ QList<int> defaultList;
+#ifndef QT_NO_PHONON_PLATFORMPLUGIN
+ if (PlatformPlugin *platformPlugin = Factory::platformPlugin()) {
+ // the platform plugin lists the audio devices for the platform
+ // this list already is in default order (as defined by the platform plugin)
+ defaultList = platformPlugin->objectDescriptionIndexes(Phonon::AudioOutputDeviceType);
+ if (hideAdvancedDevices) {
+ QMutableListIterator<int> it(defaultList);
+ while (it.hasNext()) {
+ AudioOutputDevice objDesc = AudioOutputDevice::fromIndex(it.next());
+ const QVariant var = objDesc.property("isAdvanced");
+ if (var.isValid() && var.toBool()) {
+ it.remove();
+ }
+ }
+ }
+ }
+#endif //QT_NO_PHONON_PLATFORMPLUGIN
+
+ // lookup the available devices directly from the backend (mostly for virtual devices)
+ if (BackendInterface *backendIface = qobject_cast<BackendInterface *>(Factory::backend())) {
+ // this list already is in default order (as defined by the backend)
+ QList<int> list = backendIface->objectDescriptionIndexes(Phonon::AudioOutputDeviceType);
+ if (hideAdvancedDevices || !defaultList.isEmpty() || (override & HideUnavailableDevices)) {
+ filter(AudioOutputDeviceType, backendIface, &list,
+ (hideAdvancedDevices ? FilterAdvancedDevices : 0)
+ // the platform plugin already provided the hardware devices
+ | (defaultList.isEmpty() ? 0 : FilterHardwareDevices)
+ | ((override & HideUnavailableDevices) ? FilterUnavailableDevices : 0)
+ );
+ }
+ defaultList += list;
+ }
+
+ return listSortedByConfig(backendConfig, category, defaultList);
+}
+
+int GlobalConfig::audioOutputDeviceFor(Phonon::Category category, int override) const
+{
+ QList<int> ret = audioOutputDeviceListFor(category, override);
+ if (ret.isEmpty())
+ return -1;
+ return ret.first();
+}
+
+#ifndef QT_NO_PHONON_AUDIOCAPTURE
+QList<int> GlobalConfig::audioCaptureDeviceListFor(Phonon::Category category, int override) const
+{
+ //The devices need to be stored independently for every backend
+ const QSettingsGroup backendConfig(&m_config, QLatin1String("AudioCaptureDevice")); // + Factory::identifier());
+ const QSettingsGroup generalGroup(&m_config, QLatin1String("General"));
+ const bool hideAdvancedDevices = ((override & AdvancedDevicesFromSettings)
+ ? generalGroup.value(QLatin1String("HideAdvancedDevices"), true)
+ : static_cast<bool>(override & HideAdvancedDevices));
+
+ QList<int> defaultList;
+#ifndef QT_NO_PHONON_PLATFORMPLUGIN
+ if (PlatformPlugin *platformPlugin = Factory::platformPlugin()) {
+ // the platform plugin lists the audio devices for the platform
+ // this list already is in default order (as defined by the platform plugin)
+ defaultList = platformPlugin->objectDescriptionIndexes(Phonon::AudioCaptureDeviceType);
+ if (hideAdvancedDevices) {
+ QMutableListIterator<int> it(defaultList);
+ while (it.hasNext()) {
+ AudioCaptureDevice objDesc = AudioCaptureDevice::fromIndex(it.next());
+ const QVariant var = objDesc.property("isAdvanced");
+ if (var.isValid() && var.toBool()) {
+ it.remove();
+ }
+ }
+ }
+ }
+#endif //QT_NO_PHONON_PLATFORMPLUGIN
+
+ // lookup the available devices directly from the backend (mostly for virtual devices)
+ if (BackendInterface *backendIface = qobject_cast<BackendInterface *>(Factory::backend())) {
+ // this list already is in default order (as defined by the backend)
+ QList<int> list = backendIface->objectDescriptionIndexes(Phonon::AudioCaptureDeviceType);
+ if (hideAdvancedDevices || !defaultList.isEmpty() || (override & HideUnavailableDevices)) {
+ filter(AudioCaptureDeviceType, backendIface, &list,
+ (hideAdvancedDevices ? FilterAdvancedDevices : 0)
+ // the platform plugin already provided the hardware devices
+ | (defaultList.isEmpty() ? 0 : FilterHardwareDevices)
+ | ((override & HideUnavailableDevices) ? FilterUnavailableDevices : 0)
+ );
+ }
+ defaultList += list;
+ }
+
+ return listSortedByConfig(backendConfig, category, defaultList);
+}
+
+int GlobalConfig::audioCaptureDeviceFor(Phonon::Category category, int override) const
+{
+ QList<int> ret = audioCaptureDeviceListFor(category, override);
+ if (ret.isEmpty())
+ return -1;
+ return ret.first();
+}
+#endif //QT_NO_PHONON_AUDIOCAPTURE
+
+
+} // namespace Phonon
+
+QT_END_NAMESPACE
diff --git a/src/3rdparty/phonon/phonon/globalconfig_p.h b/src/3rdparty/phonon/phonon/globalconfig_p.h
new file mode 100644
index 0000000000..023858f87a
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/globalconfig_p.h
@@ -0,0 +1,65 @@
+/* This file is part of the KDE project
+Copyright (C) 2006-2008 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef PHONON_GLOBALCONFIG_P_H
+#define PHONON_GLOBALCONFIG_P_H
+
+#include <QtCore/QSettings>
+
+#include "phonon_export.h"
+#include "phononnamespace.h"
+
+QT_BEGIN_HEADER
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+ class PHONON_EXPORT GlobalConfig
+ {
+ public:
+ GlobalConfig();
+ virtual ~GlobalConfig();
+
+ enum DevicesToHideFlag {
+ ShowUnavailableDevices = 0,
+ ShowAdvancedDevices = 0,
+ HideAdvancedDevices = 1,
+ AdvancedDevicesFromSettings = 2,
+ HideUnavailableDevices = 4
+ };
+ QList<int> audioOutputDeviceListFor(Phonon::Category category, int override = AdvancedDevicesFromSettings) const;
+ int audioOutputDeviceFor(Phonon::Category category, int override = AdvancedDevicesFromSettings) const;
+
+#ifndef QT_NO_PHONON_AUDIOCAPTURE
+ QList<int> audioCaptureDeviceListFor(Phonon::Category category, int override = AdvancedDevicesFromSettings) const;
+ int audioCaptureDeviceFor(Phonon::Category category, int override = AdvancedDevicesFromSettings) const;
+#endif //QT_NO_PHONON_AUDIOCAPTURE
+
+ protected:
+ QSettings m_config;
+ };
+} // namespace Phonon
+
+QT_END_NAMESPACE
+QT_END_HEADER
+
+#endif // PHONON_GLOBALCONFIG_P_H
diff --git a/src/3rdparty/phonon/phonon/globalstatic_p.h b/src/3rdparty/phonon/phonon/globalstatic_p.h
new file mode 100644
index 0000000000..04f83955bc
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/globalstatic_p.h
@@ -0,0 +1,293 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2007 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef PHONON_GLOBALSTATIC_P_H
+#define PHONON_GLOBALSTATIC_P_H
+
+#include <QtCore/QAtomicPointer>
+
+//
+// WARNING!!
+// This code uses undocumented Qt API
+// Do not copy it to your application! Use only the functions that are here!
+// Otherwise, it could break when a new version of Qt ships.
+//
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+
+/**
+ * @internal
+ */
+typedef void (*CleanUpFunction)();
+
+/**
+ * @internal
+ *
+ * Helper class for PHONON_GLOBAL_STATIC to clean up the object on library unload or application
+ * shutdown.
+ */
+class CleanUpGlobalStatic
+{
+ public:
+ CleanUpFunction func;
+
+ inline ~CleanUpGlobalStatic() { func(); }
+};
+
+} // namespace Phonon
+
+#ifdef Q_CC_MSVC
+/**
+ * @internal
+ *
+ * MSVC seems to give anonymous structs the same name which fails at link time. So instead we name
+ * the struct and hope that by adding the line number to the name it's unique enough to never clash.
+ */
+# define PHONON_GLOBAL_STATIC_STRUCT_NAME(NAME) _k_##NAME##__LINE__
+#else
+/**
+ * @internal
+ *
+ * Make the struct of the PHONON_GLOBAL_STATIC anonymous.
+ */
+# define PHONON_GLOBAL_STATIC_STRUCT_NAME(NAME)
+#endif
+
+/**
+ * This macro makes it easy to use non-POD types as global statics.
+ * The object is created on first use and creation is threadsafe.
+ *
+ * The object is destructed on library unload or application exit.
+ * Be careful with calling other objects in the destructor of the class
+ * as you have to be sure that they (or objects they depend on) are not already destructed.
+ *
+ * @param TYPE The type of the global static object. Do not add a *.
+ * @param NAME The name of the function to get a pointer to the global static object.
+ *
+ * If you have code that might be called after the global object has been destroyed you can check
+ * for that using the isDestroyed() function.
+ *
+ * If needed (If the destructor of the global object calls other functions that depend on other
+ * global statics (e.g. KConfig::sync) your destructor has to be called before those global statics
+ * are destroyed. A Qt post routine does that.) you can also install a post routine (@ref qAddPostRoutine) to clean up the object
+ * using the destroy() method. If you registered a post routine and the object is destroyed because
+ * of a lib unload you have to call qRemovePostRoutine!
+ *
+ * Example:
+ * @code
+ * class A {
+ * public:
+ * ~A();
+ * ...
+ * };
+ *
+ * PHONON_GLOBAL_STATIC(A, globalA)
+ * // The above creates a new globally static variable named 'globalA' which you
+ * // can use as a pointer to an instance of A.
+ *
+ * void doSomething()
+ * {
+ * // The first time you access globalA a new instance of A will be created automatically.
+ * A *a = globalA;
+ * ...
+ * }
+ *
+ * void doSomethingElse()
+ * {
+ * if (globalA.isDestroyed()) {
+ * return;
+ * }
+ * A *a = globalA;
+ * ...
+ * }
+ *
+ * void installPostRoutine()
+ * {
+ * // A post routine can be used to delete the object when QCoreApplication destructs,
+ * // not adding such a post routine will delete the object normally at program unload
+ * qAddPostRoutine(globalA.destroy);
+ * }
+ *
+ * A::~A()
+ * {
+ * // When you install a post routine you have to remove the post routine from the destructor of
+ * // the class used as global static!
+ * qRemovePostRoutine(globalA.destroy);
+ * }
+ * @endcode
+ *
+ * A common case for the need of deletion on lib unload/app shutdown are Singleton classes. Here's
+ * an example how to do it:
+ * @code
+ * class MySingletonPrivate;
+ * class EXPORT_MACRO MySingleton
+ * {
+ * friend class MySingletonPrivate;
+ * public:
+ * static MySingleton *self();
+ * QString someFunction();
+ *
+ * private:
+ * MySingleton();
+ * ~MySingleton();
+ * };
+ * @endcode
+ * in the .cpp file:
+ * @code
+ * // This class will be instantiated and referenced as a singleton in this example
+ * class MySingletonPrivate
+ * {
+ * public:
+ * QString foo;
+ * MySingleton instance;
+ * };
+ *
+ * PHONON_GLOBAL_STATIC(MySingletonPrivate, mySingletonPrivate)
+ *
+ * MySingleton *MySingleton::self()
+ * {
+ * // returns the singleton; automatically creates a new instance if that has not happened yet.
+ * return &mySingletonPrivate->instance;
+ * }
+ * QString MySingleton::someFunction()
+ * {
+ * // Refencing the singleton directly is possible for your convenience
+ * return mySingletonPrivate->foo;
+ * }
+ * @endcode
+ *
+ * Instead of the above you can use also the following pattern (ignore the name of the namespace):
+ * @code
+ * namespace MySingleton
+ * {
+ * EXPORT_MACRO QString someFunction();
+ * }
+ * @endcode
+ * in the .cpp file:
+ * @code
+ * class MySingletonPrivate
+ * {
+ * public:
+ * QString foo;
+ * };
+ *
+ * PHONON_GLOBAL_STATIC(MySingletonPrivate, mySingletonPrivate)
+ *
+ * QString MySingleton::someFunction()
+ * {
+ * return mySingletonPrivate->foo;
+ * }
+ * @endcode
+ *
+ * Now code that wants to call someFunction() doesn't have to do
+ * @code
+ * MySingleton::self()->someFunction();
+ * @endcode
+ * anymore but instead:
+ * @code
+ * MySingleton::someFunction();
+ * @endcode
+ *
+ * @ingroup KDEMacros
+ */
+#define PHONON_GLOBAL_STATIC(TYPE, NAME) PHONON_GLOBAL_STATIC_WITH_ARGS(TYPE, NAME, ())
+
+/**
+ * @overload
+ * This is the same as PHONON_GLOBAL_STATIC, but can take arguments that are passed
+ * to the object's constructor
+ *
+ * @param TYPE The type of the global static object. Do not add a *.
+ * @param NAME The name of the function to get a pointer to the global static object.
+ * @param ARGS the list of arguments, between brackets
+ *
+ * Example:
+ * @code
+ * class A
+ * {
+ * public:
+ * A(const char *s, int i);
+ * ...
+ * };
+ *
+ * PHONON_GLOBAL_STATIC_WITH_ARG(A, globalA, ("foo", 0))
+ * // The above creates a new globally static variable named 'globalA' which you
+ * // can use as a pointer to an instance of A.
+ *
+ * void doSomething()
+ * {
+ * // The first time you access globalA a new instance of A will be created automatically.
+ * A *a = globalA;
+ * ...
+ * }
+ * @endcode
+ *
+ * @ingroup KDEMacros
+ */
+#define PHONON_GLOBAL_STATIC_WITH_ARGS(TYPE, NAME, ARGS) \
+static QBasicAtomicPointer<TYPE > _k_static_##NAME = Q_BASIC_ATOMIC_INITIALIZER(0); \
+static bool _k_static_##NAME##_destroyed; \
+static struct PHONON_GLOBAL_STATIC_STRUCT_NAME(NAME) \
+{ \
+ bool isDestroyed() \
+ { \
+ return _k_static_##NAME##_destroyed; \
+ } \
+ inline operator TYPE*() \
+ { \
+ return operator->(); \
+ } \
+ inline TYPE *operator->() \
+ { \
+ TYPE *p = _k_static_##NAME; \
+ if (!p) { \
+ if (isDestroyed()) { \
+ qFatal("Fatal Error: Accessed global static '%s *%s()' after destruction. " \
+ "Defined at %s:%d", #TYPE, #NAME, __FILE__, __LINE__); \
+ } \
+ p = new TYPE ARGS; \
+ if (!_k_static_##NAME.testAndSetOrdered(0, p)) { \
+ delete p; \
+ p = _k_static_##NAME; \
+ } else { \
+ static Phonon::CleanUpGlobalStatic cleanUpObject = { destroy }; \
+ } \
+ } \
+ return p; \
+ } \
+ inline TYPE &operator*() \
+ { \
+ return *operator->(); \
+ } \
+ static void destroy() \
+ { \
+ _k_static_##NAME##_destroyed = true; \
+ TYPE *x = _k_static_##NAME; \
+ _k_static_##NAME = 0; \
+ delete x; \
+ } \
+} NAME;
+
+QT_END_NAMESPACE
+#endif // PHONON_GLOBALSTATIC_P_H
diff --git a/src/3rdparty/phonon/phonon/iodevicestream.cpp b/src/3rdparty/phonon/phonon/iodevicestream.cpp
new file mode 100644
index 0000000000..5376da3e82
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/iodevicestream.cpp
@@ -0,0 +1,100 @@
+/* This file is part of the KDE project
+ Copyright (C) 2007 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "iodevicestream_p.h"
+#include "abstractmediastream_p.h"
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
+
+namespace Phonon
+{
+
+class IODeviceStreamPrivate : public AbstractMediaStreamPrivate
+{
+ Q_DECLARE_PUBLIC(IODeviceStream)
+ protected:
+ IODeviceStreamPrivate(QIODevice *_ioDevice)
+ : ioDevice(_ioDevice)
+ {
+ if (!ioDevice->isOpen()) {
+ ioDevice->open(QIODevice::ReadOnly);
+ }
+ Q_ASSERT(ioDevice->isOpen());
+ Q_ASSERT(ioDevice->isReadable());
+ streamSize = ioDevice->size();
+ streamSeekable = !ioDevice->isSequential();
+ }
+
+ private:
+ QIODevice *ioDevice;
+};
+
+IODeviceStream::IODeviceStream(QIODevice *ioDevice, QObject *parent)
+ : AbstractMediaStream(*new IODeviceStreamPrivate(ioDevice), parent)
+{
+ Q_D(IODeviceStream);
+ d->ioDevice->reset();
+}
+
+IODeviceStream::~IODeviceStream()
+{
+}
+
+void IODeviceStream::reset()
+{
+ Q_D(IODeviceStream);
+ d->ioDevice->reset();
+ //resetDone();
+}
+
+void IODeviceStream::needData()
+{
+ quint32 size = 4096;
+ Q_D(IODeviceStream);
+ const QByteArray data = d->ioDevice->read(size);
+ if (data.isEmpty() && !d->ioDevice->atEnd()) {
+ error(Phonon::NormalError, d->ioDevice->errorString());
+ }
+ writeData(data);
+ if (d->ioDevice->atEnd()) {
+ endOfData();
+ }
+}
+
+void IODeviceStream::seekStream(qint64 offset)
+{
+ Q_D(IODeviceStream);
+ d->ioDevice->seek(offset);
+ //seekStreamDone();
+}
+
+} // namespace Phonon
+
+#endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
+
+QT_END_NAMESPACE
+
+#include "moc_iodevicestream_p.cpp"
+
+// vim: sw=4 sts=4 et tw=100
diff --git a/src/3rdparty/phonon/phonon/iodevicestream_p.h b/src/3rdparty/phonon/phonon/iodevicestream_p.h
new file mode 100644
index 0000000000..5eb90bcae4
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/iodevicestream_p.h
@@ -0,0 +1,58 @@
+/* This file is part of the KDE project
+ Copyright (C) 2007 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef PHONON_IODEVICESTREAM_P_H
+#define PHONON_IODEVICESTREAM_P_H
+
+#include "abstractmediastream.h"
+
+QT_BEGIN_HEADER
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
+
+class QIODevice;
+
+namespace Phonon
+{
+
+class IODeviceStreamPrivate;
+class IODeviceStream : public AbstractMediaStream
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(IODeviceStream)
+ public:
+ explicit IODeviceStream(QIODevice *ioDevice, QObject *parent = 0);
+ ~IODeviceStream();
+
+ void reset();
+ void needData();
+ void seekStream(qint64);
+};
+} // namespace Phonon
+
+#endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
+
+QT_END_NAMESPACE
+QT_END_HEADER
+
+#endif // PHONON_IODEVICESTREAM_P_H
diff --git a/src/3rdparty/phonon/phonon/mediacontroller.cpp b/src/3rdparty/phonon/phonon/mediacontroller.cpp
new file mode 100644
index 0000000000..d094381667
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/mediacontroller.cpp
@@ -0,0 +1,239 @@
+/* This file is part of the KDE project
+ Copyright (C) 2007 Matthias Kretz <kretz@kde.org>
+ Copyright (C) 2008 Ian Monroe <ian@monroe.nu>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "mediacontroller.h"
+#include "mediaobject.h"
+#include "addoninterface.h"
+#include <QtCore/QList>
+#include <QtCore/QVariant>
+#include "frontendinterface_p.h"
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_PHONON_MEDIACONTROLLER
+
+namespace Phonon
+{
+
+class MediaControllerPrivate : public FrontendInterfacePrivate
+{
+ public:
+ MediaControllerPrivate(MediaObject *mp) : FrontendInterfacePrivate(mp) {}
+
+ virtual void backendObjectChanged(QObject *);
+ MediaController *q;
+};
+
+MediaController::MediaController(MediaObject *mp)
+ : QObject(mp)
+ , d(new MediaControllerPrivate(mp))
+{
+ d->q = this;
+ d->_backendObjectChanged();
+}
+
+void MediaControllerPrivate::backendObjectChanged(QObject *m_backendObject)
+{
+ QObject::connect(m_backendObject, SIGNAL(availableSubtitlesChanged()), q, SIGNAL(availableSubtitlesChanged()));
+ QObject::connect(m_backendObject, SIGNAL(availableAudioChannelsChanged()), q, SIGNAL(availableAudioChannelsChanged()));
+ QObject::connect(m_backendObject, SIGNAL(titleChanged(int)), q, SIGNAL(titleChanged(int)));
+ QObject::connect(m_backendObject, SIGNAL(availableTitlesChanged(int)), q, SIGNAL(availableTitlesChanged(int)));
+ QObject::connect(m_backendObject, SIGNAL(chapterChanged(int)), q, SIGNAL(chapterChanged(int)));
+ QObject::connect(m_backendObject, SIGNAL(availableChaptersChanged(int)), q, SIGNAL(availableChaptersChanged(int)));
+ QObject::connect(m_backendObject, SIGNAL(angleChanged(int)), q, SIGNAL(angleChanged(int)));
+ QObject::connect(m_backendObject, SIGNAL(availableAnglesChanged(int)), q, SIGNAL(availableAnglesChanged(int)));
+}
+
+MediaController::~MediaController()
+{
+ delete d;
+}
+
+#define IFACE \
+ AddonInterface *iface = d->iface(); \
+ if (!iface) return
+
+MediaController::Features MediaController::supportedFeatures() const
+{
+ if (!d || !d->media) {
+ return false;
+ }
+ IFACE false;
+ Features ret;
+ if (iface->hasInterface(AddonInterface::AngleInterface)) {
+ ret |= Angles;
+ }
+ if (iface->hasInterface(AddonInterface::ChapterInterface)) {
+ ret |= Chapters;
+ }
+ if (iface->hasInterface(AddonInterface::TitleInterface)) {
+ ret |= Titles;
+ }
+ return ret;
+}
+
+int MediaController::availableTitles() const
+{
+ IFACE 0;
+ return iface->interfaceCall(AddonInterface::TitleInterface,
+ AddonInterface::availableTitles).toInt();
+}
+
+int MediaController::currentTitle() const
+{
+ IFACE 0;
+ return iface->interfaceCall(AddonInterface::TitleInterface,
+ AddonInterface::title).toInt();
+}
+
+void MediaController::setCurrentTitle(int titleNumber)
+{
+ IFACE;
+ iface->interfaceCall(AddonInterface::TitleInterface,
+ AddonInterface::setTitle, QList<QVariant>() << QVariant(titleNumber));
+}
+
+bool MediaController::autoplayTitles() const
+{
+ IFACE true;
+ return iface->interfaceCall(AddonInterface::TitleInterface,
+ AddonInterface::autoplayTitles).toBool();
+}
+
+void MediaController::setAutoplayTitles(bool b)
+{
+ IFACE;
+ iface->interfaceCall(AddonInterface::TitleInterface,
+ AddonInterface::setAutoplayTitles, QList<QVariant>() << QVariant(b));
+}
+
+void MediaController::nextTitle()
+{
+ setCurrentTitle(currentTitle() + 1);
+}
+
+void MediaController::previousTitle()
+{
+ setCurrentTitle(currentTitle() - 1);
+}
+
+int MediaController::availableChapters() const
+{
+ IFACE 0;
+ return iface->interfaceCall(AddonInterface::ChapterInterface,
+ AddonInterface::availableChapters).toInt();
+}
+
+int MediaController::currentChapter() const
+{
+ IFACE 0;
+ return iface->interfaceCall(AddonInterface::ChapterInterface,
+ AddonInterface::chapter).toInt();
+}
+
+void MediaController::setCurrentChapter(int titleNumber)
+{
+ IFACE;
+ iface->interfaceCall(AddonInterface::ChapterInterface,
+ AddonInterface::setChapter, QList<QVariant>() << QVariant(titleNumber));
+}
+
+int MediaController::availableAngles() const
+{
+ IFACE 0;
+ return iface->interfaceCall(AddonInterface::AngleInterface,
+ AddonInterface::availableAngles).toInt();
+}
+
+int MediaController::currentAngle() const
+{
+ IFACE 0;
+ return iface->interfaceCall(AddonInterface::AngleInterface,
+ AddonInterface::angle).toInt();
+}
+
+void MediaController::setCurrentAngle(int titleNumber)
+{
+ IFACE;
+ iface->interfaceCall(AddonInterface::AngleInterface,
+ AddonInterface::setAngle, QList<QVariant>() << QVariant(titleNumber));
+}
+
+AudioChannelDescription MediaController::currentAudioChannel() const
+{
+ IFACE AudioChannelDescription();
+ return iface->interfaceCall(AddonInterface::AudioChannelInterface,
+ AddonInterface::currentAudioChannel).value<AudioChannelDescription>();
+}
+
+SubtitleDescription MediaController::currentSubtitle() const
+{
+ IFACE SubtitleDescription();
+ return iface->interfaceCall(AddonInterface::SubtitleInterface,
+ AddonInterface::currentSubtitle).value<SubtitleDescription>();
+}
+
+QList<AudioChannelDescription> MediaController::availableAudioChannels() const
+{
+ QList<AudioChannelDescription> retList;
+ IFACE retList;
+ retList = iface->interfaceCall(AddonInterface::AudioChannelInterface,
+ AddonInterface::availableAudioChannels).value< QList<AudioChannelDescription> >();
+ return retList;
+}
+
+QList<SubtitleDescription> MediaController::availableSubtitles() const
+{
+ QList<SubtitleDescription> retList;
+ IFACE retList;
+ retList = iface->interfaceCall(AddonInterface::SubtitleInterface,
+ AddonInterface::availableSubtitles)
+ .value< QList<SubtitleDescription> >();
+ return retList;
+}
+
+void MediaController::setCurrentAudioChannel(const Phonon::AudioChannelDescription &stream)
+{
+ IFACE;
+ iface->interfaceCall(AddonInterface::AudioChannelInterface,
+ AddonInterface::setCurrentAudioChannel, QList<QVariant>() << qVariantFromValue(stream));
+}
+
+void MediaController::setCurrentSubtitle(const Phonon::SubtitleDescription &stream)
+{
+ IFACE;
+ iface->interfaceCall(AddonInterface::SubtitleInterface,
+ AddonInterface::setCurrentSubtitle, QList<QVariant>() << qVariantFromValue(stream));
+}
+
+#undef IFACE
+
+} // namespace Phonon
+
+#endif //QT_NO_PHONON_MEDIACONTROLLER
+
+QT_END_NAMESPACE
+
+#include "moc_mediacontroller.cpp"
+
+// vim: sw=4 sts=4 et tw=100
diff --git a/src/3rdparty/phonon/phonon/mediacontroller.h b/src/3rdparty/phonon/phonon/mediacontroller.h
new file mode 100644
index 0000000000..19aaf1316f
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/mediacontroller.h
@@ -0,0 +1,188 @@
+/* This file is part of the KDE project
+ Copyright (C) 2007 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef PHONON_MEDIACONTROLLER_H
+#define PHONON_MEDIACONTROLLER_H
+
+#include "phonon_export.h"
+#include "objectdescription.h"
+
+#include <QtCore/QObject>
+#include <QtCore/QtGlobal>
+
+QT_BEGIN_HEADER
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_PHONON_MEDIACONTROLLER
+
+namespace Phonon
+{
+class MediaControllerPrivate;
+class MediaObject;
+
+/** \class MediaController mediacontroller.h Phonon/MediaController
+ * \brief Controls optional features of a media file/device like title, chapter, angle.
+ *
+ * \ingroup Playback
+ * \author Matthias Kretz <kretz@kde.org>
+ */
+class PHONON_EXPORT MediaController : public QObject
+{
+ Q_OBJECT
+ Q_FLAGS(Features)
+ public:
+ enum Feature {
+ Angles = 1,
+ Chapters = 2,
+ Titles = 4
+ };
+ Q_DECLARE_FLAGS(Features, Feature)
+
+ MediaController(MediaObject *parent);
+ ~MediaController();
+
+ Features supportedFeatures() const;
+
+ int availableAngles() const;
+ int currentAngle() const;
+
+ int availableChapters() const;
+ int currentChapter() const;
+
+ int availableTitles() const;
+ int currentTitle() const;
+
+ bool autoplayTitles() const;
+
+ /**
+ * Returns the selected audio stream.
+ *
+ * \see availableAudioChannels
+ * \see setCurrentAudioChannel
+ */
+ AudioChannelDescription currentAudioChannel() const;
+
+ /**
+ * Returns the selected subtitle stream.
+ *
+ * \see availableSubtitles
+ * \see setCurrentSubtitle
+ */
+ SubtitleDescription currentSubtitle() const;
+
+ /**
+ * Returns the audio streams that can be selected by the user. The
+ * strings can directly be used in the user interface.
+ *
+ * \see selectedAudioChannel
+ * \see setCurrentAudioChannel
+ */
+ QList<AudioChannelDescription> availableAudioChannels() const;
+
+ /**
+ * Returns the subtitle streams that can be selected by the user. The
+ * strings can directly be used in the user interface.
+ *
+ * \see selectedSubtitle
+ * \see setCurrentSubtitle
+ */
+ QList<SubtitleDescription> availableSubtitles() const;
+
+ /**
+ * Selects an audio stream from the media.
+ *
+ * Some media formats allow multiple audio streams to be stored in
+ * the same file. Normally only one should be played back.
+ *
+ * \param stream Description of an audio stream
+ *
+ * \see availableAudioChannels()
+ * \see currentAudioChannel()
+ */
+ void setCurrentAudioChannel(const Phonon::AudioChannelDescription &stream);
+
+ /**
+ * Selects a subtitle stream from the media.
+ *
+ * Some media formats allow multiple subtitle streams to be stored in
+ * the same file. Normally only one should be displayed.
+ *
+ * \param stream description of a subtitle stream
+ *
+ * \see availableSubtitles()
+ * \see currentSubtitle()
+ */
+ void setCurrentSubtitle(const Phonon::SubtitleDescription &stream);
+
+ public Q_SLOTS:
+ void setCurrentAngle(int angleNumber);
+ void setCurrentChapter(int chapterNumber);
+
+ /**
+ * Skips to the given title \p titleNumber.
+ *
+ * If it was playing before the title change it will start playback on the new title if
+ * autoplayTitles is enabled.
+ */
+ void setCurrentTitle(int titleNumber);
+ void setAutoplayTitles(bool);
+
+ /**
+ * Skips to the next title.
+ *
+ * If it was playing before the title change it will start playback on the next title if
+ * autoplayTitles is enabled.
+ */
+ void nextTitle();
+
+ /**
+ * Skips to the previous title.
+ *
+ * If it was playing before the title change it will start playback on the previous title if
+ * autoplayTitles is enabled.
+ */
+ void previousTitle();
+
+ Q_SIGNALS:
+ void availableSubtitlesChanged();
+ void availableAudioChannelsChanged();
+ void availableAnglesChanged(int availableAngles);
+ void angleChanged(int angleNumber);
+ void availableChaptersChanged(int availableChapters);
+ void chapterChanged(int chapterNumber);
+ void availableTitlesChanged(int availableTitles);
+ void titleChanged(int titleNumber);
+
+ protected:
+ MediaControllerPrivate *const d;
+};
+
+} // namespace Phonon
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(Phonon::MediaController::Features)
+
+#endif //QT_NO_PHONON_MEDIACONTROLLER
+
+QT_END_NAMESPACE
+QT_END_HEADER
+
+#endif // PHONON_MEDIACONTROLLER_H
diff --git a/src/3rdparty/phonon/phonon/medianode.cpp b/src/3rdparty/phonon/phonon/medianode.cpp
new file mode 100644
index 0000000000..4693cb856d
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/medianode.cpp
@@ -0,0 +1,130 @@
+/* This file is part of the KDE project
+ Copyright (C) 2007 Matthias Kretz <kretz@kde.org>
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). <thierry.bastian@trolltech.com>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "medianode.h"
+#include "medianode_p.h"
+#include "medianodedestructionhandler_p.h"
+#include "factory_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+
+ MediaNode::MediaNode(MediaNodePrivate &dd)
+ : k_ptr(&dd)
+ {
+ k_ptr->q_ptr = this;
+ }
+
+bool MediaNode::isValid() const
+{
+ return const_cast<MediaNodePrivate *>(k_ptr)->backendObject() != 0;
+}
+
+ QList<Path> MediaNode::inputPaths() const
+ {
+ return k_ptr->inputPaths;
+ }
+
+ QList<Path> MediaNode::outputPaths() const
+ {
+ return k_ptr->outputPaths;
+ }
+
+ MediaNode::~MediaNode()
+ {
+ delete k_ptr;
+ }
+
+ QObject *MediaNodePrivate::backendObject()
+ {
+ if (!m_backendObject && Factory::backend()) {
+ createBackendObject();
+ }
+ return m_backendObject;
+ }
+
+ MediaNodePrivate::~MediaNodePrivate()
+ {
+ foreach (MediaNodeDestructionHandler *handler, handlers) {
+ handler->phononObjectDestroyed(this);
+ }
+ Factory::deregisterFrontendObject(this);
+ delete m_backendObject;
+ m_backendObject = 0;
+ }
+
+void MediaNodePrivate::deleteBackendObject()
+{
+ if (m_backendObject && aboutToDeleteBackendObject()) {
+ delete m_backendObject;
+ m_backendObject = 0;
+ }
+}
+
+ MediaNodePrivate::MediaNodePrivate(MediaNodePrivate::CastId _castId) : castId(_castId),
+ m_backendObject(0)
+ {
+ Factory::registerFrontendObject(this);
+ }
+
+ void MediaNodePrivate::addDestructionHandler(MediaNodeDestructionHandler *handler)
+ {
+ handlers.append(handler);
+ }
+
+ void MediaNodePrivate::removeDestructionHandler(MediaNodeDestructionHandler *handler)
+ {
+ handlers.removeAll(handler);
+ }
+
+ void MediaNodePrivate::addOutputPath(const Path &p)
+ {
+ outputPaths.append(p);
+ }
+
+ void MediaNodePrivate::addInputPath(const Path &p)
+ {
+ inputPaths.append(p);
+ }
+
+ void MediaNodePrivate::removeOutputPath(const Path &p)
+ {
+ int ret = outputPaths.removeAll(p);
+ Q_ASSERT(ret == 1);
+ Q_UNUSED(ret);
+ }
+
+ void MediaNodePrivate::removeInputPath(const Path &p)
+ {
+ int ret = inputPaths.removeAll(p);
+ Q_ASSERT(ret == 1);
+ Q_UNUSED(ret);
+ }
+
+
+
+} // namespace Phonon
+
+QT_END_NAMESPACE
diff --git a/src/3rdparty/phonon/phonon/medianode.h b/src/3rdparty/phonon/phonon/medianode.h
new file mode 100644
index 0000000000..86931acfd7
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/medianode.h
@@ -0,0 +1,69 @@
+/* This file is part of the KDE project
+ Copyright (C) 2007 Matthias Kretz <kretz@kde.org>
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). <thierry.bastian@trolltech.com>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef PHONON_MEDIANODE_H
+#define PHONON_MEDIANODE_H
+
+#include "phonondefs.h"
+#include "phonon_export.h"
+#include "path.h"
+
+QT_BEGIN_HEADER
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+
+ class Path;
+ class MediaNodePrivate;
+ class PHONON_EXPORT MediaNode
+ {
+ friend class Path;
+ friend class PathPrivate;
+ friend PHONON_EXPORT Path createPath(MediaNode *source, MediaNode *sink);
+ K_DECLARE_PRIVATE(MediaNode)
+ public:
+ virtual ~MediaNode();
+ /**
+ * Tells whether the backend provides an implementation of this
+ * class.
+ *
+ * \return \c true if backend provides an implementation
+ * \return \c false if the object is not implemented by the backend
+ */
+ bool isValid() const;
+
+ QList<Path> inputPaths() const;
+ QList<Path> outputPaths() const;
+
+ protected:
+ MediaNode(MediaNodePrivate &dd);
+ MediaNodePrivate *const k_ptr;
+ };
+
+} // namespace Phonon
+
+QT_END_NAMESPACE
+QT_END_HEADER
+
+#endif // PHONON_MEDIANODE_H
diff --git a/src/3rdparty/phonon/phonon/medianode_p.h b/src/3rdparty/phonon/phonon/medianode_p.h
new file mode 100644
index 0000000000..d5424b7291
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/medianode_p.h
@@ -0,0 +1,145 @@
+/* This file is part of the KDE project
+Copyright (C) 2007 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef PHONON_MEDIANODE_P_H
+#define PHONON_MEDIANODE_P_H
+
+#include <QtCore/QtGlobal>
+#include <QtCore/QList>
+#include <QtCore/QObject>
+#include "path.h"
+#include "phonon_export.h"
+
+QT_BEGIN_NAMESPACE
+
+class QObject;
+
+namespace Phonon
+{
+ class MediaNode;
+ class MediaNodeDestructionHandler;
+
+ class PHONON_EXPORT MediaNodePrivate
+ {
+ Q_DECLARE_PUBLIC(MediaNode)
+
+ friend class AudioOutputPrivate;
+ friend class FactoryPrivate;
+
+ protected:
+ enum CastId {
+ MediaNodePrivateType,
+ AbstractAudioOutputPrivateType,
+ AudioOutputType
+ };
+ public:
+ /**
+ * Returns the backend object. If the object does not exist it tries to
+ * create it before returning.
+ *
+ * \return the Iface object, might return \c 0
+ */
+ QObject *backendObject();
+
+ const CastId castId;
+
+ protected:
+ MediaNodePrivate(CastId _castId = MediaNodePrivateType);
+
+ virtual ~MediaNodePrivate();
+
+ /**
+ * \internal
+ * This method cleanly deletes the Iface object. It is called on
+ * destruction and before a backend change.
+ */
+ void deleteBackendObject();
+
+ virtual bool aboutToDeleteBackendObject() = 0;
+
+ /**
+ * \internal
+ * Creates the Iface object belonging to this class. For most cases the
+ * implementation is
+ * \code
+ * Q_Q(ClassName);
+ * m_iface = Factory::createClassName(this);
+ * return m_iface;
+ * \endcode
+ *
+ * This function should not be called except from slotCreateIface.
+ *
+ * \see slotCreateIface
+ */
+ virtual void createBackendObject() = 0;
+
+ public:
+ /**
+ * \internal
+ * This class has its own destroyed signal since some cleanup calls
+ * need the pointer to the backend object intact. The
+ * QObject::destroyed signals comes after the backend object was
+ * deleted.
+ *
+ * As this class cannot derive from QObject a simple handler
+ * interface is used.
+ */
+ void addDestructionHandler(MediaNodeDestructionHandler *handler);
+
+ /**
+ * \internal
+ * This class has its own destroyed signal since some cleanup calls
+ * need the pointer to the backend object intact. The
+ * QObject::destroyed signals comes after the backend object was
+ * deleted.
+ *
+ * As this class cannot derive from QObject a simple handler
+ * interface is used.
+ */
+ void removeDestructionHandler(MediaNodeDestructionHandler *handler);
+
+ void addOutputPath(const Path &);
+ void addInputPath(const Path &);
+ void removeOutputPath(const Path &);
+ void removeInputPath(const Path &);
+
+ const QObject *qObject() const { return const_cast<MediaNodePrivate *>(this)->qObject(); }
+ virtual QObject *qObject() { return 0; }
+
+ protected:
+ MediaNode *q_ptr;
+ public:
+ QObject *m_backendObject;
+ protected:
+ QList<Path> outputPaths;
+ QList<Path> inputPaths;
+
+ private:
+ QList<MediaNodeDestructionHandler *> handlers;
+ Q_DISABLE_COPY(MediaNodePrivate)
+ };
+
+} // namespace Phonon
+
+QT_END_NAMESPACE
+
+#endif // PHONON_MEDIANODE_P_H
diff --git a/src/3rdparty/phonon/phonon/medianodedestructionhandler_p.h b/src/3rdparty/phonon/phonon/medianodedestructionhandler_p.h
new file mode 100644
index 0000000000..38c090726d
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/medianodedestructionhandler_p.h
@@ -0,0 +1,62 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef MEDIANODEDESTRUCTIONHANDLER_P_H
+#define MEDIANODEDESTRUCTIONHANDLER_P_H
+
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_HEADER
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+/**
+ * \internal
+ *
+ * Callback interface to keep track of Phonon frontend object destruction.
+ *
+ * \author Matthias Kretz <kretz@kde.org>
+ */
+
+class MediaNodePrivate;
+
+class MediaNodeDestructionHandler
+{
+ friend class MediaNodePrivate;
+
+public:
+ virtual ~MediaNodeDestructionHandler() {}
+protected:
+ /**
+ * \internal
+ * called from Base::~Base if this object was registered
+ * using BasePrivate::addDestructionHandler().
+ */
+ virtual void phononObjectDestroyed(MediaNodePrivate *) = 0;
+};
+}
+
+QT_END_NAMESPACE
+QT_END_HEADER
+
+#endif // MEDIANODEDESTRUCTIONHANDLER_P_H
diff --git a/src/3rdparty/phonon/phonon/mediaobject.cpp b/src/3rdparty/phonon/phonon/mediaobject.cpp
new file mode 100644
index 0000000000..de5fbc8c4f
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/mediaobject.cpp
@@ -0,0 +1,572 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005-2007 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+#include "mediaobject.h"
+#include "mediaobject_p.h"
+
+#include "factory_p.h"
+#include "mediaobjectinterface.h"
+#include "audiooutput.h"
+#include "phonondefs_p.h"
+#include "abstractmediastream.h"
+#include "abstractmediastream_p.h"
+#include "frontendinterface_p.h"
+
+#include <QtCore/QStringList>
+#include <QtCore/QUrl>
+#include <QtCore/QTimer>
+
+#include "phononnamespace_p.h"
+#include "platform_p.h"
+
+#define PHONON_CLASSNAME MediaObject
+#define PHONON_INTERFACENAME MediaObjectInterface
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+PHONON_OBJECT_IMPL
+
+MediaObject::~MediaObject()
+{
+ K_D(MediaObject);
+ if (d->m_backendObject) {
+ switch (state()) {
+ case PlayingState:
+ case BufferingState:
+ case PausedState:
+ stop();
+ break;
+ case ErrorState:
+ case StoppedState:
+ case LoadingState:
+ break;
+ }
+ }
+}
+
+Phonon::State MediaObject::state() const
+{
+ K_D(const MediaObject);
+#ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ if (d->errorOverride) {
+ return d->state;
+ }
+ if (d->ignoreLoadingToBufferingStateChange) {
+ return BufferingState;
+ }
+ if (d->ignoreErrorToLoadingStateChange) {
+ return LoadingState;
+ }
+#endif // QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ if (!d->m_backendObject) {
+ return d->state;
+ }
+ return INTERFACE_CALL(state());
+}
+
+PHONON_INTERFACE_SETTER(setTickInterval, tickInterval, qint32)
+PHONON_INTERFACE_GETTER(qint32, tickInterval, d->tickInterval)
+PHONON_INTERFACE_GETTER(bool, hasVideo, false)
+PHONON_INTERFACE_GETTER(bool, isSeekable, false)
+PHONON_INTERFACE_GETTER(qint64, currentTime, d->currentTime)
+
+static inline bool isPlayable(const MediaSource::Type t)
+{
+ return t != MediaSource::Invalid && t != MediaSource::Empty;
+}
+
+void MediaObject::play()
+{
+ K_D(MediaObject);
+ if (d->backendObject() && isPlayable(d->mediaSource.type())) {
+ INTERFACE_CALL(play());
+ }
+}
+
+void MediaObject::pause()
+{
+ K_D(MediaObject);
+ if (d->backendObject() && isPlayable(d->mediaSource.type())) {
+ INTERFACE_CALL(pause());
+ }
+}
+
+void MediaObject::stop()
+{
+ K_D(MediaObject);
+ if (d->backendObject() && isPlayable(d->mediaSource.type())) {
+ INTERFACE_CALL(stop());
+ }
+}
+
+void MediaObject::seek(qint64 time)
+{
+ K_D(MediaObject);
+ if (d->backendObject() && isPlayable(d->mediaSource.type())) {
+ INTERFACE_CALL(seek(time));
+ }
+}
+
+QString MediaObject::errorString() const
+{
+ if (state() == Phonon::ErrorState) {
+ K_D(const MediaObject);
+#ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ if (d->errorOverride) {
+ return d->errorString;
+ }
+#endif // QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ return INTERFACE_CALL(errorString());
+ }
+ return QString();
+}
+
+ErrorType MediaObject::errorType() const
+{
+ if (state() == Phonon::ErrorState) {
+ K_D(const MediaObject);
+#ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ if (d->errorOverride) {
+ return d->errorType;
+ }
+#endif // QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ return INTERFACE_CALL(errorType());
+ }
+ return Phonon::NoError;
+}
+
+QStringList MediaObject::metaData(Phonon::MetaData f) const
+{
+ switch (f) {
+ case ArtistMetaData:
+ return metaData(QLatin1String("ARTIST" ));
+ case AlbumMetaData:
+ return metaData(QLatin1String("ALBUM" ));
+ case TitleMetaData:
+ return metaData(QLatin1String("TITLE" ));
+ case DateMetaData:
+ return metaData(QLatin1String("DATE" ));
+ case GenreMetaData:
+ return metaData(QLatin1String("GENRE" ));
+ case TracknumberMetaData:
+ return metaData(QLatin1String("TRACKNUMBER"));
+ case DescriptionMetaData:
+ return metaData(QLatin1String("DESCRIPTION"));
+ case MusicBrainzDiscIdMetaData:
+ return metaData(QLatin1String("MUSICBRAINZ_DISCID"));
+ }
+ return QStringList();
+}
+
+QStringList MediaObject::metaData(const QString &key) const
+{
+ K_D(const MediaObject);
+ return d->metaData.values(key);
+}
+
+QMultiMap<QString, QString> MediaObject::metaData() const
+{
+ K_D(const MediaObject);
+ return d->metaData;
+}
+
+PHONON_INTERFACE_GETTER(qint32, prefinishMark, d->prefinishMark)
+PHONON_INTERFACE_SETTER(setPrefinishMark, prefinishMark, qint32)
+
+PHONON_INTERFACE_GETTER(qint32, transitionTime, d->transitionTime)
+PHONON_INTERFACE_SETTER(setTransitionTime, transitionTime, qint32)
+
+qint64 MediaObject::totalTime() const
+{
+ K_D(const MediaObject);
+ if (!d->m_backendObject) {
+ return -1;
+ }
+ return INTERFACE_CALL(totalTime());
+}
+
+qint64 MediaObject::remainingTime() const
+{
+ K_D(const MediaObject);
+ if (!d->m_backendObject) {
+ return -1;
+ }
+ qint64 ret = INTERFACE_CALL(remainingTime());
+ if (ret < 0) {
+ return -1;
+ }
+ return ret;
+}
+
+MediaSource MediaObject::currentSource() const
+{
+ K_D(const MediaObject);
+ return d->mediaSource;
+}
+
+void MediaObject::setCurrentSource(const MediaSource &newSource)
+{
+ K_D(MediaObject);
+ if (!k_ptr->backendObject()) {
+ d->mediaSource = newSource;
+ return;
+ }
+
+ pDebug() << Q_FUNC_INFO << newSource.url();
+
+ stop(); // first call stop as that often is the expected state
+ // for setting a new URL
+
+ d->mediaSource = newSource;
+#ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ d->kiofallback = 0; // kiofallback auto-deletes
+#endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
+
+//X if (url.scheme() == "http") {
+//X d->kiofallback = Platform::createMediaStream(url, this);
+//X if (d->kiofallback) {
+//X ...
+//X return;
+//X }
+//X }
+
+#ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ if (d->mediaSource.type() == MediaSource::Stream) {
+ Q_ASSERT(d->mediaSource.stream());
+ d->mediaSource.stream()->d_func()->setMediaObjectPrivate(d);
+ }
+#endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
+
+ INTERFACE_CALL(setSource(d->mediaSource));
+}
+
+void MediaObject::clear()
+{
+ K_D(MediaObject);
+ d->sourceQueue.clear();
+ setCurrentSource(MediaSource());
+}
+
+QList<MediaSource> MediaObject::queue() const
+{
+ K_D(const MediaObject);
+ return d->sourceQueue;
+}
+
+void MediaObject::setQueue(const QList<MediaSource> &sources)
+{
+ K_D(MediaObject);
+ d->sourceQueue.clear();
+ enqueue(sources);
+}
+
+void MediaObject::setQueue(const QList<QUrl> &urls)
+{
+ K_D(MediaObject);
+ d->sourceQueue.clear();
+ enqueue(urls);
+}
+
+void MediaObject::enqueue(const MediaSource &source)
+{
+ K_D(MediaObject);
+ if (!isPlayable(d->mediaSource.type())) {
+ // the current source is nothing valid so this source needs to become the current one
+ setCurrentSource(source);
+ } else {
+ d->sourceQueue << source;
+ }
+}
+
+void MediaObject::enqueue(const QList<MediaSource> &sources)
+{
+ foreach (const MediaSource &m, sources) {
+ enqueue(m);
+ }
+}
+
+void MediaObject::enqueue(const QList<QUrl> &urls)
+{
+ foreach (const QUrl &url, urls) {
+ enqueue(url);
+ }
+}
+
+void MediaObject::clearQueue()
+{
+ K_D(MediaObject);
+ d->sourceQueue.clear();
+}
+
+bool MediaObjectPrivate::aboutToDeleteBackendObject()
+{
+ //pDebug() << Q_FUNC_INFO;
+ prefinishMark = pINTERFACE_CALL(prefinishMark());
+ transitionTime = pINTERFACE_CALL(transitionTime());
+ //pDebug() << Q_FUNC_INFO;
+ if (m_backendObject) {
+ state = pINTERFACE_CALL(state());
+ currentTime = pINTERFACE_CALL(currentTime());
+ tickInterval = pINTERFACE_CALL(tickInterval());
+ }
+ return true;
+}
+
+#ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
+void MediaObjectPrivate::streamError(Phonon::ErrorType type, const QString &text)
+{
+ Q_Q(MediaObject);
+ State lastState = q->state();
+ errorOverride = true;
+ errorType = type;
+ errorString = text;
+ state = ErrorState;
+ QMetaObject::invokeMethod(q, "stateChanged", Qt::QueuedConnection, Q_ARG(Phonon::State, Phonon::ErrorState), Q_ARG(Phonon::State, lastState));
+ //emit q->stateChanged(ErrorState, lastState);
+}
+
+void MediaObjectPrivate::_k_stateChanged(Phonon::State newstate, Phonon::State oldstate)
+{
+ Q_Q(MediaObject);
+ if (mediaSource.type() != MediaSource::Url) {
+ // special handling only necessary for URLs because of the fallback
+ emit q->stateChanged(newstate, oldstate);
+ return;
+ }
+
+ if (errorOverride) {
+ errorOverride = false;
+ if (newstate == ErrorState) {
+ return;
+ }
+ oldstate = ErrorState;
+ }
+
+ // backend MediaObject reached ErrorState, try a KioMediaSource
+ if (newstate == Phonon::ErrorState && !kiofallback) {
+ kiofallback = Platform::createMediaStream(mediaSource.url(), q);
+ if (!kiofallback) {
+ pDebug() << "backend MediaObject reached ErrorState, no KIO fallback available";
+ emit q->stateChanged(newstate, oldstate);
+ return;
+ }
+ pDebug() << "backend MediaObject reached ErrorState, trying Platform::createMediaStream now";
+ ignoreLoadingToBufferingStateChange = false;
+ ignoreErrorToLoadingStateChange = false;
+ switch (oldstate) {
+ case Phonon::BufferingState:
+ // play() has already been called, we need to make sure it is called
+ // on the backend with the KioMediaStream MediaSource now, too
+ ignoreLoadingToBufferingStateChange = true;
+ break;
+ case Phonon::LoadingState:
+ ignoreErrorToLoadingStateChange = true;
+ // no extras
+ break;
+ default:
+ pError() << "backend MediaObject reached ErrorState after " << oldstate
+ << ". It seems a KioMediaStream will not help here, trying anyway.";
+ emit q->stateChanged(Phonon::LoadingState, oldstate);
+ break;
+ }
+ kiofallback->d_func()->setMediaObjectPrivate(this);
+ MediaSource mediaSource(kiofallback);
+ mediaSource.setAutoDelete(true);
+ pINTERFACE_CALL(setSource(mediaSource));
+ if (oldstate == Phonon::BufferingState) {
+ q->play();
+ }
+ return;
+ } else if (ignoreLoadingToBufferingStateChange &&
+ kiofallback &&
+ oldstate == Phonon::LoadingState) {
+ if (newstate != Phonon::BufferingState) {
+ emit q->stateChanged(newstate, Phonon::BufferingState);
+ }
+ return;
+ } else if (ignoreErrorToLoadingStateChange && kiofallback && oldstate == ErrorState) {
+ if (newstate != LoadingState) {
+ emit q->stateChanged(newstate, Phonon::LoadingState);
+ }
+ return;
+ }
+
+ emit q->stateChanged(newstate, oldstate);
+}
+#endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
+
+void MediaObjectPrivate::_k_aboutToFinish()
+{
+ Q_Q(MediaObject);
+ pDebug() << Q_FUNC_INFO;
+
+#ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ kiofallback = 0; // kiofallback auto-deletes
+#endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
+
+ if (sourceQueue.isEmpty()) {
+ emit q->aboutToFinish();
+ if (sourceQueue.isEmpty()) {
+ return;
+ }
+ }
+
+ mediaSource = sourceQueue.head();
+ pINTERFACE_CALL(setNextSource(mediaSource));
+}
+
+void MediaObjectPrivate::_k_currentSourceChanged(const MediaSource &source)
+{
+ Q_Q(MediaObject);
+ pDebug() << Q_FUNC_INFO;
+
+ if (!sourceQueue.isEmpty() && sourceQueue.head() == source)
+ sourceQueue.dequeue();
+
+ emit q->currentSourceChanged(source);
+}
+
+void MediaObjectPrivate::setupBackendObject()
+{
+ Q_Q(MediaObject);
+ Q_ASSERT(m_backendObject);
+ //pDebug() << Q_FUNC_INFO;
+
+#ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ QObject::connect(m_backendObject, SIGNAL(stateChanged(Phonon::State, Phonon::State)), q, SLOT(_k_stateChanged(Phonon::State, Phonon::State)));
+#else
+ QObject::connect(m_backendObject, SIGNAL(stateChanged(Phonon::State, Phonon::State)), q, SIGNAL(stateChanged(Phonon::State, Phonon::State)));
+#endif // QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ QObject::connect(m_backendObject, SIGNAL(tick(qint64)), q, SIGNAL(tick(qint64)));
+ QObject::connect(m_backendObject, SIGNAL(seekableChanged(bool)), q, SIGNAL(seekableChanged(bool)));
+#ifndef QT_NO_PHONON_VIDEO
+ QObject::connect(m_backendObject, SIGNAL(hasVideoChanged(bool)), q, SIGNAL(hasVideoChanged(bool)));
+#endif //QT_NO_PHONON_VIDEO
+ QObject::connect(m_backendObject, SIGNAL(bufferStatus(int)), q, SIGNAL(bufferStatus(int)));
+ QObject::connect(m_backendObject, SIGNAL(finished()), q, SIGNAL(finished()));
+ QObject::connect(m_backendObject, SIGNAL(aboutToFinish()), q, SLOT(_k_aboutToFinish()));
+ QObject::connect(m_backendObject, SIGNAL(prefinishMarkReached(qint32)), q, SIGNAL(prefinishMarkReached(qint32)));
+ QObject::connect(m_backendObject, SIGNAL(totalTimeChanged(qint64)), q, SIGNAL(totalTimeChanged(qint64)));
+ QObject::connect(m_backendObject, SIGNAL(metaDataChanged(const QMultiMap<QString, QString> &)),
+ q, SLOT(_k_metaDataChanged(const QMultiMap<QString, QString> &)));
+ QObject::connect(m_backendObject, SIGNAL(currentSourceChanged(const MediaSource&)),
+ q, SLOT(_k_currentSourceChanged(const MediaSource&)));
+
+ // set up attributes
+ pINTERFACE_CALL(setTickInterval(tickInterval));
+ pINTERFACE_CALL(setPrefinishMark(prefinishMark));
+ pINTERFACE_CALL(setTransitionTime(transitionTime));
+
+ switch(state)
+ {
+ case LoadingState:
+ case StoppedState:
+ case ErrorState:
+ break;
+ case PlayingState:
+ case BufferingState:
+ QTimer::singleShot(0, q, SLOT(_k_resumePlay()));
+ break;
+ case PausedState:
+ QTimer::singleShot(0, q, SLOT(_k_resumePause()));
+ break;
+ }
+ const State backendState = pINTERFACE_CALL(state());
+ if (state != backendState && state != ErrorState) {
+ // careful: if state is ErrorState we might be switching from a
+ // MediaObject to a ByteStream for KIO fallback. In that case the state
+ // change to ErrorState was already suppressed.
+ pDebug() << "emitting a state change because the backend object has been replaced";
+ emit q->stateChanged(backendState, state);
+ state = backendState;
+ }
+
+#ifndef QT_NO_PHONON_MEDIACONTROLLER
+ foreach (FrontendInterfacePrivate *f, interfaceList) {
+ f->_backendObjectChanged();
+ }
+#endif //QT_NO_PHONON_MEDIACONTROLLER
+
+ // set up attributes
+ if (isPlayable(mediaSource.type())) {
+#ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ if (mediaSource.type() == MediaSource::Stream) {
+ Q_ASSERT(mediaSource.stream());
+ mediaSource.stream()->d_func()->setMediaObjectPrivate(this);
+ }
+#endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ pINTERFACE_CALL(setSource(mediaSource));
+ }
+}
+
+void MediaObjectPrivate::_k_resumePlay()
+{
+ qobject_cast<MediaObjectInterface *>(m_backendObject)->play();
+ if (currentTime > 0) {
+ qobject_cast<MediaObjectInterface *>(m_backendObject)->seek(currentTime);
+ }
+}
+
+void MediaObjectPrivate::_k_resumePause()
+{
+ pINTERFACE_CALL(pause());
+ if (currentTime > 0) {
+ qobject_cast<MediaObjectInterface *>(m_backendObject)->seek(currentTime);
+ }
+}
+
+void MediaObjectPrivate::_k_metaDataChanged(const QMultiMap<QString, QString> &newMetaData)
+{
+ metaData = newMetaData;
+ emit q_func()->metaDataChanged();
+}
+
+void MediaObjectPrivate::phononObjectDestroyed(MediaNodePrivate *bp)
+{
+ // this method is called from Phonon::Base::~Base(), meaning the AudioPath
+ // dtor has already been called, also virtual functions don't work anymore
+ // (therefore qobject_cast can only downcast from Base)
+ Q_ASSERT(bp);
+ Q_UNUSED(bp);
+}
+
+MediaObject *createPlayer(Phonon::Category category, const MediaSource &source)
+{
+ MediaObject *mo = new MediaObject;
+ AudioOutput *ao = new AudioOutput(category, mo);
+ createPath(mo, ao);
+ if (isPlayable(source.type())) {
+ mo->setCurrentSource(source);
+ }
+ return mo;
+}
+
+} //namespace Phonon
+
+QT_END_NAMESPACE
+
+#include "moc_mediaobject.cpp"
+
+#undef PHONON_CLASSNAME
+#undef PHONON_INTERFACENAME
+// vim: sw=4 tw=100 et
diff --git a/src/3rdparty/phonon/phonon/mediaobject.dox b/src/3rdparty/phonon/phonon/mediaobject.dox
new file mode 100644
index 0000000000..cc6fe5f9f5
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/mediaobject.dox
@@ -0,0 +1,71 @@
+/**
+\page phonon_MediaObject The MediaObject class
+
+\section phonon_MediaObject_derived Media Data Producing Class
+
+There is the class that produces the media data (often called a source in
+media frameworks).
+
+\section phonon_MediaObject_requiredfunctions Required Functions
+\li qint32 \ref phonon_MediaObject_prefinishMark "prefinishMark()"
+\li void \ref phonon_MediaObject_setPrefinishMark "setPrefinishMark(qint32)"
+
+\section phonon_MediaObject_optionalfunctions Optional Functions
+\li qint64 \ref phonon_MediaObject_remainingTime "remainingTime()"
+
+\section phonon_MediaObject_signals Signals
+\li void \ref phonon_MediaObject_totalTimeChanged "totalTimeChanged(qint64 totalTime)"
+\li void \ref phonon_MediaObject_prefinishMarkReached "prefinishMarkReached(qint32 msec)"
+\li void \ref phonon_MediaObject_finished "finished()"
+
+\section phonon_MediaObject_memberdocs Member Function Documentation
+
+\see \ref phonon_MediaObject_totalTimeChanged
+
+\subsection phonon_MediaObject_prefinishMark qint32 prefinishMark()
+Returns the time in milliseconds the \ref phonon_MediaObject_prefinishMarkReached
+"prefinishMarkReached" signal is emitted before the playback if finished and \ref
+phonon_MediaObject_finished "finished" is emitted.
+
+\subsection phonon_MediaObject_setPrefinishMark void setPrefinishMark(qint32 msec)
+Sets the time in milliseconds the \ref phonon_MediaObject_prefinishMarkReached
+"prefinishMarkReached" signal is emitted before the playback if finished and \ref
+phonon_MediaObject_finished "finished" is emitted.
+
+\param msec The time in milliseconds. If the value is less than or equal to 0
+the \ref phonon_MediaObject_prefinishMarkReached "prefinishMarkReached" signal is disabled.
+
+\subsection phonon_MediaObject_remainingTime qint64 remainingTime()
+Get the remaining time (in milliseconds) of the file currently being played. If
+the method is not implemented in the backend the frontend will use the
+difference between \link Phonon::MediaObjectInterface::totalTime() MediaObjectInterface::totalTime() \endlink and
+\link Phonon::MediaObjectInterface::currentTime() MediaObjectInterface::currentTime() \endlink.
+
+\section phonon_MediaObject_signaldocs Signals Documentation
+\subsection phonon_MediaObject_prefinishMarkReached void prefinishMarkReached(qint32 msec)
+Emitted when the file has finished playing on its own.
+I.e. it is not emitted if you call stop(), pause() or
+load(), but only on end-of-file or a critical error.
+void finished()
+
+\param msec The remaining time until the playback finishes
+
+\subsection phonon_MediaObject_totalTimeChanged void totalTimeChanged(qint64 totalTime)
+This signal is emitted as soon as the length of the media file is
+known or has changed. For most non-local media data the length of
+the media can only be known after some time. At that time the
+totalTime function can not return useful information. You have
+to wait for this signal to know the real length.
+
+\param totalTimeChanged The total time of the media file in milliseconds.
+
+\see \link Phonon::MediaObjectInterface::totalTime() MediaObjectInterface::totalTime() \endlink
+
+\subsection phonon_MediaObject_finished void finished()
+This signal is emitted when the playback of the media finished (on its own).
+It is not emitted if stop() or pause() are called - only on end-of-file or a
+critical error (for example the media data stream is corrupted and playback of
+the media has to be finished).
+
+\see \ref phonon_MediaObject_prefinishMarkReached
+*/
diff --git a/src/3rdparty/phonon/phonon/mediaobject.h b/src/3rdparty/phonon/phonon/mediaobject.h
new file mode 100644
index 0000000000..5cbddbbefd
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/mediaobject.h
@@ -0,0 +1,625 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+#ifndef Phonon_MEDIAOBJECT_H
+#define Phonon_MEDIAOBJECT_H
+
+#include "medianode.h"
+#include "mediasource.h"
+#include "phonon_export.h"
+#include "phonondefs.h"
+#include "phononnamespace.h"
+
+QT_BEGIN_HEADER
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+ class MediaObjectPrivate;
+
+ /** \class MediaObject mediaobject.h Phonon/MediaObject
+ * \short Interface for media playback of a given URL.
+ *
+ * This class is the most important class in %Phonon. Use it to open a media
+ * file at an arbitrary location, a CD or DVD or to stream media data from
+ * the application to the backend.
+ *
+ * This class controls the state (play, pause, stop, seek)
+ * and you can use it to get a lot of information about the media data.
+ *
+ * Notice that most functions of this class are asynchronous.
+ * That means if you call play() the object only starts playing when the
+ * stateChanged() signal tells you that the object changed into PlayingState.
+ * The states you can expect are documented for those methods.
+ *
+ * A common usage example is the following:
+ * \code
+ * media = new MediaObject(this);
+ * connect(media, SIGNAL(finished()), SLOT(slotFinished());
+ * media->setCurrentSource("/home/username/music/filename.ogg");
+ * media->play();
+ * \endcode
+ *
+ * If you want to play more that one media file (one after another) you can
+ * either tell MediaObject about all those files
+ * \code
+ * media->setCurrentSource(":/sounds/startsound.ogg");
+ * media->enqueue("/home/username/music/song.mp3");
+ * media->enqueue(":/sounds/endsound.ogg");
+ * \endcode
+ * or provide the next file just in time:
+ * \code
+ * media->setCurrentSource(":/sounds/startsound.ogg");
+ * connect(media, SIGNAL(aboutToFinish()), SLOT(enqueueNextSource()));
+ * }
+ *
+ * void enqueueNextSource()
+ * {
+ * media->enqueue("/home/username/music/song.mp3");
+ * }
+ * \endcode
+ *
+ * \ingroup Playback
+ * \ingroup Recording
+ * \author Matthias Kretz <kretz@kde.org>
+ */
+ class PHONON_EXPORT MediaObject : public QObject, public MediaNode
+ {
+ friend class FrontendInterfacePrivate;
+ Q_OBJECT
+ K_DECLARE_PRIVATE(MediaObject)
+ PHONON_OBJECT(MediaObject)
+ /**
+ * \brief Defines the time between media sources.
+ *
+ * A positive transition time defines a gap of silence between queued
+ * media sources.
+ *
+ * A transition time of 0 ms requests gapless playback (sample precise
+ * queueing of the next source).
+ *
+ * A negative transition time defines a crossfade between the queued
+ * media sources.
+ *
+ * Defaults to 0 (gapless playback).
+ *
+ * \warning This feature might not work reliably on every platform.
+ */
+ Q_PROPERTY(qint32 transitionTime READ transitionTime WRITE setTransitionTime)
+
+ /**
+ * \brief Get a signal before playback finishes.
+ *
+ * This property specifies the time in milliseconds the
+ * prefinishMarkReached signal is
+ * emitted before the playback finishes. A value of \c 0 disables the
+ * signal.
+ *
+ * Defaults to \c 0 (disabled).
+ *
+ * \warning For some media data the total time cannot be determined
+ * accurately, therefore the accuracy of the prefinishMarkReached signal
+ * can be bad sometimes. Still, it is better to use this method than to
+ * look at totalTime() and currentTime() to emulate the behaviour
+ * because the backend might have more information available than your
+ * application does through totalTime and currentTime.
+ *
+ * \see prefinishMarkReached
+ */
+ Q_PROPERTY(qint32 prefinishMark READ prefinishMark WRITE setPrefinishMark)
+
+ /**
+ * \brief The time interval in milliseconds between two ticks.
+ *
+ * The %tick interval is the time that elapses between the emission of two tick signals.
+ * If you set the interval to \c 0 the tick signal gets disabled.
+ *
+ * Defaults to \c 0 (disabled).
+ *
+ * \warning The back-end is free to choose a different tick interval close
+ * to what you asked for. This means that the following code \em may \em fail:
+ * \code
+ * int x = 200;
+ * media->setTickInterval(x);
+ * Q_ASSERT(x == producer->tickInterval());
+ * \endcode
+ * On the other hand the following is guaranteed:
+ * \code
+ * int x = 200;
+ * media->setTickInterval(x);
+ * Q_ASSERT(x >= producer->tickInterval() &&
+ * x <= 2 * producer->tickInterval());
+ * \endcode
+ *
+ * \see tick
+ */
+ Q_PROPERTY(qint32 tickInterval READ tickInterval WRITE setTickInterval)
+ public:
+ /**
+ * Destroys the MediaObject.
+ */
+ ~MediaObject();
+
+ /**
+ * Get the current state.
+ *
+ * @return The state of the object.
+ *
+ * @see State
+ * \see stateChanged
+ */
+ State state() const;
+
+ /**
+ * Check whether the media data includes a video stream.
+ *
+ * \warning This information cannot be known immediately. It is best
+ * to also listen to the hasVideoChanged signal.
+ *
+ * \code
+ * connect(media, SIGNAL(hasVideoChanged(bool)), hasVideoChanged(bool));
+ * media->setCurrentSource("somevideo.avi");
+ * media->hasVideo(); // returns false;
+ * }
+ *
+ * void hasVideoChanged(bool b)
+ * {
+ * // b == true
+ * media->hasVideo(); // returns true;
+ * }
+ * \endcode
+ *
+ * \return \c true if the media contains video data. \c false
+ * otherwise.
+ *
+ * \see hasVideoChanged
+ */
+ bool hasVideo() const;
+
+ /**
+ * Check whether the current media may be seeked.
+ *
+ * \warning This information cannot be known immediately. It is best
+ * to also listen to the hasVideoChanged signal.
+ *
+ * \code
+ * connect(media, SIGNAL(hasVideoChanged(bool)), hasVideoChanged(bool));
+ * media->setCurrentSource("somevideo.avi");
+ * media->hasVideo(); // returns false;
+ * }
+ *
+ * void hasVideoChanged(bool b)
+ * {
+ * // b == true
+ * media->hasVideo(); // returns true;
+ * }
+ * \endcode
+ *
+ * \return \c true when the current media may be seeked. \c false
+ * otherwise.
+ *
+ * \see seekableChanged()
+ */
+ bool isSeekable() const;
+
+ qint32 tickInterval() const;
+
+ /**
+ * Returns the strings associated with the given \p key.
+ *
+ * Backends should use the keys specified in the Ogg Vorbis
+ * documentation: http://xiph.org/vorbis/doc/v-comment.html
+ *
+ * Therefore the following should work with every backend:
+ *
+ * A typical usage looks like this:
+ * \code
+ * setMetaArtist (media->metaData("ARTIST" ));
+ * setMetaAlbum (media->metaData("ALBUM" ));
+ * setMetaTitle (media->metaData("TITLE" ));
+ * setMetaDate (media->metaData("DATE" ));
+ * setMetaGenre (media->metaData("GENRE" ));
+ * setMetaTrack (media->metaData("TRACKNUMBER"));
+ * setMetaComment(media->metaData("DESCRIPTION"));
+ * \endcode
+ *
+ * For Audio CDs you can query
+ * \code
+ * metaData("MUSICBRAINZ_DISCID");
+ * \endcode
+ * to get a DiscID hash that you can use with the MusicBrainz
+ * service:
+ * http://musicbrainz.org/doc/ClientHOWTO
+ */
+ QStringList metaData(const QString &key) const;
+
+ /**
+ * Returns the strings associated with the given \p key.
+ *
+ * Same as above except that the keys are defined in the
+ * Phonon::MetaData enum.
+ */
+ QStringList metaData(Phonon::MetaData key) const;
+
+ /**
+ * Returns all meta data.
+ */
+ QMultiMap<QString, QString> metaData() const;
+
+ /**
+ * Returns a human-readable description of the last error that occurred.
+ */
+ QString errorString() const;
+
+ /**
+ * Tells your program what to do about the error.
+ *
+ * \see Phonon::ErrorType
+ */
+ ErrorType errorType() const;
+
+ /**
+ * Returns the current media source.
+ *
+ * \see setCurrentSource
+ */
+ MediaSource currentSource() const;
+
+ /**
+ * Set the media source the MediaObject should use.
+ *
+ * \param source The MediaSource object to the media data. You can
+ * just as well use a QUrl or QString (for a local file) here.
+ * Setting an empty (invalid) source, will stop and remove the
+ * current source.
+ *
+ * \code
+ * QUrl url("http://www.example.com/music.ogg");
+ * media->setCurrentSource(url);
+ * \endcode
+ *
+ * \see currentSource
+ */
+ void setCurrentSource(const MediaSource &source);
+
+ /**
+ * Returns the queued media sources. This does list does not include
+ * the current source (returned by currentSource).
+ */
+ QList<MediaSource> queue() const;
+
+ /**
+ * Set the MediaSources to play when the current media has finished.
+ *
+ * This function will overwrite the current queue.
+ *
+ * \see clearQueue
+ * \see enqueue
+ */
+ void setQueue(const QList<MediaSource> &sources);
+
+ /**
+ * Set the MediaSources to play when the current media has finished.
+ *
+ * This function overwrites the current queue.
+ *
+ * \see clearQueue
+ * \see enqueue
+ */
+ void setQueue(const QList<QUrl> &urls);
+
+ /**
+ * Appends one source to the queue. Use this function to provide
+ * the next source just in time after the aboutToFinish signal was
+ * emitted.
+ *
+ * \see aboutToFinish
+ * \see setQueue
+ * \see clearQueue
+ */
+ void enqueue(const MediaSource &source);
+
+ /**
+ * Appends multiple sources to the queue.
+ *
+ * \see setQueue
+ * \see clearQueue
+ */
+ void enqueue(const QList<MediaSource> &sources);
+
+ /**
+ * Appends multiple sources to the queue.
+ *
+ * \see setQueue
+ * \see clearQueue
+ */
+ void enqueue(const QList<QUrl> &urls);
+
+ /**
+ * Clears the queue of sources.
+ */
+ void clearQueue();
+
+ /**
+ * Get the current time (in milliseconds) of the file currently being played.
+ *
+ * \return The current time in milliseconds.
+ *
+ * \see tick
+ */
+ qint64 currentTime() const;
+
+ /**
+ * Get the total time (in milliseconds) of the file currently being played.
+ *
+ * \return The total time in milliseconds.
+ *
+ * \see totalTimeChanged
+ */
+ qint64 totalTime() const;
+
+ /**
+ * Get the remaining time (in milliseconds) of the file currently being played.
+ *
+ * \return The remaining time in milliseconds.
+ */
+ qint64 remainingTime() const;
+
+ qint32 prefinishMark() const;
+ void setPrefinishMark(qint32 msecToEnd);
+
+ qint32 transitionTime() const;
+ void setTransitionTime(qint32 msec);
+
+ public Q_SLOTS:
+
+ void setTickInterval(qint32 newTickInterval);
+
+ /**
+ * Requests playback of the media data to start. Playback only
+ * starts when stateChanged() signals that it goes into PlayingState,
+ * though.
+ *
+ * \par Possible states right after this call:
+ * \li BufferingState
+ * \li PlayingState
+ * \li ErrorState
+ */
+ void play();
+
+ /**
+ * Requests playback to pause. If it was paused before nothing changes.
+ *
+ * \par Possible states right after this call:
+ * \li PlayingState
+ * \li PausedState
+ * \li ErrorState
+ */
+ void pause();
+
+ /**
+ * Requests playback to stop. If it was stopped before nothing changes.
+ *
+ * \par Possible states right after this call:
+ * \li the state it was in before (e.g. PlayingState)
+ * \li StoppedState
+ * \li ErrorState
+ */
+ void stop();
+
+ /**
+ * Requests a seek to the time indicated.
+ *
+ * You can only seek if state() == PlayingState, BufferingState or PausedState.
+ *
+ * The call is asynchronous, so currentTime can still be the old
+ * value right after this method was called. If all you need is a
+ * slider that shows the current position and allows the user to
+ * seek use the class SeekSlider.
+ *
+ * @param time The time in milliseconds where to continue playing.
+ *
+ * \par Possible states right after this call:
+ * \li BufferingState
+ * \li PlayingState
+ * \li ErrorState
+ *
+ * \see SeekSlider
+ */
+ void seek(qint64 time);
+
+ /**
+ * Stops and removes all playing and enqueued media sources.
+ *
+ * \see setCurrentSource
+ */
+ void clear();
+
+ Q_SIGNALS:
+ /**
+ * Emitted when the state of the MediaObject has changed.
+ * In case you're not interested in the old state you can also
+ * connect to a slot that only has one State argument.
+ *
+ * @param newstate The state the Player is in now.
+ * @param oldstate The state the Player was in before.
+ */
+ void stateChanged(Phonon::State newstate, Phonon::State oldstate);
+
+ /**
+ * This signal gets emitted every tickInterval milliseconds.
+ *
+ * @param time The position of the media file in milliseconds.
+ *
+ * @see setTickInterval, tickInterval
+ */
+ void tick(qint64 time);
+
+ /**
+ * This signal is emitted whenever the audio/video data that is
+ * being played is associated with new meta data. E.g. for radio
+ * streams this happens when the next song is played.
+ *
+ * You can get the new meta data with the metaData methods.
+ */
+ void metaDataChanged();
+
+ /**
+ * Emitted whenever the return value of isSeekable() changes.
+ *
+ * Normally you'll check isSeekable() first and then let this signal
+ * tell you whether seeking is possible now or not. That way you
+ * don't have to poll isSeekable().
+ *
+ * \param isSeekable \p true if the stream is seekable (i.e. calling
+ * seek() works)
+ * \p false if the stream is not seekable (i.e.
+ * all calls to seek() will be ignored)
+ */
+ void seekableChanged(bool isSeekable);
+
+ /**
+ * Emitted whenever the return value of hasVideo() changes.
+ *
+ * Normally you'll check hasVideo() first and then let this signal
+ * tell you whether video is available now or not. That way you
+ * don't have to poll hasVideo().
+ *
+ * \param hasVideo \p true The stream contains video and adding a
+ * VideoWidget will show a video.
+ * \p false There is no video data in the stream and
+ * adding a VideoWidget will show an empty (black)
+ * VideoWidget.
+ */
+#ifndef QT_NO_PHONON_VIDEO
+ void hasVideoChanged(bool hasVideo);
+#endif //QT_NO_PHONON_VIDEO
+
+ /**
+ * Tells about the status of the buffer.
+ *
+ * You can use this signal to show a progress bar to the user when
+ * in BufferingState:
+ *
+ * \code
+ * progressBar->setRange(0, 100); // this is the default
+ * connect(media, SIGNAL(bufferStatus(int)), progressBar, SLOT(setValue(int)));
+ * \endcode
+ *
+ * \param percentFilled A number between 0 and 100 telling you how
+ * much the buffer is filled.
+ */ // other names: bufferingProgress
+ void bufferStatus(int percentFilled);
+
+ /**
+ * Emitted when the object has finished playback.
+ * It is not emitted if you call stop(), pause() or
+ * load(), but only on end-of-queue or a critical error.
+ *
+ * \warning This signal is not emitted when the current source has
+ * finished and there's another source in the queue. It is only
+ * emitted when the queue is empty.
+ *
+ * \see currentSourceChanged
+ * \see aboutToFinish
+ * \see prefinishMarkReached
+ */
+ void finished();
+
+ /**
+ * Emitted when the MediaObject makes a transition to the next
+ * MediaSource in the queue().
+ *
+ * In other words, it is emitted when an individual MediaSource is
+ * finished.
+ *
+ * \param newSource The source that starts to play at the time the
+ * signal is emitted.
+ */
+ void currentSourceChanged(const Phonon::MediaSource &newSource);
+
+ /**
+ * Emitted before the playback of the whole queue stops. When this
+ * signal is emitted you still have time to provide the next
+ * MediaSource (using enqueue()) so that playback continues.
+ *
+ * This signal can be used to provide the next MediaSource just in
+ * time for the transition still to work.
+ *
+ * \see enqueue
+ */
+ void aboutToFinish();
+
+ /**
+ * Emitted when there are only \p msecToEnd milliseconds left
+ * for playback.
+ *
+ * \param msecToEnd The remaining time until the playback queue finishes.
+ *
+ * \warning This signal is not emitted when there is another source in the queue.
+ * It is only emitted when the queue is empty.
+ *
+ * \see setPrefinishMark
+ * \see prefinishMark
+ * \see aboutToFinish
+ * \see finished
+ */
+ void prefinishMarkReached(qint32 msecToEnd);
+
+ /**
+ * This signal is emitted as soon as the total time of the media file is
+ * known or has changed. For most non-local media data the total
+ * time of the media can only be known after some time. At that time the
+ * totalTime function can not return useful information. You have
+ * to wait for this signal to know the real total time.
+ *
+ * \param newTotalTime The length of the media file in milliseconds.
+ *
+ * \see totalTime
+ */
+ void totalTimeChanged(qint64 newTotalTime);
+
+ protected:
+ //MediaObject(Phonon::MediaObjectPrivate &dd, QObject *parent);
+
+ private:
+ Q_PRIVATE_SLOT(k_func(), void _k_resumePlay())
+ Q_PRIVATE_SLOT(k_func(), void _k_resumePause())
+ Q_PRIVATE_SLOT(k_func(), void _k_metaDataChanged(const QMultiMap<QString, QString> &))
+#ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ Q_PRIVATE_SLOT(k_func(), void _k_stateChanged(Phonon::State, Phonon::State))
+#endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ Q_PRIVATE_SLOT(k_func(), void _k_aboutToFinish())
+ Q_PRIVATE_SLOT(k_func(), void _k_currentSourceChanged(const MediaSource &))
+ };
+
+ /**
+ * Convenience function to create a MediaObject and AudioOutput connected by
+ * a path.
+ */
+ PHONON_EXPORT MediaObject *createPlayer(Phonon::Category category, const MediaSource &source = MediaSource());
+} //namespace Phonon
+
+QT_END_NAMESPACE
+QT_END_HEADER
+
+// vim: sw=4 ts=4 tw=80
+#endif // Phonon_MEDIAOBJECT_H
diff --git a/src/3rdparty/phonon/phonon/mediaobject_p.h b/src/3rdparty/phonon/phonon/mediaobject_p.h
new file mode 100644
index 0000000000..5419341806
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/mediaobject_p.h
@@ -0,0 +1,113 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006-2007 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef MEDIAOBJECT_P_H
+#define MEDIAOBJECT_P_H
+
+#include "mediaobject.h"
+#include "medianode_p.h"
+#include <QtCore/QString>
+#include "medianodedestructionhandler_p.h"
+#include "mediasource.h"
+#include <QtCore/QQueue>
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+class KioFallback;
+class KioFallbackImpl;
+class FrontendInterfacePrivate;
+
+class MediaObjectPrivate : public MediaNodePrivate, private MediaNodeDestructionHandler
+{
+ friend class KioFallbackImpl;
+ friend class AbstractMediaStream;
+ friend class AbstractMediaStreamPrivate;
+ Q_DECLARE_PUBLIC(MediaObject)
+ public:
+ virtual QObject *qObject() { return q_func(); }
+ QList<FrontendInterfacePrivate *> interfaceList;
+ protected:
+ virtual bool aboutToDeleteBackendObject();
+ virtual void createBackendObject();
+ virtual void phononObjectDestroyed(MediaNodePrivate *);
+ PHONON_EXPORT void setupBackendObject();
+
+ void _k_resumePlay();
+ void _k_resumePause();
+ void _k_metaDataChanged(const QMultiMap<QString, QString> &);
+ void _k_aboutToFinish();
+ void _k_currentSourceChanged(const MediaSource &);
+#ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ void streamError(Phonon::ErrorType, const QString &);
+ PHONON_EXPORT void _k_stateChanged(Phonon::State, Phonon::State);
+#endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
+
+ MediaObjectPrivate()
+ : currentTime(0),
+ tickInterval(0),
+ metaData(),
+ errorString(),
+ prefinishMark(0),
+ transitionTime(0), // gapless playback
+#ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ kiofallback(0),
+#endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ state(Phonon::LoadingState)
+#ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ , errorType(Phonon::NormalError),
+ errorOverride(false),
+ ignoreLoadingToBufferingStateChange(false),
+ ignoreErrorToLoadingStateChange(false)
+#endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ {
+ }
+
+ qint64 currentTime;
+ qint32 tickInterval;
+ QMultiMap<QString, QString> metaData;
+ QString errorString;
+ qint32 prefinishMark;
+ qint32 transitionTime;
+#ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ AbstractMediaStream *kiofallback;
+#endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ State state
+#ifdef QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ ;
+#else
+ : 8;
+ ErrorType errorType : 4;
+ bool errorOverride : 1;
+ bool ignoreLoadingToBufferingStateChange : 1;
+ bool ignoreErrorToLoadingStateChange : 1;
+#endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ MediaSource mediaSource;
+ QQueue<MediaSource> sourceQueue;
+};
+}
+
+QT_END_NAMESPACE
+
+#endif // MEDIAOBJECT_P_H
+// vim: sw=4 ts=4 tw=80
diff --git a/src/3rdparty/phonon/phonon/mediaobjectinterface.h b/src/3rdparty/phonon/phonon/mediaobjectinterface.h
new file mode 100644
index 0000000000..a5e2c513e1
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/mediaobjectinterface.h
@@ -0,0 +1,242 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006-2007 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef PHONON_MEDIAOBJECTINTERFACE_H
+#define PHONON_MEDIAOBJECTINTERFACE_H
+
+#include "mediaobject.h"
+#include <QtCore/QObject>
+
+QT_BEGIN_HEADER
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+class StreamInterface;
+
+/** \class MediaObjectInterface mediaobjectinterface.h Phonon/MediaObjectInterface
+ * \short Backend interface for media sources.
+ *
+ * The backend implementation has to provide two signals, that are not defined
+ * in this interface:
+ * <ul>
+ * <li>\anchor phonon_MediaObjectInterface_stateChanged
+ * <b>void stateChanged(\ref Phonon::State newstate, \ref Phonon::State oldstate)</b>
+ *
+ * Emitted when the state of the MediaObject has changed.
+ * In case you're not interested in the old state you can also
+ * connect to a slot that only has one State argument.
+ *
+ * \param newstate The state the Player is in now.
+ * \param oldstate The state the Player was in before.
+ * </li>
+ * <li>\anchor phonon_MediaObjectInterface_tick
+ * <b>void tick(qint64 time)</b>
+ *
+ * This signal gets emitted every tickInterval milliseconds.
+ *
+ * \param time The position of the media file in milliseconds.
+ *
+ * \see setTickInterval()
+ * \see tickInterval()
+ * </li>
+ * </ul>
+ *
+ * \author Matthias Kretz <kretz@kde.org>
+ * \see MediaObject
+ */
+class MediaObjectInterface
+{
+ public:
+ virtual ~MediaObjectInterface() {}
+
+ /**
+ * Requests the playback to start.
+ *
+ * This method is only called if the state transition to \ref PlayingState is possible.
+ *
+ * The backend should react immediately
+ * by either going into \ref PlayingState or \ref BufferingState if the
+ * former is not possible.
+ */
+ virtual void play() = 0;
+
+ /**
+ * Requests the playback to pause.
+ *
+ * This method is only called if the state transition to \ref PausedState is possible.
+ *
+ * The backend should react as fast as possible. Go to \ref PausedState
+ * as soon as playback is paused.
+ */
+ virtual void pause() = 0;
+
+ /**
+ * Requests the playback to be stopped.
+ *
+ * This method is only called if the state transition to \ref StoppedState is possible.
+ *
+ * The backend should react as fast as possible. Go to \ref StoppedState
+ * as soon as playback is stopped.
+ *
+ * A subsequent call to play() will start playback at the beginning of
+ * the media.
+ */
+ virtual void stop() = 0;
+
+ /**
+ * Requests the playback to be seeked to the given time.
+ *
+ * The backend does not have to finish seeking while in this function
+ * (i.e. the backend does not need to block the thread until the seek is
+ * finished; even worse it might lead to deadlocks when using a
+ * ByteStream which gets its data from the thread this function would
+ * block).
+ *
+ * As soon as the seek is done the currentTime() function and
+ * the tick() signal will report it.
+ *
+ * \param milliseconds The time where playback should seek to in
+ * milliseconds.
+ */
+ virtual void seek(qint64 milliseconds) = 0;
+
+ /**
+ * Return the time interval in milliseconds between two ticks.
+ *
+ * \returns Returns the tick interval that it was set to (might not
+ * be the same as you asked for).
+ */
+ virtual qint32 tickInterval() const = 0;
+ /**
+ * Change the interval the tick signal is emitted. If you set \p
+ * interval to 0 the signal gets disabled.
+ *
+ * \param interval tick interval in milliseconds
+ *
+ * \returns Returns the tick interval that it was set to (might not
+ * be the same as you asked for).
+ */
+ virtual void setTickInterval(qint32 interval) = 0;
+
+ /**
+ * Check whether the media data includes a video stream.
+ *
+ * \return returns \p true if the media contains video data
+ */
+ virtual bool hasVideo() const = 0;
+ /**
+ * If the current media may be seeked returns true.
+ *
+ * \returns whether the current media may be seeked.
+ */
+ virtual bool isSeekable() const = 0;
+ /**
+ * Get the current time (in milliseconds) of the file currently being played.
+ */
+ virtual qint64 currentTime() const = 0;
+ /**
+ * Get the current state.
+ */
+ virtual Phonon::State state() const = 0;
+
+ /**
+ * A translated string describing the error.
+ */
+ virtual QString errorString() const = 0;
+
+ /**
+ * Tells your program what to do about the error.
+ *
+ * \see Phonon::ErrorType
+ */
+ virtual Phonon::ErrorType errorType() const = 0;
+
+ /**
+ * Returns the total time of the media in milliseconds.
+ *
+ * If the total time is not know return -1. Do not block until it is
+ * known, instead emit the totalTimeChanged signal as soon as the total
+ * time is known or changes.
+ */
+ virtual qint64 totalTime() const = 0;
+
+ /**
+ * Returns the current source.
+ */
+ virtual MediaSource source() const = 0;
+
+ /**
+ * Sets the current source. When this function is called the MediaObject is
+ * expected to stop all current activity and start loading the new
+ * source (i.e. go into LoadingState).
+ *
+ * It is expected that the
+ * backend now starts preloading the media data, filling the audio
+ * and video buffers and making all media meta data available. It
+ * will also trigger the totalTimeChanged signal.
+ *
+ * If the backend does not know how to handle the source it needs to
+ * change state to Phonon::ErrorState. Don't bother about handling KIO
+ * URLs. It is enough to handle AbstractMediaStream sources correctly.
+ *
+ * \warning Keep the MediaSource object around as long as the backend
+ * uses the AbstractMediaStream returned by the MediaSource. In case
+ * that no other reference to the MediaSource exists and it is set to
+ * MediaSource::autoDelete, the AbstractMediaStream is deleted when the
+ * last MediaSource ref is deleted.
+ */
+ virtual void setSource(const MediaSource &) = 0;
+
+ /**
+ * Sets the next source to be used for transitions. When a next source
+ * is set playback should continue with the new source. In that case
+ * finished and prefinishMarkReached are not emitted.
+ *
+ * \param source The source to transition to (crossfade/gapless/gap). If
+ * \p source is an invalid MediaSource object then the queue is empty
+ * and the playback should stop normally.
+ *
+ * \warning Keep the MediaSource object around as long as the backend
+ * uses the AbstractMediaStream returned by the MediaSource. In case
+ * that no other reference to the MediaSource exists and it is set to
+ * MediaSource::autoDelete, the AbstractMediaStream is deleted when the
+ * last MediaSource ref is deleted.
+ */
+ virtual void setNextSource(const MediaSource &source) = 0;
+
+ virtual qint64 remainingTime() const { return totalTime() - currentTime(); }
+ virtual qint32 prefinishMark() const = 0;
+ virtual void setPrefinishMark(qint32) = 0;
+
+ virtual qint32 transitionTime() const = 0;
+ virtual void setTransitionTime(qint32) = 0;
+};
+}
+
+Q_DECLARE_INTERFACE(Phonon::MediaObjectInterface, "MediaObjectInterface3.phonon.kde.org")
+
+QT_END_NAMESPACE
+QT_END_HEADER
+
+#endif // PHONON_MEDIAOBJECTINTERFACE_H
+// vim: sw=4 ts=4 tw=80
diff --git a/src/3rdparty/phonon/phonon/mediasource.cpp b/src/3rdparty/phonon/phonon/mediasource.cpp
new file mode 100644
index 0000000000..0a21c87664
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/mediasource.cpp
@@ -0,0 +1,232 @@
+/* This file is part of the KDE project
+ Copyright (C) 2007 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "mediasource.h"
+#include "mediasource_p.h"
+#include "iodevicestream_p.h"
+#include "abstractmediastream_p.h"
+
+#include <QtCore/QFileInfo>
+#include <QtCore/QFile>
+#include <QtCore/QFSFileEngine>
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+
+MediaSource::MediaSource(MediaSourcePrivate &dd)
+ : d(&dd)
+{
+}
+
+MediaSource::MediaSource()
+ : d(new MediaSourcePrivate(Empty))
+{
+}
+
+MediaSource::MediaSource(const QString &filename)
+ : d(new MediaSourcePrivate(LocalFile))
+{
+ const QFileInfo fileInfo(filename);
+ if (fileInfo.exists()) {
+ bool localFs = QAbstractFileEngine::LocalDiskFlag & QFSFileEngine(filename).fileFlags(QAbstractFileEngine::LocalDiskFlag);
+ if (localFs) {
+ d->url = QUrl::fromLocalFile(fileInfo.absoluteFilePath());
+ } else {
+#ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ // it's a Qt resource -> use QFile
+ d->type = Stream;
+ d->ioDevice = new QFile(filename);
+ d->setStream(new IODeviceStream(d->ioDevice, d->ioDevice));
+#else
+ d->type = Invalid;
+#endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ }
+ } else {
+ d->url = filename;
+ if (d->url.isValid()) {
+ d->type = Url;
+ } else {
+ d->type = Invalid;
+ }
+ }
+}
+
+MediaSource::MediaSource(const QUrl &url)
+ : d(new MediaSourcePrivate(Url))
+{
+ if (url.isValid()) {
+ d->url = url;
+ } else {
+ d->type = Invalid;
+ }
+}
+
+MediaSource::MediaSource(Phonon::DiscType dt, const QString &deviceName)
+ : d(new MediaSourcePrivate(Disc))
+{
+ if (dt == NoDisc) {
+ d->type = Invalid;
+ return;
+ }
+ d->discType = dt;
+ d->deviceName = deviceName;
+}
+
+#ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
+MediaSource::MediaSource(AbstractMediaStream *stream)
+ : d(new MediaSourcePrivate(Stream))
+{
+ if (stream) {
+ d->setStream(stream);
+ } else {
+ d->type = Invalid;
+ }
+}
+
+MediaSource::MediaSource(QIODevice *ioDevice)
+ : d(new MediaSourcePrivate(Stream))
+{
+ if (ioDevice) {
+ d->setStream(new IODeviceStream(ioDevice, ioDevice));
+ d->ioDevice = ioDevice;
+ } else {
+ d->type = Invalid;
+ }
+}
+#endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
+
+/* post 4.0
+MediaSource::MediaSource(const QList<MediaSource> &mediaList)
+ : d(new MediaSourcePrivate(Link))
+{
+ d->linkedSources = mediaList;
+ foreach (MediaSource ms, mediaList) {
+ Q_ASSERT(ms.type() != Link);
+ }
+}
+
+QList<MediaSource> MediaSource::substreams() const
+{
+ return d->linkedSources;
+}
+*/
+
+MediaSource::~MediaSource()
+{
+}
+
+MediaSourcePrivate::~MediaSourcePrivate()
+{
+#ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ if (autoDelete) {
+ delete stream;
+ delete ioDevice;
+ }
+#endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
+}
+
+MediaSource::MediaSource(const MediaSource &rhs)
+ : d(rhs.d)
+{
+}
+
+MediaSource &MediaSource::operator=(const MediaSource &rhs)
+{
+ d = rhs.d;
+ return *this;
+}
+
+bool MediaSource::operator==(const MediaSource &rhs) const
+{
+ return d == rhs.d;
+}
+
+void MediaSource::setAutoDelete(bool autoDelete)
+{
+ d->autoDelete = autoDelete;
+}
+
+bool MediaSource::autoDelete() const
+{
+ return d->autoDelete;
+}
+
+MediaSource::Type MediaSource::type() const
+{
+#ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ if (d->type == Stream && d->stream == 0) {
+ return Invalid;
+ }
+#endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ return d->type;
+}
+
+QString MediaSource::fileName() const
+{
+ return d->url.toLocalFile();
+}
+
+QUrl MediaSource::url() const
+{
+ return d->url;
+}
+
+Phonon::DiscType MediaSource::discType() const
+{
+ return d->discType;
+}
+
+QString MediaSource::deviceName() const
+{
+ return d->deviceName;
+}
+
+#ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
+AbstractMediaStream *MediaSource::stream() const
+{
+ return d->stream;
+}
+
+void MediaSourcePrivate::setStream(AbstractMediaStream *s)
+{
+ stream = s;
+}
+#endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
+
+
+//X AudioCaptureDevice MediaSource::audioCaptureDevice() const
+//X {
+//X return d->audioCaptureDevice;
+//X }
+//X
+//X VideoCaptureDevice MediaSource::videoCaptureDevice() const
+//X {
+//X return d->videoCaptureDevice;
+//X }
+
+} // namespace Phonon
+
+QT_END_NAMESPACE
+
+// vim: sw=4 sts=4 et tw=100
diff --git a/src/3rdparty/phonon/phonon/mediasource.h b/src/3rdparty/phonon/phonon/mediasource.h
new file mode 100644
index 0000000000..da010d9e96
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/mediasource.h
@@ -0,0 +1,279 @@
+/* This file is part of the KDE project
+ Copyright (C) 2007 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef PHONON_MEDIASOURCE_H
+#define PHONON_MEDIASOURCE_H
+
+#include "phonon_export.h"
+#include "phononnamespace.h"
+#include "objectdescription.h"
+#include <QtCore/QSharedData>
+#include <QtCore/QString>
+
+QT_BEGIN_HEADER
+QT_BEGIN_NAMESPACE
+
+class QUrl;
+class QIODevice;
+
+namespace Phonon
+{
+
+class MediaSourcePrivate;
+class AbstractMediaStream;
+
+/** \class MediaSource mediasource.h Phonon/MediaSource
+ * Note that all constructors of this class are implicit, so that you can simply write
+ * \code
+ * MediaObject m;
+ * QString fileName("/home/foo/bar.ogg");
+ * QUrl url("http://www.example.com/stream.mp3");
+ * QBuffer *someBuffer;
+ * m.setCurrentSource(fileName);
+ * m.setCurrentSource(url);
+ * m.setCurrentSource(someBuffer);
+ * m.setCurrentSource(Phonon::Cd);
+ * \endcode
+ *
+ * \ingroup Playback
+ * \ingroup Recording
+ * \author Matthias Kretz <kretz@kde.org>
+ */
+class PHONON_EXPORT MediaSource
+{
+ friend class StreamInterface;
+ public:
+ /**
+ * Identifies the type of media described by the MediaSource object.
+ *
+ * \see MediaSource::type()
+ */
+ enum Type {
+ /**
+ * The MediaSource object does not describe any valid source.
+ */
+ Invalid = -1,
+ /**
+ * The MediaSource object describes a local file.
+ */
+ LocalFile,
+ /**
+ * The MediaSource object describes a URL, which can be both a local file and a file on
+ * the network.
+ */
+ Url,
+ /**
+ * The MediaSource object describes a disc.
+ */
+ Disc,
+ /**
+ * The MediaSource object describes a data stream.
+ *
+ * This is also the type used for QIODevices.
+ *
+ * \see AbstractMediaStream
+ */
+ Stream,
+ /**
+ * An empty MediaSource.
+ *
+ * It can be used to unload the current media from a MediaObject.
+ *
+ * \see MediaSource()
+ */
+ Empty
+/* post 4.0:
+ / **
+ * Links multiple MediaSource objects together.
+ * /
+ Link
+*/
+ };
+
+ /**
+ * Creates an empty MediaSource.
+ *
+ * An empty MediaSource is considered valid and can be set on a MediaObject to unload its
+ * current media.
+ *
+ * \see Empty
+ */
+ MediaSource();
+
+ /**
+ * Creates a MediaSource object for a local file or a Qt resource.
+ *
+ * \param fileName file name of a local media file or a Qt resource that was compiled in.
+ */
+ MediaSource(const QString &fileName); //krazy:exclude=explicit
+
+ /**
+ * Creates a MediaSource object for a URL.
+ *
+ * \param url URL to a media file or stream.
+ */
+ MediaSource(const QUrl &url); //krazy:exclude=explicit
+
+ /**
+ * Creates a MediaSource object for discs.
+ *
+ * \param discType See \ref DiscType
+ * \param deviceName A platform dependent device name. This can be useful if the computer
+ * has more than one CD drive. It is recommended to use Solid to retrieve the device name in
+ * a portable way.
+ */
+ MediaSource(Phonon::DiscType discType, const QString &deviceName = QString()); //krazy:exclude=explicit
+
+#ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ /**
+ * Creates a MediaSource object for a data stream.
+ *
+ * Your application can provide the media data by subclassing AbstractMediaStream and
+ * passing a pointer to that object. %Phonon will never delete the \p stream.
+ *
+ * \param stream The AbstractMediaStream subclass to provide the media data.
+ *
+ * \see setAutoDelete
+ */
+ MediaSource(AbstractMediaStream *stream); //krazy:exclude=explicit
+
+ /**
+ * Creates a MediaSource object for a QIODevice.
+ *
+ * This constructor can be very handy in the combination of QByteArray and QBuffer.
+ *
+ * \param ioDevice An arbitrary readable QIODevice subclass. If the device is not opened
+ * MediaSource will open it as QIODevice::ReadOnly. Sequential I/O devices are possible,
+ * too. For those MediaObject::isSeekable() will have to return false obviously.
+ *
+ * \see setAutoDelete
+ */
+ MediaSource(QIODevice *ioDevice); //krazy:exclude=explicit
+#endif
+
+ /**
+ * Creates a MediaSource object for capture devices.
+ */
+ //MediaSource(const AudioCaptureDevice &, const VideoCaptureDevice &);
+
+ /**
+ * Destroys the MediaSource object.
+ */
+ ~MediaSource();
+
+ /**
+ * Constructs a copy of \p rhs.
+ *
+ * This constructor is fast thanks to explicit sharing.
+ */
+ MediaSource(const MediaSource &rhs);
+
+ /**
+ * Assigns \p rhs to this MediaSource and returns a reference to this MediaSource.
+ *
+ * This operation is fast thanks to explicit sharing.
+ */
+ MediaSource &operator=(const MediaSource &rhs);
+
+ /**
+ * Returns \p true if this MediaSource is equal to \p rhs; otherwise returns \p false.
+ */
+ bool operator==(const MediaSource &rhs) const;
+
+ /**
+ * Tell the MediaSource to take ownership of the AbstractMediaStream or QIODevice that was
+ * passed in the constructor.
+ *
+ * The default setting is \p false, for safety. If you turn it on, you should only access
+ * the AbstractMediaStream/QIODevice object as long as you yourself keep a MediaSource
+ * object around. As long as you keep the MediaSource object wrapping the stream/device
+ * the object will not get deleted.
+ *
+ * \see autoDelete
+ */
+ void setAutoDelete(bool enable);
+
+ /**
+ * Returns the setting of the auto-delete option. The default is \p false.
+ *
+ * \see setAutoDelete
+ */
+ bool autoDelete() const;
+
+ /**
+ * Returns the type of the MediaSource (depends on the constructor that was used).
+ *
+ * \see Type
+ */
+ Type type() const;
+
+ /**
+ * Returns the file name of the MediaSource if type() == LocalFile; otherwise returns
+ * QString().
+ */
+ QString fileName() const;
+
+ /**
+ * Returns the url of the MediaSource if type() == URL or type() == LocalFile; otherwise
+ * returns QUrl().
+ */
+ QUrl url() const;
+
+ /**
+ * Returns the disc type of the MediaSource if type() == Disc; otherwise returns \ref
+ * NoDisc.
+ */
+ Phonon::DiscType discType() const;
+
+ /**
+ * Returns the device name of the MediaSource if type() == Disc; otherwise returns
+ * QString().
+ */
+ QString deviceName() const;
+
+#ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ /**
+ * Returns the media stream of the MediaSource if type() == Stream; otherwise returns 0.
+ * QIODevices are handled as streams, too.
+ */
+ AbstractMediaStream *stream() const;
+#endif
+
+ //AudioCaptureDevice audioCaptureDevice() const;
+ //VideoCaptureDevice videoCaptureDevice() const;
+
+/* post 4.0:
+ MediaSource(const QList<MediaSource> &mediaList);
+ QList<MediaSource> substreams() const;
+*/
+
+ protected:
+ QExplicitlySharedDataPointer<MediaSourcePrivate> d;
+ MediaSource(MediaSourcePrivate &);
+};
+
+} // namespace Phonon
+
+QT_END_NAMESPACE
+QT_END_HEADER
+
+#endif // PHONON_MEDIASOURCE_H
diff --git a/src/3rdparty/phonon/phonon/mediasource_p.h b/src/3rdparty/phonon/phonon/mediasource_p.h
new file mode 100644
index 0000000000..bfac7ad964
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/mediasource_p.h
@@ -0,0 +1,89 @@
+/* This file is part of the KDE project
+ Copyright (C) 2007 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef MEDIASOURCE_P_H
+#define MEDIASOURCE_P_H
+
+#include "mediasource.h"
+#include "objectdescription.h"
+#include "abstractmediastream.h"
+
+#include <QtCore/QUrl>
+#include <QtCore/QString>
+#include <QtCore/QSharedData>
+#include <QtCore/QPointer>
+
+QT_BEGIN_NAMESPACE
+
+class QFile;
+
+namespace Phonon
+{
+
+class PHONON_EXPORT MediaSourcePrivate : public QSharedData
+{
+ public:
+ MediaSourcePrivate(MediaSource::Type t)
+ : type(t), discType(NoDisc),
+#ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ stream(0),
+ ioDevice(0),
+#endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ autoDelete(false)
+ {
+ }
+
+ virtual ~MediaSourcePrivate();
+
+#ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ void setStream(AbstractMediaStream *s);
+#endif
+
+ MediaSource::Type type;
+ QUrl url;
+ Phonon::DiscType discType;
+ QString deviceName;
+
+#ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ // The AbstractMediaStream(2) may be deleted at any time by the application. If that happens
+ // stream will be 0 automatically, but streamEventQueue will stay valid as we hold a
+ // reference to it. This is necessary to avoid a races when setting the MediaSource while
+ // another thread deletes the AbstractMediaStream2. StreamInterface(2) will then just get a
+ // StreamEventQueue where nobody answers.
+ QPointer<AbstractMediaStream> stream;
+
+// AudioCaptureDevice audioCaptureDevice;
+// VideoCaptureDevice videoCaptureDevice;
+ QIODevice *ioDevice;
+#endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
+ //QList<MediaSource> linkedSources;
+ bool autoDelete;
+};
+
+} // namespace Phonon
+
+QT_END_NAMESPACE
+
+#endif // MEDIASOURCE_P_H
+// vim: sw=4 sts=4 et tw=100
+
+
diff --git a/src/3rdparty/phonon/phonon/objectdescription.cpp b/src/3rdparty/phonon/phonon/objectdescription.cpp
new file mode 100644
index 0000000000..32967925aa
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/objectdescription.cpp
@@ -0,0 +1,140 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006-2008 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "objectdescription.h"
+#include "objectdescription_p.h"
+
+#include <QtCore/QObject>
+#include <QtCore/QSet>
+#include "factory_p.h"
+#include <QtCore/QStringList>
+#include "backendinterface.h"
+#include "platformplugin.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+
+ObjectDescriptionData::ObjectDescriptionData(int index, const QHash<QByteArray, QVariant> &properties)
+ : d(new ObjectDescriptionPrivate(index, properties))
+{
+}
+
+ObjectDescriptionData::ObjectDescriptionData(ObjectDescriptionPrivate *dd)
+ : d(dd)
+{
+}
+
+ObjectDescriptionData::~ObjectDescriptionData()
+{
+ delete d;
+}
+
+bool ObjectDescriptionData::operator==(const ObjectDescriptionData &otherDescription) const
+{
+ if (!isValid()) {
+ return !otherDescription.isValid();
+ }
+ if (!otherDescription.isValid()) {
+ return false;
+ }
+ return *d == *otherDescription.d;
+}
+
+int ObjectDescriptionData::index() const
+{
+ if (!isValid()) {
+ return -1;
+ }
+ return d->index;
+}
+
+QString ObjectDescriptionData::name() const
+{
+ if (!isValid()) {
+ return QString();
+ }
+ return d->name;
+}
+
+QString ObjectDescriptionData::description() const
+{
+ if (!isValid()) {
+ return QString();
+ }
+ return d->description;
+}
+
+QVariant ObjectDescriptionData::property(const char *name) const
+{
+ if (!isValid()) {
+ return QVariant();
+ }
+ return d->properties.value(name);
+}
+
+QList<QByteArray> ObjectDescriptionData::propertyNames() const
+{
+ if (!isValid()) {
+ return QList<QByteArray>();
+ }
+ return d->properties.keys();
+}
+
+bool ObjectDescriptionData::isValid() const
+{
+ return d != 0;
+}
+
+ObjectDescriptionData *ObjectDescriptionData::fromIndex(ObjectDescriptionType type, int index)
+{
+ // prefer to get the ObjectDescriptionData from the platform plugin for audio devices
+#ifndef QT_NO_PHONON_PLATFORMPLUGIN
+ if (type == AudioOutputDeviceType || type == AudioCaptureDeviceType) {
+ PlatformPlugin *platformPlugin = Factory::platformPlugin();
+ if (platformPlugin) {
+ QList<int> indexes = platformPlugin->objectDescriptionIndexes(type);
+ if (indexes.contains(index)) {
+ QHash<QByteArray, QVariant> properties = platformPlugin->objectDescriptionProperties(type, index);
+ return new ObjectDescriptionData(index, properties);
+ }
+ }
+ }
+#endif //QT_NO_PHONON_PLATFORMPLUGIN
+
+ QObject *b = Factory::backend();
+ BackendInterface *iface = qobject_cast<BackendInterface *>(b);
+ if (iface) {
+ QList<int> indexes = iface->objectDescriptionIndexes(type);
+ if (indexes.contains(index)) {
+ QHash<QByteArray, QVariant> properties = iface->objectDescriptionProperties(type, index);
+ return new ObjectDescriptionData(index, properties);
+ }
+ }
+ return new ObjectDescriptionData(0); // invalid
+}
+
+} //namespace Phonon
+
+QT_END_NAMESPACE
+// vim: sw=4 ts=4
diff --git a/src/3rdparty/phonon/phonon/objectdescription.h b/src/3rdparty/phonon/phonon/objectdescription.h
new file mode 100644
index 0000000000..108f02c9fa
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/objectdescription.h
@@ -0,0 +1,342 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006-2007 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef PHONON_OBJECTDESCRIPTION_H
+#define PHONON_OBJECTDESCRIPTION_H
+
+#include "phonon_export.h"
+
+#include <QtCore/QExplicitlySharedDataPointer>
+#include <QtCore/QtDebug>
+#include <QtCore/QList>
+#include <QtCore/QSharedData>
+#include <QtCore/QString>
+#include <QtCore/QVariant>
+
+QT_BEGIN_HEADER
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+ class ObjectDescriptionPrivate;
+
+ /**
+ * Defines the type of information that is contained in a ObjectDescription
+ * object.
+ *
+ * \ingroup Backend
+ */
+ enum ObjectDescriptionType
+ {
+ /**
+ * Audio output devices. This can be soundcards (with different drivers), soundservers or
+ * other virtual outputs like playback on a different computer on the
+ * network.
+ *
+ * For Hardware devices the backend should use libkaudiodevicelist
+ * (AudioDevice and AudioDeviceEnumerator) which will list removable
+ * devices even when they are unplugged and provide a unique identifier
+ * that can make backends use the same identifiers.
+ */
+ AudioOutputDeviceType,
+
+ /**
+ * Lists all processing effects the backend supports.
+ */
+ EffectType,
+ AudioChannelType,
+ SubtitleType,
+
+ /**
+ * Audio capture devices. This can be soundcards (with different drivers), soundservers or
+ * other virtual inputs like capture on a different computer on the
+ * network.
+ *
+ * For Hardware devices the backend should use libkaudiodevicelist
+ * (AudioDevice and AudioDeviceEnumerator) which will list removable
+ * devices even when they are unplugged and provide a unique identifier
+ * that can make backends use the same identifiers.
+ */
+ AudioCaptureDeviceType
+
+ //VideoOutputDeviceType,
+ //VideoCaptureDeviceType,
+ //AudioCodecType,
+ //VideoCodecType,
+ //ContainerFormatType,
+ //VisualizationType,
+ };
+
+/** \internal
+ * \class ObjectDescriptionData objectdescription.h Phonon/ObjectDescription
+ * \brief Data class for objects describing devices or features of the backend.
+ *
+ * \author Matthias Kretz <kretz@kde.org>
+ * \see BackendCapabilities
+ */
+class PHONON_EXPORT ObjectDescriptionData : public QSharedData //krazy:exclude=dpointer (it's protected, which should be fine for this type of class)
+{
+ public:
+ /**
+ * Returns \c true if this ObjectDescription describes the same
+ * as \p otherDescription; otherwise returns \c false.
+ */
+ bool operator==(const ObjectDescriptionData &otherDescription) const;
+
+ /**
+ * Returns the name of the capture source.
+ *
+ * \return A string that should be presented to the user to
+ * choose the capture source.
+ */
+ QString name() const;
+
+ /**
+ * Returns a description of the capture source. This text should
+ * make clear what sound source this is, which is sometimes hard
+ * to describe or understand from just the name.
+ *
+ * \return A string describing the capture source.
+ */
+ QString description() const;
+
+ /**
+ * Returns a named property.
+ *
+ * If the property is not set an invalid value is returned.
+ *
+ * \see propertyNames()
+ */
+ QVariant property(const char *name) const;
+
+ /**
+ * Returns all names that return valid data when property() is called.
+ *
+ * \see property()
+ */
+ QList<QByteArray> propertyNames() const;
+
+ /**
+ * Returns \c true if the Tuple is valid (index != -1); otherwise returns
+ * \c false.
+ */
+ bool isValid() const;
+
+ /**
+ * A unique identifier for this device/. Used internally
+ * to distinguish between the devices/.
+ *
+ * \return An integer that uniquely identifies every device/
+ */
+ int index() const;
+
+ static ObjectDescriptionData *fromIndex(ObjectDescriptionType type, int index);
+
+ ~ObjectDescriptionData();
+
+ ObjectDescriptionData(ObjectDescriptionPrivate * = 0);
+ ObjectDescriptionData(int index, const QHash<QByteArray, QVariant> &properties);
+
+ protected:
+ ObjectDescriptionPrivate *const d;
+
+ private:
+ ObjectDescriptionData &operator=(const ObjectDescriptionData &rhs);
+};
+
+template<ObjectDescriptionType T> class ObjectDescriptionModel;
+
+/** \class ObjectDescription objectdescription.h Phonon/ObjectDescription
+ * \short Provides a tuple of enduser visible name and description.
+ *
+ * Some parts give the enduser choices, e.g. what source to capture audio from.
+ * These choices are described by the name and description methods of this class
+ * and identified with the id method. Subclasses then define additional
+ * information like which audio and video choices belong together.
+ *
+ * \ingroup Frontend
+ * \author Matthias Kretz <kretz@kde.org>
+ */
+template<ObjectDescriptionType T>
+class ObjectDescription
+{
+ public:
+ /**
+ * Returns a new description object that describes the
+ * device/effect/codec/... with the given \p index.
+ */
+ static inline ObjectDescription<T> fromIndex(int index) { //krazy:exclude=inline
+ return ObjectDescription<T>(QExplicitlySharedDataPointer<ObjectDescriptionData>(ObjectDescriptionData::fromIndex(T, index)));
+ }
+
+ /**
+ * Returns \c true if this ObjectDescription describes the same
+ * as \p otherDescription; otherwise returns \c false.
+ */
+ inline bool operator==(const ObjectDescription &otherDescription) const { //krazy:exclude=inline
+ return *d == *otherDescription.d;
+ }
+
+ /**
+ * Returns \c false if this ObjectDescription describes the same
+ * as \p otherDescription; otherwise returns \c true.
+ */
+ inline bool operator!=(const ObjectDescription &otherDescription) const { //krazy:exclude=inline
+ return !operator==(otherDescription);
+ }
+
+ /**
+ * Returns the name of the capture source.
+ *
+ * \return A string that should be presented to the user to
+ * choose the capture source.
+ */
+ inline QString name() const { return d->name(); } //krazy:exclude=inline
+
+ /**
+ * Returns a description of the capture source. This text should
+ * make clear what sound source this is, which is sometimes hard
+ * to describe or understand from just the name.
+ *
+ * \return A string describing the capture source.
+ */
+ inline QString description() const { return d->description(); } //krazy:exclude=inline
+
+ /**
+ * Returns a named property.
+ *
+ * If the property is not set an invalid value is returned.
+ *
+ * \see propertyNames()
+ */
+ inline QVariant property(const char *name) const { return d->property(name); } //krazy:exclude=inline
+
+ /**
+ * Returns all names that return valid data when property() is called.
+ *
+ * \see property()
+ */
+ inline QList<QByteArray> propertyNames() const { return d->propertyNames(); } //krazy:exclude=inline
+
+ /**
+ * Returns \c true if the Tuple is valid (index != -1); otherwise returns
+ * \c false.
+ */
+ inline bool isValid() const { return d->isValid(); } //krazy:exclude=inline
+
+ /**
+ * A unique identifier for this device/. Used internally
+ * to distinguish between the devices/.
+ *
+ * \return An integer that uniquely identifies every device/
+ */
+ inline int index() const { return d->index(); } //krazy:exclude=inline
+
+ ObjectDescription() : d(new ObjectDescriptionData(0)) {}
+ ObjectDescription(int index, const QHash<QByteArray, QVariant> &properties) : d(new ObjectDescriptionData(index, properties)) {}
+
+ protected:
+ friend class ObjectDescriptionModel<T>;
+ ObjectDescription(const QExplicitlySharedDataPointer<ObjectDescriptionData> &dd) : d(dd) {}
+ QExplicitlySharedDataPointer<ObjectDescriptionData> d;
+};
+
+template<ObjectDescriptionType T>
+inline QDebug operator<<(QDebug s, const ObjectDescription<T> &o) //krazy:exclude=inline
+{
+ return s << o.name();
+}
+
+/**
+ * \ingroup BackendInformation
+ */
+typedef ObjectDescription<AudioOutputDeviceType> AudioOutputDevice;
+/**
+ * \ingroup BackendInformation
+ */
+#ifndef QT_NO_PHONON_AUDIOCAPTURE
+typedef ObjectDescription<AudioCaptureDeviceType> AudioCaptureDevice;
+#endif //QT_NO_PHONON_AUDIOCAPTURE
+/**
+ * \ingroup BackendInformation
+ */
+//typedef ObjectDescription<VideoOutputDeviceType> VideoOutputDevice;
+/**
+ * \ingroup BackendInformation
+ */
+//typedef ObjectDescription<VideoCaptureDeviceType> VideoCaptureDevice;
+/**
+ * \ingroup BackendInformation
+ */
+#ifndef QT_NO_PHONON_EFFECT
+typedef ObjectDescription<EffectType> EffectDescription;
+#endif //QT_NO_PHONON_EFFECT
+
+/**
+ * \ingroup BackendInformation
+ */
+//typedef ObjectDescription<AudioCodecType> AudioCodecDescription;
+/**
+ * \ingroup BackendInformation
+ */
+//typedef ObjectDescription<VideoCodecType> VideoCodecDescription;
+/**
+ * \ingroup BackendInformation
+ */
+//typedef ObjectDescription<ContainerFormatType> ContainerFormatDescription;
+/**
+ * \ingroup BackendInformation
+ */
+//typedef ObjectDescription<VisualizationType> VisualizationDescription;
+#ifndef QT_NO_PHONON_MEDIACONTROLLER
+typedef ObjectDescription<AudioChannelType> AudioChannelDescription;
+typedef ObjectDescription<SubtitleType> SubtitleDescription;
+#endif //QT_NO_PHONON_MEDIACONTROLLER
+
+} //namespace Phonon
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(Phonon::AudioOutputDevice)
+Q_DECLARE_METATYPE(QList<Phonon::AudioOutputDevice>)
+
+#ifndef QT_NO_PHONON_AUDIOCAPTURE
+Q_DECLARE_METATYPE(Phonon::AudioCaptureDevice)
+Q_DECLARE_METATYPE(QList<Phonon::AudioCaptureDevice>)
+#endif //QT_NO_PHONON_AUDIOCAPTURE
+
+#ifndef QT_NO_PHONON_EFFECT
+Q_DECLARE_METATYPE(QList<Phonon::EffectDescription>)
+Q_DECLARE_METATYPE(Phonon::EffectDescription)
+#endif //QT_NO_PHONON_EFFECT
+
+
+#ifndef QT_NO_PHONON_MEDIACONTROLLER
+Q_DECLARE_METATYPE(Phonon::AudioChannelDescription)
+Q_DECLARE_METATYPE(Phonon::SubtitleDescription)
+Q_DECLARE_METATYPE(QList<Phonon::AudioChannelDescription>)
+Q_DECLARE_METATYPE(QList<Phonon::SubtitleDescription>)
+#endif //QT_NO_PHONON_MEDIACONTROLLER
+
+QT_END_HEADER
+
+#endif // PHONON_OBJECTDESCRIPTION_H
diff --git a/src/3rdparty/phonon/phonon/objectdescription_p.h b/src/3rdparty/phonon/phonon/objectdescription_p.h
new file mode 100644
index 0000000000..1069f11a86
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/objectdescription_p.h
@@ -0,0 +1,64 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006-2007 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef PHONON_OBJECTDESCRIPTION_P_H
+#define PHONON_OBJECTDESCRIPTION_P_H
+
+#include <QtCore/QByteRef>
+#include <QtCore/QHash>
+#include <QtCore/QString>
+#include <QtCore/QVariant>
+#include "phononnamespace_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+ class ObjectDescriptionPrivate
+ {
+ public:
+ ObjectDescriptionPrivate(int _index, const QHash<QByteArray, QVariant> &_properties)
+ : index(_index),
+ name(_properties["name"].toString()),
+ description(_properties["description"].toString()),
+ properties(_properties)
+ {
+ }
+
+ bool operator==(const ObjectDescriptionPrivate &rhs) const
+ {
+ if (index == rhs.index && (name != rhs.name || description != rhs.description))
+ pError() << "Same index (" << index <<
+ "), but different name/description. This is a bug in the Phonon backend.";
+ return index == rhs.index;// && name == rhs.name && description == rhs.description;
+ }
+
+ int index;
+ QString name, description;
+ QHash<QByteArray, QVariant> properties;
+ };
+} // namespace Phonon
+
+QT_END_NAMESPACE
+
+#endif // PHONON_OBJECTDESCRIPTION_P_H
+// vim: sw=4 ts=4 tw=80
diff --git a/src/3rdparty/phonon/phonon/objectdescriptionmodel.cpp b/src/3rdparty/phonon/phonon/objectdescriptionmodel.cpp
new file mode 100644
index 0000000000..e989d0c5a9
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/objectdescriptionmodel.cpp
@@ -0,0 +1,392 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006-2007 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "objectdescriptionmodel.h"
+#include "objectdescriptionmodel_p.h"
+#include "phonondefs_p.h"
+#include "platform_p.h"
+#include <QtCore/QList>
+#include "objectdescription.h"
+#include "phononnamespace_p.h"
+#include <QtCore/QMimeData>
+#include <QtCore/QStringList>
+#include <QtGui/QIcon>
+#include "factory_p.h"
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_PHONON_OBJECTDESCRIPTIONMODEL
+
+
+static const uint qt_meta_data_Phonon__ObjectDescriptionModel[] = {
+
+ // content:
+ 1, // revision
+ 0, // classname
+ 0, 0, // classinfo
+ 0, 0, // methods
+ 0, 0, // properties
+ 0, 0, // enums/sets
+
+ 0 // eod
+};
+
+static const char qt_meta_stringdata_Phonon__ObjectDescriptionModel_AudioOutputDeviceType[] = { "Phonon::AudioOutputDevice\0" };
+static const char qt_meta_stringdata_Phonon__ObjectDescriptionModel_AudioCaptureDeviceType[] = { "Phonon::AudioCaptureDevice\0" };
+static const char qt_meta_stringdata_Phonon__ObjectDescriptionModel_EffectType[] = { "Phonon::EffectDescription\0" };
+static const char qt_meta_stringdata_Phonon__ObjectDescriptionModel_AudioChannelType[] = { "Phonon::AudioChannelDescription\0" };
+static const char qt_meta_stringdata_Phonon__ObjectDescriptionModel_SubtitleType[] = { "Phonon::SubtitleDescription\0" };
+/*
+static const char qt_meta_stringdata_Phonon__ObjectDescriptionModel_VideoOutputDeviceType[] = { "Phonon::VideoOutputDevice\0" };
+static const char qt_meta_stringdata_Phonon__ObjectDescriptionModel_VideoCaptureDeviceType[] = { "Phonon::VideoCaptureDevice\0" };
+static const char qt_meta_stringdata_Phonon__ObjectDescriptionModel_AudioCodecType[] = { "Phonon::AudioCodecDescription\0" };
+static const char qt_meta_stringdata_Phonon__ObjectDescriptionModel_VideoCodecType[] = { "Phonon::VideoCodecDescription\0" };
+static const char qt_meta_stringdata_Phonon__ObjectDescriptionModel_ContainerFormatType[] = { "Phonon::ContainerFormatDescription\0" };
+static const char qt_meta_stringdata_Phonon__ObjectDescriptionModel_VisualizationType[] = { "Phonon::VisualizationDescription\0" };
+*/
+
+namespace Phonon
+{
+
+#if !defined(Q_CC_MINGW) || __MINGW32_MAJOR_VERSION >= 4
+
+template<> const QMetaObject ObjectDescriptionModel<AudioOutputDeviceType>::staticMetaObject = {
+ { &QAbstractListModel::staticMetaObject, qt_meta_stringdata_Phonon__ObjectDescriptionModel_AudioOutputDeviceType,
+ qt_meta_data_Phonon__ObjectDescriptionModel, 0 }
+};
+template<> const QMetaObject ObjectDescriptionModel<EffectType>::staticMetaObject = {
+ { &QAbstractListModel::staticMetaObject, qt_meta_stringdata_Phonon__ObjectDescriptionModel_EffectType,
+ qt_meta_data_Phonon__ObjectDescriptionModel, 0 }
+};
+template<> const QMetaObject ObjectDescriptionModel<AudioChannelType>::staticMetaObject = {
+ { &QAbstractListModel::staticMetaObject, qt_meta_stringdata_Phonon__ObjectDescriptionModel_AudioChannelType,
+ qt_meta_data_Phonon__ObjectDescriptionModel, 0 }
+};
+template<> const QMetaObject ObjectDescriptionModel<SubtitleType>::staticMetaObject = {
+ { &QAbstractListModel::staticMetaObject, qt_meta_stringdata_Phonon__ObjectDescriptionModel_SubtitleType,
+ qt_meta_data_Phonon__ObjectDescriptionModel, 0 }
+};
+template<> const QMetaObject ObjectDescriptionModel<AudioCaptureDeviceType>::staticMetaObject = {
+ { &QAbstractListModel::staticMetaObject, qt_meta_stringdata_Phonon__ObjectDescriptionModel_AudioCaptureDeviceType,
+ qt_meta_data_Phonon__ObjectDescriptionModel, 0 }
+};
+/*template<> const QMetaObject ObjectDescriptionModel<VideoOutputDeviceType>::staticMetaObject = {
+ { &QAbstractListModel::staticMetaObject, qt_meta_stringdata_Phonon__ObjectDescriptionModel_VideoOutputDeviceType,
+ qt_meta_data_Phonon__ObjectDescriptionModel, 0 }
+};
+template<> const QMetaObject ObjectDescriptionModel<VideoCaptureDeviceType>::staticMetaObject = {
+ { &QAbstractListModel::staticMetaObject, qt_meta_stringdata_Phonon__ObjectDescriptionModel_VideoCaptureDeviceType,
+ qt_meta_data_Phonon__ObjectDescriptionModel, 0 }
+};
+template<> const QMetaObject ObjectDescriptionModel<AudioCodecType>::staticMetaObject = {
+ { &QAbstractListModel::staticMetaObject, qt_meta_stringdata_Phonon__ObjectDescriptionModel_AudioCodecType,
+ qt_meta_data_Phonon__ObjectDescriptionModel, 0 }
+};
+template<> const QMetaObject ObjectDescriptionModel<VideoCodecType>::staticMetaObject = {
+ { &QAbstractListModel::staticMetaObject, qt_meta_stringdata_Phonon__ObjectDescriptionModel_VideoCodecType,
+ qt_meta_data_Phonon__ObjectDescriptionModel, 0 }
+};
+template<> const QMetaObject ObjectDescriptionModel<ContainerFormatType>::staticMetaObject = {
+ { &QAbstractListModel::staticMetaObject, qt_meta_stringdata_Phonon__ObjectDescriptionModel_ContainerFormatType,
+ qt_meta_data_Phonon__ObjectDescriptionModel, 0 }
+};
+template<> const QMetaObject ObjectDescriptionModel<VisualizationType>::staticMetaObject = {
+ { &QAbstractListModel::staticMetaObject, qt_meta_stringdata_Phonon__ObjectDescriptionModel_VisualizationType,
+ qt_meta_data_Phonon__ObjectDescriptionModel, 0 }
+};*/
+
+template<ObjectDescriptionType type>
+const QMetaObject *ObjectDescriptionModel<type>::metaObject() const
+{
+ return &staticMetaObject;
+}
+
+template<ObjectDescriptionType type>
+void *ObjectDescriptionModel<type>::qt_metacast(const char *_clname)
+{
+ if (!_clname) {
+ return 0;
+ }
+ if (!strcmp(_clname, ObjectDescriptionModel<type>::staticMetaObject.className())) {
+ return static_cast<void *>(const_cast<ObjectDescriptionModel<type> *>(this));
+ }
+ return QAbstractListModel::qt_metacast(_clname);
+}
+
+/*
+template<ObjectDescriptionType type>
+int ObjectDescriptionModel<type>::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
+{
+ return QAbstractListModel::qt_metacall(_c, _id, _a);
+}
+*/
+#endif
+
+int ObjectDescriptionModelData::rowCount(const QModelIndex &parent) const
+{
+ if (parent.isValid())
+ return 0;
+
+ return d->data.size();
+}
+
+QVariant ObjectDescriptionModelData::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid() || index.row() >= d->data.size() || index.column() != 0)
+ return QVariant();
+
+ switch(role)
+ {
+ case Qt::EditRole:
+ case Qt::DisplayRole:
+ return d->data.at(index.row())->name();
+ break;
+ case Qt::ToolTipRole:
+ return d->data.at(index.row())->description();
+ break;
+ case Qt::DecorationRole:
+ {
+ QVariant icon = d->data.at(index.row())->property("icon");
+ if (icon.isValid()) {
+ if (icon.type() == QVariant::String) {
+ return Platform::icon(icon.toString());
+ } else if (icon.type() == QVariant::Icon) {
+ return icon;
+ }
+ }
+ }
+ return QVariant();
+ default:
+ return QVariant();
+}
+}
+
+Qt::ItemFlags ObjectDescriptionModelData::flags(const QModelIndex &index) const
+{
+ if(!index.isValid() || index.row() >= d->data.size() || index.column() != 0) {
+ return Qt::ItemIsDropEnabled;
+ }
+
+ QVariant available = d->data.at(index.row())->property("available");
+ if (available.isValid() && available.type() == QVariant::Bool && !available.toBool()) {
+ return Qt::ItemIsSelectable | Qt::ItemIsDragEnabled;
+ }
+ return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled;
+}
+
+QList<int> ObjectDescriptionModelData::tupleIndexOrder() const
+{
+ QList<int> ret;
+ for (int i = 0; i < d->data.size(); ++i) {
+ ret.append(d->data.at(i)->index());
+ }
+ return ret;
+}
+
+int ObjectDescriptionModelData::tupleIndexAtPositionIndex(int positionIndex) const
+{
+ return d->data.at(positionIndex)->index();
+}
+
+QMimeData *ObjectDescriptionModelData::mimeData(ObjectDescriptionType type, const QModelIndexList &indexes) const
+{
+ QMimeData *mimeData = new QMimeData;
+ QByteArray encodedData;
+ QDataStream stream(&encodedData, QIODevice::WriteOnly);
+ QModelIndexList::const_iterator end = indexes.constEnd();
+ QModelIndexList::const_iterator index = indexes.constBegin();
+ for(; index!=end; ++index) {
+ if ((*index).isValid()) {
+ stream << d->data.at((*index).row())->index();
+ }
+ }
+ //pDebug() << Q_FUNC_INFO << "setting mimeData to" << mimeTypes(type).first() << "=>" << encodedData.toHex();
+ mimeData->setData(mimeTypes(type).first(), encodedData);
+ return mimeData;
+}
+
+void ObjectDescriptionModelData::moveUp(const QModelIndex &index)
+{
+ if (!index.isValid() || index.row() >= d->data.size() || index.row() < 1 || index.column() != 0)
+ return;
+
+ emit d->model->layoutAboutToBeChanged();
+ QModelIndex above = index.sibling(index.row() - 1, index.column());
+ d->data.swap(index.row(), above.row());
+ QModelIndexList from, to;
+ from << index << above;
+ to << above << index;
+ d->model->changePersistentIndexList(from, to);
+ emit d->model->layoutChanged();
+}
+
+void ObjectDescriptionModelData::moveDown(const QModelIndex &index)
+{
+ if (!index.isValid() || index.row() >= d->data.size() - 1 || index.column() != 0)
+ return;
+
+ emit d->model->layoutAboutToBeChanged();
+ QModelIndex below = index.sibling(index.row() + 1, index.column());
+ d->data.swap(index.row(), below.row());
+ QModelIndexList from, to;
+ from << index << below;
+ to << below << index;
+ d->model->changePersistentIndexList(from, to);
+ emit d->model->layoutChanged();
+}
+
+ObjectDescriptionModelData::ObjectDescriptionModelData(QAbstractListModel *model)
+ : d(new ObjectDescriptionModelDataPrivate(model))
+{
+}
+
+ObjectDescriptionModelData::~ObjectDescriptionModelData()
+{
+ delete d;
+}
+
+void ObjectDescriptionModelData::setModelData(const QList<QExplicitlySharedDataPointer<ObjectDescriptionData> > &newData)
+{
+ d->data = newData;
+ d->model->reset();
+}
+
+QList<QExplicitlySharedDataPointer<ObjectDescriptionData> > ObjectDescriptionModelData::modelData() const
+{
+ return d->data;
+}
+
+QExplicitlySharedDataPointer<ObjectDescriptionData> ObjectDescriptionModelData::modelData(const QModelIndex &index) const
+{
+ if (!index.isValid() || index.row() >= d->data.size() || index.column() != 0) {
+ return QExplicitlySharedDataPointer<ObjectDescriptionData>(new ObjectDescriptionData(0));
+ }
+ return d->data.at(index.row());
+}
+
+Qt::DropActions ObjectDescriptionModelData::supportedDropActions() const
+{
+ //pDebug() << Q_FUNC_INFO;
+ return Qt::MoveAction;
+}
+
+bool ObjectDescriptionModelData::dropMimeData(ObjectDescriptionType type, const QMimeData *data, Qt::DropAction action,
+ int row, int column, const QModelIndex &parent)
+{
+ Q_UNUSED(action);
+ Q_UNUSED(column);
+ Q_UNUSED(parent);
+ //pDebug() << Q_FUNC_INFO << data << action << row << column << parent;
+
+ QString format = mimeTypes(type).first();
+ if (!data->hasFormat(format)) {
+ return false;
+ }
+
+ if (row == -1) {
+ row = d->data.size();
+ }
+
+ QByteArray encodedData = data->data(format);
+ QDataStream stream(&encodedData, QIODevice::ReadOnly);
+ QList<QExplicitlySharedDataPointer<ObjectDescriptionData> > toInsert;
+ while (!stream.atEnd()) {
+ int otherIndex;
+ stream >> otherIndex;
+ ObjectDescriptionData *obj = ObjectDescriptionData::fromIndex(type, otherIndex);
+
+ if (obj->isValid()) {
+ toInsert << QExplicitlySharedDataPointer<ObjectDescriptionData>(obj);
+ } else {
+ delete obj;
+ }
+ }
+ d->model->beginInsertRows(QModelIndex(), row, row + toInsert.size() - 1);
+ foreach (const QExplicitlySharedDataPointer<ObjectDescriptionData> &obj, toInsert) {
+ d->data.insert(row, obj);
+ }
+ d->model->endInsertRows();
+ return true;
+}
+
+
+bool ObjectDescriptionModelData::removeRows(int row, int count, const QModelIndex &parent)
+{
+ //pDebug() << Q_FUNC_INFO << row << count << parent;
+ if (parent.isValid() || row + count > d->data.size()) {
+ return false;
+ }
+ d->model->beginRemoveRows(parent, row, row + count - 1);
+ for (;count > 0; --count) {
+ d->data.removeAt(row);
+ }
+ d->model->endRemoveRows();
+ return true;
+}
+
+/*
+template<ObjectDescriptionType type>
+bool ObjectDescriptionModel<type>::insertRows(int row, int count, const QModelIndex &parent)
+{
+ pDebug() << Q_FUNC_INFO << row << count << parent;
+ if (parent.isValid() || row < 0 || row > d->data.size()) {
+ return false;
+ }
+ beginInsertRows(parent, row, row + count - 1);
+ for (;count > 0; --count) {
+ d->data.insert(row, ObjectDescription<type>());
+ }
+ endInsertRows();
+ return true;
+}
+*/
+
+QStringList ObjectDescriptionModelData::mimeTypes(ObjectDescriptionType type) const
+{
+ return QStringList(QLatin1String("application/x-phonon-objectdescription") + QString::number(static_cast<int>(type)));
+}
+
+#if !defined(Q_CC_MINGW) || __MINGW32_MAJOR_VERSION >= 4
+#if !defined(Q_CC_MSVC) || _MSC_VER > 1300 || defined(Q_CC_INTEL)
+#define INSTANTIATE_META_FUNCTIONS(type) \
+template const QMetaObject *ObjectDescriptionModel<type>::metaObject() const; \
+template void *ObjectDescriptionModel<type>::qt_metacast(const char *)
+
+INSTANTIATE_META_FUNCTIONS(AudioOutputDeviceType);
+INSTANTIATE_META_FUNCTIONS(AudioCaptureDeviceType);
+INSTANTIATE_META_FUNCTIONS(EffectType);
+INSTANTIATE_META_FUNCTIONS(AudioChannelType);
+INSTANTIATE_META_FUNCTIONS(SubtitleType);
+#endif
+/*INSTANTIATE_META_FUNCTIONS(VideoOutputDeviceType);
+INSTANTIATE_META_FUNCTIONS(VideoCaptureDeviceType);
+INSTANTIATE_META_FUNCTIONS(AudioCodecType);
+INSTANTIATE_META_FUNCTIONS(VideoCodecType);
+INSTANTIATE_META_FUNCTIONS(ContainerFormatType);
+INSTANTIATE_META_FUNCTIONS(VisualizationType);
+*/
+#endif //Q_CC_MINGW
+} // namespace Phonon
+
+#endif //QT_NO_PHONON_OBJECTDESCRIPTIONMODEL
+
+QT_END_NAMESPACE
diff --git a/src/3rdparty/phonon/phonon/objectdescriptionmodel.h b/src/3rdparty/phonon/phonon/objectdescriptionmodel.h
new file mode 100644
index 0000000000..84dc0bbc47
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/objectdescriptionmodel.h
@@ -0,0 +1,380 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006-2007 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef PHONON_OBJECTDESCRIPTIONMODEL_H
+#define PHONON_OBJECTDESCRIPTIONMODEL_H
+
+#include "phonon_export.h"
+#include "phonondefs.h"
+#include "objectdescription.h"
+#include <QtCore/QList>
+#include <QtCore/QModelIndex>
+#include <QtCore/QStringList>
+
+QT_BEGIN_HEADER
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_PHONON_OBJECTDESCRIPTIONMODEL
+
+namespace Phonon
+{
+ class ObjectDescriptionModelDataPrivate;
+
+ /** \internal
+ * \class ObjectDescriptionModelData objectdescriptionmodel.h Phonon/ObjectDescriptionModelData
+ * \brief Data class for models for ObjectDescription objects.
+ *
+ * \author Matthias Kretz <kretz@kde.org>
+ */
+ class PHONON_EXPORT ObjectDescriptionModelData
+ {
+ public:
+ /**
+ * Returns the number of rows in the model. This value corresponds
+ * to the size of the list passed through setModelData.
+ *
+ * \param parent The optional \p parent argument is used in most models to specify
+ * the parent of the rows to be counted. Because this is a list if a
+ * valid parent is specified the result will always be 0.
+ *
+ * Reimplemented from QAbstractItemModel.
+ *
+ * \see QAbstractItemModel::rowCount
+ */
+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
+
+ /**
+ * Returns data from the item with the given \p index for the specified
+ * \p role.
+ * If the view requests an invalid index, an invalid variant is
+ * returned.
+ *
+ * Reimplemented from QAbstractItemModel.
+ *
+ * \see QAbstractItemModel::data
+ * \see Qt::ItemDataRole
+ */
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+
+ /**
+ * Reimplemented to show unavailable devices as disabled (but still
+ * selectable).
+ */
+ Qt::ItemFlags flags(const QModelIndex &index) const;
+
+ /**
+ * Returns a list of indexes in the same order as they are in the
+ * model. The indexes come from the ObjectDescription::index
+ * method.
+ *
+ * This is useful to let the user define a list of preference.
+ */
+ QList<int> tupleIndexOrder() const;
+
+ /**
+ * Returns the ObjectDescription::index for the tuple
+ * at the given position \p positionIndex. For example a
+ * QComboBox will give you the currentIndex as the
+ * position in the list. But to select the according
+ * AudioOutputDevice using AudioOutputDevice::fromIndex
+ * you can use this method.
+ *
+ * \param positionIndex The position in the list.
+ */
+ int tupleIndexAtPositionIndex(int positionIndex) const;
+
+ /**
+ * Returns the MIME data that dropMimeData() can use to create new
+ * items.
+ */
+ QMimeData *mimeData(ObjectDescriptionType type, const QModelIndexList &indexes) const;
+
+ /**
+ * Moves the item at the given \p index up. In the resulting list
+ * the items at index.row() and index.row() - 1 are swapped.
+ *
+ * Connected views are updated automatically.
+ */
+ void moveUp(const QModelIndex &index);
+
+ /**
+ * Moves the item at the given \p index down. In the resulting list
+ * the items at index.row() and index.row() + 1 are swapped.
+ *
+ * Connected views are updated automatically.
+ */
+ void moveDown(const QModelIndex &index);
+
+ void setModelData(const QList<QExplicitlySharedDataPointer<ObjectDescriptionData> > &data);
+ QList<QExplicitlySharedDataPointer<ObjectDescriptionData> > modelData() const;
+ QExplicitlySharedDataPointer<ObjectDescriptionData> modelData(const QModelIndex &index) const;
+ Qt::DropActions supportedDropActions() const;
+ bool dropMimeData(ObjectDescriptionType type, const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent);
+ bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex());
+ QStringList mimeTypes(ObjectDescriptionType type) const;
+
+ ObjectDescriptionModelData(QAbstractListModel *);
+ protected:
+ ~ObjectDescriptionModelData();
+ //ObjectDescriptionModelData(ObjectDescriptionModelDataPrivate *dd);
+ ObjectDescriptionModelDataPrivate *const d;
+ };
+
+ /** \class ObjectDescriptionModel objectdescriptionmodel.h Phonon/ObjectDescriptionModel
+ * \short The ObjectDescriptionModel class provides a model from
+ * a list of ObjectDescription objects.
+ *
+ * ObjectDescriptionModel is a readonly model that supplies a list
+ * using ObjectDescription::name() for the text and
+ * ObjectDescription::description() for the tooltip. If set the properties
+ * "icon" and "available" are used to set the decoration and disable the
+ * item (disabled only visually, you can still select and drag it).
+ *
+ * It also provides the methods moveUp() and moveDown() to order the list.
+ * Additionally drag and drop is possible so that
+ * QAbstractItemView::InternalMove can be used.
+ * The resulting order of the ObjectDescription::index() values can then be
+ * retrieved using tupleIndexOrder().
+ *
+ * An example use case would be to give the user a QComboBox to select
+ * the output device:
+ * \code
+ * QComboBox *cb = new QComboBox(parentWidget);
+ * ObjectDescriptionModel *model = new ObjectDescriptionModel(cb);
+ * model->setModelData(BackendCapabilities::availableAudioOutputDevices());
+ * cb->setModel(model);
+ * cb->setCurrentIndex(0); // select first entry
+ * \endcode
+ *
+ * And to retrieve the selected AudioOutputDevice:
+ * \code
+ * int cbIndex = cb->currentIndex();
+ * AudioOutputDevice selectedDevice = model->modelData(cbIndex);
+ * \endcode
+ *
+ * \ingroup Frontend
+ * \author Matthias Kretz <kretz@kde.org>
+ */
+ template<ObjectDescriptionType type>
+ class ObjectDescriptionModel : public QAbstractListModel
+ {
+ public:
+ Q_OBJECT_CHECK
+
+/* MinGW 3.4.x gives an ICE when trying to instantiate one of the
+ ObjectDescriptionModel<foo> classes because it can't handle
+ half exported classes correct. gcc 4.3.x has a fix for this but
+ we currently there's no official gcc 4.3 on windows available.
+ Because of this we need this little hack
+ */
+#if !defined(Q_CC_MINGW) || __MINGW32_MAJOR_VERSION >= 4
+ /** \internal */
+ static PHONON_EXPORT const QMetaObject staticMetaObject;
+ /** \internal */
+ PHONON_EXPORT const QMetaObject *metaObject() const;
+ /** \internal */
+ PHONON_EXPORT void *qt_metacast(const char *_clname);
+ //int qt_metacall(QMetaObject::Call _c, int _id, void **_a);
+#endif
+
+ /**
+ * Returns the number of rows in the model. This value corresponds
+ * to the size of the list passed through setModelData.
+ *
+ * \param parent The optional \p parent argument is used in most models to specify
+ * the parent of the rows to be counted. Because this is a list if a
+ * valid parent is specified the result will always be 0.
+ *
+ * Reimplemented from QAbstractItemModel.
+ *
+ * \see QAbstractItemModel::rowCount
+ */
+ inline int rowCount(const QModelIndex &parent = QModelIndex()) const { return d->rowCount(parent); } //krazy:exclude=inline
+
+ /**
+ * Returns data from the item with the given \p index for the specified
+ * \p role.
+ * If the view requests an invalid index, an invalid variant is
+ * returned.
+ *
+ * Reimplemented from QAbstractItemModel.
+ *
+ * \see QAbstractItemModel::data
+ * \see Qt::ItemDataRole
+ */
+ inline QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const { return d->data(index, role); } //krazy:exclude=inline
+
+ /**
+ * Reimplemented to show unavailable devices as disabled (but still
+ * selectable).
+ */
+ inline Qt::ItemFlags flags(const QModelIndex &index) const { return d->flags(index); } //krazy:exclude=inline
+
+ /**
+ * Returns a list of indexes in the same order as they are in the
+ * model. The indexes come from the ObjectDescription::index
+ * method.
+ *
+ * This is useful to let the user define a list of preference.
+ */
+ inline QList<int> tupleIndexOrder() const { return d->tupleIndexOrder(); } //krazy:exclude=inline
+
+ /**
+ * Returns the ObjectDescription::index for the tuple
+ * at the given position \p positionIndex. For example a
+ * QComboBox will give you the currentIndex as the
+ * position in the list. But to select the according
+ * AudioOutputDevice using AudioOutputDevice::fromIndex
+ * you can use this method.
+ *
+ * \param positionIndex The position in the list.
+ */
+ inline int tupleIndexAtPositionIndex(int positionIndex) const { return d->tupleIndexAtPositionIndex(positionIndex); } //krazy:exclude=inline
+
+ /**
+ * Returns the MIME data that dropMimeData() can use to create new
+ * items.
+ */
+ inline QMimeData *mimeData(const QModelIndexList &indexes) const { return d->mimeData(type, indexes); } //krazy:exclude=inline
+
+ /**
+ * Moves the item at the given \p index up. In the resulting list
+ * the items at index.row() and index.row() - 1 are swapped.
+ *
+ * Connected views are updated automatically.
+ */
+ inline void moveUp(const QModelIndex &index) { d->moveUp(index); } //krazy:exclude=inline
+
+ /**
+ * Moves the item at the given \p index down. In the resulting list
+ * the items at index.row() and index.row() + 1 are swapped.
+ *
+ * Connected views are updated automatically.
+ */
+ inline void moveDown(const QModelIndex &index) { d->moveDown(index); } //krazy:exclude=inline
+
+ /**
+ * Constructs a ObjectDescription model with the
+ * given \p parent.
+ */
+ explicit inline ObjectDescriptionModel(QObject *parent = 0) : QAbstractListModel(parent), d(new ObjectDescriptionModelData(this)) {} //krazy:exclude=inline
+
+ /**
+ * Constructs a ObjectDescription model with the
+ * given \p parent and the given \p data.
+ */
+ explicit inline ObjectDescriptionModel(const QList<ObjectDescription<type> > &data, QObject *parent = 0) //krazy:exclude=inline
+ : QAbstractListModel(parent), d(new ObjectDescriptionModelData(this)) { setModelData(data); }
+
+ /**
+ * Sets the model data using the list provided by \p data.
+ *
+ * All previous model data is cleared.
+ */
+ inline void setModelData(const QList<ObjectDescription<type> > &data) { //krazy:exclude=inline
+ QList<QExplicitlySharedDataPointer<ObjectDescriptionData> > list;
+ Q_FOREACH (const ObjectDescription<type> &desc, data) {
+ list << desc.d;
+ }
+ d->setModelData(list);
+ }
+
+ /**
+ * Returns the model data.
+ *
+ * As the order of the list might have changed this can be different
+ * to what was set using setModelData().
+ */
+ inline QList<ObjectDescription<type> > modelData() const { //krazy:exclude=inline
+ QList<ObjectDescription<type> > ret;
+ QList<QExplicitlySharedDataPointer<ObjectDescriptionData> > list = d->modelData();
+ Q_FOREACH (const QExplicitlySharedDataPointer<ObjectDescriptionData> &data, list) {
+ ret << ObjectDescription<type>(data);
+ }
+ return ret;
+ }
+
+ /**
+ * Returns one ObjectDescription of the model data for the given \p index.
+ */
+ inline ObjectDescription<type> modelData(const QModelIndex &index) const { return ObjectDescription<type>(d->modelData(index)); } //krazy:exclude=inline
+
+ /**
+ * This model supports drag and drop to copy or move
+ * items.
+ */
+ inline Qt::DropActions supportedDropActions() const { return d->supportedDropActions(); } //krazy:exclude=inline
+
+ /**
+ * Accept drops from other models of the same ObjectDescriptionType.
+ *
+ * If a valid \p parent is given the dropped items will be inserted
+ * above that item.
+ */
+ inline bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) { //krazy:exclude=inline
+ return d->dropMimeData(type, data, action, row, column, parent);
+ }
+
+ /**
+ * Removes count rows starting with the given row.
+ *
+ * If a valid \p parent is given no rows are removed since this is a
+ * list model.
+ *
+ * Returns true if the rows were successfully removed; otherwise returns false.
+ */
+ inline bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()) { //krazy:exclude=inline
+ return d->removeRows(row, count, parent);
+ }
+
+ /**
+ * Returns a list of supported drag and drop MIME types. Currently
+ * it only supports one type used internally.
+ */
+ inline QStringList mimeTypes() const { return d->mimeTypes(type); } //krazy:exclude=inline
+
+ protected:
+ ObjectDescriptionModelData *const d;
+ };
+
+ typedef ObjectDescriptionModel<AudioOutputDeviceType> AudioOutputDeviceModel;
+ typedef ObjectDescriptionModel<AudioCaptureDeviceType> AudioCaptureDeviceModel;
+ typedef ObjectDescriptionModel<EffectType> EffectDescriptionModel;
+ typedef ObjectDescriptionModel<AudioChannelType> AudioChannelDescriptionModel;
+ typedef ObjectDescriptionModel<SubtitleType> SubtitleDescriptionModel;
+/*
+ typedef ObjectDescriptionModel<VideoOutputDeviceType> VideoOutputDeviceModel;
+ typedef ObjectDescriptionModel<VideoCaptureDeviceType> VideoCaptureDeviceModel;
+ typedef ObjectDescriptionModel<AudioCodecType> AudioCodecDescriptionModel;
+ typedef ObjectDescriptionModel<VideoCodecType> VideoCodecDescriptionModel;
+ typedef ObjectDescriptionModel<ContainerFormatType> ContainerFormatDescriptionModel;
+ typedef ObjectDescriptionModel<VisualizationType> VisualizationDescriptionModel;*/
+
+}
+
+#endif //QT_NO_PHONON_OBJECTDESCRIPTIONMODEL
+
+QT_END_NAMESPACE
+QT_END_HEADER
+
+#endif // PHONON_OBJECTDESCRIPTIONMODEL_H
+// vim: sw=4 ts=4 tw=80
diff --git a/src/3rdparty/phonon/phonon/objectdescriptionmodel_p.h b/src/3rdparty/phonon/phonon/objectdescriptionmodel_p.h
new file mode 100644
index 0000000000..f036bc8381
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/objectdescriptionmodel_p.h
@@ -0,0 +1,65 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006-2007 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef PHONON_OBJECTDESCRIPTIONMODEL_P_H
+#define PHONON_OBJECTDESCRIPTIONMODEL_P_H
+
+#include "objectdescriptionmodel.h"
+#include <QtCore/QList>
+#include "objectdescription.h"
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_PHONON_OBJECTDESCRIPTIONMODEL
+
+namespace Phonon
+{
+
+class ListModelHelper : public QAbstractListModel
+{
+ public:
+ using QAbstractListModel::layoutAboutToBeChanged;
+ using QAbstractListModel::changePersistentIndexList;
+ using QAbstractListModel::layoutChanged;
+ using QAbstractListModel::reset;
+ using QAbstractListModel::beginInsertRows;
+ using QAbstractListModel::endInsertRows;
+ using QAbstractListModel::beginRemoveRows;
+ using QAbstractListModel::endRemoveRows;
+};
+
+class ObjectDescriptionModelDataPrivate
+{
+ public:
+ ObjectDescriptionModelDataPrivate(QAbstractListModel *m) : model(reinterpret_cast<ListModelHelper *>(m)) {}
+ QList<QExplicitlySharedDataPointer<ObjectDescriptionData> > data;
+ ListModelHelper *model;
+};
+
+}
+
+#endif //QT_NO_PHONON_OBJECTDESCRIPTIONMODEL
+
+QT_END_NAMESPACE
+
+#endif // PHONON_OBJECTDESCRIPTIONMODEL_P_H
+// vim: sw=4 ts=4 tw=80
diff --git a/src/3rdparty/phonon/phonon/org.kde.Phonon.AudioOutput.xml b/src/3rdparty/phonon/phonon/org.kde.Phonon.AudioOutput.xml
new file mode 100644
index 0000000000..24983372cf
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/org.kde.Phonon.AudioOutput.xml
@@ -0,0 +1,32 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node>
+ <interface name="org.kde.Phonon.AudioOutput">
+ <property name="volume" type="d" access="readwrite"/>
+ <property name="muted" type="b" access="readwrite"/>
+ <property name="outputDeviceIndex" type="i" access="readwrite"/>
+ <signal name="volumeChanged">
+ <arg type="d" direction="out"/>
+ </signal>
+ <signal name="mutedChanged">
+ <arg type="b" direction="out"/>
+ </signal>
+ <signal name="outputDeviceIndexChanged">
+ <arg type="i" direction="out"/>
+ </signal>
+ <signal name="nameChanged">
+ <arg name="newName" type="s" direction="out"/>
+ </signal>
+ <signal name="newOutputAvailable">
+ <arg name="service" type="s" direction="out"/>
+ <arg name="path" type="s" direction="out"/>
+ </signal>
+ <signal name="outputDestroyed">
+ </signal>
+ <method name="category">
+ <arg type="s" direction="out"/>
+ </method>
+ <method name="name">
+ <arg type="s" direction="out"/>
+ </method>
+ </interface>
+</node>
diff --git a/src/3rdparty/phonon/phonon/path.cpp b/src/3rdparty/phonon/phonon/path.cpp
new file mode 100644
index 0000000000..b46d30afc9
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/path.cpp
@@ -0,0 +1,472 @@
+/* This file is part of the KDE project
+ Copyright (C) 2007 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "path.h"
+#include "path_p.h"
+
+#include "phononnamespace_p.h"
+#include "backendinterface.h"
+#include "factory_p.h"
+#include "medianode.h"
+#include "medianode_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+
+class ConnectionTransaction
+{
+ public:
+ ConnectionTransaction(BackendInterface *b, const QSet<QObject*> &x) : backend(b), list(x)
+ {
+ success = backend->startConnectionChange(list);
+ }
+ ~ConnectionTransaction()
+ {
+ backend->endConnectionChange(list);
+ }
+ operator bool()
+ {
+ return success;
+ }
+ private:
+ bool success;
+ BackendInterface *const backend;
+ const QSet<QObject*> list;
+};
+
+PathPrivate::~PathPrivate()
+{
+#ifndef QT_NO_PHONON_EFFECT
+ foreach (Effect *e, effects) {
+ e->k_ptr->removeDestructionHandler(this);
+ }
+ delete effectsParent;
+#endif
+}
+
+Path::~Path()
+{
+}
+
+Path::Path()
+ : d(new PathPrivate)
+{
+}
+
+Path::Path(const Path &rhs)
+ : d(rhs.d)
+{
+}
+
+bool Path::isValid() const
+{
+ return d->sourceNode != 0 && d->sinkNode != 0;
+}
+
+#ifndef QT_NO_PHONON_EFFECT
+Effect *Path::insertEffect(const EffectDescription &desc, Effect *insertBefore)
+{
+ if (!d->effectsParent) {
+ d->effectsParent = new QObject;
+ }
+ Effect *e = new Effect(desc, d->effectsParent);
+ if (!e->isValid()) {
+ delete e;
+ return 0;
+ }
+ bool success = insertEffect(e, insertBefore);
+ if (!success) {
+ delete e;
+ return 0;
+ }
+ return e;
+}
+
+bool Path::insertEffect(Effect *newEffect, Effect *insertBefore)
+{
+ QObject *newEffectBackend = newEffect ? newEffect->k_ptr->backendObject() : 0;
+ if (!isValid() || !newEffectBackend || d->effects.contains(newEffect) ||
+ (insertBefore && (!d->effects.contains(insertBefore) || !insertBefore->k_ptr->backendObject()))) {
+ return false;
+ }
+ QObject *leftNode = 0;
+ QObject *rightNode = 0;
+ const int insertIndex = insertBefore ? d->effects.indexOf(insertBefore) : d->effects.size();
+ if (insertIndex == 0) {
+ //prepend
+ leftNode = d->sourceNode->k_ptr->backendObject();
+ } else {
+ leftNode = d->effects[insertIndex - 1]->k_ptr->backendObject();
+ }
+
+ if (insertIndex == d->effects.size()) {
+ //append
+ rightNode = d->sinkNode->k_ptr->backendObject();
+ } else {
+ Q_ASSERT(insertBefore);
+ rightNode = insertBefore->k_ptr->backendObject();
+ }
+
+ QList<QObjectPair> disconnections, connections;
+ disconnections << QObjectPair(leftNode, rightNode);
+ connections << QObjectPair(leftNode, newEffectBackend)
+ << QObjectPair(newEffectBackend, rightNode);
+
+ if (d->executeTransaction(disconnections, connections)) {
+ newEffect->k_ptr->addDestructionHandler(d.data());
+ d->effects.insert(insertIndex, newEffect);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool Path::removeEffect(Effect *effect)
+{
+ return d->removeEffect(effect);
+}
+
+QList<Effect *> Path::effects() const
+{
+ return d->effects;
+}
+#endif //QT_NO_PHONON_EFFECT
+
+bool Path::reconnect(MediaNode *source, MediaNode *sink)
+{
+ if (!source || !sink || !source->k_ptr->backendObject() || !sink->k_ptr->backendObject()) {
+ return false;
+ }
+
+ QList<QObjectPair> disconnections, connections;
+
+ //backend objects
+ QObject *bnewSource = source->k_ptr->backendObject();
+ QObject *bnewSink = sink->k_ptr->backendObject();
+ QObject *bcurrentSource = d->sourceNode ? d->sourceNode->k_ptr->backendObject() : 0;
+ QObject *bcurrentSink = d->sinkNode ? d->sinkNode->k_ptr->backendObject() : 0;
+
+ if (bnewSource != bcurrentSource) {
+ //we need to change the source
+#ifndef QT_NO_PHONON_EFFECT
+ MediaNode *next = d->effects.isEmpty() ? sink : d->effects.first();
+#else
+ MediaNode *next = sink;
+#endif //QT_NO_PHONON_EFFECT
+ QObject *bnext = next->k_ptr->backendObject();
+ if (bcurrentSource)
+ disconnections << QObjectPair(bcurrentSource, bnext);
+ connections << QObjectPair(bnewSource, bnext);
+ }
+
+ if (bnewSink != bcurrentSink) {
+#ifndef QT_NO_PHONON_EFFECT
+ MediaNode *previous = d->effects.isEmpty() ? source : d->effects.last();
+#else
+ MediaNode *previous = source;
+#endif //QT_NO_PHONON_EFFECT
+ QObject *bprevious = previous->k_ptr->backendObject();
+ if (bcurrentSink)
+ disconnections << QObjectPair(bprevious, bcurrentSink);
+ QObjectPair pair(bprevious, bnewSink);
+ if (!connections.contains(pair)) //avoid connecting twice
+ connections << pair;
+ }
+
+ if (d->executeTransaction(disconnections, connections)) {
+
+ //everything went well: let's update the path and the sink node
+ if (d->sinkNode != sink) {
+ if (d->sinkNode) {
+ d->sinkNode->k_ptr->removeInputPath(*this);
+ d->sinkNode->k_ptr->removeDestructionHandler(d.data());
+ }
+ sink->k_ptr->addInputPath(*this);
+ d->sinkNode = sink;
+ d->sinkNode->k_ptr->addDestructionHandler(d.data());
+ }
+
+ //everything went well: let's update the path and the source node
+ if (d->sourceNode != source) {
+ source->k_ptr->addOutputPath(*this);
+ if (d->sourceNode) {
+ d->sourceNode->k_ptr->removeOutputPath(*this);
+ d->sourceNode->k_ptr->removeDestructionHandler(d.data());
+ }
+ d->sourceNode = source;
+ d->sourceNode->k_ptr->addDestructionHandler(d.data());
+ }
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool Path::disconnect()
+{
+ if (!isValid()) {
+ return false;
+ }
+
+ QObjectList list;
+ if (d->sourceNode)
+ list << d->sourceNode->k_ptr->backendObject();
+#ifndef QT_NO_PHONON_EFFECT
+ foreach(Effect *e, d->effects) {
+ list << e->k_ptr->backendObject();
+ }
+#endif
+ if (d->sinkNode) {
+ list << d->sinkNode->k_ptr->backendObject();
+ }
+
+ //lets build the disconnection list
+ QList<QObjectPair> disco;
+ if (list.count() >=2 ) {
+ QObjectList::const_iterator it = list.begin();
+ for(;it+1 != list.end();++it) {
+ disco << QObjectPair(*it, *(it+1));
+ }
+ }
+
+ if (d->executeTransaction(disco, QList<QObjectPair>())) {
+ //everything went well, let's remove the reference
+ //to the paths from the source and sink
+ if (d->sourceNode) {
+ d->sourceNode->k_ptr->removeOutputPath(*this);
+ d->sourceNode->k_ptr->removeDestructionHandler(d.data());
+ }
+ d->sourceNode = 0;
+
+#ifndef QT_NO_PHONON_EFFECT
+ foreach(Effect *e, d->effects) {
+ e->k_ptr->removeDestructionHandler(d.data());
+ }
+ d->effects.clear();
+#endif
+
+ if (d->sinkNode) {
+ d->sinkNode->k_ptr->removeInputPath(*this);
+ d->sinkNode->k_ptr->removeDestructionHandler(d.data());
+ }
+ d->sinkNode = 0;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+MediaNode *Path::source() const
+{
+ return d->sourceNode;
+}
+
+MediaNode *Path::sink() const
+{
+ return d->sinkNode;
+}
+
+
+
+bool PathPrivate::executeTransaction( const QList<QObjectPair> &disconnections, const QList<QObjectPair> &connections)
+{
+ QSet<QObject*> nodesForTransaction;
+ foreach(const QObjectPair &pair, disconnections) {
+ nodesForTransaction << pair.first;
+ nodesForTransaction << pair.second;
+ }
+ foreach(const QObjectPair &pair, connections) {
+ nodesForTransaction << pair.first;
+ nodesForTransaction << pair.second;
+ }
+ BackendInterface *backend = qobject_cast<BackendInterface *>(Factory::backend());
+ if (!backend)
+ return false;
+
+ ConnectionTransaction transaction(backend, nodesForTransaction);
+ if (!transaction)
+ return false;
+
+ QList<QObjectPair>::const_iterator it = disconnections.begin();
+ for(;it != disconnections.end();++it) {
+ const QObjectPair &pair = *it;
+ if (!backend->disconnectNodes(pair.first, pair.second)) {
+
+ //Error: a disconnection failed
+ QList<QObjectPair>::const_iterator it2 = disconnections.begin();
+ for(; it2 != it; ++it2) {
+ const QObjectPair &pair = *it2;
+ bool success = backend->connectNodes(pair.first, pair.second);
+ Q_ASSERT(success); //a failure here means it is impossible to reestablish the connection
+ Q_UNUSED(success);
+ }
+ return false;
+ }
+ }
+
+ for(it = connections.begin(); it != connections.end();++it) {
+ const QObjectPair &pair = *it;
+ if (!backend->connectNodes(pair.first, pair.second)) {
+ //Error: a connection failed
+ QList<QObjectPair>::const_iterator it2 = connections.begin();
+ for(; it2 != it; ++it2) {
+ const QObjectPair &pair = *it2;
+ bool success = backend->disconnectNodes(pair.first, pair.second);
+ Q_ASSERT(success); //a failure here means it is impossible to reestablish the connection
+ Q_UNUSED(success);
+ }
+
+ //and now let's reconnect the nodes that were disconnected: rollback
+ foreach(const QObjectPair &pair, disconnections) {
+ bool success = backend->connectNodes(pair.first, pair.second);
+ Q_ASSERT(success); //a failure here means it is impossible to reestablish the connection
+ Q_UNUSED(success);
+ }
+
+ return false;
+
+ }
+ }
+ return true;
+}
+
+#ifndef QT_NO_PHONON_EFFECT
+bool PathPrivate::removeEffect(Effect *effect)
+{
+ if (!effects.contains(effect))
+ return false;
+
+ QObject *leftNode = 0;
+ QObject *rightNode = 0;
+ const int index = effects.indexOf(effect);
+ if (index == 0) {
+ leftNode = sourceNode->k_ptr->backendObject(); //append
+ } else {
+ leftNode = effects[index - 1]->k_ptr->backendObject();
+ }
+ if (index == effects.size()-1) {
+ rightNode = sinkNode->k_ptr->backendObject(); //prepend
+ } else {
+ rightNode = effects[index + 1]->k_ptr->backendObject();
+ }
+
+ QList<QObjectPair> disconnections, connections;
+ QObject *beffect = effect->k_ptr->backendObject();
+ disconnections << QObjectPair(leftNode, beffect) << QObjectPair(beffect, rightNode);
+ connections << QObjectPair(leftNode, rightNode);
+
+ if (executeTransaction(disconnections, connections)) {
+ effect->k_ptr->removeDestructionHandler(this);
+ effects.removeAt(index);
+ return true;
+ }
+ return false;
+}
+#endif //QT_NO_PHONON_EFFECT
+
+
+void PathPrivate::phononObjectDestroyed(MediaNodePrivate *mediaNodePrivate)
+{
+ Q_ASSERT(mediaNodePrivate);
+ if (mediaNodePrivate == sinkNode->k_ptr || mediaNodePrivate == sourceNode->k_ptr) {
+ //let's first disconnectq the path from its source and sink
+ QObject *bsink = sinkNode->k_ptr->backendObject();
+ QObject *bsource = sourceNode->k_ptr->backendObject();
+ QList<QObjectPair> disconnections;
+#ifndef QT_NO_PHONON_EFFECT
+ disconnections << QObjectPair(bsource, effects.isEmpty() ? bsink : effects.first()->k_ptr->backendObject());
+ if (!effects.isEmpty())
+ disconnections << QObjectPair(effects.last()->k_ptr->backendObject(), bsink);
+#else
+ disconnections << QObjectPair(bsource, bsink);
+#endif //QT_NO_PHONON_EFFECT
+
+ executeTransaction(disconnections, QList<QObjectPair>());
+
+ Path p; //temporary path
+ p.d = this;
+ if (mediaNodePrivate == sinkNode->k_ptr) {
+ sourceNode->k_ptr->removeOutputPath(p);
+ sourceNode->k_ptr->removeDestructionHandler(this);
+ } else {
+ sinkNode->k_ptr->removeInputPath(p);
+ sinkNode->k_ptr->removeDestructionHandler(this);
+ }
+ sourceNode = 0;
+ sinkNode = 0;
+ } else {
+#ifndef QT_NO_PHONON_EFFECT
+ foreach (Effect *e, effects) {
+ if (e->k_ptr == mediaNodePrivate) {
+ removeEffect(e);
+ }
+ }
+#endif //QT_NO_PHONON_EFFECT
+ }
+}
+
+Path createPath(MediaNode *source, MediaNode *sink)
+{
+ Path p;
+ if (!p.reconnect(source, sink)) {
+ const QObject *const src = source ? (source->k_ptr->qObject()
+#ifndef QT_NO_DYNAMIC_CAST
+ ? source->k_ptr->qObject() : dynamic_cast<QObject *>(source)
+#endif
+ ) : 0;
+ const QObject *const snk = sink ? (sink->k_ptr->qObject()
+#ifndef QT_NO_DYNAMIC_CAST
+ ? sink->k_ptr->qObject() : dynamic_cast<QObject *>(sink)
+#endif
+ ) : 0;
+ pWarning() << "Phonon::createPath: Cannot connect "
+ << (src ? src->metaObject()->className() : "")
+ << '(' << (src ? (src->objectName().isEmpty() ? "no objectName" : qPrintable(src->objectName())) : "null") << ") to "
+ << (snk ? snk->metaObject()->className() : "")
+ << '(' << (snk ? (snk->objectName().isEmpty() ? "no objectName" : qPrintable(snk->objectName())) : "null")
+ << ").";
+ }
+ return p;
+}
+
+
+Path & Path::operator=(const Path &other)
+{
+ d = other.d;
+ return *this;
+}
+
+bool Path::operator==(const Path &other) const
+{
+ return d == other.d;
+}
+
+bool Path::operator!=(const Path &other) const
+{
+ return !operator==(other);
+}
+
+} // namespace Phonon
+
+QT_END_NAMESPACE
diff --git a/src/3rdparty/phonon/phonon/path.h b/src/3rdparty/phonon/phonon/path.h
new file mode 100644
index 0000000000..eeabe82fbf
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/path.h
@@ -0,0 +1,243 @@
+/* This file is part of the KDE project
+ Copyright (C) 2007 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef PHONON_PATH_H
+#define PHONON_PATH_H
+
+#include "phonon_export.h"
+#include "objectdescription.h"
+
+#include <QtCore/QExplicitlySharedDataPointer>
+
+QT_BEGIN_HEADER
+QT_BEGIN_NAMESPACE
+
+template<class T> class QList;
+
+namespace Phonon
+{
+
+class PathPrivate;
+class Effect;
+class MediaNode;
+
+/** \class Path path.h Phonon/Path
+ * \short Connection object providing convenient effect insertion
+ *
+ * \code
+MediaObject *media = new MediaObject;
+AudioOutput *output = new AudioOutput(Phonon::MusicCategory);
+Path path = Phonon::createPath(media, output);
+Q_ASSERT(path.isValid()); // for this simple case the path should always be
+ //valid - there are unit tests to ensure it
+// insert an effect
+QList<EffectDescription> effectList = BackendCapabilities::availableAudioEffects();
+if (!effectList.isEmpty()) {
+ Effect *effect = path.insertEffect(effectList.first());
+}
+ * \endcode
+ * \ingroup Playback
+ * \ingroup Recording
+ * \author Matthias Kretz <kretz@kde.org>
+ * \author Thierry Bastian <thierry.bastian@trolltech.com>
+ */
+class PHONON_EXPORT Path
+{
+ friend class FactoryPrivate;
+ public:
+ /**
+ * Destroys this reference to the Path. If the path was valid the connection is not broken
+ * as both the source and the sink MediaNodes still keep a reference to the Path.
+ *
+ * \see disconnect
+ */
+ ~Path();
+
+ /**
+ * Creates an invalid path.
+ *
+ * You can still make it a valid path by calling reconnect. To create a path you should use
+ * createPath, though.
+ *
+ * \see createPath
+ * \see isValid
+ */
+ Path();
+
+ /**
+ * Constructs a copy of the given path.
+ *
+ * This constructor is fast thanks to explicit sharing.
+ */
+ Path(const Path &);
+
+ /**
+ * Returns whether the path object connects two MediaNodes or not.
+ *
+ * \return \p true when the path connects two MediaNodes
+ * \return \p false when the path is disconnected
+ */
+ bool isValid() const;
+ //MediaStreamTypes mediaStreamTypes() const;
+
+#ifndef QT_NO_PHONON_EFFECT
+ /**
+ * Creates and inserts an effect into the path.
+ *
+ * You may insert effects of the same class as often as you like,
+ * but if you insert the same object, the call will fail.
+ *
+ * \param desc The EffectDescription object for the effect to be inserted.
+ *
+ * \param insertBefore If you already inserted an effect you can
+ * tell with this parameter in which order the data gets
+ * processed. If this is \c 0 the effect is appended at the end of
+ * the processing list. If the effect has not been inserted before
+ * the method will do nothing and return \c false.
+ *
+ * \return Returns a pointer to the effect object if it could be inserted
+ * at the specified position. If \c 0 is returned the effect was not
+ * inserted.
+ *
+ * \see removeEffect
+ * \see effects
+ */
+ Effect *insertEffect(const EffectDescription &desc, Effect *insertBefore = 0);
+
+ /**
+ * Inserts an effect into the path.
+ *
+ * You may insert effects of the same class as often as you like,
+ * but if you insert the same object, the call will fail.
+ *
+ * \param newEffect An Effect object.
+ *
+ * \param insertBefore If you already inserted an effect you can
+ * tell with this parameter in which order the data gets
+ * processed. If this is \c 0 the effect is appended at the end of
+ * the processing list. If the effect has not been inserted before
+ * the method will do nothing and return \c false.
+ *
+ * \return Returns whether the effect could be inserted at the
+ * specified position. If \c false is returned the effect was not
+ * inserted.
+ *
+ * \see removeEffect
+ * \see effects
+ */
+ bool insertEffect(Effect *newEffect, Effect *insertBefore = 0);
+
+ /**
+ * Removes an effect from the path.
+ *
+ * If the effect gets deleted while it is still connected the effect
+ * will be removed automatically.
+ *
+ * \param effect The effect to be removed.
+ *
+ * \return Returns whether the call was successful. If it returns
+ * \c false the effect could not be found in the path, meaning it
+ * has not been inserted before.
+ *
+ * \see insertEffect
+ * \see effects
+ */
+ bool removeEffect(Effect *effect);
+
+ /**
+ * Returns a list of Effect objects that are currently
+ * used as effects. The order in the list determines the order the
+ * signal is sent through the effects.
+ *
+ * \return A list with all current effects.
+ *
+ * \see insertEffect
+ * \see removeEffect
+ */
+ QList<Effect *> effects() const;
+#endif //QT_NO_PHONON_EFFECT
+
+ /**
+ * Tries to change the MediaNodes the path is connected to.
+ *
+ * If reconnect fails the old connection is kept.
+ */
+ bool reconnect(MediaNode *source, MediaNode *sink);
+
+ /**
+ * Disconnects the path from the MediaNodes it was connected to. This invalidates the path
+ * (isValid returns \p false then).
+ */
+ bool disconnect();
+
+ /**
+ * Assigns \p p to this Path and returns a reference to this Path.
+ *
+ * This operation is fast thanks to explicit sharing.
+ */
+ Path &operator=(const Path &p);
+
+ /**
+ * Returns \p true if this Path is equal to \p p; otherwise returns \p false;
+ */
+ bool operator==(const Path &p) const;
+
+ /**
+ * Returns \p true if this Path is not equal to \p p; otherwise returns \p false;
+ */
+ bool operator!=(const Path &p) const;
+
+ /**
+ * Returns the source MediaNode used by the path.
+ */
+ MediaNode *source() const;
+
+ /**
+ * Returns the sink MediaNode used by the path.
+ */
+ MediaNode *sink() const;
+
+
+ protected:
+ friend class PathPrivate;
+ QExplicitlySharedDataPointer<PathPrivate> d;
+};
+
+/**
+ * \relates Path
+ * Creates a new Path connecting two MediaNodes.
+ *
+ * The implementation will automatically select the right format and media type. E.g. connecting a
+ * MediaObject and AudioOutput will create a Path object connecting the audio. This might be
+ * represented as PCM or perhaps even AC3 depending on the AudioOutput object.
+ *
+ * \param source The MediaNode to connect an output from
+ * \param sink The MediaNode to connect to.
+ */
+PHONON_EXPORT Path createPath(MediaNode *source, MediaNode *sink);
+
+} // namespace Phonon
+
+QT_END_NAMESPACE
+QT_END_HEADER
+
+#endif // PHONON_PATH_H
diff --git a/src/3rdparty/phonon/phonon/path_p.h b/src/3rdparty/phonon/phonon/path_p.h
new file mode 100644
index 0000000000..1345ad5ddf
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/path_p.h
@@ -0,0 +1,79 @@
+/* This file is part of the KDE project
+ Copyright (C) 2007 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef PATH_P_H
+#define PATH_P_H
+
+#include "path.h"
+#include <QtCore/QPair>
+#include <QtCore/QList>
+#include <QtCore/QSharedData>
+#include "effect.h"
+#include "medianodedestructionhandler_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QObject;
+
+namespace Phonon
+{
+
+class MediaNode;
+typedef QPair<QObject*, QObject*> QObjectPair;
+
+
+class PathPrivate : public QSharedData, private MediaNodeDestructionHandler
+{
+ friend class Path;
+ public:
+ PathPrivate()
+ : sourceNode(0), sinkNode(0)
+#ifndef QT_NO_PHONON_EFFECT
+ , effectsParent(0)
+#endif //QT_NO_PHONON_EFFECT
+ {
+ }
+
+ ~PathPrivate();
+
+ MediaNode *sourceNode;
+ MediaNode *sinkNode;
+
+ protected:
+ void phononObjectDestroyed(MediaNodePrivate *);
+
+#ifndef QT_NO_PHONON_EFFECT
+ QObject *effectsParent; // used as parent for Effects created in insertEffect
+ QList<Effect *> effects;
+#endif
+ private:
+ bool executeTransaction( const QList<QObjectPair> &disconnections, const QList<QObjectPair> &connections);
+#ifndef QT_NO_PHONON_EFFECT
+ bool removeEffect(Effect *effect);
+#endif
+};
+
+} // namespace Phonon
+
+QT_END_NAMESPACE
+
+#endif // PATH_P_H
diff --git a/src/3rdparty/phonon/phonon/phonon_export.h b/src/3rdparty/phonon/phonon/phonon_export.h
new file mode 100644
index 0000000000..e579f67b04
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/phonon_export.h
@@ -0,0 +1,58 @@
+/* This file is part of the KDE project
+ Copyright (C) 2007 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef PHONON_EXPORT_H
+#define PHONON_EXPORT_H
+
+#include <QtCore/QtGlobal>
+
+#ifndef PHONON_EXPORT
+# if defined Q_WS_WIN
+# ifdef MAKE_PHONON_LIB /* We are building this library */
+# define PHONON_EXPORT Q_DECL_EXPORT
+# else /* We are using this library */
+# define PHONON_EXPORT Q_DECL_IMPORT
+# endif
+# else /* UNIX */
+# define PHONON_EXPORT Q_DECL_EXPORT
+# endif
+#endif
+
+#ifndef PHONON_EXPORT_DEPRECATED
+# define PHONON_EXPORT_DEPRECATED Q_DECL_DEPRECATED PHONON_EXPORT
+#endif
+
+// QT_(BEGIN|END)_NAMESPACE appeared in 4.4
+#ifndef QT_BEGIN_NAMESPACE
+# define QT_BEGIN_NAMESPACE
+#endif
+#ifndef QT_END_NAMESPACE
+# define QT_END_NAMESPACE
+#endif
+
+// silence syncqt
+QT_BEGIN_HEADER
+QT_BEGIN_NAMESPACE
+
+QT_END_NAMESPACE
+QT_END_HEADER
+
+#endif
diff --git a/src/3rdparty/phonon/phonon/phonondefs.h b/src/3rdparty/phonon/phonon/phonondefs.h
new file mode 100644
index 0000000000..d1a114a52d
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/phonondefs.h
@@ -0,0 +1,144 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006-2007 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef PHONONDEFS_H
+#define PHONONDEFS_H
+
+#include <QtCore/QtGlobal>
+#include "phonon_export.h"
+
+QT_BEGIN_HEADER
+QT_BEGIN_NAMESPACE
+
+#ifdef PHONON_BACKEND_VERSION_4_3
+# ifndef PHONON_BACKEND_VERSION_4_2
+# define PHONON_BACKEND_VERSION_4_2
+# endif
+#endif
+
+// the following inlines are correct - exclude per line doesn't work for multiline-macros so exclude
+// the whole file for inline checks
+//krazy:excludeall=inline
+#define K_DECLARE_PRIVATE(Class) \
+ inline Class##Private* k_func() { return reinterpret_cast<Class##Private *>(k_ptr); } \
+ inline const Class##Private* k_func() const { return reinterpret_cast<const Class##Private *>(k_ptr); } \
+ friend class Class##Private;
+
+/**
+ * \internal
+ * Used in class declarations to provide the needed functions. This is used for
+ * abstract base classes.
+ *
+ * \param classname The Name of the class this macro is used for.
+ *
+ * Example:
+ * \code
+ * class AbstractEffect : public QObject
+ * {
+ * Q _OBJECT
+ * Q_PROPERTY(int propertyA READ propertyA WRITE setPropertyA)
+ * PHONON_ABSTRACTBASE(AbstractEffect)
+ * public:
+ * int propertyA() const;
+ * void setPropertyA(int);
+ * };
+ * \endcode
+ *
+ * \see PHONON_OBJECT
+ * \see PHONON_HEIR
+ */
+#define PHONON_ABSTRACTBASE(classname) \
+protected: \
+ /**
+ * \internal
+ * Constructor that is called from derived classes.
+ *
+ * \param parent Standard QObject parent.
+ */ \
+ classname(classname ## Private &dd, QObject *parent); \
+private:
+
+/**
+ * \internal
+ * Used in class declarations to provide the needed functions. This is used for
+ * classes that inherit QObject directly.
+ *
+ * \param classname The Name of the class this macro is used for.
+ *
+ * Example:
+ * \code
+ * class EffectSettings : public QObject
+ * {
+ * Q _OBJECT
+ * Q_PROPERTY(int propertyA READ propertyA WRITE setPropertyA)
+ * PHONON_OBJECT(EffectSettings)
+ * public:
+ * int propertyA() const;
+ * void setPropertyA(int);
+ * };
+ * \endcode
+ *
+ * \see PHONON_ABSTRACTBASE
+ * \see PHONON_HEIR
+ */
+#define PHONON_OBJECT(classname) \
+public: \
+ /**
+ * Constructs an object with the given \p parent.
+ */ \
+ classname(QObject *parent = 0); \
+private:
+
+/**
+ * \internal
+ * Used in class declarations to provide the needed functions. This is used for
+ * classes that inherit another Phonon object.
+ *
+ * \param classname The Name of the class this macro is used for.
+ *
+ * Example:
+ * \code
+ * class ConcreteEffect : public AbstractEffect
+ * {
+ * Q _OBJECT
+ * Q_PROPERTY(int propertyB READ propertyB WRITE setPropertyB)
+ * PHONON_HEIR(ConcreteEffect)
+ * public:
+ * int propertyB() const;
+ * void setPropertyB(int);
+ * };
+ * \endcode
+ *
+ * \see PHONON_ABSTRACTBASE
+ * \see PHONON_OBJECT
+ */
+#define PHONON_HEIR(classname) \
+public: \
+ /**
+ * Constructs an object with the given \p parent.
+ */ \
+ classname(QObject *parent = 0); \
+
+QT_END_NAMESPACE
+QT_END_HEADER
+
+#endif // PHONONDEFS_H
diff --git a/src/3rdparty/phonon/phonon/phonondefs_p.h b/src/3rdparty/phonon/phonon/phonondefs_p.h
new file mode 100644
index 0000000000..09037b56a6
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/phonondefs_p.h
@@ -0,0 +1,369 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006-2007 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef PHONONDEFS_P_H
+#define PHONONDEFS_P_H
+
+#include <QtCore/QMetaType>
+#include "medianode_p.h"
+
+#define K_D(Class) Class##Private *const d = k_func()
+
+#define PHONON_CONCAT_HELPER_INTERNAL(x, y) x ## y
+#define PHONON_CONCAT_HELPER(x, y) PHONON_CONCAT_HELPER_INTERNAL(x, y)
+
+#define PHONON_PRIVATECLASS \
+protected: \
+ virtual bool aboutToDeleteBackendObject(); \
+ virtual void createBackendObject(); \
+ /**
+ * \internal
+ * After construction of the Iface object this method is called
+ * throughout the complete class hierarchy in order to set up the
+ * properties that were already set on the public interface.
+ *
+ * An example implementation could look like this:
+ * \code
+ * ParentClassPrivate::setupBackendObject();
+ * m_iface->setPropertyA(d->propertyA);
+ * m_iface->setPropertyB(d->propertyB);
+ * \endcode
+ */ \
+ void setupBackendObject();
+
+#define PHONON_PRIVATEABSTRACTCLASS \
+protected: \
+ virtual bool aboutToDeleteBackendObject(); \
+ /**
+ * \internal
+ * After construction of the Iface object this method is called
+ * throughout the complete class hierarchy in order to set up the
+ * properties that were already set on the public interface.
+ *
+ * An example implementation could look like this:
+ * \code
+ * ParentClassPrivate::setupBackendObject();
+ * m_iface->setPropertyA(d->propertyA);
+ * m_iface->setPropertyB(d->propertyB);
+ * \endcode
+ */ \
+ void setupBackendObject();
+
+#define PHONON_ABSTRACTBASE_IMPL \
+PHONON_CLASSNAME::PHONON_CLASSNAME(PHONON_CONCAT_HELPER(PHONON_CLASSNAME, Private) &dd, QObject *parent) \
+ : QObject(parent), \
+ MediaNode(dd) \
+{ \
+}
+
+#define PHONON_OBJECT_IMPL \
+PHONON_CLASSNAME::PHONON_CLASSNAME(QObject *parent) \
+ : QObject(parent), \
+ MediaNode(*new PHONON_CONCAT_HELPER(PHONON_CLASSNAME, Private)()) \
+{ \
+} \
+void PHONON_CONCAT_HELPER(PHONON_CLASSNAME, Private)::createBackendObject() \
+{ \
+ if (m_backendObject) \
+ return; \
+ Q_Q(PHONON_CLASSNAME); \
+ m_backendObject = Factory::PHONON_CONCAT_HELPER(create, PHONON_CLASSNAME)(q); \
+ if (m_backendObject) { \
+ setupBackendObject(); \
+ } \
+}
+
+#define PHONON_HEIR_IMPL(parentclass) \
+PHONON_CLASSNAME::PHONON_CLASSNAME(QObject *parent) \
+ : parentclass(*new PHONON_CONCAT_HELPER(PHONON_CLASSNAME, Private), parent) \
+{ \
+} \
+void PHONON_CONCAT_HELPER(PHONON_CLASSNAME, Private)::createBackendObject() \
+{ \
+ if (m_backendObject) \
+ return; \
+ Q_Q(PHONON_CLASSNAME); \
+ m_backendObject = Factory::PHONON_CONCAT_HELPER(create, PHONON_CLASSNAME)(q); \
+ if (m_backendObject) { \
+ setupBackendObject(); \
+ } \
+}
+
+#define BACKEND_GET(returnType, returnVar, methodName) \
+QMetaObject::invokeMethod(d->m_backendObject, methodName, Qt::DirectConnection, Q_RETURN_ARG(returnType, returnVar))
+#define BACKEND_GET1(returnType, returnVar, methodName, varType1, var1) \
+QMetaObject::invokeMethod(d->m_backendObject, methodName, Qt::DirectConnection, Q_RETURN_ARG(returnType, returnVar), Q_ARG(varType1, var1))
+#define BACKEND_GET2(returnType, returnVar, methodName, varType1, var1, varType2, var2) \
+QMetaObject::invokeMethod(d->m_backendObject, methodName, Qt::DirectConnection, Q_RETURN_ARG(returnType, returnVar), Q_ARG(varType1, var1), Q_ARG(varType2, var2))
+#define BACKEND_CALL(methodName) \
+QMetaObject::invokeMethod(d->m_backendObject, methodName, Qt::DirectConnection)
+#define BACKEND_CALL1(methodName, varType1, var1) \
+QMetaObject::invokeMethod(d->m_backendObject, methodName, Qt::DirectConnection, Q_ARG(varType1, var1))
+#define BACKEND_CALL2(methodName, varType1, var1, varType2, var2) \
+QMetaObject::invokeMethod(d->m_backendObject, methodName, Qt::DirectConnection, Q_ARG(varType1, var1), Q_ARG(varType2, var2))
+
+#define pBACKEND_GET(returnType, returnVar, methodName) \
+QMetaObject::invokeMethod(m_backendObject, methodName, Qt::DirectConnection, Q_RETURN_ARG(returnType, returnVar))
+#define pBACKEND_GET1(returnType, returnVar, methodName, varType1, var1) \
+QMetaObject::invokeMethod(m_backendObject, methodName, Qt::DirectConnection, Q_RETURN_ARG(returnType, returnVar), Q_ARG(varType1, var1))
+#define pBACKEND_GET2(returnType, returnVar, methodName, varType1, var1, varType2, var2) \
+QMetaObject::invokeMethod(m_backendObject, methodName, Qt::DirectConnection, Q_RETURN_ARG(returnType, returnVar), Q_ARG(varType1, var1), Q_ARG(varType2, var2))
+#define pBACKEND_CALL(methodName) \
+QMetaObject::invokeMethod(m_backendObject, methodName, Qt::DirectConnection)
+#define pBACKEND_CALL1(methodName, varType1, var1) \
+QMetaObject::invokeMethod(m_backendObject, methodName, Qt::DirectConnection, Q_ARG(varType1, var1))
+#define pBACKEND_CALL2(methodName, varType1, var1, varType2, var2) \
+QMetaObject::invokeMethod(m_backendObject, methodName, Qt::DirectConnection, Q_ARG(varType1, var1), Q_ARG(varType2, var2))
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+ namespace
+ {
+ class NoIface;
+
+ /// All template arguments are valid
+ template<typename T> struct IsValid { enum { Result = true }; };
+ /// except NoIface
+ template<> struct IsValid<NoIface> { enum { Result = false }; };
+
+ template<class T> inline T my_cast(QObject *o) { return qobject_cast<T>(o); }
+ template<class T> inline T my_cast(const QObject *o) { return qobject_cast<T>(o); }
+
+ template<> inline NoIface *my_cast<NoIface *>(QObject *) { return 0; }
+ template<> inline NoIface *my_cast<NoIface *>(const QObject *) { return 0; }
+ } // anonymous namespace
+
+ /**
+ * \internal
+ *
+ * \brief Helper class to cast the backend object to the correct version of the interface.
+ *
+ * Additions to the backend interfaces cannot be done by adding virtual methods as that would
+ * break the binary interface. So the old class is renamed and a new class with the old name
+ * inheriting the old class is added, containing all the new virtual methods.
+ * Example:
+ * \code
+ class FooInterface
+ {
+ public:
+ virtual ~FooInterface() {}
+ virtual oldMethod() = 0;
+ };
+ Q_DECLARE_INTERFACE(FooInterface, "FooInterface0.phonon.kde.org")
+ * \endcode
+ * becomes
+ * \code
+ class FooInterface0
+ {
+ public:
+ virtual ~FooInterface0() {}
+ virtual oldMethod() = 0;
+ };
+ class FooInterface : public FooInterface0
+ {
+ public:
+ virtual newMethod() = 0;
+ };
+ Q_DECLARE_INTERFACE(FooInterface0, "FooInterface0.phonon.kde.org")
+ Q_DECLARE_INTERFACE(FooInterface, "FooInterface1.phonon.kde.org")
+ * \endcode
+ *
+ * With this, backends compiled against the old header can be qobject_casted to FooInterface0,
+ * but not to FooInterface. On the other hand backends compiled against the new header (they first
+ * need to implement newMethod) can only be qobject_casted to FooInterface but not to
+ * FooInterface0. (The qobject_cast relies on the string in Q_DECLARE_INTERFACE and not the
+ * class name which is why it behaves that way.)
+ *
+ * Now, in order to call oldMethod, the code needs to try to cast to both FooInterface and
+ * FooInterface0 (new backends will work with the former, old backends with the latter) and then
+ * if one of them in non-zero call oldMethod on it.
+ *
+ * To call newMethod only a cast to FooInterface needs to be done.
+ *
+ * The Iface class does all this for you for up to three (for now) interface revisions. Just
+ * create an object like this:
+ * \code
+ Iface<FooInterface0, FooInterface> iface0(d);
+ if (iface0) {
+ iface0->oldMethod();
+ }
+ Iface<FooInterface> iface(d);
+ if (iface) {
+ iface->newMethod();
+ }
+ * \endcode
+ *
+ * This becomes a bit more convenient if you add macros like this:
+ * \code
+ #define IFACES1 FooInterface
+ #define IFACES0 FooInterface0, IFACES1
+ * \endcode
+ * which you can use like this:
+ * \code
+ Iface<IFACES0> iface0(d);
+ if (iface0) {
+ iface0->oldMethod();
+ }
+ Iface<IFACES1> iface(d);
+ if (iface) {
+ iface->newMethod();
+ }
+ * \endcode
+ * With the next revision you can then change the macros to
+ * \code
+ #define IFACES2 FooInterface
+ #define IFACES1 FooInterface1, IFACES2
+ #define IFACES0 FooInterface0, IFACES1
+ * \endcode
+ *
+ * \author Matthias Kretz <kretz@kde.org>
+ */
+ template<class T0, class T1 = NoIface, class T2 = NoIface>
+ class Iface
+ {
+ public:
+ static inline T0 *cast(MediaNodePrivate *const d)
+ {
+ if (IsValid<T1>::Result) {
+ T0 *ret;
+ if (IsValid<T2>::Result) {
+ ret = reinterpret_cast<T0 *>(my_cast<T2 *>(d->m_backendObject));
+ if (ret) return ret;
+ }
+ ret = reinterpret_cast<T0 *>(my_cast<T1 *>(d->m_backendObject));
+ if (ret) return ret;
+ }
+ return qobject_cast<T0 *>(d->m_backendObject);
+ }
+
+ static inline const T0 *cast(const MediaNodePrivate *const d)
+ {
+ if (IsValid<T1>::Result) {
+ const T0 *ret;
+ if (IsValid<T2>::Result) {
+ ret = reinterpret_cast<const T0 *>(my_cast<T2 *>(d->m_backendObject));
+ if (ret) return ret;
+ }
+ ret = reinterpret_cast<const T0 *>(my_cast<T1 *>(d->m_backendObject));
+ if (ret) return ret;
+ }
+ return qobject_cast<T0 *>(d->m_backendObject);
+ }
+
+ inline Iface(MediaNodePrivate *const d) : iface(cast(d)) {}
+ inline operator T0 *() { return iface; }
+ inline operator const T0 *() const { return iface; }
+ inline T0 *operator->() { Q_ASSERT(iface); return iface; }
+ inline const T0 *operator->() const { Q_ASSERT(iface); return iface; }
+ private:
+ T0 *const iface;
+ };
+
+ template<class T0, class T1 = NoIface, class T2 = NoIface>
+ class ConstIface
+ {
+ public:
+ inline ConstIface(const MediaNodePrivate *const d) : iface(Iface<T0, T1, T2>::cast(d)) {}
+ inline operator const T0 *() const { return iface; }
+ inline const T0 *operator->() const { Q_ASSERT(iface); return iface; }
+ private:
+ const T0 *const iface;
+ };
+} // namespace Phonon
+
+QT_END_NAMESPACE
+
+#define INTERFACE_CALL(function) \
+Iface<PHONON_INTERFACENAME >::cast(d)->function
+
+#define pINTERFACE_CALL(function) \
+Iface<PHONON_INTERFACENAME >::cast(this)->function
+
+#define PHONON_GETTER(rettype, name, retdefault) \
+rettype PHONON_CLASSNAME::name() const \
+{ \
+ const PHONON_CONCAT_HELPER(PHONON_CLASSNAME, Private) *d = k_func(); \
+ if (!d->m_backendObject) \
+ return retdefault; \
+ rettype ret; \
+ BACKEND_GET(rettype, ret, #name); \
+ return ret; \
+}
+
+#define PHONON_INTERFACE_GETTER(rettype, name, retdefault) \
+rettype PHONON_CLASSNAME::name() const \
+{ \
+ const PHONON_CONCAT_HELPER(PHONON_CLASSNAME, Private) *d = k_func(); \
+ if (!d->m_backendObject) \
+ return retdefault; \
+ return Iface<PHONON_INTERFACENAME >::cast(d)->name(); \
+}
+
+#define PHONON_GETTER1(rettype, name, retdefault, argtype1, argvar1) \
+rettype PHONON_CLASSNAME::name(argtype1 argvar1) const \
+{ \
+ const PHONON_CONCAT_HELPER(PHONON_CLASSNAME, Private) *d = k_func(); \
+ if (!d->m_backendObject) \
+ return retdefault; \
+ rettype ret; \
+ BACKEND_GET1(rettype, ret, #name, const QObject *, argvar1->k_ptr->backendObject()); \
+ return ret; \
+}
+
+#define PHONON_INTERFACE_GETTER1(rettype, name, retdefault, argtype1, argvar1) \
+rettype PHONON_CLASSNAME::name(argtype1 argvar1) const \
+{ \
+ const PHONON_CONCAT_HELPER(PHONON_CLASSNAME, Private) *d = k_func(); \
+ if (!d->m_backendObject) \
+ return retdefault; \
+ return Iface<PHONON_INTERFACENAME >::cast(d)->name(argvar1->k_ptr->backendObject()); \
+}
+
+#define PHONON_SETTER(functionname, privatevar, argtype1) \
+void PHONON_CLASSNAME::functionname(argtype1 x) \
+{ \
+ PHONON_CONCAT_HELPER(PHONON_CLASSNAME, Private) *d = k_func(); \
+ d->privatevar = x; \
+ if (k_ptr->backendObject()) { \
+ BACKEND_CALL1(#functionname, argtype1, x); \
+ } \
+}
+
+#define PHONON_INTERFACE_SETTER(functionname, privatevar, argtype1) \
+void PHONON_CLASSNAME::functionname(argtype1 x) \
+{ \
+ PHONON_CONCAT_HELPER(PHONON_CLASSNAME, Private) *d = k_func(); \
+ d->privatevar = x; \
+ if (k_ptr->backendObject()) { \
+ Iface<PHONON_INTERFACENAME >::cast(d)->functionname(x); \
+ } \
+}
+
+#ifndef METATYPE_QLIST_INT_DEFINED
+#define METATYPE_QLIST_INT_DEFINED
+// Want this exactly once, see phonondefs_p.h kcm/outputdevicechoice.cpp
+Q_DECLARE_METATYPE(QList<int>)
+#endif
+
+#endif // PHONONDEFS_P_H
diff --git a/src/3rdparty/phonon/phonon/phononnamespace.cpp b/src/3rdparty/phonon/phonon/phononnamespace.cpp
new file mode 100644
index 0000000000..f594d3c627
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/phononnamespace.cpp
@@ -0,0 +1,92 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006-2007 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "phononnamespace.h"
+#include "phononnamespace_p.h"
+#include "phonondefs_p.h"
+
+#include "factory_p.h"
+
+#include <QtCore/QCoreApplication>
+#include <QtCore/QList>
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+ /*!
+ Returns the version number of Phonon at run-time as a string (for
+ example, "4.0.0"). This may be a different version than the
+ version the application was compiled against.
+
+ \sa PHONON_VERSION_STR
+ */
+ const char *phononVersion()
+ {
+ return PHONON_VERSION_STR;
+ }
+
+ QString categoryToString(Category c)
+ {
+ switch(c)
+ {
+ case Phonon::NoCategory:
+ break;
+ case Phonon::NotificationCategory:
+ return QCoreApplication::translate("Phonon::", "Notifications");
+ case Phonon::MusicCategory:
+ return QCoreApplication::translate("Phonon::", "Music");
+ case Phonon::VideoCategory:
+ return QCoreApplication::translate("Phonon::", "Video");
+ case Phonon::CommunicationCategory:
+ return QCoreApplication::translate("Phonon::", "Communication");
+ case Phonon::GameCategory:
+ return QCoreApplication::translate("Phonon::", "Games");
+ case Phonon::AccessibilityCategory:
+ return QCoreApplication::translate("Phonon::", "Accessibility");
+ }
+ return QString();
+ }
+}
+
+static int registerPhononMetaTypes()
+{
+ qRegisterMetaType<Phonon::State>();
+ qRegisterMetaType<Phonon::ErrorType>();
+ qRegisterMetaType<Phonon::Category>();
+
+ // need those for QSettings
+ qRegisterMetaType<QList<int> >();
+ qRegisterMetaTypeStreamOperators<QList<int> >("QList<int>");
+
+ return 0; // something
+}
+
+#ifdef Q_CONSTRUCTOR_FUNCTION
+Q_CONSTRUCTOR_FUNCTION(registerPhononMetaTypes)
+#else
+static const int _Phonon_registerMetaTypes = registerPhononMetaTypes();
+#endif
+
+QT_END_NAMESPACE
+
+// vim: sw=4 ts=4
diff --git a/src/3rdparty/phonon/phonon/phononnamespace.h b/src/3rdparty/phonon/phonon/phononnamespace.h
new file mode 100644
index 0000000000..0bbf4f4e46
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/phononnamespace.h
@@ -0,0 +1,306 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005-2008 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef PHONONNAMESPACE_H
+#define PHONONNAMESPACE_H
+
+#include "phonon_export.h"
+
+/**
+ * Helper macro that can be used like
+ * \code
+ * #if (PHONON_VERSION >= PHONON_VERSION_CHECK(4, 4, 0))
+ * \endcode
+ */
+#define PHONON_VERSION_CHECK(major, minor, patch) ((major<<16)|(minor<<8)|(patch))
+
+/**
+ * PHONON_VERSION is (major << 16) + (minor << 8) + patch.
+ */
+#define PHONON_VERSION PHONON_VERSION_CHECK(4, 3, 1)
+
+/**
+ * PHONON_VERSION_STR is "major.minor.patch". E.g. "4.2.1"
+ */
+#define PHONON_VERSION_STR "4.3.1"
+
+QT_BEGIN_HEADER
+QT_BEGIN_NAMESPACE
+
+class QString;
+
+/**
+ * \brief The %KDE Multimedia classes
+ *
+ * In this Namespace you find the classes to access Multimedia functions for
+ * audio and video playback. Those classes are not dependent
+ * on any specific framework (like they were in pre KDE4 times) but rather use
+ * exchangeable backends to do the work.
+ *
+ * If you want to write a new backend take a look at \ref phonon_backend_development_page.
+ *
+ * \author Matthias Kretz <kretz@kde.org>
+ */
+namespace Phonon
+{
+ PHONON_EXPORT const char *phononVersion();
+
+ /**
+ * Enum to identify the media discs supported by MediaObject.
+ *
+ * \see MediaSource(Phonon::DiscType, const QString &deviceName)
+ */
+ enum DiscType {
+ /**
+ * No disc was selected. This is only useful as a return value from
+ * MediaSource::distType();
+ */
+ NoDisc = -1,
+ /**
+ * Identifies Audio CDs.
+ */
+ Cd = 0,
+ /**
+ * Identifies DVDs (not arbitrary data DVDs, only movie DVDs).
+ */
+ Dvd = 1,
+ /**
+ * Identifies Video CDs.
+ */
+ Vcd = 2
+ };
+
+ /**
+ * Provided as keys for \ref MediaObject::metaData for convenience, in addition to the strings defined in
+ * the Ogg Vorbis specification.
+ */
+ enum MetaData {
+ /**
+ * The artist generally considered responsible for the work. In popular
+ * music this is usually the performing band or singer. For classical
+ * music it would be the composer. For an audio book it would be the
+ * author of the original text.
+ */
+ ArtistMetaData,
+ /**
+ * The collection name to which this track belongs.
+ */
+ AlbumMetaData,
+ /**
+ * Track/Work name
+ */
+ TitleMetaData,
+ /**
+ * Date the track was recorded
+ */
+ DateMetaData,
+ /**
+ * A short text indication of music genre
+ */
+ GenreMetaData,
+ /**
+ * The track number of this piece if part of a specific larger
+ * collection or album
+ */
+ TracknumberMetaData,
+ /**
+ * A short text description of the contents
+ */
+ DescriptionMetaData,
+ MusicBrainzDiscIdMetaData
+ };
+
+ /**
+ * The state the media producing object is in at the moment.
+ *
+ * \see MediaObject
+ */
+ enum State
+ {
+ /**
+ * After construction it might take a while before the Player is
+ * ready to play(). Normally this doesn't happen for local
+ * files, but can happen for remote files where the asynchronous
+ * mimetype detection and prebuffering can take a while.
+ */
+ LoadingState,
+ /**
+ * The Player has a valid media file loaded and is ready for
+ * playing.
+ */
+ StoppedState,
+ /**
+ * The Player is playing a media file.
+ */
+ PlayingState,
+ /**
+ * The Player is waiting for data to be able to continue
+ * playing.
+ */
+ BufferingState,
+ /**
+ * The Player is currently paused.
+ */
+ PausedState,
+ /**
+ * An unrecoverable error occurred. The Object is unusable in this state.
+ */
+ ErrorState
+ };
+
+ /**
+ * Set's the category your program should be listed in in the mixer.
+ *
+ * A Jukebox will set this to Music, a VoIP program to Communication, a
+ * DVD player to video, and so on.
+ *
+ * \note These categories can also become useful for an application that
+ * controls the volumes automatically, like turning down the music when a call
+ * comes in, or turning down the notifications when the media player knows
+ * it's playing classical music.
+ *
+ * \see AudioOutput::setCategory
+ */
+ enum Category
+ {
+ /**
+ * Will make use of the default device.
+ */
+ NoCategory = -1,
+ /**
+ * If the sounds produced are notifications (bing, beep and such) you
+ * should use this category.
+ */
+ NotificationCategory = 0,
+ /**
+ * If your application is a music player (like a jukebox or media player
+ * playing an audio file).
+ */
+ MusicCategory = 1,
+ /**
+ * If the sound is the audio channel of a video.
+ */
+ VideoCategory = 2,
+ /**
+ * If your applications produces sounds from communication with somebody
+ * else (VoIP, voice chat).
+ */
+ CommunicationCategory = 3,
+ /**
+ * Sound produced by a computer game should go into this category.
+ */
+ GameCategory = 4,
+ /**
+ * Sounds produced for accessibility (e.g. Text-To-Speech)
+ */
+ AccessibilityCategory = 5,
+ /**
+ * \internal
+ * Holds the largest value of categories.
+ */
+ LastCategory = AccessibilityCategory
+ };
+
+ /**
+ * Tells your program how to recover from an error.
+ *
+ * \see MediaObject::errorType()
+ */
+ enum ErrorType {
+ /**
+ * No error. MediaObject::errorType() returns this if
+ * MediaObject::state() != Phonon::ErrorState.
+ */
+ NoError = 0,
+ /**
+ * Playback should work, and trying with another URL should work.
+ */
+ NormalError = 1,
+ /**
+ * Something important does not work. Your program cannot continue
+ * playback or capture or whatever it was trying to do
+ * without help from the user.
+ */
+ FatalError = 2
+ };
+
+ /**
+ * Returns a (translated) string to show to the user identifying the given
+ * Category.
+ */
+ PHONON_EXPORT QString categoryToString(Category c);
+
+ // TODO: naming
+ /*enum MediaStreamType {
+ Audio = 1,
+ Video = 2,
+ StillImage = 4,
+ Subtitle = 8,
+ AllMedia = 0xFFFFFFFF
+ };
+ Q_DECLARE_FLAGS(MediaStreamTypes, MediaStreamType)*/
+} // namespace Phonon
+//Q_DECLARE_OPERATORS_FOR_FLAGS(Phonon::MediaStreamTypes)
+
+QT_END_NAMESPACE
+
+//X class kdbgstream;
+//X #include <kdebug.h>
+//X /**
+//X * Implements needed operator to use Phonon::State with kDebug
+//X */
+//X inline PHONON_EXPORT kdbgstream &operator<<(kdbgstream & stream, const Phonon::State state)
+//X {
+//X switch(state)
+//X {
+//X case Phonon::ErrorState:
+//X stream << "ErrorState";
+//X break;
+//X case Phonon::LoadingState:
+//X stream << "LoadingState";
+//X break;
+//X case Phonon::StoppedState:
+//X stream << "StoppedState";
+//X break;
+//X case Phonon::PlayingState:
+//X stream << "PlayingState";
+//X break;
+//X case Phonon::BufferingState:
+//X stream << "BufferingState";
+//X break;
+//X case Phonon::PausedState:
+//X stream << "PausedState";
+//X break;
+//X }
+//X return stream;
+//X }
+
+#include <QtCore/QMetaType>
+
+Q_DECLARE_METATYPE(Phonon::State)
+Q_DECLARE_METATYPE(Phonon::ErrorType)
+Q_DECLARE_METATYPE(Phonon::Category)
+
+QT_END_HEADER
+
+// vim: sw=4 ts=4 tw=80
+#endif // PHONONNAMESPACE_H
diff --git a/src/3rdparty/phonon/phonon/phononnamespace.h.in b/src/3rdparty/phonon/phonon/phononnamespace.h.in
new file mode 100644
index 0000000000..54c557861d
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/phononnamespace.h.in
@@ -0,0 +1,306 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005-2008 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef PHONONNAMESPACE_H
+#define PHONONNAMESPACE_H
+
+#include "phonon_export.h"
+
+/**
+ * Helper macro that can be used like
+ * \code
+ * #if (PHONON_VERSION >= PHONON_VERSION_CHECK(4, 4, 0))
+ * \endcode
+ */
+#define PHONON_VERSION_CHECK(major, minor, patch) ((major<<16)|(minor<<8)|(patch))
+
+/**
+ * PHONON_VERSION is (major << 16) + (minor << 8) + patch.
+ */
+#define PHONON_VERSION PHONON_VERSION_CHECK(@PHONON_LIB_MAJOR_VERSION@, @PHONON_LIB_MINOR_VERSION@, @PHONON_LIB_PATCH_VERSION@)
+
+/**
+ * PHONON_VERSION_STR is "major.minor.patch". E.g. "4.2.1"
+ */
+#define PHONON_VERSION_STR "@PHONON_LIB_MAJOR_VERSION@.@PHONON_LIB_MINOR_VERSION@.@PHONON_LIB_PATCH_VERSION@"
+
+QT_BEGIN_HEADER
+QT_BEGIN_NAMESPACE
+
+class QString;
+
+/**
+ * \brief The %KDE Multimedia classes
+ *
+ * In this Namespace you find the classes to access Multimedia functions for
+ * audio and video playback. Those classes are not dependent
+ * on any specific framework (like they were in pre KDE4 times) but rather use
+ * exchangeable backends to do the work.
+ *
+ * If you want to write a new backend take a look at \ref phonon_backend_development_page.
+ *
+ * \author Matthias Kretz <kretz@kde.org>
+ */
+namespace Phonon
+{
+ PHONON_EXPORT const char *phononVersion();
+
+ /**
+ * Enum to identify the media discs supported by MediaObject.
+ *
+ * \see MediaSource(Phonon::DiscType, const QString &deviceName)
+ */
+ enum DiscType {
+ /**
+ * No disc was selected. This is only useful as a return value from
+ * MediaSource::distType();
+ */
+ NoDisc = -1,
+ /**
+ * Identifies Audio CDs.
+ */
+ Cd = 0,
+ /**
+ * Identifies DVDs (not arbitrary data DVDs, only movie DVDs).
+ */
+ Dvd = 1,
+ /**
+ * Identifies Video CDs.
+ */
+ Vcd = 2
+ };
+
+ /**
+ * Provided as keys for \ref MediaObject::metaData for convenience, in addition to the strings defined in
+ * the Ogg Vorbis specification.
+ */
+ enum MetaData {
+ /**
+ * The artist generally considered responsible for the work. In popular
+ * music this is usually the performing band or singer. For classical
+ * music it would be the composer. For an audio book it would be the
+ * author of the original text.
+ */
+ ArtistMetaData,
+ /**
+ * The collection name to which this track belongs.
+ */
+ AlbumMetaData,
+ /**
+ * Track/Work name
+ */
+ TitleMetaData,
+ /**
+ * Date the track was recorded
+ */
+ DateMetaData,
+ /**
+ * A short text indication of music genre
+ */
+ GenreMetaData,
+ /**
+ * The track number of this piece if part of a specific larger
+ * collection or album
+ */
+ TracknumberMetaData,
+ /**
+ * A short text description of the contents
+ */
+ DescriptionMetaData,
+ MusicBrainzDiscIdMetaData
+ };
+
+ /**
+ * The state the media producing object is in at the moment.
+ *
+ * \see MediaObject
+ */
+ enum State
+ {
+ /**
+ * After construction it might take a while before the Player is
+ * ready to play(). Normally this doesn't happen for local
+ * files, but can happen for remote files where the asynchronous
+ * mimetype detection and prebuffering can take a while.
+ */
+ LoadingState,
+ /**
+ * The Player has a valid media file loaded and is ready for
+ * playing.
+ */
+ StoppedState,
+ /**
+ * The Player is playing a media file.
+ */
+ PlayingState,
+ /**
+ * The Player is waiting for data to be able to continue
+ * playing.
+ */
+ BufferingState,
+ /**
+ * The Player is currently paused.
+ */
+ PausedState,
+ /**
+ * An unrecoverable error occurred. The Object is unusable in this state.
+ */
+ ErrorState
+ };
+
+ /**
+ * Set's the category your program should be listed in in the mixer.
+ *
+ * A Jukebox will set this to Music, a VoIP program to Communication, a
+ * DVD player to video, and so on.
+ *
+ * \note These categories can also become useful for an application that
+ * controls the volumes automatically, like turning down the music when a call
+ * comes in, or turning down the notifications when the media player knows
+ * it's playing classical music.
+ *
+ * \see AudioOutput::setCategory
+ */
+ enum Category
+ {
+ /**
+ * Will make use of the default device.
+ */
+ NoCategory = -1,
+ /**
+ * If the sounds produced are notifications (bing, beep and such) you
+ * should use this category.
+ */
+ NotificationCategory = 0,
+ /**
+ * If your application is a music player (like a jukebox or media player
+ * playing an audio file).
+ */
+ MusicCategory = 1,
+ /**
+ * If the sound is the audio channel of a video.
+ */
+ VideoCategory = 2,
+ /**
+ * If your applications produces sounds from communication with somebody
+ * else (VoIP, voice chat).
+ */
+ CommunicationCategory = 3,
+ /**
+ * Sound produced by a computer game should go into this category.
+ */
+ GameCategory = 4,
+ /**
+ * Sounds produced for accessibility (e.g. Text-To-Speech)
+ */
+ AccessibilityCategory = 5,
+ /**
+ * \internal
+ * Holds the largest value of categories.
+ */
+ LastCategory = AccessibilityCategory
+ };
+
+ /**
+ * Tells your program how to recover from an error.
+ *
+ * \see MediaObject::errorType()
+ */
+ enum ErrorType {
+ /**
+ * No error. MediaObject::errorType() returns this if
+ * MediaObject::state() != Phonon::ErrorState.
+ */
+ NoError = 0,
+ /**
+ * Playback should work, and trying with another URL should work.
+ */
+ NormalError = 1,
+ /**
+ * Something important does not work. Your program cannot continue
+ * playback or capture or whatever it was trying to do
+ * without help from the user.
+ */
+ FatalError = 2
+ };
+
+ /**
+ * Returns a (translated) string to show to the user identifying the given
+ * Category.
+ */
+ PHONON_EXPORT QString categoryToString(Category c);
+
+ // TODO: naming
+ /*enum MediaStreamType {
+ Audio = 1,
+ Video = 2,
+ StillImage = 4,
+ Subtitle = 8,
+ AllMedia = 0xFFFFFFFF
+ };
+ Q_DECLARE_FLAGS(MediaStreamTypes, MediaStreamType)*/
+} // namespace Phonon
+//Q_DECLARE_OPERATORS_FOR_FLAGS(Phonon::MediaStreamTypes)
+
+QT_END_NAMESPACE
+
+//X class kdbgstream;
+//X #include <kdebug.h>
+//X /**
+//X * Implements needed operator to use Phonon::State with kDebug
+//X */
+//X inline PHONON_EXPORT kdbgstream &operator<<(kdbgstream & stream, const Phonon::State state)
+//X {
+//X switch(state)
+//X {
+//X case Phonon::ErrorState:
+//X stream << "ErrorState";
+//X break;
+//X case Phonon::LoadingState:
+//X stream << "LoadingState";
+//X break;
+//X case Phonon::StoppedState:
+//X stream << "StoppedState";
+//X break;
+//X case Phonon::PlayingState:
+//X stream << "PlayingState";
+//X break;
+//X case Phonon::BufferingState:
+//X stream << "BufferingState";
+//X break;
+//X case Phonon::PausedState:
+//X stream << "PausedState";
+//X break;
+//X }
+//X return stream;
+//X }
+
+#include <QtCore/QMetaType>
+
+Q_DECLARE_METATYPE(Phonon::State)
+Q_DECLARE_METATYPE(Phonon::ErrorType)
+Q_DECLARE_METATYPE(Phonon::Category)
+
+QT_END_HEADER
+
+// vim: sw=4 ts=4 tw=80
+#endif // PHONONNAMESPACE_H
diff --git a/src/3rdparty/phonon/phonon/phononnamespace_p.h b/src/3rdparty/phonon/phonon/phononnamespace_p.h
new file mode 100644
index 0000000000..4dd0ee8930
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/phononnamespace_p.h
@@ -0,0 +1,38 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005-2006 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef PHONONNAMESPACE_P_H
+#define PHONONNAMESPACE_P_H
+
+#include <QtCore/QDebug>
+
+#if defined(QT_NO_DEBUG)
+#define pDebug if (true) {} else qDebug
+#else
+#define pDebug if (qgetenv("PHONON_DEBUG").isEmpty()) {} else qDebug
+#endif
+#define pWarning() qDebug() << "WARNING:"
+#define pError() qDebug() << "ERROR:"
+#define pFatal(message) qDebug() << "FATAL ERROR:" << message; ::abort()
+
+// vim: sw=4 ts=4 tw=80
+#endif // PHONONNAMESPACE_P_H
diff --git a/src/3rdparty/phonon/phonon/platform.cpp b/src/3rdparty/phonon/phonon/platform.cpp
new file mode 100644
index 0000000000..ed660dc074
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/platform.cpp
@@ -0,0 +1,144 @@
+/* This file is part of the KDE project
+ Copyright (C) 2007 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "platform_p.h"
+#include "platformplugin.h"
+#include "factory_p.h"
+#include <QtCore/QCoreApplication>
+#include <QtCore/QUrl>
+#include <QtGui/QIcon>
+#include <QtGui/QStyle>
+#include <QtGui/QApplication>
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+
+void Platform::saveVolume(const QString &outputName, qreal volume)
+{
+#ifndef QT_NO_PHONON_PLATFORMPLUGIN
+ PlatformPlugin *f = Factory::platformPlugin();
+ if (f) {
+ f->saveVolume(outputName, volume);
+ }
+#else
+ Q_UNUSED(outputName);
+ Q_UNUSED(volume);
+#endif //QT_NO_PHONON_PLATFORMPLUGIN
+}
+
+qreal Platform::loadVolume(const QString &outputName)
+{
+#ifndef QT_NO_PHONON_PLATFORMPLUGIN
+ const PlatformPlugin *f = Factory::platformPlugin();
+ if (f) {
+ return f->loadVolume(outputName);
+ }
+#else
+ Q_UNUSED(outputName);
+#endif //QT_NO_PHONON_PLATFORMPLUGIN
+ return 1.0;
+}
+
+AbstractMediaStream *Platform::createMediaStream(const QUrl &url, QObject *parent)
+{
+#ifndef QT_NO_PHONON_PLATFORMPLUGIN
+ PlatformPlugin *f = Factory::platformPlugin();
+ if (f) {
+ return f->createMediaStream(url, parent);
+ }
+#else
+ Q_UNUSED(url);
+ Q_UNUSED(parent);
+#endif //QT_NO_PHONON_PLATFORMPLUGIN
+ return 0;
+}
+
+QIcon Platform::icon(const QString &name, QStyle *style)
+{
+ QIcon ret;
+#ifndef QT_NO_PHONON_PLATFORMPLUGIN
+ if (const PlatformPlugin *f = Factory::platformPlugin()) {
+ ret = f->icon(name);
+ }
+#endif //QT_NO_PHONON_PLATFORMPLUGIN
+ if (ret.isNull()) {
+ if (!style) {
+ style = QApplication::style();
+ }
+ if (name == QLatin1String("player-volume")) {
+ ret = style->standardPixmap(QStyle::SP_MediaVolume);
+ } else if (name == QLatin1String("player-volume-muted")) {
+ ret = style->standardPixmap(QStyle::SP_MediaVolumeMuted);
+ }
+ }
+
+ return ret;
+}
+
+void Platform::notification(const char *notificationName, const QString &text,
+ const QStringList &actions, QObject *receiver,
+ const char *actionSlot)
+{
+#ifndef QT_NO_PHONON_PLATFORMPLUGIN
+ const PlatformPlugin *f = Factory::platformPlugin();
+ if (f) {
+ f->notification(notificationName, text, actions, receiver, actionSlot);
+ }
+#else
+ Q_UNUSED(notificationName);
+ Q_UNUSED(text);
+ Q_UNUSED(actions);
+ Q_UNUSED(receiver);
+ Q_UNUSED(actionSlot);
+#endif //QT_NO_PHONON_PLATFORMPLUGIN
+}
+
+QString Platform::applicationName()
+{
+#ifndef QT_NO_PHONON_PLATFORMPLUGIN
+ const PlatformPlugin *f = Factory::platformPlugin();
+ if (f) {
+ return f->applicationName();
+ }
+#endif //QT_NO_PHONON_PLATFORMPLUGIN
+ QString ret = QCoreApplication::applicationName();
+ if (ret.isEmpty())
+ ret = QCoreApplication::applicationFilePath();
+ return ret;
+}
+
+QList<QPair<QByteArray, QString> > Platform::deviceAccessListFor(const Phonon::AudioOutputDevice &deviceDesc)
+{
+#ifndef QT_NO_PHONON_PLATFORMPLUGIN
+ const PlatformPlugin *f = Factory::platformPlugin();
+ if (f) {
+ return f->deviceAccessListFor(deviceDesc);
+ }
+#endif //QT_NO_PHONON_PLATFORMPLUGIN
+ return QList<QPair<QByteArray, QString> >();
+}
+
+} // namespace Phonon
+
+QT_END_NAMESPACE
diff --git a/src/3rdparty/phonon/phonon/platform_p.h b/src/3rdparty/phonon/phonon/platform_p.h
new file mode 100644
index 0000000000..379c54bae3
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/platform_p.h
@@ -0,0 +1,62 @@
+/* This file is part of the KDE project
+ Copyright (C) 2007 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef PHONON_PLATFORM_P_H
+#define PHONON_PLATFORM_P_H
+
+
+#include <QtCore/QStringList>
+#include <QtCore/QtGlobal>
+#include <QtCore/QPair>
+#include "phonon_export.h"
+#include "objectdescription.h"
+
+QT_BEGIN_NAMESPACE
+
+class QIcon;
+class QObject;
+class QUrl;
+class QStyle;
+
+namespace Phonon
+{
+class AbstractMediaStream;
+
+namespace Platform
+{
+
+void saveVolume(const QString &outputName, qreal volume);
+qreal loadVolume(const QString &outputName);
+AbstractMediaStream *createMediaStream(const QUrl &url, QObject *parent);
+QIcon icon(const QString &name, QStyle *style = 0);
+void notification(const char *notificationName, const QString &text,
+ const QStringList &actions = QStringList(), QObject *receiver = 0,
+ const char *actionSlot = 0);
+QString applicationName();
+QList<QPair<QByteArray, QString> > deviceAccessListFor(const Phonon::AudioOutputDevice &deviceDesc);
+
+} // namespace Platform
+} // namespace Phonon
+
+QT_END_NAMESPACE
+
+#endif // PHONON_PLATFORM_P_H
diff --git a/src/3rdparty/phonon/phonon/platformplugin.h b/src/3rdparty/phonon/phonon/platformplugin.h
new file mode 100644
index 0000000000..e1ab1b726d
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/platformplugin.h
@@ -0,0 +1,118 @@
+/* This file is part of the KDE project
+ Copyright (C) 2007-2008 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef PHONON_PLATFORMPLUGIN_H
+#define PHONON_PLATFORMPLUGIN_H
+
+#include <QtCore/QObject>
+#include <QtCore/QStringList>
+#include <QtCore/QPair>
+#include "phonon_export.h"
+#include "objectdescription.h"
+
+QT_BEGIN_HEADER
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_PHONON_PLATFORMPLUGIN
+
+class QUrl;
+class QObject;
+class QIcon;
+
+namespace Phonon
+{
+class AbstractMediaStream;
+
+class PlatformPlugin
+{
+ public:
+ virtual ~PlatformPlugin() {}
+
+ /**
+ * Creates a AbstractMediaStream object that provides the data for the given \p url. On KDE
+ * this uses KIO.
+ */
+ virtual AbstractMediaStream *createMediaStream(const QUrl &url, QObject *parent) = 0;
+
+ /**
+ * Returns the icon for the given icon name.
+ */
+ virtual QIcon icon(const QString &name) const = 0;
+
+ /**
+ * Shows a notification popup
+ */
+ virtual void notification(const char *notificationName, const QString &text,
+ const QStringList &actions = QStringList(), QObject *receiver = 0,
+ const char *actionSlot = 0) const = 0;
+
+ /**
+ * Returns the name of the application. For most Qt application this is
+ * QCoreApplication::applicationName(), but for KDE this is overridden by KAboutData.
+ */
+ virtual QString applicationName() const = 0;
+
+ /**
+ * Creates a backend object. This way the platform can decide the backend preference.
+ */
+ virtual QObject *createBackend() = 0;
+
+ /**
+ * Using the library loader of the platform, loads a given backend.
+ */
+ virtual QObject *createBackend(const QString &library, const QString &version) = 0;
+
+ /**
+ * Tries to check whether the default backend supports a given MIME type without loading the
+ * actual backend library. On KDE this reads the MIME type list from the .desktop file of
+ * the backend.
+ */
+ virtual bool isMimeTypeAvailable(const QString &mimeType) const = 0;
+
+ /**
+ * Saves the volume for the given output.
+ */
+ virtual void saveVolume(const QString &outputName, qreal volume) = 0;
+
+ /**
+ * Loads the volume for the given output.
+ */
+ virtual qreal loadVolume(const QString &outputName) const = 0;
+
+ virtual QList<int> objectDescriptionIndexes(ObjectDescriptionType type) const = 0;
+ virtual QHash<QByteArray, QVariant> objectDescriptionProperties(ObjectDescriptionType type, int index) const = 0;
+
+ /**
+ * Returns a list of (driver, handle) pairs for the given AudioOutputDevice description.
+ */
+ virtual QList<QPair<QByteArray, QString> > deviceAccessListFor(const Phonon::AudioOutputDevice &) const { return QList<QPair<QByteArray, QString> >(); }
+};
+} // namespace Phonon
+
+Q_DECLARE_INTERFACE(Phonon::PlatformPlugin, "3PlatformPlugin.phonon.kde.org")
+
+#endif //QT_NO_PHONON_PLATFORMPLUGIN
+
+QT_END_NAMESPACE
+QT_END_HEADER
+
+#endif // PHONON_PLATFORMPLUGIN_H
diff --git a/src/3rdparty/phonon/phonon/preprocessandextract.sh b/src/3rdparty/phonon/phonon/preprocessandextract.sh
new file mode 100755
index 0000000000..13b1704fdc
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/preprocessandextract.sh
@@ -0,0 +1,39 @@
+#!/bin/sh
+EXTRACT="`dirname $0`/extractmethodcalls.rb"
+IGNORE="^\(streameventqueue\|abstractmediastream2\|lockfreequeue\|path\|platform\|iodevicestream\|medianode\|streaminterface\|mediasource\|abstractmediastream\|audioplayer\|globalconfig\|objectdescriptionmodel\|audiooutputadaptor\|effectwidget\|videoplayer\|seekslider\|volumeslider\).cpp$"
+
+if test -n "$1" -a -f "$1"; then
+ echo "preprocessing $1"
+ cpp $1 2>/dev/null > tmp
+ echo "extracting backend calls from $1"
+ $EXTRACT tmp > tests/methods/$1
+ rm tmp
+else
+ for i in *.cpp; do
+ if echo $i | grep -q "$IGNORE"; then
+ printf "%-30s ignored.\n" "$i:"
+ elif echo $i | grep -q '_p\.cpp$'; then
+ printf "%-30s postponed.\n" "$i:"
+ else
+ printf "%-30s preprocessing" "$i:"
+ cpp $i 2>/dev/null > tmp
+ echo -n ", extracting backend calls"
+ $EXTRACT tmp > tests/methods/$i
+ rm tmp
+ echo "."
+ fi
+ done
+ for i in *_p.cpp; do
+ cpp=`echo $i | sed 's,_p\.cpp$,\.cpp,'`
+ if echo $cpp | grep -q "$IGNORE"; then
+ printf "%-30s ignored.\n" "$i:"
+ elif test "$i" != "*_p.cpp"; then
+ printf "%-30s preprocessing" "$i:"
+ cpp $i 2>/dev/null > tmp
+ echo -n ", extracting backend calls"
+ $EXTRACT tmp >> tests/methods/$cpp
+ rm tmp
+ echo "."
+ fi
+ done
+fi
diff --git a/src/3rdparty/phonon/phonon/qsettingsgroup_p.h b/src/3rdparty/phonon/phonon/qsettingsgroup_p.h
new file mode 100644
index 0000000000..95f6c9bafa
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/qsettingsgroup_p.h
@@ -0,0 +1,91 @@
+/* This file is part of the KDE project
+ Copyright (C) 2007 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef PHONON_QSETTINGSGROUP_P_H
+#define PHONON_QSETTINGSGROUP_P_H
+
+#include <QtCore/QSettings>
+#include <QtCore/QString>
+#include <QtCore/QVariant>
+
+QT_BEGIN_HEADER
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+class QSettingsGroup
+{
+ public:
+ inline QSettingsGroup(QSettings *settings, const QString &name)
+ : m_mutableSettings(settings),
+ m_settings(settings),
+ m_group(name + QLatin1Char('/'))
+ {
+ }
+
+ inline QSettingsGroup(const QSettings *settings, const QString &name)
+ : m_mutableSettings(0),
+ m_settings(settings),
+ m_group(name + QLatin1Char('/'))
+ {
+ }
+
+ template<typename T>
+ inline T value(const QString &key, const T &def) const
+ {
+ return qvariant_cast<T>(value(key, qVariantFromValue(def)));
+ }
+
+ inline QVariant value(const QString &key, const QVariant &def) const
+ {
+ return m_settings->value(m_group + key, def);
+ }
+
+ template<typename T>
+ inline void setValue(const QString &key, const T &value)
+ {
+ Q_ASSERT(m_mutableSettings);
+ m_mutableSettings->setValue(m_group + key, qVariantFromValue(value));
+ }
+
+ inline void removeEntry(const QString &key)
+ {
+ Q_ASSERT(m_mutableSettings);
+ m_mutableSettings->remove(m_group + key);
+ }
+
+ inline bool hasKey(const QString &key) const
+ {
+ return m_settings->contains(m_group + key);
+ }
+
+ private:
+ QSettings *const m_mutableSettings;
+ const QSettings *const m_settings;
+ QString m_group;
+};
+} // namespace Phonon
+
+QT_END_NAMESPACE
+QT_END_HEADER
+
+#endif // PHONON_QSETTINGSGROUP_P_H
diff --git a/src/3rdparty/phonon/phonon/seekslider.cpp b/src/3rdparty/phonon/phonon/seekslider.cpp
new file mode 100644
index 0000000000..e1eea54262
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/seekslider.cpp
@@ -0,0 +1,263 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006-2007 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "seekslider.h"
+#include "seekslider_p.h"
+#include "mediaobject.h"
+#include "phonondefs_p.h"
+
+#include <QtGui/QMouseEvent>
+#include <QtGui/QApplication>
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_PHONON_SEEKSLIDER
+
+namespace Phonon
+{
+
+SeekSlider::SeekSlider(QWidget *parent)
+ : QWidget(parent)
+ , k_ptr(new SeekSliderPrivate(this))
+{
+ K_D(SeekSlider);
+ connect(&d->slider, SIGNAL(valueChanged(int)), SLOT(_k_seek(int)));
+}
+
+SeekSlider::SeekSlider(MediaObject *mo, QWidget *parent)
+ : QWidget(parent)
+ , k_ptr(new SeekSliderPrivate(this))
+{
+ K_D(SeekSlider);
+ connect(&d->slider, SIGNAL(valueChanged(int)), SLOT(_k_seek(int)));
+ setMediaObject(mo);
+}
+
+/*SeekSlider::SeekSlider(SeekSliderPrivate &_d, QWidget *parent)
+ : QWidget(parent)
+ , k_ptr(&_d)
+{
+} */
+
+SeekSlider::~SeekSlider()
+{
+ delete k_ptr;
+}
+
+void SeekSlider::setMediaObject(MediaObject *media)
+{
+ K_D(SeekSlider);
+ if (d->media) {
+ disconnect(d->media, 0, this, 0);
+ }
+ d->media = media;
+
+ if (media) {
+ connect(media, SIGNAL(stateChanged(Phonon::State, Phonon::State)),
+ SLOT(_k_stateChanged(Phonon::State)));
+ connect(media, SIGNAL(totalTimeChanged(qint64)), SLOT(_k_length(qint64)));
+ connect(media, SIGNAL(tick(qint64)), SLOT(_k_tick(qint64)));
+ connect(media, SIGNAL(seekableChanged(bool)), SLOT(_k_seekableChanged(bool)));
+ connect(media, SIGNAL(currentSourceChanged(const Phonon::MediaSource&)), SLOT(_k_currentSourceChanged()));
+ d->_k_stateChanged(media->state());
+ d->_k_seekableChanged(media->isSeekable());
+ d->_k_length(media->totalTime());
+ } else {
+ d->_k_stateChanged(Phonon::StoppedState);
+ d->_k_seekableChanged(false);
+ }
+}
+
+MediaObject *SeekSlider::mediaObject() const
+{
+ K_D(const SeekSlider);
+ return d->media;
+}
+
+void SeekSliderPrivate::_k_seek(int msec)
+{
+ if (!ticking && media) {
+ media->seek(msec);
+ }
+}
+
+void SeekSliderPrivate::_k_tick(qint64 msec)
+{
+ ticking = true;
+ slider.setValue(msec);
+ ticking = false;
+}
+
+void SeekSliderPrivate::_k_length(qint64 msec)
+{
+ ticking = true;
+ slider.setRange(0, msec);
+ ticking = false;
+}
+
+void SeekSliderPrivate::_k_seekableChanged(bool isSeekable)
+{
+ if (!isSeekable || !media) {
+ setEnabled(false);
+ } else {
+ switch (media->state()) {
+ case Phonon::PlayingState:
+ if (media->tickInterval() == 0) {
+ // if the tick signal is not enabled the slider is useless
+ // set the tickInterval to some common value
+ media->setTickInterval(350);
+ }
+ case Phonon::BufferingState:
+ case Phonon::PausedState:
+ setEnabled(true);
+ break;
+ case Phonon::StoppedState:
+ case Phonon::LoadingState:
+ case Phonon::ErrorState:
+ setEnabled(false);
+ ticking = true;
+ slider.setValue(0);
+ ticking = false;
+ break;
+ }
+ }
+}
+
+void SeekSliderPrivate::_k_currentSourceChanged()
+{
+ //this releases the mouse and makes the seek slider stop seeking if the current source has changed
+ QMouseEvent event(QEvent::MouseButtonRelease, QPoint(), Qt::LeftButton, 0, 0);
+ QApplication::sendEvent(&slider, &event);
+}
+
+void SeekSliderPrivate::setEnabled(bool x)
+{
+ slider.setEnabled(x);
+ iconLabel.setPixmap(icon.pixmap(iconSize, x ? QIcon::Normal : QIcon::Disabled));
+}
+
+void SeekSliderPrivate::_k_stateChanged(State newstate)
+{
+ if (!media || !media->isSeekable()) {
+ setEnabled(false);
+ return;
+ }
+ switch (newstate) {
+ case Phonon::PlayingState:
+ if (media->tickInterval() == 0) {
+ // if the tick signal is not enabled the slider is useless
+ // set the tickInterval to some common value
+ media->setTickInterval(350);
+ }
+ case Phonon::BufferingState:
+ case Phonon::PausedState:
+ setEnabled(true);
+ break;
+ case Phonon::StoppedState:
+ case Phonon::LoadingState:
+ case Phonon::ErrorState:
+ setEnabled(false);
+ ticking = true;
+ slider.setValue(0);
+ ticking = false;
+ break;
+ }
+}
+
+bool SeekSlider::hasTracking() const
+{
+ return k_ptr->slider.hasTracking();
+}
+
+void SeekSlider::setTracking(bool tracking)
+{
+ k_ptr->slider.setTracking(tracking);
+}
+
+int SeekSlider::pageStep() const
+{
+ return k_ptr->slider.pageStep();
+}
+
+void SeekSlider::setPageStep(int milliseconds)
+{
+ k_ptr->slider.setPageStep(milliseconds);
+}
+
+int SeekSlider::singleStep() const
+{
+ return k_ptr->slider.singleStep();
+}
+
+void SeekSlider::setSingleStep(int milliseconds)
+{
+ k_ptr->slider.setSingleStep(milliseconds);
+}
+
+bool SeekSlider::isIconVisible() const
+{
+ K_D(const SeekSlider);
+ return d->iconLabel.isVisible();
+}
+
+void SeekSlider::setIconVisible(bool vis)
+{
+ K_D(SeekSlider);
+ d->iconLabel.setVisible(vis);
+}
+
+Qt::Orientation SeekSlider::orientation() const
+{
+ return k_ptr->slider.orientation();
+}
+
+void SeekSlider::setOrientation(Qt::Orientation o)
+{
+ K_D(SeekSlider);
+ Qt::Alignment align = (o == Qt::Horizontal ? Qt::AlignVCenter : Qt::AlignHCenter);
+ d->layout.setAlignment(&d->iconLabel, align);
+ d->layout.setAlignment(&d->slider, align);
+ d->layout.setDirection(o == Qt::Horizontal ? QBoxLayout::LeftToRight : QBoxLayout::TopToBottom);
+ d->slider.setOrientation(o);
+}
+
+QSize SeekSlider::iconSize() const
+{
+ return k_ptr->iconSize;
+}
+
+void SeekSlider::setIconSize(const QSize &iconSize)
+{
+ K_D(SeekSlider);
+ d->iconSize = iconSize;
+ d->iconLabel.setPixmap(d->icon.pixmap(d->iconSize, d->slider.isEnabled() ? QIcon::Normal : QIcon::Disabled));
+}
+
+} // namespace Phonon
+
+#endif //QT_NO_PHONON_SEEKSLIDER
+
+QT_END_NAMESPACE
+
+#include "moc_seekslider.cpp"
+
+// vim: sw=4 ts=4
diff --git a/src/3rdparty/phonon/phonon/seekslider.h b/src/3rdparty/phonon/phonon/seekslider.h
new file mode 100644
index 0000000000..540079e53c
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/seekslider.h
@@ -0,0 +1,157 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006-2007 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef PHONON_UI_SEEKSLIDER_H
+#define PHONON_UI_SEEKSLIDER_H
+
+#include "phonon_export.h"
+#include "phonondefs.h"
+#include "phononnamespace.h"
+#include <QtGui/QWidget>
+
+QT_BEGIN_HEADER
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_PHONON_SEEKSLIDER
+
+namespace Phonon
+{
+class MediaObject;
+
+class SeekSliderPrivate;
+
+/** \class SeekSlider seekslider.h Phonon/SeekSlider
+ * \short Widget providing a slider for seeking in MediaObject objects.
+ *
+ * \ingroup PhononWidgets
+ * \author Matthias Kretz <kretz@kde.org>
+ */
+class PHONON_EXPORT SeekSlider : public QWidget
+{
+ Q_OBJECT
+ K_DECLARE_PRIVATE(SeekSlider)
+ /**
+ * This property holds whether the icon next to the slider is visible.
+ *
+ * By default the icon is visible if the platform provides an icon; else
+ * it's hidden.
+ */
+ Q_PROPERTY(bool iconVisible READ isIconVisible WRITE setIconVisible)
+
+ /**
+ * This property holds whether slider tracking is enabled.
+ *
+ * If tracking is enabled (the default), the media seeks
+ * while the slider is being dragged. If tracking is
+ * disabled, the media seeks only when the user
+ * releases the slider.
+ */
+ Q_PROPERTY(bool tracking READ hasTracking WRITE setTracking)
+
+ /**
+ * This property holds the page step.
+ *
+ * The larger of two natural steps that a slider provides and
+ * typically corresponds to the user pressing PageUp or PageDown.
+ *
+ * Defaults to 5 seconds.
+ */
+ Q_PROPERTY(int pageStep READ pageStep WRITE setPageStep)
+
+ /**
+ * This property holds the single step.
+ *
+ * The smaller of two natural steps that a slider provides and
+ * typically corresponds to the user pressing an arrow key.
+ *
+ * Defaults to 0.5 seconds.
+ */
+ Q_PROPERTY(int singleStep READ singleStep WRITE setSingleStep)
+
+ /**
+ * This property holds the orientation of the slider.
+ *
+ * The orientation must be Qt::Vertical or Qt::Horizontal (the default).
+ */
+ Q_PROPERTY(Qt::Orientation orientation READ orientation WRITE setOrientation)
+
+ /**
+ * \brief the icon size used for the mute button/icon.
+ *
+ * The default size is defined by the GUI style.
+ */
+ Q_PROPERTY(QSize iconSize READ iconSize WRITE setIconSize)
+
+ public:
+ /**
+ * Constructs a seek slider widget with the given \p parent.
+ */
+ explicit SeekSlider(QWidget *parent = 0);
+ explicit SeekSlider(MediaObject *media, QWidget *parent = 0);
+
+ /**
+ * Destroys the seek slider.
+ */
+ ~SeekSlider();
+
+ bool hasTracking() const;
+ void setTracking(bool tracking);
+ int pageStep() const;
+ void setPageStep(int milliseconds);
+ int singleStep() const;
+ void setSingleStep(int milliseconds);
+ Qt::Orientation orientation() const;
+ bool isIconVisible() const;
+ QSize iconSize() const;
+ MediaObject *mediaObject() const;
+
+ public Q_SLOTS:
+ void setOrientation(Qt::Orientation);
+ void setIconVisible(bool);
+ void setIconSize(const QSize &size);
+
+ /**
+ * Sets the media object to be controlled by this slider.
+ */
+ void setMediaObject(MediaObject *);
+
+ protected:
+ SeekSliderPrivate *const k_ptr;
+
+ private:
+ Q_PRIVATE_SLOT(k_func(), void _k_stateChanged(Phonon::State))
+ Q_PRIVATE_SLOT(k_func(), void _k_seek(int))
+ Q_PRIVATE_SLOT(k_func(), void _k_tick(qint64))
+ Q_PRIVATE_SLOT(k_func(), void _k_length(qint64))
+ Q_PRIVATE_SLOT(k_func(), void _k_seekableChanged(bool))
+ Q_PRIVATE_SLOT(k_func(), void _k_currentSourceChanged())
+};
+
+} // namespace Phonon
+
+#endif //QT_NO_PHONON_SEEKSLIDER
+
+QT_END_NAMESPACE
+QT_END_HEADER
+
+// vim: sw=4 ts=4 tw=80
+#endif // PHONON_UI_SEEKSLIDER_H
diff --git a/src/3rdparty/phonon/phonon/seekslider_p.h b/src/3rdparty/phonon/phonon/seekslider_p.h
new file mode 100644
index 0000000000..f4ed616ff8
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/seekslider_p.h
@@ -0,0 +1,101 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef SEEKSLIDER_P_H
+#define SEEKSLIDER_P_H
+
+#include "seekslider.h"
+#include <QtGui/QBoxLayout>
+#include <QtGui/QSlider>
+#include <QtGui/QLabel>
+#include <QtGui/QPixmap>
+#include <QtGui/QIcon>
+#include <QtGui/QStyle>
+#include "factory_p.h"
+#include <QtCore/QPointer>
+#include "platform_p.h"
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_PHONON_SEEKSLIDER
+
+namespace Phonon
+{
+class MediaObject;
+class SeekSliderPrivate
+{
+ Q_DECLARE_PUBLIC(SeekSlider)
+ protected:
+ SeekSliderPrivate(SeekSlider *parent)
+ : layout(QBoxLayout::LeftToRight, parent),
+ slider(Qt::Horizontal, parent),
+ iconLabel(parent),
+ ticking(false)
+#ifndef QT_NO_PHONON_PLATFORMPLUGIN
+ ,icon(Platform::icon(QLatin1String("player-time"), parent->style()))
+#endif //QT_NO_PHONON_PLATFORMPLUGIN
+ {
+ const int e = parent->style()->pixelMetric(QStyle::PM_ButtonIconSize);
+ iconSize = QSize(e, e);
+
+ slider.setPageStep(5000); // 5 sec
+ slider.setSingleStep(500); // 0.5 sec
+
+ layout.setMargin(0);
+ layout.setSpacing(2);
+ layout.addWidget(&iconLabel, 0, Qt::AlignVCenter);
+ layout.addWidget(&slider, 0, Qt::AlignVCenter);
+
+ setEnabled(false);
+
+ if (icon.isNull()) {
+ iconLabel.setVisible(false);
+ }
+ }
+
+ SeekSlider *q_ptr;
+
+ private:
+ void setEnabled(bool);
+ void _k_stateChanged(Phonon::State);
+ void _k_seek(int);
+ void _k_tick(qint64);
+ void _k_length(qint64);
+ void _k_seekableChanged(bool);
+ void _k_currentSourceChanged();
+
+ QBoxLayout layout;
+ QSlider slider;
+ QLabel iconLabel;
+ QPointer<MediaObject> media;
+ bool ticking;
+ QIcon icon;
+ QSize iconSize;
+};
+} // namespace Phonon
+
+#endif //QT_NO_PHONON_SEEKSLIDER
+
+QT_END_NAMESPACE
+
+#endif // SEEKSLIDER_P_H
+// vim: sw=4 ts=4 tw=80
diff --git a/src/3rdparty/phonon/phonon/stream-thoughts b/src/3rdparty/phonon/phonon/stream-thoughts
new file mode 100644
index 0000000000..5fb6711a27
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/stream-thoughts
@@ -0,0 +1,72 @@
+there are two different kind of streams: 1. media files 2. live radio/television
+
+The difference cannot reliably be determined by the backend so the application has to tell the
+frontend.
+
+This is the expected behaviour:
+1. media files
+==============
+function | prev. state | action | new state
+---------+-------------+----------------------------------------------------------------+----------
+ctor | | | Loading
+---------+-------------+----------------------------------------------------------------+----------
+setUrl | Loading | refill buffers | Loading
+ | Stopped | refill buffers | Loading
+---------+-------------+----------------------------------------------------------------+----------
+play | Loading | continue buffering | Buffering
+ | Stopped | start playing | Playing
+ | Buffering | continue buffering | Buffering
+ | Playing | | Playing
+ | Paused | continue playback | Playing
+---------+-------------+----------------------------------------------------------------+----------
+pause | Loading | | Loading
+ | Stopped | | Stopped
+ | Buffering | continue buffering | Paused
+ | Playing | pause output and fill buffers to the max | Paused
+ | Paused | | Paused
+---------+-------------+----------------------------------------------------------------+----------
+stop | Loading | | Loading
+ | Stopped | | Stopped
+ | Buffering | restart buffering from the beginning of the file | Loading
+ | Playing | stop output and refill buffers from the beginning of the file | Loading
+ | Paused | restart buffering from the beginning of the file | Loading
+
+events
+function | prev. state | event | new state
+---------+-------------+----------------------------------------------------------------+----------
+ | Buffering | when the buffers are filled start playing | Playing
+ | Loading | when buffers are filled | Stopped
+
+
+
+2. live stream
+==============
+function | prev. state | action | new state
+---------+-------------+----------------------------------------------------------------+----------
+ctor | | | Loading
+---------+-------------+----------------------------------------------------------------+----------
+setUrl | Loading | | Stopped
+ | Stopped | | Stopped
+---------+-------------+----------------------------------------------------------------+----------
+play | Loading | | Error
+ | Stopped | start buffering | Buffering
+ | Buffering | continue buffering | Buffering
+ | Playing | | Playing
+ | Paused | continue playback | Playing
+---------+-------------+----------------------------------------------------------------+----------
+pause | Loading | | Error
+ | Stopped | | Stopped
+ | Buffering | continue buffering | Paused
+ | Playing | pause output and fill (ring-)buffers to the max | Paused
+ | Paused | | Paused
+---------+-------------+----------------------------------------------------------------+----------
+stop | Loading | | Error
+ | Stopped | | Stopped
+ | Buffering | clear buffers | Stopped
+ | Playing | stop output and clear buffers | Stopped
+ | Paused | clear buffers | Stopped
+
+events
+function | prev. state | event | new state
+---------+-------------+----------------------------------------------------------------+----------
+ | Buffering | when the buffers are filled start playing | Playing
diff --git a/src/3rdparty/phonon/phonon/streaminterface.cpp b/src/3rdparty/phonon/phonon/streaminterface.cpp
new file mode 100644
index 0000000000..3646fc109a
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/streaminterface.cpp
@@ -0,0 +1,114 @@
+/* This file is part of the KDE project
+ Copyright (C) 2007 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "streaminterface.h"
+#include "streaminterface_p.h"
+#include "abstractmediastream.h"
+#include "abstractmediastream_p.h"
+#include "mediasource_p.h"
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
+
+namespace Phonon
+{
+
+StreamInterface::StreamInterface()
+ : d(new StreamInterfacePrivate)
+{
+ d->q = this;
+}
+
+StreamInterface::~StreamInterface()
+{
+ if (d->connected) {
+ AbstractMediaStreamPrivate *dd = d->mediaSource.stream()->d_func();
+ dd->setStreamInterface(0);
+ }
+ delete d;
+}
+
+void StreamInterface::connectToSource(const MediaSource &mediaSource)
+{
+ Q_ASSERT(!d->connected);
+ d->connected = true;
+ d->mediaSource = mediaSource;
+ Q_ASSERT(d->mediaSource.type() == MediaSource::Stream);
+ Q_ASSERT(d->mediaSource.stream());
+ AbstractMediaStreamPrivate *dd = d->mediaSource.stream()->d_func();
+ dd->setStreamInterface(this);
+ d->mediaSource.stream()->reset();
+}
+
+void StreamInterfacePrivate::disconnectMediaStream()
+{
+ Q_ASSERT(connected);
+ connected = false;
+
+ // if mediaSource has autoDelete set then it will delete the AbstractMediaStream again who's
+ // destructor is calling us right now
+ mediaSource.setAutoDelete(false);
+
+ mediaSource = MediaSource();
+ q->endOfData();
+ q->setStreamSeekable(false);
+}
+
+void StreamInterface::needData()
+{
+ if (d->mediaSource.type() == MediaSource::Stream) {
+ d->mediaSource.stream()->needData();
+ }
+}
+
+void StreamInterface::enoughData()
+{
+ Q_ASSERT(d->connected);
+ if (d->mediaSource.type() == MediaSource::Stream) {
+ d->mediaSource.stream()->enoughData();
+ }
+}
+
+void StreamInterface::seekStream(qint64 offset)
+{
+ Q_ASSERT(d->connected);
+ if (d->mediaSource.type() == MediaSource::Stream) {
+ d->mediaSource.stream()->seekStream(offset);
+ }
+}
+
+void StreamInterface::reset()
+{
+ Q_ASSERT(d->connected);
+ if (d->mediaSource.type() == MediaSource::Stream) {
+ d->mediaSource.stream()->reset();
+ }
+}
+
+} // namespace Phonon
+
+#endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
+
+QT_END_NAMESPACE
+
+
diff --git a/src/3rdparty/phonon/phonon/streaminterface.h b/src/3rdparty/phonon/phonon/streaminterface.h
new file mode 100644
index 0000000000..10cc06154d
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/streaminterface.h
@@ -0,0 +1,123 @@
+/* This file is part of the KDE project
+ Copyright (C) 2007 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef PHONON_STREAMINTERFACE_H
+#define PHONON_STREAMINTERFACE_H
+
+#include "phonon_export.h"
+#include <QtCore/QObject>
+
+QT_BEGIN_HEADER
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
+
+namespace Phonon
+{
+class StreamInterfacePrivate;
+class MediaSource;
+
+/** \class StreamInterface streaminterface.h Phonon/StreamInterface
+ * \brief Backend interface to handle media streams (AbstractMediaStream).
+ *
+ * \author Matthias Kretz <kretz@kde.org>
+ */
+class PHONON_EXPORT StreamInterface
+{
+ friend class StreamInterfacePrivate;
+ friend class AbstractMediaStreamPrivate;
+ public:
+ virtual ~StreamInterface();
+ /**
+ * Called by the application to send a chunk of (encoded) media data.
+ *
+ * It is recommended to keep the QByteArray object until the data is consumed so that no
+ * memcopy is needed.
+ */
+ virtual void writeData(const QByteArray &data) = 0;
+ /**
+ * Called when no more media data is available and writeData will not be called anymore.
+ */
+ virtual void endOfData() = 0;
+ /**
+ * Called at the start of the stream to tell how many bytes will be sent through writeData
+ * (if no seeks happen, of course). If this value is negative the stream size cannot be
+ * determined (might be a "theoretically infinite" stream - like webradio).
+ */
+ virtual void setStreamSize(qint64 newSize) = 0;
+ /**
+ * Tells whether the stream is seekable.
+ */
+ virtual void setStreamSeekable(bool s) = 0;
+
+ /**
+ * Call this function from the constructor of your StreamInterface implementation (or as
+ * soon as you get the MediaSource object). This will connect your object to the
+ * AbstractMediaStream object. Only after the connection is done will the following
+ * functions have an effect.
+ */
+ void connectToSource(const MediaSource &mediaSource);
+
+ /**
+ * Call this function to tell the AbstractMediaStream that you need more data. The data will
+ * arrive through writeData. Don't rely on writeData getting called from needData, though
+ * some AbstractMediaStream implementations might do so.
+ *
+ * Depending on the buffering you need you either treat needData as a replacement for a
+ * read call like QIODevice::read, or you start calling needData whenever your buffer
+ * reaches a certain lower threshold.
+ */
+ void needData();
+
+ /**
+ * Call this function to tell the AbstractMediaStream that you have enough data in your
+ * buffer and that it should pause calling writeData if possible.
+ */
+ void enoughData();
+
+ /**
+ * If the stream is seekable, calling this function will make the next call to writeData
+ * pass data that starts at the byte offset \p seekTo.
+ */
+ void seekStream(qint64 seekTo);
+
+ /**
+ * Resets the AbstractMediaStream. E.g. this can be useful for non-seekable streams to start
+ * over again.
+ */
+ void reset();
+
+ protected:
+ StreamInterface();
+
+ StreamInterfacePrivate *const d;
+};
+} // namespace Phonon
+
+Q_DECLARE_INTERFACE(Phonon::StreamInterface, "StreamInterface1.phonon.kde.org")
+
+#endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
+
+QT_END_NAMESPACE
+QT_END_HEADER
+
+#endif // PHONON_STREAMINTERFACE_H
diff --git a/src/3rdparty/phonon/phonon/streaminterface_p.h b/src/3rdparty/phonon/phonon/streaminterface_p.h
new file mode 100644
index 0000000000..cc41156845
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/streaminterface_p.h
@@ -0,0 +1,59 @@
+/* This file is part of the KDE project
+ Copyright (C) 2007 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef STREAMINTERFACE_P_H
+#define STREAMINTERFACE_P_H
+
+#include "streaminterface.h"
+#include "mediasource.h"
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
+
+namespace Phonon
+{
+class StreamInterfacePrivate
+{
+ friend class StreamInterface;
+ public:
+ void disconnectMediaStream();
+
+ protected:
+ inline StreamInterfacePrivate()
+ : connected(false)
+ {
+ }
+
+ StreamInterface *q;
+ MediaSource mediaSource;
+ bool connected;
+};
+
+} // namespace Phonon
+
+#endif // QT_NO_PHONON_ABSTRACTMEDIASTREAM
+
+QT_END_NAMESPACE
+
+#endif // STREAMINTERFACE_P_H
+// vim: sw=4 sts=4 et tw=100
diff --git a/src/3rdparty/phonon/phonon/videoplayer.cpp b/src/3rdparty/phonon/phonon/videoplayer.cpp
new file mode 100644
index 0000000000..8f76d4cd1a
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/videoplayer.cpp
@@ -0,0 +1,184 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004-2007 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "videoplayer.h"
+#include "mediaobject.h"
+#include "audiooutput.h"
+#include "videowidget.h"
+#include "path.h"
+#include <QtGui/QBoxLayout>
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_PHONON_VIDEOPLAYER
+
+namespace Phonon
+{
+
+class VideoPlayerPrivate
+{
+ public:
+ VideoPlayerPrivate()
+ : player(0)
+ , aoutput(0)
+ , voutput(0) {}
+
+ void init(VideoPlayer *q, Phonon::Category category);
+
+ MediaObject *player;
+ AudioOutput *aoutput;
+ VideoWidget *voutput;
+
+ MediaSource src;
+};
+
+void VideoPlayerPrivate::init(VideoPlayer *q, Phonon::Category category)
+{
+ QVBoxLayout *layout = new QVBoxLayout(q);
+ layout->setMargin(0);
+
+ aoutput = new AudioOutput(category, q);
+
+ voutput = new VideoWidget(q);
+ layout->addWidget(voutput);
+
+ player = new MediaObject(q);
+ Phonon::createPath(player, aoutput);
+ Phonon::createPath(player, voutput);
+
+ q->connect(player, SIGNAL(finished()), SIGNAL(finished()));
+}
+
+VideoPlayer::VideoPlayer(Phonon::Category category, QWidget *parent)
+ : QWidget(parent)
+ , d(new VideoPlayerPrivate)
+{
+ d->init(this, category);
+}
+
+VideoPlayer::VideoPlayer(QWidget *parent)
+ : QWidget(parent)
+ , d(new VideoPlayerPrivate)
+{
+ d->init(this, Phonon::VideoCategory);
+}
+
+VideoPlayer::~VideoPlayer()
+{
+ delete d;
+}
+
+MediaObject *VideoPlayer::mediaObject() const
+{
+ return d->player;
+}
+
+AudioOutput *VideoPlayer::audioOutput() const
+{
+ return d->aoutput;
+}
+
+VideoWidget *VideoPlayer::videoWidget() const
+{
+ return d->voutput;
+}
+
+void VideoPlayer::load(const MediaSource &source)
+{
+ d->player->setCurrentSource(source);
+}
+
+void VideoPlayer::play(const MediaSource &source)
+{
+ if (source == d->player->currentSource()) {
+ if (!isPlaying())
+ d->player->play();
+ return;
+ }
+ // new URL
+ d->player->setCurrentSource(source);
+
+ if (ErrorState == d->player->state())
+ return;
+
+ d->player->play();
+}
+
+void VideoPlayer::play()
+{
+ d->player->play();
+}
+
+void VideoPlayer::pause()
+{
+ d->player->pause();
+}
+
+void VideoPlayer::stop()
+{
+ d->player->stop();
+}
+
+qint64 VideoPlayer::totalTime() const
+{
+ return d->player->totalTime();
+}
+
+qint64 VideoPlayer::currentTime() const
+{
+ return d->player->currentTime();
+}
+
+void VideoPlayer::seek(qint64 ms)
+{
+ d->player->seek(ms);
+}
+
+float VideoPlayer::volume() const
+{
+ return d->aoutput->volume();
+}
+
+void VideoPlayer::setVolume(float v)
+{
+ d->aoutput->setVolume(v);
+}
+
+bool VideoPlayer::isPlaying() const
+{
+ return (d->player->state() == PlayingState);
+}
+
+bool VideoPlayer::isPaused() const
+{
+ return (d->player->state() == PausedState);
+}
+
+} // namespaces
+
+#endif //QT_NO_PHONON_VIDEOPLAYER
+
+QT_END_NAMESPACE
+
+#include "moc_videoplayer.cpp"
+
+// vim: sw=4 ts=4
diff --git a/src/3rdparty/phonon/phonon/videoplayer.h b/src/3rdparty/phonon/phonon/videoplayer.h
new file mode 100644
index 0000000000..6da1d98f56
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/videoplayer.h
@@ -0,0 +1,207 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004-2007 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef Phonon_VIDEOPLAYER_H
+#define Phonon_VIDEOPLAYER_H
+
+#include "phonon_export.h"
+#include "phononnamespace.h"
+#include "mediasource.h"
+#include <QtGui/QWidget>
+
+QT_BEGIN_HEADER
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_PHONON_VIDEOPLAYER
+
+namespace Phonon
+{
+class VideoPlayerPrivate;
+class MediaObject;
+class AudioOutput;
+class VideoWidget;
+
+/** \class VideoPlayer videoplayer.h Phonon/VideoPlayer
+ * \short Playback class for simple tasks.
+ *
+ * With %VideoPlayer you can get results quickly and easily. You can do the standard
+ * playback tasks like play, pause and stop, but also set a playback volume and
+ * seek (there's no guarantee that the seek will work, though).
+ *
+ * Keep in mind that when the %VideoPlayer instance is deleted the playback will
+ * stop.
+ *
+ * A play and forget code example:
+ * \code
+ * VideoPlayer *player = new VideoPlayer(parentWidget);
+ * connect(player, SIGNAL(finished()), player, SLOT(deleteLater()));
+ * player->play(url);
+ * \endcode
+ *
+ * \ingroup Playback
+ * \ingroup PhononVideo
+ * \author Matthias Kretz <kretz@kde.org>
+ */
+class PHONON_EXPORT VideoPlayer : public QWidget
+{
+ Q_OBJECT
+ public:
+ /**
+ * Constructs a new %VideoPlayer instance.
+ *
+ * \param category The category used for the audio output device.
+ * \param parent The QObject parent.
+ */
+ explicit VideoPlayer(Phonon::Category category, QWidget *parent = 0);
+
+ /**
+ * Constructs a new video widget with a \p parent
+ * using Phonon::VideoCategory as its category.
+ *
+ * \param parent The QObject parent.
+ */
+ VideoPlayer(QWidget *parent = 0);
+
+ /**
+ * On destruction the playback is stopped, also the audio output is
+ * removed so that the desktop mixer will not show the application
+ * anymore. If you need a persistent audio output don't use
+ * %VideoPlayer but MediaObject, VideoPath and VideoOutput.
+ */
+ ~VideoPlayer();
+
+ /**
+ * Get the total time (in milliseconds) of the file currently being played.
+ */
+ qint64 totalTime() const;
+ /**
+ * Get the current time (in milliseconds) of the file currently being played.
+ */
+ qint64 currentTime() const;
+ /**
+ * This is the current volume of the output as voltage factor.
+ *
+ * 1.0 means 100%, 0.5 means 50% voltage/25% power, 0.0 means 0%
+ */
+ float volume() const;
+
+ /**
+ * \returns \c true if it is currently playing
+ * \returns \c false if it is currently stopped or paused
+ */
+ bool isPlaying() const;
+ /**
+ * \returns \c true if it is currently paused
+ * \returns \c false if it is currently playing or stopped
+ */
+ bool isPaused() const;
+
+ /**
+ * getter for the MediaObject.
+ */
+ MediaObject *mediaObject() const;
+
+ /**
+ * getter for the AudioOutput.
+ */
+ AudioOutput *audioOutput() const;
+
+ /**
+ * getter for the VideoWidget.
+ */
+ VideoWidget *videoWidget() const;
+
+ public Q_SLOTS:
+ /**
+ * Starts preloading the media data and fill audiobuffers in the
+ * backend.
+ *
+ * When there's already a media playing (or paused) it will be stopped
+ * (the finished signal will not be emitted).
+ */
+ void load(const Phonon::MediaSource &source);
+
+ /**
+ * Play the media at the given URL. Starts playback as fast as possible.
+ * This can take a considerable time depending on the URL and the
+ * backend.
+ *
+ * If you need low latency between calling play() and the sound actually
+ * starting to play on your output device you need to use MediaObject
+ * and be able to set the URL before calling play(). Note that
+ * \code
+ * audioPlayer->load(url);
+ * audioPlayer->play();
+ * \endcode
+ * doesn't make a difference: the application should be idle between the
+ * load and play calls so that the backend can start preloading the
+ * media and fill audio buffers.
+ */
+ void play(const Phonon::MediaSource &source);
+
+ /**
+ * Continues playback of a paused media. Restarts playback of a stopped
+ * media.
+ */
+ void play();
+ /**
+ * Pauses the playback.
+ */
+ void pause();
+ /**
+ * Stops the playback.
+ */
+ void stop();
+
+ /**
+ * Seeks to the requested time. Note that the backend is free to ignore
+ * the seek request if the media source isn't seekable.
+ *
+ * \param ms Time in milliseconds from the start of the media.
+ */
+ void seek(qint64 ms);
+ /**
+ * Sets the volume of the output as voltage factor.
+ *
+ * 1.0 means 100%, 0.5 means 50% voltage/25% power, 0.0 means 0%
+ */
+ void setVolume(float volume);
+
+ Q_SIGNALS:
+ /**
+ * This signal is emitted when the playback finished.
+ */
+ void finished();
+
+ protected:
+ VideoPlayerPrivate *const d;
+};
+
+} //namespace Phonon
+
+#endif //QT_NO_PHONON_VIDEOPLAYER
+
+QT_END_NAMESPACE
+QT_END_HEADER
+
+#endif // Phonon_VIDEOPLAYER_H
+// vim: sw=4 ts=4 tw=80
diff --git a/src/3rdparty/phonon/phonon/videowidget.cpp b/src/3rdparty/phonon/phonon/videowidget.cpp
new file mode 100644
index 0000000000..63f68997a4
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/videowidget.cpp
@@ -0,0 +1,183 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005-2007 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "videowidget.h"
+#include "videowidget_p.h"
+#include "videowidgetinterface.h"
+#include "factory_p.h"
+#include "phonondefs_p.h"
+#include "phononnamespace_p.h"
+
+#include <QtGui/QAction>
+
+#define PHONON_INTERFACENAME VideoWidgetInterface
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_PHONON_VIDEO
+
+namespace Phonon
+{
+
+VideoWidget::VideoWidget(QWidget *parent)
+ : QWidget(parent)
+ , Phonon::AbstractVideoOutput(*new VideoWidgetPrivate(this))
+{
+ K_D(VideoWidget);
+ d->init();
+ d->createBackendObject();
+ setMouseTracking(true);
+}
+
+VideoWidget::VideoWidget(VideoWidgetPrivate &dd, QWidget *parent)
+ : QWidget(parent),
+ Phonon::AbstractVideoOutput(dd)
+{
+ K_D(VideoWidget);
+ d->init();
+}
+
+void VideoWidgetPrivate::init()
+{
+ Q_Q(VideoWidget);
+ changeFlags = q->windowFlags() & (Qt::SubWindow | Qt::Window);
+}
+
+void VideoWidget::mouseMoveEvent(QMouseEvent *e)
+{
+ QWidget::mouseMoveEvent(e);
+}
+
+void VideoWidgetPrivate::createBackendObject()
+{
+ if (m_backendObject)
+ return;
+ Q_Q(VideoWidget);
+ m_backendObject = Factory::createVideoWidget(q);
+ if (m_backendObject) {
+ setupBackendObject();
+ }
+}
+
+#define PHONON_CLASSNAME VideoWidget
+
+PHONON_INTERFACE_GETTER(Phonon::VideoWidget::AspectRatio, aspectRatio, d->aspectRatio)
+PHONON_INTERFACE_SETTER(setAspectRatio, aspectRatio, Phonon::VideoWidget::AspectRatio)
+
+PHONON_INTERFACE_GETTER(Phonon::VideoWidget::ScaleMode, scaleMode, d->scaleMode)
+PHONON_INTERFACE_SETTER(setScaleMode, scaleMode, Phonon::VideoWidget::ScaleMode)
+
+PHONON_INTERFACE_GETTER(qreal, brightness, d->brightness)
+PHONON_INTERFACE_SETTER(setBrightness, brightness, qreal)
+
+PHONON_INTERFACE_GETTER(qreal, contrast, d->contrast)
+PHONON_INTERFACE_SETTER(setContrast, contrast, qreal)
+
+PHONON_INTERFACE_GETTER(qreal, hue, d->hue)
+PHONON_INTERFACE_SETTER(setHue, hue, qreal)
+
+PHONON_INTERFACE_GETTER(qreal, saturation, d->saturation)
+PHONON_INTERFACE_SETTER(setSaturation, saturation, qreal)
+
+void VideoWidget::setFullScreen(bool newFullScreen)
+{
+ pDebug() << Q_FUNC_INFO << newFullScreen;
+ K_D(VideoWidget);
+ // TODO: disable screensaver? or should we leave that responsibility to the
+ // application?
+ Qt::WindowFlags flags = windowFlags();
+ if (newFullScreen) {
+ if (!isFullScreen()) {
+ //we only update that value if it is not already fullscreen
+ d->changeFlags = flags & (Qt::Window | Qt::SubWindow);
+ flags |= Qt::Window;
+ flags ^= Qt::SubWindow;
+ setWindowFlags(flags);
+#ifdef Q_WS_X11
+ // This works around a bug with Compiz
+ // as the window must be visible before we can set the state
+ show();
+ raise();
+ setWindowState( windowState() | Qt::WindowFullScreen ); // set
+#else
+ setWindowState( windowState() | Qt::WindowFullScreen ); // set
+ show();
+#endif
+ }
+ } else if (isFullScreen()) {
+ flags ^= (Qt::Window | Qt::SubWindow); //clear the flags...
+ flags |= d->changeFlags; //then we reset the flags (window and subwindow)
+ setWindowFlags(flags);
+ setWindowState( windowState() ^ Qt::WindowFullScreen ); // reset
+ show();
+ }
+}
+
+void VideoWidget::exitFullScreen()
+{
+ setFullScreen(false);
+}
+
+void VideoWidget::enterFullScreen()
+{
+ setFullScreen(true);
+}
+
+bool VideoWidgetPrivate::aboutToDeleteBackendObject()
+{
+ aspectRatio = pINTERFACE_CALL(aspectRatio());
+ scaleMode = pINTERFACE_CALL(scaleMode());
+ return AbstractVideoOutputPrivate::aboutToDeleteBackendObject();
+}
+
+void VideoWidgetPrivate::setupBackendObject()
+{
+ Q_Q(VideoWidget);
+ Q_ASSERT(m_backendObject);
+ //AbstractVideoOutputPrivate::setupBackendObject();
+ pDebug() << "calling setAspectRatio on the backend " << aspectRatio;
+ pINTERFACE_CALL(setAspectRatio(aspectRatio));
+ pINTERFACE_CALL(setScaleMode(scaleMode));
+
+ QWidget *w = pINTERFACE_CALL(widget());
+ if (w) {
+ layout.addWidget(w);
+ q->setSizePolicy(w->sizePolicy());
+ w->setMouseTracking(true);
+ }
+}
+
+bool VideoWidget::event(QEvent *e)
+{
+ return QWidget::event(e);
+}
+
+} //namespace Phonon
+
+#endif //QT_NO_PHONON_VIDEO
+
+QT_END_NAMESPACE
+
+#include "moc_videowidget.cpp"
+
+#undef PHONON_CLASSNAME
+// vim: sw=4 ts=4 tw=80
diff --git a/src/3rdparty/phonon/phonon/videowidget.h b/src/3rdparty/phonon/phonon/videowidget.h
new file mode 100644
index 0000000000..bde73330fe
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/videowidget.h
@@ -0,0 +1,219 @@
+/* This file is part of the KDE project
+ Copyright (C) 2005-2007 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+#ifndef Phonon_VIDEOWIDGET_H
+#define Phonon_VIDEOWIDGET_H
+
+#include "phonon_export.h"
+#include "phonondefs.h"
+#include "abstractvideooutput.h"
+#include <QtGui/QWidget>
+
+QT_BEGIN_HEADER
+QT_BEGIN_NAMESPACE
+
+class QString;
+
+#ifndef QT_NO_PHONON_VIDEO
+
+namespace Phonon
+{
+class AbstractVideoOutput;
+ class VideoWidgetPrivate;
+ /** \class VideoWidget videowidget.h Phonon/VideoWidget
+ * \short Widget to display video.
+ *
+ * This widget shows the video signal.
+ *
+ * \code
+ * MediaObject *media = new MediaObject(parent);
+ * VideoWidget *vwidget = new VideoWidget(parent);
+ * Phonon::createPath(media, vwidget);
+ * \endcode
+ *
+ * \ingroup PhononVideo
+ * \ingroup PhononWidgets
+ * \author Matthias Kretz <kretz@kde.org>
+ */
+ class PHONON_EXPORT VideoWidget : public QWidget, public Phonon::AbstractVideoOutput
+ {
+ K_DECLARE_PRIVATE(VideoWidget)
+ Q_OBJECT
+ Q_ENUMS(AspectRatio ScaleMode)
+ /**
+ * This property holds whether the video is shown using the complete
+ * screen.
+ *
+ * The property differs from QWidget::fullScreen in that it is
+ * writeable.
+ *
+ * By default the widget is not shown in fullScreen.
+ *
+ * \warning When switching the video to fullscreen using setFullScreen
+ * your application loses control over the widget that actually shows
+ * the video (which is then shown as a toplevel window while your
+ * application still uses this widget). If you only need to capture key
+ * events the event forwarding done internally should suffice for your
+ * needs. If you need to map mouse coordinates or add widgets (that are
+ * not overlays) you should probably handle fullscreen yourself.
+ */
+ Q_PROPERTY(bool fullScreen READ isFullScreen WRITE setFullScreen)
+ /**
+ *
+ * Defaults to AspectRatioAuto.
+ *
+ * \see AspectRatio
+ */
+ Q_PROPERTY(AspectRatio aspectRatio READ aspectRatio WRITE setAspectRatio)
+
+ /**
+ * If the size of the widget and the size of the video are not equal.
+ * The video will be zoomed to fit the widget. The smaller zoom
+ * (AddBarsScaleMode) adds black bars at the left/right or top/bottom to
+ * make all of the image visible (default). The bigger zoom (ExpandMode)
+ * fills the widget completely, keeping all information in one direction
+ * and leaving parts of the image outside of the widget in the other
+ * direction.
+ */
+ Q_PROPERTY(ScaleMode scaleMode READ scaleMode WRITE setScaleMode)
+
+ /**
+ * This property holds brightness of the video.
+ *
+ * Default is 0. Acceptable values are in range of -1, 1.
+ */
+ Q_PROPERTY(qreal brightness READ brightness WRITE setBrightness)
+ /**
+ * This property holds the contrast of the video.
+ *
+ * Default is 0. Acceptable values are in range of -1, 1.
+ */
+ Q_PROPERTY(qreal contrast READ contrast WRITE setContrast)
+ /**
+ * This property holds the hue of the video.
+ *
+ * Default is 0. Acceptable values are in range of -1, 1.
+ */
+ Q_PROPERTY(qreal hue READ hue WRITE setHue)
+ /**
+ * This property holds saturation of the video.
+ *
+ * Default is 0. Acceptable values are in range of -1, 1.
+ */
+ Q_PROPERTY(qreal saturation READ saturation WRITE setSaturation)
+
+ public:
+ /**
+ * Defines the width:height to be used for the video.
+ */
+ enum AspectRatio
+ {
+ /**
+ * Let the decoder find the aspect ratio automatically from the
+ * media file (this is the default).
+ */
+ AspectRatioAuto = 0,
+ /**
+ * Fits the video into the widget making the aspect ratio depend
+ * solely on the size of the widget. This way the aspect ratio
+ * is freely resizeable by the user.
+ */
+ AspectRatioWidget = 1,
+ /**
+ * Make width/height == 4/3, which is the old TV size and
+ * monitor size (1024/768 == 4/3). (4:3)
+ */
+ AspectRatio4_3 = 2,
+ /**
+ * Make width/height == 16/9, which is the size of most current
+ * media. (16:9)
+ */
+ AspectRatio16_9 = 3
+//X /**
+//X * Assume that every pixel of the video image needs to be displayed with the same
+//X * physical width and height. (1:1 image pixels, not imagewidth
+//X * = imageheight)
+//X */
+//X AspectRatioSquare = 4,
+ };
+
+ enum ScaleMode {
+ FitInView = 0,
+ ScaleAndCrop = 1
+ };
+
+ /**
+ * Constructs a new video widget with a \p parent.
+ */
+ VideoWidget(QWidget *parent = 0);
+
+ AspectRatio aspectRatio() const;
+ ScaleMode scaleMode() const;
+
+ qreal brightness() const;
+ qreal contrast() const;
+ qreal hue() const;
+ qreal saturation() const;
+
+ //TODO: bar colors property
+ public Q_SLOTS:
+ void setFullScreen(bool fullscreen);
+
+ /**
+ * Convenience slot, calling setFullScreen(false)
+ */
+ void exitFullScreen();
+
+ /**
+ * Convenience slot, calling setFullScreen(true)
+ */
+ void enterFullScreen();
+
+ void setAspectRatio(AspectRatio);
+ void setScaleMode(ScaleMode);
+
+ void setBrightness(qreal value);
+ void setContrast(qreal value);
+ void setHue(qreal value);
+ void setSaturation(qreal value);
+
+ protected:
+ /**
+ * \internal
+ *
+ * Constructs a new video widget with private data pointer \p d and
+ * a \p parent.
+ */
+ VideoWidget(VideoWidgetPrivate &d, QWidget *parent);
+
+ void mouseMoveEvent(QMouseEvent *);
+ bool event(QEvent *);
+ };
+
+} //namespace Phonon
+
+#endif //QT_NO_PHONON_VIDEO
+
+QT_END_NAMESPACE
+QT_END_HEADER
+
+// vim: sw=4 ts=4 tw=80
+#endif // Phonon_VIDEOWIDGET_H
diff --git a/src/3rdparty/phonon/phonon/videowidget_p.h b/src/3rdparty/phonon/phonon/videowidget_p.h
new file mode 100644
index 0000000000..c2434f244b
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/videowidget_p.h
@@ -0,0 +1,84 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006-2007 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef VIDEOWIDGET_P_H
+#define VIDEOWIDGET_P_H
+
+#include "videowidget.h"
+#include "abstractvideooutput_p.h"
+#include <QtGui/QBoxLayout>
+#include <QtCore/QEvent>
+#include <QtCore/QCoreApplication>
+#include <QtGui/QPalette>
+#include <QtGui/QKeyEvent>
+#include <QtCore/QTimer>
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_PHONON_VIDEO
+
+namespace Phonon
+{
+
+class VideoWidgetPrivate : public Phonon::AbstractVideoOutputPrivate
+{
+ Q_DECLARE_PUBLIC(VideoWidget)
+ public:
+ virtual QObject *qObject() { return q_func(); }
+ protected:
+ virtual bool aboutToDeleteBackendObject();
+ virtual void createBackendObject();
+ void setupBackendObject();
+
+ VideoWidgetPrivate(VideoWidget *parent)
+ : layout(parent),
+ aspectRatio(VideoWidget::AspectRatioAuto),
+ scaleMode(VideoWidget::FitInView),
+ brightness(0),
+ contrast(0),
+ hue(0),
+ saturation(0)
+ {
+ layout.setMargin(0);
+ }
+
+ QHBoxLayout layout;
+ VideoWidget::AspectRatio aspectRatio;
+ VideoWidget::ScaleMode scaleMode;
+ Qt::WindowFlags changeFlags;
+
+ qreal brightness;
+ qreal contrast;
+ qreal hue;
+ qreal saturation;
+
+ private:
+ void init();
+};
+
+} // namespace Phonon
+
+#endif //QT_NO_PHONON_VIDEO
+
+QT_END_NAMESPACE
+#endif // VIDEOWIDGET_P_H
+// vim: sw=4 ts=4 tw=80
diff --git a/src/3rdparty/phonon/phonon/videowidgetinterface.h b/src/3rdparty/phonon/phonon/videowidgetinterface.h
new file mode 100644
index 0000000000..7ed8a8a272
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/videowidgetinterface.h
@@ -0,0 +1,65 @@
+/* This file is part of the KDE project
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). <thierry.bastian@trolltech.com>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef PHONON_VIDEOWIDGETINTERFACE_H
+#define PHONON_VIDEOWIDGETINTERFACE_H
+
+#include "videowidget.h"
+
+QT_BEGIN_HEADER
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_PHONON_VIDEO
+
+namespace Phonon
+{
+class VideoWidgetInterface
+{
+ public:
+ virtual ~VideoWidgetInterface() {}
+
+ virtual Phonon::VideoWidget::AspectRatio aspectRatio() const = 0;
+ virtual void setAspectRatio(Phonon::VideoWidget::AspectRatio) = 0;
+ virtual qreal brightness() const = 0;
+ virtual void setBrightness(qreal) = 0;
+ virtual Phonon::VideoWidget::ScaleMode scaleMode() const = 0;
+ virtual void setScaleMode(Phonon::VideoWidget::ScaleMode) = 0;
+ virtual qreal contrast() const = 0;
+ virtual void setContrast(qreal) = 0;
+ virtual qreal hue() const = 0;
+ virtual void setHue(qreal) = 0;
+ virtual qreal saturation() const = 0;
+ virtual void setSaturation(qreal) = 0;
+ virtual QWidget *widget() = 0;
+//X virtual int overlayCapabilities() const = 0;
+//X virtual bool createOverlay(QWidget *widget, int type) = 0;
+};
+}
+
+Q_DECLARE_INTERFACE(Phonon::VideoWidgetInterface, "VideoWidgetInterface3.phonon.kde.org")
+
+#endif //QT_NO_PHONON_VIDEO
+
+QT_END_NAMESPACE
+QT_END_HEADER
+
+#endif // PHONON_VIDEOWIDGETINTERFACE_H
diff --git a/src/3rdparty/phonon/phonon/volumefadereffect.cpp b/src/3rdparty/phonon/phonon/volumefadereffect.cpp
new file mode 100644
index 0000000000..066199ea42
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/volumefadereffect.cpp
@@ -0,0 +1,108 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "volumefadereffect.h"
+#include "volumefadereffect_p.h"
+#include "volumefaderinterface.h"
+#include "factory_p.h"
+
+#include <QtCore/qmath.h>
+
+#define PHONON_CLASSNAME VolumeFaderEffect
+#define PHONON_INTERFACENAME VolumeFaderInterface
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_PHONON_VOLUMEFADEREFFECT
+
+namespace Phonon
+{
+PHONON_HEIR_IMPL(Effect)
+
+PHONON_INTERFACE_GETTER(float, volume, d->currentVolume)
+PHONON_INTERFACE_SETTER(setVolume, currentVolume, float)
+PHONON_INTERFACE_GETTER(Phonon::VolumeFaderEffect::FadeCurve, fadeCurve, d->fadeCurve)
+PHONON_INTERFACE_SETTER(setFadeCurve, fadeCurve, Phonon::VolumeFaderEffect::FadeCurve)
+
+#ifndef PHONON_LOG10OVER20
+#define PHONON_LOG10OVER20
+static const double log10over20 = 0.1151292546497022842; // ln(10) / 20
+#endif // PHONON_LOG10OVER20
+
+double VolumeFaderEffect::volumeDecibel() const
+{
+ return log(volume()) / log10over20;
+}
+
+void VolumeFaderEffect::setVolumeDecibel(double newVolumeDecibel)
+{
+ setVolume(exp(newVolumeDecibel * log10over20));
+}
+
+
+void VolumeFaderEffect::fadeIn(int fadeTime)
+{
+ fadeTo(1.0, fadeTime);
+}
+
+void VolumeFaderEffect::fadeOut(int fadeTime)
+{
+ fadeTo(0.0, fadeTime);
+}
+
+void VolumeFaderEffect::fadeTo(float volume, int fadeTime)
+{
+ K_D(VolumeFaderEffect);
+ if (k_ptr->backendObject())
+ INTERFACE_CALL(fadeTo(volume, fadeTime));
+ else
+ d->currentVolume = volume;
+}
+
+bool VolumeFaderEffectPrivate::aboutToDeleteBackendObject()
+{
+ if (m_backendObject) {
+ currentVolume = pINTERFACE_CALL(volume());
+ fadeCurve = pINTERFACE_CALL(fadeCurve());
+ }
+ return true;
+}
+
+void VolumeFaderEffectPrivate::setupBackendObject()
+{
+ Q_ASSERT(m_backendObject);
+
+ // set up attributes
+ pINTERFACE_CALL(setVolume(currentVolume));
+ pINTERFACE_CALL(setFadeCurve(fadeCurve));
+}
+}
+
+
+#endif //QT_NO_PHONON_VOLUMEFADEREFFECT
+
+QT_END_NAMESPACE
+
+#include "moc_volumefadereffect.cpp"
+
+#undef PHONON_CLASSNAME
+// vim: sw=4 ts=4
diff --git a/src/3rdparty/phonon/phonon/volumefadereffect.h b/src/3rdparty/phonon/phonon/volumefadereffect.h
new file mode 100644
index 0000000000..22f2137797
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/volumefadereffect.h
@@ -0,0 +1,178 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef PHONON_VOLUMEFADEREFFECT_H
+#define PHONON_VOLUMEFADEREFFECT_H
+
+#include "phonon_export.h"
+#include "effect.h"
+
+QT_BEGIN_HEADER
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_PHONON_VOLUMEFADEREFFECT
+
+namespace Phonon
+{
+ class VolumeFaderEffectPrivate;
+
+ /** \class VolumeFaderEffect volumefadereffect.h Phonon/VolumeFaderEffect
+ * Audio effect to gradually fade the audio volume.
+ *
+ * This effect differs from gradually changing the output volume in that
+ * a dedicated effect can change the volume in the smallest possible
+ * steps while every other volume control will make more or less
+ * noticeable steps.
+ *
+ * \ingroup PhononEffects
+ * \author Matthias Kretz <kretz@kde.org>
+ * \see AudioOutput::volume
+ */
+ class PHONON_EXPORT VolumeFaderEffect : public Effect
+ {
+ Q_OBJECT
+ K_DECLARE_PRIVATE(VolumeFaderEffect)
+ PHONON_HEIR(VolumeFaderEffect)
+ Q_ENUMS(FadeCurve)
+ /**
+ * This is the current volume of the output as voltage factor.
+ * Setting this property changes the volume immediately.
+ *
+ * 1.0 means 100%, 0.5 means 50% voltage/25% power, 0.0 means 0%
+ *
+ * \see volumeDecibel
+ */
+ Q_PROPERTY(float volume READ volume WRITE setVolume)
+ /**
+ * This is the current volume of the output in decibel.
+ * Setting this property changes the volume immediately.
+ *
+ * 0 dB means no change in volume, -6dB means an attenuation of the
+ * voltage to 50% and an attenuation of the power to 25%, -inf dB means
+ * silence.
+ *
+ * \see volume
+ */
+ Q_PROPERTY(double volumeDecibel READ volumeDecibel WRITE setVolumeDecibel)
+ /**
+ * This property holds the fade curve to be used for the fadeIn(), fadeOut()
+ * and fadeTo() slots.
+ *
+ * Defaults to Fade3Decibel.
+ *
+ * \see FadeCurve
+ */
+ Q_PROPERTY(FadeCurve fadeCurve READ fadeCurve WRITE setFadeCurve)
+ public:
+ /**
+ * Determines the curve of the volume change.
+ */
+ enum FadeCurve {
+ /**
+ * "Crossfade curve" / "fast" fade out
+ *
+ * Often the best fade for a crossfade, as after half of the
+ * time the volume reached -3dB. This means that half the
+ * possible power (which is proportional to the square of the
+ * voltage) is reached. Summed, the maximum power of two audio
+ * signals fading with a -3dB curve will always be equal.
+ *
+ * For fading in or out the -3dB curve is too abrupt in the end.
+ *
+ * This is the default fade curve.
+ */
+ Fade3Decibel,
+ /**
+ * "Linear" fade out
+ *
+ * With a -6dB fade curve after half of the fading time -6dB has
+ * been reached. -6dB is equal to half of the voltage meaning
+ * that the voltage multiplier changes linearly from the start
+ * of the fade to the end.
+ */
+ Fade6Decibel,
+ /**
+ * "slow" fade out
+ *
+ * After half of the fade time -9dB are reached. So the fade is
+ * fast in the beginning and slow in the end. This is a good
+ * fade for ending music.
+ */
+ Fade9Decibel,
+ /**
+ * more extreme version of the -9dB fade
+ */
+ Fade12Decibel
+ };
+
+ float volume() const;
+ double volumeDecibel() const;
+
+ FadeCurve fadeCurve() const;
+
+ public Q_SLOTS:
+ /**
+ * Tells the Fader to change the volume from the current volume to 100%
+ * in \p fadeTime milliseconds.
+ * Short for \c fadeTo(1.0, fadeTime).
+ *
+ * \param fadeTime the fade duration in milliseconds
+ *
+ * \see fadeTo
+ * \see volume
+ */
+ void fadeIn(int fadeTime);
+
+ /**
+ * Tells the Fader to change the volume from the current volume to 0%
+ * in \p fadeTime milliseconds.
+ * Short for \c fadeTo(0.0, fadeTime).
+ *
+ * \param fadeTime the fade duration in milliseconds
+ *
+ * \see fadeTo
+ */
+ void fadeOut(int fadeTime);
+
+ void setVolume(float volume);
+ void setVolumeDecibel(double volumeDecibel);
+
+ void setFadeCurve(FadeCurve curve);
+
+ /**
+ * Tells the Fader to change the volume from the current value to
+ * \p volume in \p fadeTime milliseconds
+ *
+ * \see fadeIn
+ * \see fadeOut
+ */
+ void fadeTo(float volume, int fadeTime);
+ };
+} //namespace Phonon
+
+#endif //QT_NO_PHONON_VOLUMEFADEREFFECT
+
+QT_END_NAMESPACE
+QT_END_HEADER
+
+// vim: sw=4 ts=4 tw=80
+#endif // PHONON_VOLUMEFADEREFFECT_H
diff --git a/src/3rdparty/phonon/phonon/volumefadereffect_p.h b/src/3rdparty/phonon/phonon/volumefadereffect_p.h
new file mode 100644
index 0000000000..cdd4e00f84
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/volumefadereffect_p.h
@@ -0,0 +1,58 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef PHONON_VOLUMEFADEREFFECT_P_H
+#define PHONON_VOLUMEFADEREFFECT_P_H
+
+#include "volumefadereffect.h"
+#include "effect_p.h"
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_PHONON_VOLUMEFADEREFFECT
+
+namespace Phonon
+{
+class VolumeFaderEffectPrivate : public EffectPrivate
+{
+ Q_DECLARE_PUBLIC(VolumeFaderEffect)
+ PHONON_PRIVATECLASS
+ protected:
+ VolumeFaderEffectPrivate()
+ : currentVolume(1.0)
+ , fadeCurve(VolumeFaderEffect::Fade3Decibel)
+ {
+ // invalid EffectDescription
+ // ############# parameter functions are incorrect
+ }
+
+ float currentVolume;
+ VolumeFaderEffect::FadeCurve fadeCurve;
+};
+}
+
+#endif //QT_NO_PHONON_VOLUMEFADEREFFECT
+
+QT_END_NAMESPACE
+
+#endif // PHONON_VOLUMEFADEREFFECT_P_H
+// vim: sw=4 ts=4 tw=80
diff --git a/src/3rdparty/phonon/phonon/volumefaderinterface.h b/src/3rdparty/phonon/phonon/volumefaderinterface.h
new file mode 100644
index 0000000000..da4262b04d
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/volumefaderinterface.h
@@ -0,0 +1,58 @@
+/* This file is part of the KDE project
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). <thierry.bastian@trolltech.com>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef PHONON_VOLUMEFADERINTERFACE_H
+#define PHONON_VOLUMEFADERINTERFACE_H
+
+#include "volumefadereffect.h"
+#include <QtCore/QObject>
+
+QT_BEGIN_HEADER
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_PHONON_VOLUMEFADEREFFECT
+
+namespace Phonon
+{
+class VolumeFaderInterface
+{
+ public:
+ virtual ~VolumeFaderInterface() {}
+
+ virtual float volume() const { return 1.0; }
+ virtual void setVolume(float) {}
+ virtual Phonon::VolumeFaderEffect::FadeCurve fadeCurve() const {
+ return VolumeFaderEffect::Fade3Decibel;
+ }
+ virtual void setFadeCurve(Phonon::VolumeFaderEffect::FadeCurve) {}
+ virtual void fadeTo(float, int) {}
+};
+}
+
+Q_DECLARE_INTERFACE(Phonon::VolumeFaderInterface, "VolumeFaderInterface4.phonon.kde.org")
+
+#endif //QT_NO_PHONON_VOLUMEFADEREFFECT
+
+QT_END_NAMESPACE
+QT_END_HEADER
+
+#endif // PHONON_VOLUMEFADERINTERFACE_H
diff --git a/src/3rdparty/phonon/phonon/volumeslider.cpp b/src/3rdparty/phonon/phonon/volumeslider.cpp
new file mode 100644
index 0000000000..b59f689bc0
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/volumeslider.cpp
@@ -0,0 +1,262 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006-2007 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "volumeslider.h"
+#include "volumeslider_p.h"
+#include "audiooutput.h"
+#include "phonondefs_p.h"
+#include "phononnamespace_p.h"
+#include "factory_p.h"
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_PHONON_VOLUMESLIDER
+
+namespace Phonon
+{
+VolumeSlider::VolumeSlider(QWidget *parent)
+ : QWidget(parent),
+ k_ptr(new VolumeSliderPrivate(this))
+{
+ K_D(VolumeSlider);
+#ifndef QT_NO_TOOLTIP
+ setToolTip(tr("Volume: %1%").arg(100));
+#endif
+#ifndef QT_NO_WHATSTHIS
+ setWhatsThis(tr("Use this slider to adjust the volume. The leftmost position is 0%, the rightmost is %1%").arg(100));
+#endif
+
+ connect(&d->slider, SIGNAL(valueChanged(int)), SLOT(_k_sliderChanged(int)));
+ connect(&d->muteButton, SIGNAL(clicked()), SLOT(_k_buttonClicked()));
+
+ setFocusProxy(&d->slider);
+}
+
+VolumeSlider::VolumeSlider(AudioOutput *output, QWidget *parent)
+ : QWidget(parent),
+ k_ptr(new VolumeSliderPrivate(this))
+{
+ K_D(VolumeSlider);
+#ifndef QT_NO_TOOLTIP
+ setToolTip(tr("Volume: %1%").arg(100));
+#endif
+#ifndef QT_NO_WHATSTHIS
+ setWhatsThis(tr("Use this slider to adjust the volume. The leftmost position is 0%, the rightmost is %1%").arg(100));
+#endif
+
+ connect(&d->slider, SIGNAL(valueChanged(int)), SLOT(_k_sliderChanged(int)));
+ connect(&d->muteButton, SIGNAL(clicked()), SLOT(_k_buttonClicked()));
+
+ if (output) {
+ d->output = output;
+ d->slider.setValue(qRound(100 * output->volume()));
+ d->slider.setEnabled(true);
+ d->muteButton.setEnabled(true);
+ connect(output, SIGNAL(volumeChanged(qreal)), SLOT(_k_volumeChanged(qreal)));
+ connect(output, SIGNAL(mutedChanged(bool)), SLOT(_k_mutedChanged(bool)));
+ }
+
+ setFocusProxy(&d->slider);
+}
+
+VolumeSlider::~VolumeSlider()
+{
+ delete k_ptr;
+}
+
+bool VolumeSlider::isMuteVisible() const
+{
+ return k_ptr->muteButton.isVisible();
+}
+
+void VolumeSlider::setMuteVisible(bool visible)
+{
+ k_ptr->muteButton.setVisible(visible);
+}
+
+QSize VolumeSlider::iconSize() const
+{
+ return k_ptr->muteButton.iconSize();
+}
+
+void VolumeSlider::setIconSize(const QSize &iconSize)
+{
+ pDebug() << Q_FUNC_INFO << iconSize;
+ k_ptr->muteButton.setIconSize(iconSize);
+}
+
+qreal VolumeSlider::maximumVolume() const
+{
+ return k_ptr->slider.maximum() * 0.01;
+}
+
+void VolumeSlider::setMaximumVolume(qreal volume)
+{
+ int max = static_cast<int>(volume * 100);
+ k_ptr->slider.setMaximum(max);
+#ifndef QT_NO_WHATSTHIS
+ setWhatsThis(tr("Use this slider to adjust the volume. The leftmost position is 0%, the rightmost is %1%")
+ .arg(max));
+#endif
+}
+
+Qt::Orientation VolumeSlider::orientation() const
+{
+ return k_ptr->slider.orientation();
+}
+
+void VolumeSlider::setOrientation(Qt::Orientation o)
+{
+ K_D(VolumeSlider);
+ Qt::Alignment align = (o == Qt::Horizontal ? Qt::AlignVCenter : Qt::AlignHCenter);
+ d->layout.setAlignment(&d->muteButton, align);
+ d->layout.setAlignment(&d->slider, align);
+ d->layout.setDirection(o == Qt::Horizontal ? QBoxLayout::LeftToRight : QBoxLayout::TopToBottom);
+ d->slider.setOrientation(o);
+}
+
+AudioOutput *VolumeSlider::audioOutput() const
+{
+ K_D(const VolumeSlider);
+ return d->output;
+}
+
+void VolumeSlider::setAudioOutput(AudioOutput *output)
+{
+ K_D(VolumeSlider);
+ if (d->output) {
+ disconnect(d->output, 0, this, 0);
+ }
+ d->output = output;
+ if (output) {
+ d->slider.setValue(qRound(100 * output->volume()));
+ d->slider.setEnabled(true);
+ d->muteButton.setEnabled(true);
+
+ d->_k_volumeChanged(output->volume());
+ d->_k_mutedChanged(output->isMuted());
+
+ connect(output, SIGNAL(volumeChanged(qreal)), SLOT(_k_volumeChanged(qreal)));
+ connect(output, SIGNAL(mutedChanged(bool)), SLOT(_k_mutedChanged(bool)));
+ } else {
+ d->slider.setValue(100);
+ d->slider.setEnabled(false);
+ d->muteButton.setEnabled(false);
+ }
+}
+
+void VolumeSliderPrivate::_k_buttonClicked()
+{
+ if (output) {
+ output->setMuted(!output->isMuted());
+ } else {
+ slider.setEnabled(false);
+ muteButton.setEnabled(false);
+ }
+}
+
+void VolumeSliderPrivate::_k_mutedChanged(bool muted)
+{
+#ifndef QT_NO_TOOLTIP
+ Q_Q(VolumeSlider);
+#endif
+ if (muted) {
+#ifndef QT_NO_TOOLTIP
+ q->setToolTip(VolumeSlider::tr("Muted"));
+#endif
+ muteButton.setIcon(mutedIcon);
+ } else {
+#ifndef QT_NO_TOOLTIP
+ q->setToolTip(VolumeSlider::tr("Volume: %1%").arg(static_cast<int>(output->volume() * 100.0)));
+#endif
+ muteButton.setIcon(volumeIcon);
+ }
+}
+
+void VolumeSliderPrivate::_k_sliderChanged(int value)
+{
+#ifndef QT_NO_TOOLTIP
+ Q_Q(VolumeSlider);
+#endif
+
+ if (output) {
+#ifndef QT_NO_TOOLTIP
+ if (!output->isMuted()) {
+ q->setToolTip(VolumeSlider::tr("Volume: %1%").arg(value));
+ }
+#endif
+
+ ignoreVolumeChange = true;
+ output->setVolume((static_cast<qreal>(value)) * 0.01);
+ ignoreVolumeChange = false;
+ } else {
+ slider.setEnabled(false);
+ muteButton.setEnabled(false);
+ }
+}
+
+void VolumeSliderPrivate::_k_volumeChanged(qreal value)
+{
+ if (!ignoreVolumeChange) {
+ slider.setValue(qRound(100 * value));
+ }
+}
+
+bool VolumeSlider::hasTracking() const
+{
+ return k_ptr->slider.hasTracking();
+}
+
+void VolumeSlider::setTracking(bool tracking)
+{
+ k_ptr->slider.setTracking(tracking);
+}
+
+int VolumeSlider::pageStep() const
+{
+ return k_ptr->slider.pageStep();
+}
+
+void VolumeSlider::setPageStep(int milliseconds)
+{
+ k_ptr->slider.setPageStep(milliseconds);
+}
+
+int VolumeSlider::singleStep() const
+{
+ return k_ptr->slider.singleStep();
+}
+
+void VolumeSlider::setSingleStep(int milliseconds)
+{
+ k_ptr->slider.setSingleStep(milliseconds);
+}
+
+} // namespace Phonon
+
+#endif //QT_NO_PHONON_VOLUMESLIDER
+
+QT_END_NAMESPACE
+
+#include "moc_volumeslider.cpp"
+
+// vim: sw=4 et
diff --git a/src/3rdparty/phonon/phonon/volumeslider.h b/src/3rdparty/phonon/phonon/volumeslider.h
new file mode 100644
index 0000000000..47863a8e80
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/volumeslider.h
@@ -0,0 +1,155 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006-2007 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef PHONON_UI_VOLUMESLIDER_H
+#define PHONON_UI_VOLUMESLIDER_H
+
+#include "phonon_export.h"
+#include "phonondefs.h"
+#include <QtGui/QWidget>
+
+QT_BEGIN_HEADER
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_PHONON_VOLUMESLIDER
+
+namespace Phonon
+{
+class AudioOutput;
+class VolumeSliderPrivate;
+
+/** \class VolumeSlider volumeslider.h Phonon/VolumeSlider
+ * \short Widget providing a slider to control the volume of an AudioOutput.
+ *
+ * \ingroup PhononWidgets
+ * \author Matthias Kretz <kretz@kde.org>
+ */
+class PHONON_EXPORT VolumeSlider : public QWidget
+{
+ Q_OBJECT
+ K_DECLARE_PRIVATE(VolumeSlider)
+ /**
+ * This property holds the maximum volume that can be set with this slider.
+ *
+ * By default the maximum value is 1.0 (100%).
+ */
+ Q_PROPERTY(qreal maximumVolume READ maximumVolume WRITE setMaximumVolume)
+ /**
+ * This property holds the orientation of the slider.
+ *
+ * The orientation must be Qt::Vertical (the default) or Qt::Horizontal.
+ */
+ Q_PROPERTY(Qt::Orientation orientation READ orientation WRITE setOrientation)
+
+ /**
+ * This property holds whether slider tracking is enabled.
+ *
+ * If tracking is enabled (the default), the volume changes
+ * while the slider is being dragged. If tracking is
+ * disabled, the volume changes only when the user
+ * releases the slider.
+ */
+ Q_PROPERTY(bool tracking READ hasTracking WRITE setTracking)
+
+ /**
+ * This property holds the page step.
+ *
+ * The larger of two natural steps that a slider provides and
+ * typically corresponds to the user pressing PageUp or PageDown.
+ *
+ * Defaults to 5 (5% of the voltage).
+ */
+ Q_PROPERTY(int pageStep READ pageStep WRITE setPageStep)
+
+ /**
+ * This property holds the single step.
+ *
+ * The smaller of two natural steps that a slider provides and
+ * typically corresponds to the user pressing an arrow key.
+ *
+ * Defaults to 1 (1% of the voltage).
+ */
+ Q_PROPERTY(int singleStep READ singleStep WRITE setSingleStep)
+
+ /**
+ * This property holds whether the mute button/icon next to the slider is visible.
+ *
+ * By default the mute button/icon is visible.
+ */
+ Q_PROPERTY(bool muteVisible READ isMuteVisible WRITE setMuteVisible)
+
+ /**
+ * \brief the icon size used for the mute button/icon.
+ *
+ * The default size is defined by the GUI style.
+ */
+ Q_PROPERTY(QSize iconSize READ iconSize WRITE setIconSize)
+ public:
+ /**
+ * Constructs a new volume slider with a \p parent.
+ */
+ explicit VolumeSlider(QWidget *parent = 0);
+ explicit VolumeSlider(AudioOutput *, QWidget *parent = 0);
+ ~VolumeSlider();
+
+ bool hasTracking() const;
+ void setTracking(bool tracking);
+ int pageStep() const;
+ void setPageStep(int milliseconds);
+ int singleStep() const;
+ void setSingleStep(int milliseconds);
+ bool isMuteVisible() const;
+ QSize iconSize() const;
+ qreal maximumVolume() const;
+ Qt::Orientation orientation() const;
+ AudioOutput *audioOutput() const;
+
+ public Q_SLOTS:
+ void setMaximumVolume(qreal);
+ void setOrientation(Qt::Orientation);
+ void setMuteVisible(bool);
+ void setIconSize(const QSize &size);
+
+ /**
+ * Sets the audio output object to be controlled by this slider.
+ */
+ void setAudioOutput(Phonon::AudioOutput *);
+
+ protected:
+ VolumeSliderPrivate *const k_ptr;
+
+ private:
+ Q_PRIVATE_SLOT(k_ptr, void _k_sliderChanged(int))
+ Q_PRIVATE_SLOT(k_ptr, void _k_volumeChanged(qreal))
+ Q_PRIVATE_SLOT(k_ptr, void _k_mutedChanged(bool))
+ Q_PRIVATE_SLOT(k_ptr, void _k_buttonClicked())
+};
+
+} // namespace Phonon
+
+#endif //QT_NO_PHONON_VOLUMESLIDER
+
+QT_END_NAMESPACE
+QT_END_HEADER
+
+// vim: sw=4 ts=4 et
+#endif // PHONON_UI_VOLUMESLIDER_H
diff --git a/src/3rdparty/phonon/phonon/volumeslider_p.h b/src/3rdparty/phonon/phonon/volumeslider_p.h
new file mode 100644
index 0000000000..6d8009ae53
--- /dev/null
+++ b/src/3rdparty/phonon/phonon/volumeslider_p.h
@@ -0,0 +1,101 @@
+/* This file is part of the KDE project
+ Copyright (C) 2006-2007 Matthias Kretz <kretz@kde.org>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) version 3, or any
+ later version accepted by the membership of KDE e.V. (or its
+ successor approved by the membership of KDE e.V.), Trolltech ASA
+ (or its successors, if any) and the KDE Free Qt Foundation, which shall
+ act as a proxy defined in Section 6 of version 3 of the license.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef VOLUMESLIDER_P_H
+#define VOLUMESLIDER_P_H
+
+#include "volumeslider.h"
+#include <QtGui/QBoxLayout>
+#include <QtGui/QSlider>
+#include <QtGui/QLabel>
+#include <QtGui/QPixmap>
+#include <QtGui/QToolButton>
+#include "factory_p.h"
+#include "audiooutput.h"
+#include <QtGui/QIcon>
+#include <QtCore/QPointer>
+#include "platform_p.h"
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_PHONON_VOLUMESLIDER
+
+namespace Phonon
+{
+class VolumeSliderPrivate
+{
+ Q_DECLARE_PUBLIC(VolumeSlider)
+ protected:
+ VolumeSliderPrivate(VolumeSlider *parent)
+ : q_ptr(parent),
+ layout(QBoxLayout::LeftToRight, parent),
+ slider(Qt::Horizontal, parent),
+ muteButton(parent),
+ volumeIcon(Platform::icon(QLatin1String("player-volume"), parent->style())),
+ mutedIcon(Platform::icon(QLatin1String("player-volume-muted"), parent->style())),
+ output(0),
+ ignoreVolumeChange(false)
+ {
+ slider.setRange(0, 100);
+ slider.setPageStep(5);
+ slider.setSingleStep(1);
+
+ muteButton.setIcon(volumeIcon);
+ muteButton.setAutoRaise(true);
+ layout.setMargin(0);
+ layout.setSpacing(2);
+ layout.addWidget(&muteButton, 0, Qt::AlignVCenter);
+ layout.addWidget(&slider, 0, Qt::AlignVCenter);
+
+ slider.setEnabled(false);
+ muteButton.setEnabled(false);
+
+ if (volumeIcon.isNull()) {
+ muteButton.setVisible(false);
+ }
+ }
+
+ VolumeSlider *q_ptr;
+
+ void _k_sliderChanged(int);
+ void _k_volumeChanged(qreal);
+ void _k_mutedChanged(bool);
+ void _k_buttonClicked();
+
+ private:
+ QBoxLayout layout;
+ QSlider slider;
+ QToolButton muteButton;
+ QIcon volumeIcon;
+ QIcon mutedIcon;
+
+ QPointer<AudioOutput> output;
+ bool ignoreVolumeChange;
+};
+} // namespace Phonon
+
+#endif //QT_NO_PHONON_VOLUMESLIDER
+
+QT_END_NAMESPACE
+
+#endif // VOLUMESLIDER_P_H
+// vim: sw=4 sts=4 et tw=100
diff --git a/src/3rdparty/phonon/qt7/CMakeLists.txt b/src/3rdparty/phonon/qt7/CMakeLists.txt
new file mode 100644
index 0000000000..5310be12ef
--- /dev/null
+++ b/src/3rdparty/phonon/qt7/CMakeLists.txt
@@ -0,0 +1,58 @@
+# Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+#
+# This library 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, either version 2 or 3 of the License.
+#
+# This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+project(phonon-qt7)
+include(ConfigureChecks.cmake)
+
+include_directories(${OPENGL_INCLUDE_DIR})
+
+if (BUILD_PHONON_QT7)
+ set(phonon_qt7_SRCS
+ quicktimevideoplayer.mm
+ backendheader.mm
+ medianodevideopart.mm
+ medianodeevent.mm
+ audiooutput.mm
+ backendinfo.mm
+ audiosplitter.mm
+ audioeffects.mm
+ quicktimestreamreader.mm
+ medianode.mm
+ backend.mm
+ mediaobject.mm
+ mediaobjectaudionode.mm
+ audiomixer.mm
+ quicktimeaudioplayer.mm
+ videoframe.mm
+ quicktimemetadata.mm
+ audiodevice.mm
+ audioconnection.mm
+ audiograph.mm
+ audionode.mm
+ videowidget.mm
+ )
+
+ automoc4_add_library(phonon_qt7 MODULE ${phonon_qt7_SRCS})
+ target_link_libraries(phonon_qt7
+ ${QT_QTGUI_LIBRARY} ${QT_QTOPENGL_LIBRARY}
+ ${PHONON_LIBS}
+ "-framework QuickTime"
+ "-framework AudioUnit"
+ "-framework AudioToolbox"
+ "-framework CoreAudio"
+ "-framework QuartzCore"
+ "-framework QTKit"
+ )
+ install(TARGETS phonon_qt7 DESTINATION ${PLUGIN_INSTALL_DIR})
+
+endif (BUILD_PHONON_QT7)
diff --git a/src/3rdparty/phonon/qt7/ConfigureChecks.cmake b/src/3rdparty/phonon/qt7/ConfigureChecks.cmake
new file mode 100644
index 0000000000..96448679bb
--- /dev/null
+++ b/src/3rdparty/phonon/qt7/ConfigureChecks.cmake
@@ -0,0 +1,16 @@
+# Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+#
+# This library 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, either version 2 or 3 of the License.
+#
+# This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+
+# Find the frameworks if necessary
+set(BUILD_PHONON_QT7 TRUE)
diff --git a/src/3rdparty/phonon/qt7/audioconnection.h b/src/3rdparty/phonon/qt7/audioconnection.h
new file mode 100644
index 0000000000..21297441b0
--- /dev/null
+++ b/src/3rdparty/phonon/qt7/audioconnection.h
@@ -0,0 +1,84 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef Phonon_QT7_AudioConnection_H
+#define Phonon_QT7_AudioConnection_H
+
+#include <QtCore/QObject>
+#include "backendheader.h"
+
+#include <AudioToolbox/AudioToolbox.h>
+#include <AudioUnit/AudioUnit.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace QT7
+{
+ class MediaNode;
+ class AudioNode;
+ class AudioGraph;
+
+ class AudioConnection {
+ public:
+ AudioConnection();
+ AudioConnection(MediaNode *sink);
+ AudioConnection(MediaNode *source, int output, MediaNode *sink, int input);
+
+ AudioConnection(AudioNode *sink);
+ AudioConnection(AudioNode *source, int output, AudioNode *sink, int input);
+
+ ~AudioConnection();
+
+ bool connect(AudioGraph *graph);
+ bool disconnect(AudioGraph *graph);
+
+ bool updateStreamSpecification();
+ bool isBetween(MediaNode *source, MediaNode *sink);
+ bool isValid();
+ bool isSinkOnly();
+ void freeMemoryAllocations();
+ void invalidate();
+
+ MediaNode *m_source;
+ AudioNode *m_sourceAudioNode;
+ int m_sourceOutputBus;
+
+ MediaNode *m_sink;
+ AudioNode *m_sinkAudioNode;
+ int m_sinkInputBus;
+
+ AudioChannelLayout *m_sourceChannelLayout;
+ UInt32 m_sourceChannelLayoutSize;
+
+ AudioChannelLayout *m_sinkChannelLayout;
+ UInt32 m_sinkChannelLayoutSize;
+
+ AudioStreamBasicDescription m_sourceStreamDescription;
+ AudioStreamBasicDescription m_sinkStreamDescription;
+
+ bool m_hasSourceSpecification;
+ bool m_hasSinkSpecification;
+ bool m_connected;
+ };
+
+}} // namespace Phonon::QT7
+
+QT_END_NAMESPACE
+
+#endif // Phonon_QT7_AudioConnection_H
diff --git a/src/3rdparty/phonon/qt7/audioconnection.mm b/src/3rdparty/phonon/qt7/audioconnection.mm
new file mode 100644
index 0000000000..39b8b3062c
--- /dev/null
+++ b/src/3rdparty/phonon/qt7/audioconnection.mm
@@ -0,0 +1,152 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "audioconnection.h"
+#include "medianode.h"
+#include "audionode.h"
+#include "audiograph.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace QT7
+{
+
+ AudioConnection::AudioConnection()
+ : m_source(0), m_sourceAudioNode(0), m_sourceOutputBus(0),
+ m_sink(0), m_sinkAudioNode(0), m_sinkInputBus(0),
+ m_sourceChannelLayout(0), m_sinkChannelLayout(0),
+ m_hasSourceSpecification(false), m_hasSinkSpecification(false), m_connected(false)
+ {}
+
+ AudioConnection::AudioConnection(MediaNode *source, int output, MediaNode *sink, int input)
+ : m_source(source), m_sourceAudioNode(source->m_audioNode), m_sourceOutputBus(output),
+ m_sink(sink), m_sinkAudioNode(sink->m_audioNode), m_sinkInputBus(input),
+ m_sourceChannelLayout(0), m_sinkChannelLayout(0),
+ m_hasSourceSpecification(false), m_hasSinkSpecification(false), m_connected(false)
+ {}
+
+ AudioConnection::AudioConnection(MediaNode *sink)
+ : m_source(0), m_sourceAudioNode(0), m_sourceOutputBus(0),
+ m_sink(sink), m_sinkAudioNode(sink->m_audioNode), m_sinkInputBus(0),
+ m_sourceChannelLayout(0), m_sinkChannelLayout(0), m_connected(false)
+ {}
+
+ AudioConnection::AudioConnection(AudioNode *source, int output, AudioNode *sink, int input)
+ : m_source(0), m_sourceAudioNode(source), m_sourceOutputBus(output),
+ m_sink(0), m_sinkAudioNode(sink), m_sinkInputBus(input),
+ m_sourceChannelLayout(0), m_sinkChannelLayout(0),
+ m_hasSourceSpecification(false), m_hasSinkSpecification(false), m_connected(false)
+ {}
+
+ AudioConnection::AudioConnection(AudioNode *sink)
+ : m_source(0), m_sourceAudioNode(0), m_sourceOutputBus(0),
+ m_sink(0), m_sinkAudioNode(sink), m_sinkInputBus(0),
+ m_sourceChannelLayout(0), m_sinkChannelLayout(0), m_connected(false)
+ {}
+
+ AudioConnection::~AudioConnection()
+ {
+ freeMemoryAllocations();
+ }
+
+ void AudioConnection::freeMemoryAllocations()
+ {
+ if (m_sinkChannelLayout && m_sourceChannelLayout != m_sinkChannelLayout)
+ free(m_sinkChannelLayout);
+ if (m_sourceChannelLayout)
+ free(m_sourceChannelLayout);
+ m_sinkChannelLayout = 0;
+ m_sourceChannelLayout = 0;
+ }
+
+ bool AudioConnection::updateStreamSpecification()
+ {
+ m_hasSourceSpecification = false;
+ m_hasSinkSpecification = false;
+ freeMemoryAllocations();
+
+ bool updateOk;
+ if (m_sourceAudioNode){
+ updateOk = m_sourceAudioNode->fillInStreamSpecification(this, AudioNode::Source);
+ if (!updateOk)
+ return false;
+ updateOk = m_sourceAudioNode->setStreamSpecification(this, AudioNode::Source);
+ if (!updateOk)
+ return false;
+ }
+ updateOk = m_sinkAudioNode->fillInStreamSpecification(this, AudioNode::Sink);
+ if (!updateOk)
+ return false;
+ updateOk = m_sinkAudioNode->setStreamSpecification(this, AudioNode::Sink);
+ if (!updateOk)
+ return false;
+ return true;
+ }
+
+ bool AudioConnection::connect(AudioGraph *graph)
+ {
+ if (m_connected || !m_sourceAudioNode)
+ return true;
+
+ DEBUG_AUDIO_GRAPH("Connection" << int(this) << "connect"
+ << int(m_sourceAudioNode) << m_sourceOutputBus << "->"
+ << int(m_sinkAudioNode) << m_sinkInputBus)
+
+ AUNode sourceOut = m_sourceAudioNode->getOutputAUNode();
+ AUNode sinkIn = m_sinkAudioNode->getInputAUNode();
+ OSStatus err = AUGraphConnectNodeInput(graph->audioGraphRef(), sourceOut, m_sourceOutputBus, sinkIn, m_sinkInputBus);
+ m_connected = (err == noErr) ? true : false;
+ return m_connected;
+ }
+
+ bool AudioConnection::disconnect(AudioGraph *graph)
+ {
+ if (!m_connected || !m_sourceAudioNode)
+ return true;
+
+ DEBUG_AUDIO_GRAPH("Connection" << int(this) << "disconnect"
+ << int(m_sourceAudioNode) << m_sourceOutputBus << "->"
+ << int(m_sinkAudioNode) << m_sinkInputBus)
+
+ AUNode sinkIn = m_sinkAudioNode->getInputAUNode();
+ AUGraphDisconnectNodeInput(graph->audioGraphRef(), sinkIn, m_sinkInputBus);
+ m_connected = false;
+ return true;
+ }
+
+ void AudioConnection::invalidate()
+ {
+ m_connected = false;
+ }
+
+ bool AudioConnection::isBetween(MediaNode *source, MediaNode *sink){
+ return (source == m_source) && (sink == m_sink);
+ }
+
+ bool AudioConnection::isValid(){
+ return (m_sourceAudioNode != 0);
+ }
+
+ bool AudioConnection::isSinkOnly(){
+ return (m_sourceAudioNode == 0) && (m_sinkAudioNode != 0);
+ }
+
+}} //namespace Phonon::QT7
+
+QT_END_NAMESPACE
diff --git a/src/3rdparty/phonon/qt7/audiodevice.h b/src/3rdparty/phonon/qt7/audiodevice.h
new file mode 100644
index 0000000000..36e937e13c
--- /dev/null
+++ b/src/3rdparty/phonon/qt7/audiodevice.h
@@ -0,0 +1,52 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef Phonon_QT7_AUDIODEVICE_H
+#define Phonon_QT7_AUDIODEVICE_H
+
+#include <AudioToolbox/AudioToolbox.h>
+#include <AudioUnit/AudioUnit.h>
+#include <QtCore/QList>
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace QT7
+{
+ class AudioDevice
+ {
+ public:
+ enum Scope {In, Out};
+
+ static QList<AudioDeviceID> devices(Scope scope);
+ static AudioDeviceID defaultDevice(Scope scope);
+ static AudioDeviceID defaultSystemDevice(Scope scope);
+ static AudioDeviceID currentDevice(AudioUnit unit, Scope scope);
+ static bool setDevice(AudioUnit unit, AudioDeviceID deviceID, Scope scope);
+ static QString deviceName(AudioDeviceID deviceId);
+ static QString deviceSourceName(AudioDeviceID deviceID);
+ static QString deviceSourceNameElseDeviceName(AudioDeviceID deviceID);
+ static QString deviceNameElseDeviceSourceName(AudioDeviceID deviceID);
+ static QString deviceUID(AudioDeviceID deviceID);
+ };
+
+}} //namespace Phonon::QT7
+
+QT_END_NAMESPACE
+
+#endif // Phonon_QT7_AUDIODEVICE_H
diff --git a/src/3rdparty/phonon/qt7/audiodevice.mm b/src/3rdparty/phonon/qt7/audiodevice.mm
new file mode 100644
index 0000000000..6bec62d8ea
--- /dev/null
+++ b/src/3rdparty/phonon/qt7/audiodevice.mm
@@ -0,0 +1,177 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "audiodevice.h"
+#include "audiograph.h"
+#include <QtCore/QVector>
+#include "backendheader.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace QT7
+{
+
+QList<AudioDeviceID> AudioDevice::devices(Scope scope)
+{
+ QList<AudioDeviceID> devices;
+
+ // Insert the default device explicit
+ if (AudioDeviceID defdev = defaultDevice(scope))
+ devices << defdev;
+
+ // How many input/output devices are awailable:
+ UInt32 deviceCount = 0;
+ OSStatus err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &deviceCount, 0);
+ BACKEND_ASSERT3(err == noErr, "Could not get number of audio devices awailable.", FATAL_ERROR, devices)
+
+ // Get list of all devices:
+ AudioDeviceID deviceArray[deviceCount];
+ err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &deviceCount, &deviceArray);
+ BACKEND_ASSERT3(err == noErr, "Could not get audio devices list.", FATAL_ERROR, devices)
+
+ for (uint i=0; i<deviceCount; i++){
+ if (!devices.contains(deviceArray[i])){
+ // Check if the current device is input or output:
+ UInt32 size;
+ err = AudioDeviceGetPropertyInfo(deviceArray[i], 0, scope == In, kAudioDevicePropertyStreams, &size, 0);
+ if (err == noErr && size > 0)
+ devices << deviceArray[i];
+ }
+ }
+ return devices;
+}
+
+AudioDeviceID AudioDevice::defaultSystemDevice(Scope scope)
+{
+ ARGUMENT_UNSUPPORTED(scope, In, NORMAL_ERROR, 0)
+ AudioDeviceID deviceID = 0;
+ UInt32 size = sizeof(deviceID);
+ OSStatus err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultSystemOutputDevice, &size, &deviceID);
+ BACKEND_ASSERT3(err == noErr, "Could not get default system audio device.", FATAL_ERROR, 0)
+ return deviceID;
+}
+
+AudioDeviceID AudioDevice::defaultDevice(Scope scope)
+{
+ ARGUMENT_UNSUPPORTED(scope, In, NORMAL_ERROR, 0)
+ AudioDeviceID deviceID = 0;
+ UInt32 size = sizeof(deviceID);
+ OSStatus err = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &size, &deviceID);
+ BACKEND_ASSERT3(err == noErr, "Could not get default output audio device.", FATAL_ERROR, 0)
+ return deviceID;
+}
+
+AudioDeviceID AudioDevice::currentDevice(AudioUnit /*unit*/, Scope /*scope*/)
+{
+ return 0;
+#if 0
+
+kAudioDevicePropertyDeviceUID
+
+ if (!m_audioUnit)
+ return 0;
+ AudioDeviceID deviceID = 0;
+ UInt32 size = sizeof(deviceID);
+ OSStatus err = AudioUnitGetProperty(m_audioUnit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &size, &deviceID);
+ BACKEND_ASSERT3(err == noErr, "Could not get current audio device.", FATAL_ERROR, 0)
+ return deviceID;
+#endif
+}
+
+bool AudioDevice::setDevice(AudioUnit unit, AudioDeviceID deviceID, Scope scope)
+{
+ ARGUMENT_UNSUPPORTED(scope, In, NORMAL_ERROR, false)
+ UInt32 size = sizeof(deviceID);
+ OSStatus err = AudioUnitSetProperty(unit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &deviceID, size);
+ if (err != noErr)
+ return false;
+ return true;
+}
+
+QString AudioDevice::deviceSourceNameElseDeviceName(AudioDeviceID deviceID)
+{
+ QString name = deviceSourceName(deviceID);
+ if (name.isEmpty())
+ name = deviceName(deviceID);
+ return name;
+}
+
+QString AudioDevice::deviceNameElseDeviceSourceName(AudioDeviceID deviceID)
+{
+ QString name = deviceName(deviceID);
+ if (name.isEmpty())
+ name = deviceSourceName(deviceID);
+ return name;
+}
+
+QString AudioDevice::deviceName(AudioDeviceID deviceID)
+{
+ if (!deviceID)
+ return QString();
+ CFStringRef cfString = 0;
+ UInt32 size = sizeof(cfString);
+ OSStatus err = AudioDeviceGetProperty(deviceID, 0, 0, kAudioDevicePropertyDeviceNameCFString, &size, &cfString);
+ if (err != noErr)
+ return QString();
+ QString name = PhononCFString::toQString(cfString);
+ CFRelease(cfString);
+ return name;
+}
+
+QString AudioDevice::deviceSourceName(AudioDeviceID deviceID)
+{
+ if (!deviceID)
+ return QString();
+ UInt32 dataSource = 0;
+ UInt32 size = sizeof(dataSource);
+ OSStatus err = AudioDeviceGetProperty(deviceID, 0, 0, kAudioDevicePropertyDataSource, &size, &dataSource);
+ if (err != noErr)
+ return QString();
+
+ CFStringRef cfName = 0;
+ AudioValueTranslation translation = {&dataSource, sizeof(dataSource), &cfName, sizeof(cfName)};
+ size = sizeof(translation);
+ err = AudioDeviceGetProperty(deviceID, 0, 0, kAudioDevicePropertyDataSourceNameForIDCFString, &size, &translation);
+ if (err != noErr){
+ CFRelease(cfName);
+ return QString();
+ }
+ QString name = PhononCFString::toQString(cfName);
+ CFRelease(cfName);
+ return name;
+}
+
+QString AudioDevice::deviceUID(AudioDeviceID deviceID)
+{
+ if (!deviceID)
+ return QString();
+
+ CFStringRef cfString = 0;
+ UInt32 size = sizeof(cfString);
+ OSStatus err = AudioDeviceGetProperty(deviceID, 0, 0, kAudioDevicePropertyDeviceUID, &size, &cfString);
+ if (err != noErr)
+ return QString();
+ QString uid = PhononCFString::toQString(cfString);
+ CFRelease(cfString);
+ return uid;
+}
+
+}} //namespace Phonon::QT7
+
+QT_END_NAMESPACE
diff --git a/src/3rdparty/phonon/qt7/audioeffects.h b/src/3rdparty/phonon/qt7/audioeffects.h
new file mode 100644
index 0000000000..33fff1c231
--- /dev/null
+++ b/src/3rdparty/phonon/qt7/audioeffects.h
@@ -0,0 +1,80 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef Phonon_QT7_AUDIOEFFECTS_H
+#define Phonon_QT7_AUDIOEFFECTS_H
+
+#include <QtCore/QVariant>
+#include <QtCore/QHash>
+#include <phonon/effectinterface.h>
+#include <phonon/effectparameter.h>
+#include "medianode.h"
+#include "audionode.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace QT7
+{
+ class AudioEffectAudioNode : public AudioNode
+ {
+ public:
+ AudioEffectAudioNode(int effectType);
+ int m_effectType;
+
+ ComponentDescription getAudioNodeDescription() const;
+ void initializeAudioUnit();
+
+ QVariant parameterValue(const Phonon::EffectParameter &value) const;
+ void setParameterValue(const Phonon::EffectParameter &parameter, const QVariant &newValue);
+
+ private:
+ QHash<int, float> m_alteredParameters;
+ };
+
+///////////////////////////////////////////////////////////////////////
+
+ class AudioEffect : public MediaNode, Phonon::EffectInterface
+ {
+ Q_OBJECT
+ Q_INTERFACES(Phonon::EffectInterface)
+
+ public:
+ AudioEffect(int effectType, QObject *parent = 0);
+ AudioEffectAudioNode *m_audioNode;
+
+ QString name();
+ QString description();
+
+ // EffectInterface:
+ virtual QList<Phonon::EffectParameter> parameters() const;
+ virtual QVariant parameterValue(const Phonon::EffectParameter &parameter) const;
+ virtual void setParameterValue(const Phonon::EffectParameter &parameter, const QVariant &newValue);
+
+ static QList<int> effectList();
+
+ private:
+ Phonon::EffectParameter createParameter(const AudioUnit &audioUnit, const AudioUnitParameterID &id) const;
+ };
+
+
+}} //namespace Phonon::QT7
+
+QT_END_NAMESPACE
+
+#endif // Phonon_QT7_AUDIOEFFECTS_H
diff --git a/src/3rdparty/phonon/qt7/audioeffects.mm b/src/3rdparty/phonon/qt7/audioeffects.mm
new file mode 100644
index 0000000000..b0ec3cce80
--- /dev/null
+++ b/src/3rdparty/phonon/qt7/audioeffects.mm
@@ -0,0 +1,254 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "audioeffects.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace QT7
+{
+
+AudioEffectAudioNode::AudioEffectAudioNode(int effectType)
+ : AudioNode(1, 1), m_effectType(effectType)
+{
+}
+
+ComponentDescription AudioEffectAudioNode::getAudioNodeDescription() const
+{
+ ComponentDescription d;
+ d.componentType = kAudioUnitType_Effect;
+ d.componentSubType = m_effectType;
+ d.componentManufacturer = kAudioUnitManufacturer_Apple;
+ d.componentFlags = 0;
+ d.componentFlagsMask = 0;
+ return d;
+}
+
+void AudioEffectAudioNode::initializeAudioUnit()
+{
+ if (!m_audioUnit)
+ return;
+ foreach(int id, m_alteredParameters.keys()){
+ Float32 value = m_alteredParameters.value(id);
+ ComponentResult res = AudioUnitSetParameter(m_audioUnit, id, kAudioUnitScope_Global, 0, value, 0);
+ BACKEND_ASSERT2(res == noErr, "Could not initialize audio effect.", NORMAL_ERROR)
+ }
+}
+
+QVariant AudioEffectAudioNode::parameterValue(const Phonon::EffectParameter &parameter) const
+{
+ if (m_audioUnit){
+ Float32 value = 0;
+ AudioUnitGetParameter(m_audioUnit, parameter.id(), kAudioUnitScope_Global, 0, &value);
+ return QVariant(value);
+ } else if (m_alteredParameters.contains(parameter.id())){
+ return QVariant(m_alteredParameters.value(parameter.id()));
+ } else {
+ // Use default value:
+ AudioUnit tmpAudioUnit;
+ ComponentDescription description = getAudioNodeDescription();
+ Component component = FindNextComponent(0, &description);
+ BACKEND_ASSERT3(component, "Could not get parameters of audio effect.", NORMAL_ERROR, QVariant())
+ OSErr err = OpenAComponent(component, &tmpAudioUnit);
+ BACKEND_ASSERT3(err == noErr, "Could not get parameters of audio effect.", NORMAL_ERROR, QVariant())
+ AudioUnitParameterInfo info;
+ UInt32 size = sizeof(info);
+ ComponentResult res = AudioUnitGetProperty(tmpAudioUnit,
+ kAudioUnitProperty_ParameterInfo, kAudioUnitScope_Global, parameter.id(), &info, &size);
+ BACKEND_ASSERT3(res == noErr, "Could not get parameter info from audio effect.", NORMAL_ERROR, QVariant())
+ return QVariant(info.defaultValue);
+ }
+}
+
+void AudioEffectAudioNode::setParameterValue(const Phonon::EffectParameter &parameter, const QVariant &newValue)
+{
+ Float32 value = 0;
+ if (newValue.isValid()){
+ value = newValue.toDouble();
+ m_alteredParameters.insert(parameter.id(), value);
+ } else {
+ // Use default value:
+ m_alteredParameters.remove(parameter.id());
+ if (m_audioUnit){
+ AudioUnit tmpAudioUnit;
+ ComponentDescription description = getAudioNodeDescription();
+ Component component = FindNextComponent(0, &description);
+ BACKEND_ASSERT2(component, "Could not get parameters of audio effect.", NORMAL_ERROR)
+ OSErr err = OpenAComponent(component, &tmpAudioUnit);
+ BACKEND_ASSERT2(err == noErr, "Could not get parameters of audio effect.", NORMAL_ERROR)
+ AudioUnitParameterInfo info;
+ UInt32 size = sizeof(info);
+ ComponentResult res = AudioUnitGetProperty(tmpAudioUnit,
+ kAudioUnitProperty_ParameterInfo, kAudioUnitScope_Global, parameter.id(), &info, &size);
+ BACKEND_ASSERT2(res == noErr, "Could not get parameter info from audio effect.", NORMAL_ERROR)
+ value = info.defaultValue;
+ }
+ }
+
+ if (m_audioUnit){
+ ComponentResult res = AudioUnitSetParameter(m_audioUnit, parameter.id(), kAudioUnitScope_Global, 0, value, 0);
+ BACKEND_ASSERT2(res == noErr, "Could not set effect parameter value.", NORMAL_ERROR)
+ }
+}
+
+///////////////////////////////////////////////////////////////////////
+
+AudioEffect::AudioEffect(int effectType, QObject *parent)
+ : MediaNode(AudioSink | AudioSource, 0, parent)
+{
+ m_audioNode = new AudioEffectAudioNode(effectType);
+ setAudioNode(m_audioNode);
+}
+
+QList<Phonon::EffectParameter> AudioEffect::parameters() const
+{
+ QList<Phonon::EffectParameter> effectList;
+ // Create a temporary audio unit:
+ AudioUnit audioUnit;
+ ComponentDescription description = m_audioNode->getAudioNodeDescription();
+ Component component = FindNextComponent(0, &description);
+ BACKEND_ASSERT3(component, "Could not get parameters of audio effect.", NORMAL_ERROR, effectList)
+ OSErr err = OpenAComponent(component, &audioUnit);
+ BACKEND_ASSERT3(err == noErr, "Could not get parameters of audio effect.", NORMAL_ERROR, effectList)
+
+ UInt32 size = 0;
+ // Get parameter count:
+ ComponentResult res = AudioUnitGetProperty(audioUnit,
+ kAudioUnitProperty_ParameterList, kAudioUnitScope_Global, 0, 0, &size);
+ BACKEND_ASSERT3(res == noErr, "Could not get parameter count from audio effect.", NORMAL_ERROR, effectList)
+ int paramCount = size / sizeof(AudioUnitParameterID);
+
+ // Get parameters:
+ AudioUnitParameterID parameters[paramCount];
+ res = AudioUnitGetProperty(audioUnit,
+ kAudioUnitProperty_ParameterList, kAudioUnitScope_Global, 0, &parameters, &size);
+ BACKEND_ASSERT3(res == noErr, "Could not get parameter list from audio effect.", NORMAL_ERROR, effectList)
+
+ for (int i=0; i<paramCount; ++i)
+ effectList << createParameter(audioUnit, parameters[i]);
+
+ CloseComponent(audioUnit);
+ return effectList;
+}
+
+QString AudioEffect::name()
+{
+ ComponentDescription description = m_audioNode->getAudioNodeDescription();
+ Component component = FindNextComponent(0, &description);
+ BACKEND_ASSERT3(component, "Could not get audio effect name.", NORMAL_ERROR, QLatin1String("<unknown effect>"))
+
+ ComponentDescription cDesc;
+ Handle nameH = NewHandle(0);
+ GetComponentInfo(component, &cDesc, nameH, 0, 0);
+ HLock(nameH);
+ char *namePtr = *nameH;
+ int len = *namePtr++;
+ namePtr[len] = 0;
+ QString qsName = QString::fromUtf8(namePtr);
+ DisposeHandle(nameH);
+ return qsName;
+}
+
+QString AudioEffect::description()
+{
+ ComponentDescription description = m_audioNode->getAudioNodeDescription();
+ Component component = FindNextComponent(0, &description);
+ BACKEND_ASSERT3(component, "Could not get audio effect description.", NORMAL_ERROR, QLatin1String("<unknown effect>"))
+
+ ComponentDescription cDesc;
+ Handle descH = NewHandle(0);
+ GetComponentInfo(component, &cDesc, 0, descH, 0);
+ HLock(descH);
+ char *descPtr = *descH;
+ int len = *descPtr++;
+ descPtr[len] = 0;
+ QString qsDesc = QString::fromUtf8(descPtr);
+ DisposeHandle(descH);
+ return qsDesc;
+}
+
+QList<int> AudioEffect::effectList()
+{
+ QList<int> effects;
+
+ ComponentDescription d;
+ d.componentType = kAudioUnitType_Effect;
+ d.componentSubType = 0;
+ d.componentManufacturer = 0;
+ d.componentFlags = 0;
+ d.componentFlagsMask = 0;
+ Component component = FindNextComponent(0, &d);
+
+ while (component) {
+ ComponentDescription cDesc;
+ GetComponentInfo(component, &cDesc, 0, 0, 0);
+ effects << cDesc.componentSubType;
+ component = FindNextComponent(component, &d);
+ }
+ return effects;
+}
+
+Phonon::EffectParameter AudioEffect::createParameter(const AudioUnit &audioUnit, const AudioUnitParameterID &id) const
+{
+ AudioUnitParameterInfo info;
+ UInt32 size = sizeof(info);
+ ComponentResult res = AudioUnitGetProperty(audioUnit,
+ kAudioUnitProperty_ParameterInfo, kAudioUnitScope_Global, id, &info, &size);
+ BACKEND_ASSERT3(res == noErr, "Could not get parameter info from audio effect.", NORMAL_ERROR, Phonon::EffectParameter())
+
+ QString name = info.flags & kAudioUnitParameterFlag_HasCFNameString
+ ? PhononCFString::toQString(info.cfNameString) : QLatin1String("<unknown parameter>");
+
+ Phonon::EffectParameter::Hint hint;
+ switch(info.unit){
+ case (kAudioUnitParameterUnit_Indexed):
+ case (kAudioUnitParameterUnit_Seconds):
+ case (kAudioUnitParameterUnit_SampleFrames):
+ case (kAudioUnitParameterUnit_Milliseconds):
+ hint = Phonon::EffectParameter::IntegerHint;
+ break;
+ case (kAudioUnitParameterUnit_Boolean):
+ hint = Phonon::EffectParameter::ToggledHint;
+ break;
+ default:
+ hint = Phonon::EffectParameter::LogarithmicHint;
+ break;
+ }
+
+ QVariant def(info.defaultValue);
+ QVariant min(info.minValue);
+ QVariant max(info.maxValue);
+ return Phonon::EffectParameter(id, name, hint, def, min, max, QVariantList(), name);
+}
+
+QVariant AudioEffect::parameterValue(const Phonon::EffectParameter &value) const
+{
+ return m_audioNode->parameterValue(value);
+}
+
+void AudioEffect::setParameterValue(const Phonon::EffectParameter &parameter, const QVariant &newValue)
+{
+ m_audioNode->setParameterValue(parameter, newValue);
+}
+
+}} //namespace Phonon::QT7
+
+QT_END_NAMESPACE
+
+#include "moc_audioeffects.cpp"
diff --git a/src/3rdparty/phonon/qt7/audiograph.h b/src/3rdparty/phonon/qt7/audiograph.h
new file mode 100644
index 0000000000..76bc21a22a
--- /dev/null
+++ b/src/3rdparty/phonon/qt7/audiograph.h
@@ -0,0 +1,86 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef Phonon_QT7_AUDIOGRAPH_H
+#define Phonon_QT7_AUDIOGRAPH_H
+
+#include <AudioToolbox/AudioToolbox.h>
+#include <AudioUnit/AudioUnit.h>
+
+#include <QtCore/qnamespace.h>
+#include "audioconnection.h"
+#include "medianode.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace QT7
+{
+ class AudioGraph : public MediaNode
+ {
+ public:
+ AudioGraph(MediaNode *root);
+ virtual ~AudioGraph();
+ AUGraph audioGraphRef();
+ void startAllOverFromScratch();
+
+ bool openAndInit();
+ void start();
+ void tryStartGraph();
+ void stop();
+ void prepare();
+ void rebuildGraph();
+ void update();
+ bool isRunning();
+ void setPaused(bool pause);
+ bool graphCannotPlay();
+ void rebuildGraphIfNeeded();
+ void updateStreamSpecifications();
+ void setStatusCannotPlay();
+ MediaNode *root();
+ void notify(const MediaNodeEvent *event, bool propagate = true);
+
+ private:
+ friend class MediaNode;
+ friend class AudioNode;
+
+ void deleteGraph();
+ bool updateStreamSpecificationRecursive(AudioConnection *connection);
+ void createAndConnectAuNodesRecursive(AudioConnection *connection);
+ bool createAudioUnitsRecursive(AudioConnection *connection);
+
+ void connectLate(AudioConnection *connection);
+ void disconnectLate(AudioConnection *connection);
+
+ int nodeCount();
+
+ bool m_initialized;
+ bool m_startedLogically;
+ bool m_rebuildLater;
+ bool m_graphCannotPlay;
+ bool m_paused;
+
+ AUGraph m_audioGraphRef;
+ MediaNode *m_root;
+ };
+
+}} // namespace Phonon::QT7
+
+QT_END_NAMESPACE
+
+#endif // Phonon_QT7_AUDIOGRAPH_H
diff --git a/src/3rdparty/phonon/qt7/audiograph.mm b/src/3rdparty/phonon/qt7/audiograph.mm
new file mode 100644
index 0000000000..0d096e375c
--- /dev/null
+++ b/src/3rdparty/phonon/qt7/audiograph.mm
@@ -0,0 +1,320 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "audiograph.h"
+#include "quicktimeaudioplayer.h"
+#include "medianode.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace QT7
+{
+
+AudioGraph::AudioGraph(MediaNode *root) : MediaNode(AudioGraphNode, 0, root), m_root(root)
+{
+ m_audioGraphRef = 0;
+ m_initialized = false;
+ m_startedLogically = false;
+ m_graphCannotPlay = false;
+ m_paused = false;
+}
+
+AudioGraph::~AudioGraph()
+{
+ deleteGraph();
+}
+
+void AudioGraph::startAllOverFromScratch()
+{
+ MediaNodeEvent event(MediaNodeEvent::AudioGraphAboutToBeDeleted, this);
+ m_root->notify(&event);
+ deleteGraph();
+}
+
+void AudioGraph::deleteGraph()
+{
+ if (m_audioGraphRef){
+ AUGraphStop(m_audioGraphRef);
+ AUGraphUninitialize(m_audioGraphRef);
+ AUGraphClose(m_audioGraphRef);
+ DisposeAUGraph(m_audioGraphRef);
+ m_initialized = false;
+ m_graphCannotPlay = false;
+ DEBUG_AUDIO_GRAPH("Graph ref in" << int(this) << "is deleted")
+ }
+}
+
+MediaNode *AudioGraph::root()
+{
+ return m_root;
+}
+
+AUGraph AudioGraph::audioGraphRef()
+{
+ return m_audioGraphRef;
+}
+
+void AudioGraph::setStatusCannotPlay()
+{
+ DEBUG_AUDIO_GRAPH("Graph" << int(this) << "received 'cannot play' request")
+ if (!m_graphCannotPlay){
+ stop();
+ m_graphCannotPlay = true;
+ MediaNodeEvent e(MediaNodeEvent::AudioGraphCannotPlay, this);
+ m_root->notify(&e);
+ }
+}
+
+void AudioGraph::rebuildGraph()
+{
+ DEBUG_AUDIO_GRAPH("Graph" << int(this) << "is rebuilding")
+ startAllOverFromScratch();
+ if (!openAndInit()){
+ setStatusCannotPlay();
+ } else {
+ tryStartGraph();
+ m_graphCannotPlay = false;
+ }
+}
+
+bool AudioGraph::graphCannotPlay()
+{
+ return m_graphCannotPlay;
+}
+
+void AudioGraph::updateStreamSpecifications()
+{
+ if (!m_initialized){
+ if (m_graphCannotPlay)
+ rebuildGraph();
+ return;
+ }
+
+ AudioConnection rootConnection(m_root);
+ bool updateOk = updateStreamSpecificationRecursive(&rootConnection);
+ if (!updateOk){
+ DEBUG_AUDIO_GRAPH("Graph" << int(this) << "could not update stream specification. Rebuild.")
+ rebuildGraph();
+ }
+}
+
+bool AudioGraph::updateStreamSpecificationRecursive(AudioConnection *connection)
+{
+ bool updateOk = connection->updateStreamSpecification();
+ if (!updateOk)
+ return false;
+
+ for (int i=0; i<connection->m_sink->m_audioSinkList.size(); ++i){
+ if (!updateStreamSpecificationRecursive(connection->m_sink->m_audioSinkList[i]))
+ return false;
+ }
+ return true;
+}
+
+bool AudioGraph::openAndInit()
+{
+ OSStatus err;
+ err = NewAUGraph(&m_audioGraphRef);
+ BACKEND_ASSERT3(err == noErr, "Could not create audio graph.", NORMAL_ERROR, false)
+
+ MediaNodeEvent eventNew(MediaNodeEvent::NewAudioGraph, this);
+ m_root->notify(&eventNew);
+
+ AudioConnection rootConnection(m_root);
+ createAndConnectAuNodesRecursive(&rootConnection);
+ err = AUGraphOpen(m_audioGraphRef);
+ BACKEND_ASSERT3(err == noErr, "Could not create audio graph.", NORMAL_ERROR, false)
+
+ if (!createAudioUnitsRecursive(&rootConnection))
+ return false;
+
+ err = AUGraphInitialize(m_audioGraphRef);
+ BACKEND_ASSERT3(err == noErr, "Could not initialize audio graph.", NORMAL_ERROR, false)
+
+ m_initialized = true;
+ MediaNodeEvent eventInit(MediaNodeEvent::AudioGraphInitialized, this);
+ m_root->notify(&eventInit);
+ return true;
+}
+
+void AudioGraph::createAndConnectAuNodesRecursive(AudioConnection *connection)
+{
+ connection->m_sink->m_audioNode->createAndConnectAUNodes();
+ for (int i=0; i<connection->m_sink->m_audioSinkList.size(); ++i){
+ AudioConnection *c = connection->m_sink->m_audioSinkList[i];
+ createAndConnectAuNodesRecursive(c);
+ bool ok = c->connect(this);
+ BACKEND_ASSERT2(ok, "Could not connect an audio nodes pair in the audio graph.", NORMAL_ERROR)
+ }
+}
+
+bool AudioGraph::createAudioUnitsRecursive(AudioConnection *connection)
+{
+ connection->m_sink->m_audioNode->createAudioUnits();
+ bool ok = connection->updateStreamSpecification();
+ if (!ok)
+ return false;
+ for (int i=0; i<connection->m_sink->m_audioSinkList.size(); ++i){
+ if (!createAudioUnitsRecursive(connection->m_sink->m_audioSinkList[i]))
+ return false;
+ }
+ return true;
+}
+
+void AudioGraph::tryStartGraph()
+{
+ // The graph will only start if the background AUGraph
+ // is valid. Therefore we just try. If it fails, user
+ // actions like connect etc. migh make the graph valid
+ // at a later point.
+ if (m_startedLogically && !isRunning()){
+ OSStatus err = AUGraphStart(m_audioGraphRef);
+ if (err == noErr)
+ DEBUG_AUDIO_GRAPH("Graph" << int(this) << "started")
+ else
+ DEBUG_AUDIO_GRAPH("Graph" << int(this) << "could not start")
+ }
+}
+
+bool AudioGraph::isRunning()
+{
+ Boolean running = false;
+ AUGraphIsRunning(m_audioGraphRef, &running);
+ return running;
+}
+
+void AudioGraph::setPaused(bool pause)
+{
+ // This function should only make
+ // a difference if the graph is
+ // running before pausing.
+ if (pause){
+ if (isRunning()){
+ stop();
+ m_paused = true;
+ }
+ } else if (m_paused){
+ start();
+ m_paused = false;
+ }
+}
+
+void AudioGraph::connectLate(AudioConnection *connection)
+{
+ MediaNodeEvent event(MediaNodeEvent::NewAudioGraph, this);
+ connection->m_sink->notify(&event);
+
+ if (!m_initialized)
+ return;
+
+ DEBUG_AUDIO_GRAPH("Graph:" << int(this) << "create and connect audio sink after init:" << int(connection->m_sink->m_audioNode))
+ AudioConnection startConnection(connection->m_source);
+ createAndConnectAuNodesRecursive(&startConnection);
+
+ if (!createAudioUnitsRecursive(&startConnection)){
+ DEBUG_AUDIO_GRAPH("Graph" << int(this) << "could not update stream specification. Rebuild.")
+ rebuildGraph();
+ }
+}
+
+void AudioGraph::disconnectLate(AudioConnection *connection)
+{
+ if (!m_initialized)
+ return;
+
+ DEBUG_AUDIO_GRAPH("Graph:" << int(this) << "disconnect audio sink after init:" << int(connection->m_sink->m_audioNode))
+
+ if (!connection->disconnect(this)){
+ DEBUG_AUDIO_GRAPH("Graph" << int(this) << "could not disconnect audio sink. Rebuild.")
+ rebuildGraph();
+ }
+}
+
+void AudioGraph::update()
+{
+ if (m_startedLogically){
+ if (m_initialized){
+ // Quick solution:
+ AUGraphUpdate(m_audioGraphRef, 0);
+ tryStartGraph();
+ } else
+ rebuildGraph();
+ }
+}
+
+int AudioGraph::nodeCount()
+{
+ if (!m_audioGraphRef)
+ return 0;
+ UInt32 count;
+ AUGraphGetNodeCount(m_audioGraphRef, &count);
+ return int(count);
+}
+
+void AudioGraph::prepare()
+{
+ if (!m_initialized)
+ rebuildGraph();
+}
+
+void AudioGraph::start()
+{
+ // Start does not mean 'start to play
+ // music'. It means 'prepare to receive
+ // audio from the player units'.
+ DEBUG_AUDIO_GRAPH("Graph" << int(this) << "asked to start (cannot play:" << m_graphCannotPlay << ")")
+ m_startedLogically = true;
+
+ if (m_graphCannotPlay)
+ return;
+
+ if (!m_initialized)
+ rebuildGraph();
+
+ if (!m_graphCannotPlay)
+ tryStartGraph();
+}
+
+void AudioGraph::stop()
+{
+ DEBUG_AUDIO_GRAPH("Graph" << int(this) << "asked to stop")
+ if (m_audioGraphRef)
+ AUGraphStop(m_audioGraphRef);
+ m_startedLogically = false;
+}
+
+void AudioGraph::notify(const MediaNodeEvent *event, bool propagate)
+{
+ switch (event->type()){
+ case MediaNodeEvent::StartConnectionChange:
+ if (m_graphCannotPlay)
+ startAllOverFromScratch();
+ break;
+ case MediaNodeEvent::EndConnectionChange:
+ update();
+ break;
+ default:
+ break;
+ }
+ m_root->notify(event, propagate);
+}
+
+}} // namespace Phonon::QT7
+
+QT_END_NAMESPACE
diff --git a/src/3rdparty/phonon/qt7/audiomixer.h b/src/3rdparty/phonon/qt7/audiomixer.h
new file mode 100644
index 0000000000..275d7df35a
--- /dev/null
+++ b/src/3rdparty/phonon/qt7/audiomixer.h
@@ -0,0 +1,91 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef Phonon_QT7_AUDIOMIXER_H
+#define Phonon_QT7_AUDIOMIXER_H
+
+#include <QtCore/QObject>
+#include <QtCore/QTime>
+#include <QtCore/QEvent>
+#include <phonon/effectinterface.h>
+#include <phonon/effectparameter.h>
+#include <phonon/volumefaderinterface.h>
+#include "medianode.h"
+#include "audionode.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace QT7
+{
+ class AudioMixerAudioNode : public AudioNode
+ {
+ public:
+ AudioMixerAudioNode();
+ void setVolume(float volume, int bus = 0);
+ float volume(int bus = 0);
+
+ protected:
+ ComponentDescription getAudioNodeDescription() const;
+ void initializeAudioUnit();
+
+ private:
+ friend class AudioMixer;
+ int m_numberOfBusses;
+ float m_volume;
+ };
+
+ class AudioMixer : public MediaNode, Phonon::EffectInterface, Phonon::VolumeFaderInterface
+ {
+ Q_OBJECT
+ Q_INTERFACES(Phonon::EffectInterface Phonon::VolumeFaderInterface)
+
+ public:
+ AudioMixer(QObject *parent = 0);
+ ~AudioMixer();
+ AudioMixerAudioNode *m_audioNode;
+ Phonon::VolumeFaderEffect::FadeCurve m_fadeCurve;
+
+ int m_fadeTimer;
+ int m_fadeDuration;
+ float m_fadeToVolume;
+ float m_fadeFromVolume;
+ QTime m_fadeStartTime;
+
+ // EffectInterface:
+ QList<Phonon::EffectParameter> parameters() const;
+ QVariant parameterValue(const Phonon::EffectParameter &parameter) const;
+ void setParameterValue(const Phonon::EffectParameter &parameter, const QVariant &newValue);
+
+ // VolumeFaderInterface:
+ float volume() const;
+ void setVolume(float volume);
+ Phonon::VolumeFaderEffect::FadeCurve fadeCurve() const;
+ void setFadeCurve(Phonon::VolumeFaderEffect::FadeCurve fadeCurve);
+ void fadeTo(float volume, int fadeTime);
+ void updateFade();
+
+ protected:
+ bool event(QEvent *event);
+ };
+
+}} //namespace Phonon::QT7
+
+QT_END_NAMESPACE
+
+#endif // Phonon_QT7_AUDIOMIXER_H
diff --git a/src/3rdparty/phonon/qt7/audiomixer.mm b/src/3rdparty/phonon/qt7/audiomixer.mm
new file mode 100644
index 0000000000..30b1e6f63d
--- /dev/null
+++ b/src/3rdparty/phonon/qt7/audiomixer.mm
@@ -0,0 +1,181 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "audiomixer.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace QT7
+{
+
+AudioMixerAudioNode::AudioMixerAudioNode() : AudioNode(30, 1)
+{
+ m_numberOfBusses = 2;
+ m_volume = 1.0f;
+}
+
+ComponentDescription AudioMixerAudioNode::getAudioNodeDescription() const
+{
+ ComponentDescription description;
+ description.componentType = kAudioUnitType_Mixer;
+ description.componentSubType = kAudioUnitSubType_StereoMixer;
+ description.componentManufacturer = kAudioUnitManufacturer_Apple;
+ description.componentFlags = 0;
+ description.componentFlagsMask = 0;
+ return description;
+}
+
+void AudioMixerAudioNode::initializeAudioUnit()
+{
+ // Set bus count:
+ OSStatus err = AudioUnitSetProperty(m_audioUnit,
+ kAudioUnitProperty_BusCount, kAudioUnitScope_Input, 0, &m_numberOfBusses, sizeof(int));
+ BACKEND_ASSERT2(err == noErr, "Could not set number of busses on audio mixer node.", FATAL_ERROR)
+}
+
+void AudioMixerAudioNode::setVolume(float volume, int bus)
+{
+ if (volume < 0)
+ m_volume = 0;
+ else if (volume > 1)
+ m_volume = 1;
+ else
+ m_volume = volume;
+
+ if (m_audioUnit){
+// Float32 db = Float32(volume);//Float32(20.0 * log10(volume)); // convert to db
+ Float32 db = Float32(volume);
+ OSStatus err = AudioUnitSetParameter(m_audioUnit, kStereoMixerParam_Volume, kAudioUnitScope_Input, bus, db, 0);
+ BACKEND_ASSERT2(err == noErr, "Could not set volume on audio mixer node.", NORMAL_ERROR)
+ }
+}
+
+float AudioMixerAudioNode::volume(int bus)
+{
+ if (!m_audioUnit)
+ return 0;
+
+ Float32 db;
+ OSStatus err = AudioUnitGetParameter(m_audioUnit, kStereoMixerParam_Volume, kAudioUnitScope_Input, bus, &db);
+ BACKEND_ASSERT3(err == noErr, "Could not get volume on audio mixer node.", NORMAL_ERROR, 0)
+ return float(db);
+}
+
+///////////////////////////////////////////////////////////////////////
+
+AudioMixer::AudioMixer(QObject *parent) : MediaNode(AudioSink | AudioSource, 0, parent)
+{
+ m_audioNode = new AudioMixerAudioNode();
+ setAudioNode(m_audioNode);
+ m_fadeCurve = Phonon::VolumeFaderEffect::Fade3Decibel;
+ m_fadeTimer = 0;
+ m_fadeDuration = 0;
+ m_fadeFromVolume = 0;
+ m_fadeToVolume = 0;
+}
+
+AudioMixer::~AudioMixer()
+{
+ if (m_fadeTimer)
+ killTimer(m_fadeTimer);
+}
+
+QList<Phonon::EffectParameter> AudioMixer::parameters() const
+{
+ QList<Phonon::EffectParameter> ret;
+ return ret;
+}
+
+QVariant AudioMixer::parameterValue(const Phonon::EffectParameter &value) const
+{
+ NOT_IMPLEMENTED;
+ Q_UNUSED(value);
+ return QVariant();
+}
+
+void AudioMixer::setParameterValue(const Phonon::EffectParameter &parameter, const QVariant &newValue)
+{
+ NOT_IMPLEMENTED;
+ Q_UNUSED(parameter);
+ Q_UNUSED(newValue);
+}
+
+float AudioMixer::volume() const
+{
+ return m_audioNode->volume(0);
+}
+
+void AudioMixer::setVolume(float volume)
+{
+ m_audioNode->setVolume(volume, 0);
+}
+
+Phonon::VolumeFaderEffect::FadeCurve AudioMixer::fadeCurve() const
+{
+ return m_fadeCurve;
+}
+
+void AudioMixer::setFadeCurve(Phonon::VolumeFaderEffect::FadeCurve fadeCurve)
+{
+ m_fadeCurve = fadeCurve;
+}
+
+void AudioMixer::fadeTo(float volume, int fadeTime)
+{
+ m_fadeToVolume = volume;
+ m_fadeDuration = fadeTime;
+ m_fadeFromVolume = m_audioNode->volume(0);
+
+ m_fadeStartTime.start();
+ if (m_fadeTimer)
+ killTimer(m_fadeTimer);
+ m_fadeTimer = startTimer(100);
+}
+
+void AudioMixer::updateFade()
+{
+ float step = float(m_fadeStartTime.elapsed()) / float(m_fadeDuration);
+ if (step > 1){
+ step = 1;
+ if (m_fadeTimer)
+ killTimer(m_fadeTimer);
+ }
+ float volume = m_fadeFromVolume + ((m_fadeToVolume - m_fadeFromVolume) * step);
+ m_audioNode->setVolume(volume, 0);
+}
+
+bool AudioMixer::event(QEvent *event)
+{
+ switch (event->type()){
+ case QEvent::Timer:{
+ QTimerEvent *timerEvent = static_cast<QTimerEvent *>(event);
+ if (timerEvent->timerId() == m_fadeTimer)
+ updateFade();
+ break; }
+ default:
+ break;
+ }
+ return MediaNode::event(event);
+}
+
+}} //namespace Phonon::QT7
+
+QT_END_NAMESPACE
+
+#include "moc_audiomixer.cpp"
diff --git a/src/3rdparty/phonon/qt7/audionode.h b/src/3rdparty/phonon/qt7/audionode.h
new file mode 100644
index 0000000000..2498e4907f
--- /dev/null
+++ b/src/3rdparty/phonon/qt7/audionode.h
@@ -0,0 +1,86 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef Phonon_QT7_AudioNode_H
+#define Phonon_QT7_AudioNode_H
+
+#include <QtCore/QObject>
+#include "backendheader.h"
+#include "audioconnection.h"
+#include <AudioToolbox/AudioToolbox.h>
+#include <AudioUnit/AudioUnit.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace QT7
+{
+ class AudioGraph;
+ class MediaNodeEvent;
+ class MediaNode;
+
+ class MediaNodeConnection{
+ MediaNode *source;
+ MediaNode *sink;
+ int inputPort;
+ int outputPort;
+ };
+
+ class AudioNode
+ {
+ public:
+ enum ConnectionSide {Source, Sink};
+
+ AudioNode(int maxInput, int maxOutput);
+ virtual ~AudioNode();
+
+ virtual void createAndConnectAUNodes();
+ virtual void createAudioUnits();
+ virtual void setGraph(AudioGraph *audioGraph);
+ virtual AUNode getInputAUNode();
+ virtual AUNode getOutputAUNode();
+ virtual bool fillInStreamSpecification(AudioConnection *connection, ConnectionSide side);
+ virtual bool setStreamSpecification(AudioConnection *connection, ConnectionSide side);
+ void notify(const MediaNodeEvent *event);
+
+ virtual void mediaNodeEvent(const MediaNodeEvent *event);
+ Float64 getTimeInSamples(int timeProperty);
+
+ AudioGraph *m_audioGraph;
+ AudioConnection *m_lastConnectionIn;
+
+ int m_maxInputBusses;
+ int m_maxOutputBusses;
+
+ protected:
+ AUNode m_auNode;
+ AudioUnit m_audioUnit;
+
+ // Only the following methods needs to
+ // be overidden by only_one-audio-unit nodes:
+ virtual ComponentDescription getAudioNodeDescription() const;
+ virtual void initializeAudioUnit();
+
+ private:
+ bool setStreamHelp(AudioConnection *c, int bus, OSType scope, bool fromSource);
+ };
+}} // namespace Phonon::QT7
+
+QT_END_NAMESPACE
+
+#endif // Phonon_QT7_AudioNode_H
diff --git a/src/3rdparty/phonon/qt7/audionode.mm b/src/3rdparty/phonon/qt7/audionode.mm
new file mode 100644
index 0000000000..cb9e82f695
--- /dev/null
+++ b/src/3rdparty/phonon/qt7/audionode.mm
@@ -0,0 +1,240 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "audionode.h"
+#include "audiograph.h"
+#include "audioconnection.h"
+#include "medianode.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace QT7
+{
+
+AudioNode::AudioNode(int maxInputBusses, int maxOutputBusses)
+{
+ m_auNode = 0;
+ m_audioUnit = 0;
+ m_audioGraph = 0;
+ m_maxInputBusses = maxInputBusses;
+ m_maxOutputBusses = maxOutputBusses;
+ m_lastConnectionIn = 0;
+}
+
+AudioNode::~AudioNode()
+{
+ setGraph(0);
+}
+
+void AudioNode::setGraph(AudioGraph *audioGraph)
+{
+ if (m_audioGraph == audioGraph)
+ return;
+
+ DEBUG_AUDIO_GRAPH("AudioNode" << int(this) << "is setting graph:" << int(audioGraph))
+ if (m_auNode){
+ AUGraphRemoveNode(m_audioGraph->audioGraphRef(), m_auNode);
+ m_auNode = 0;
+ }
+
+ m_audioUnit = 0;
+ m_lastConnectionIn = 0;
+ m_audioGraph = audioGraph;
+}
+
+void AudioNode::createAndConnectAUNodes()
+{
+ if (m_auNode)
+ return;
+
+ ComponentDescription description = getAudioNodeDescription();
+ DEBUG_AUDIO_GRAPH("AudioNode" << int(this) << "creates AUNode"
+ << QString(!FindNextComponent(0, &description) ? "ERROR: COMPONENT NOT FOUND!" : "OK!"))
+
+ OSStatus err = noErr;
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
+ if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5)
+ err = AUGraphAddNode(m_audioGraph->audioGraphRef(), &description, &m_auNode);
+ else
+#endif
+ err = AUGraphNewNode(m_audioGraph->audioGraphRef(), &description, 0, 0, &m_auNode);
+
+ BACKEND_ASSERT2(err != kAUGraphErr_OutputNodeErr, "A MediaObject can only be connected to one audio output device.", FATAL_ERROR)
+ BACKEND_ASSERT2(err == noErr, "Could not create new AUNode.", FATAL_ERROR)
+}
+
+AUNode AudioNode::getInputAUNode()
+{
+ return m_auNode;
+}
+
+AUNode AudioNode::getOutputAUNode()
+{
+ return m_auNode;
+}
+
+void AudioNode::createAudioUnits()
+{
+ if (m_audioUnit)
+ return;
+
+ DEBUG_AUDIO_GRAPH("AudioNode" << int(this) << "creates AudioUnit")
+ OSStatus err = AUGraphGetNodeInfo(m_audioGraph->audioGraphRef(), m_auNode, 0, 0, 0, &m_audioUnit);
+ BACKEND_ASSERT2(err == noErr, "Could not get audio unit from audio node.", FATAL_ERROR)
+ initializeAudioUnit();
+}
+
+ComponentDescription AudioNode::getAudioNodeDescription() const
+{
+ // Override if needed.
+ ComponentDescription cd;
+ Q_UNUSED(cd);
+ return cd;
+}
+
+bool AudioNode::setStreamHelp(AudioConnection *c, int bus, OSType scope, bool fromSource)
+{
+ if (fromSource){
+ OSStatus err = AudioUnitSetProperty(m_audioUnit, kAudioUnitProperty_StreamFormat, scope,
+ bus, &c->m_sourceStreamDescription, sizeof(AudioStreamBasicDescription));
+ if (err != noErr){
+ DEBUG_AUDIO_STREAM("AudioNode" << int(this) << " - failed setting stream format")
+ return false;
+ }
+ AudioUnitSetProperty(m_audioUnit, kAudioUnitProperty_AudioChannelLayout, scope,
+ bus, c->m_sourceChannelLayout, c->m_sourceChannelLayoutSize);
+ } else {
+ OSStatus err = AudioUnitSetProperty(m_audioUnit, kAudioUnitProperty_StreamFormat, scope,
+ bus, &c->m_sinkStreamDescription, sizeof(AudioStreamBasicDescription));
+ if (err != noErr){
+ DEBUG_AUDIO_STREAM("AudioNode" << int(this) << " - failed setting stream format")
+ return false;
+ }
+ AudioUnitSetProperty(m_audioUnit, kAudioUnitProperty_AudioChannelLayout, scope,
+ bus, c->m_sinkChannelLayout, c->m_sourceChannelLayoutSize);
+ }
+ return true;
+}
+
+bool AudioNode::setStreamSpecification(AudioConnection *connection, ConnectionSide side)
+{
+ if (side == Source){
+ // This object am source of connection:
+ if (connection->m_hasSourceSpecification){
+ DEBUG_AUDIO_STREAM("AudioNode" << int(this) << "sets stream specification out"
+ << connection->m_sourceOutputBus << "from connection source")
+ return setStreamHelp(connection, connection->m_sourceOutputBus, kAudioUnitScope_Output, true);
+ } else {
+ DEBUG_AUDIO_STREAM("AudioNode" << int(this) << "did not set stream specification out")
+ }
+ } else {
+ if (connection->m_hasSinkSpecification){
+ DEBUG_AUDIO_STREAM("AudioNode" << int(this) << "sets stream specification"
+ << connection->m_sinkInputBus << "from connection sink")
+ return setStreamHelp(connection, connection->m_sinkInputBus, kAudioUnitScope_Input, false);
+ } else if (connection->m_hasSourceSpecification){
+ DEBUG_AUDIO_STREAM("AudioNode" << int(this) << "sets stream specification"
+ << connection->m_sinkInputBus << "from connection source")
+ return setStreamHelp(connection, connection->m_sinkInputBus, kAudioUnitScope_Input, true);
+ } else {
+ DEBUG_AUDIO_STREAM("AudioNode" << int(this) << "did not set stream specification in")
+ }
+ }
+ return true;
+}
+
+bool AudioNode::fillInStreamSpecification(AudioConnection *connection, ConnectionSide side)
+{
+ if (side == Source){
+ // As default, use the last description to describe the source:
+ if (m_lastConnectionIn->m_hasSinkSpecification){
+ DEBUG_AUDIO_STREAM("AudioNode" << int(this) << "is source, and fills in stream spec using last connection sink.")
+ connection->m_sourceStreamDescription = m_lastConnectionIn->m_sinkStreamDescription;
+ connection->m_sourceChannelLayout = (AudioChannelLayout *) malloc(m_lastConnectionIn->m_sinkChannelLayoutSize);
+ memcpy(connection->m_sourceChannelLayout, m_lastConnectionIn->m_sinkChannelLayout, m_lastConnectionIn->m_sinkChannelLayoutSize);
+ connection->m_sourceChannelLayoutSize = m_lastConnectionIn->m_sinkChannelLayoutSize;
+ connection->m_hasSourceSpecification = true;
+ } else if (m_lastConnectionIn->m_hasSourceSpecification){
+ DEBUG_AUDIO_STREAM("AudioNode" << int(this) << "is source, and fills in stream spec using last connection source.")
+ connection->m_sourceStreamDescription = m_lastConnectionIn->m_sourceStreamDescription;
+ connection->m_sourceChannelLayout = (AudioChannelLayout *) malloc(m_lastConnectionIn->m_sourceChannelLayoutSize);
+ memcpy(connection->m_sourceChannelLayout, m_lastConnectionIn->m_sourceChannelLayout, m_lastConnectionIn->m_sourceChannelLayoutSize);
+ connection->m_sourceChannelLayoutSize = m_lastConnectionIn->m_sourceChannelLayoutSize;
+ connection->m_hasSourceSpecification = true;
+ } else {
+ DEBUG_AUDIO_STREAM("AudioNode" << int(this) << " __WARNING__: could not get stream specification...")
+ }
+ } else {
+ DEBUG_AUDIO_STREAM("AudioNode" << int(this) << "is sink, skips filling in stream.")
+ if (!connection->isSinkOnly())
+ m_lastConnectionIn = connection;
+ }
+ return true;
+}
+
+/**
+ Let timeProperty be one of e.g
+ {kAudioUnitProperty_Latency, kAudioUnitProperty_TailTime,
+ kAudioOutputUnitProperty_StartTime, kAudioUnitProperty_CurrentPlayTime}
+*/
+Float64 AudioNode::getTimeInSamples(int timeProperty)
+{
+ if (!m_audioUnit)
+ return 0;
+
+ AudioTimeStamp timeStamp;
+ UInt32 size = sizeof(timeStamp);
+ memset(&timeStamp, 0, sizeof(timeStamp));
+ OSStatus err = AudioUnitGetProperty(m_audioUnit,
+ timeProperty, kAudioUnitScope_Global,
+ 0, &timeStamp, &size);
+ if (err != noErr)
+ return 0;
+ return timeStamp.mSampleTime;
+}
+
+void AudioNode::notify(const MediaNodeEvent *event)
+{
+ switch(event->type()){
+ case MediaNodeEvent::AudioGraphAboutToBeDeleted:
+ setGraph(0);
+ break;
+ case MediaNodeEvent::NewAudioGraph:
+ setGraph(static_cast<AudioGraph *>(event->data()));
+ break;
+ default:
+ break;
+ }
+
+ mediaNodeEvent(event);
+}
+
+void AudioNode::mediaNodeEvent(const MediaNodeEvent */*event*/)
+{
+ // Override if needed
+}
+
+void AudioNode::initializeAudioUnit()
+{
+ // Override if needed.
+}
+
+}} //namespace Phonon::QT7
+
+QT_END_NAMESPACE
diff --git a/src/3rdparty/phonon/qt7/audiooutput.h b/src/3rdparty/phonon/qt7/audiooutput.h
new file mode 100644
index 0000000000..c4a052608f
--- /dev/null
+++ b/src/3rdparty/phonon/qt7/audiooutput.h
@@ -0,0 +1,88 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef Phonon_QT7_AUDIOOUTPUT_H
+#define Phonon_QT7_AUDIOOUTPUT_H
+
+#include <QtCore/QObject>
+#include <phonon/audiooutputinterface.h>
+#include <phonon/abstractaudiooutput.h>
+
+#include "medianode.h"
+#include "audionode.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace QT7
+{
+ class AudioOutputAudioPart : public QObject, AudioNode
+ {
+ Q_OBJECT
+ public:
+ AudioOutputAudioPart();
+
+ void setVolume(float volume);
+ float volume();
+
+ protected:
+ ComponentDescription getAudioNodeDescription() const;
+ void initializeAudioUnit();
+
+ signals:
+ void volumeChanged(qreal newVolume);
+ void audioDeviceFailed();
+
+ private:
+ friend class AudioOutput;
+ qreal m_volume;
+ AudioDeviceID m_audioDevice;
+ void setAudioDevice(AudioDeviceID device);
+ };
+
+ class AudioOutput : public MediaNode, public AudioOutputInterface
+ {
+ Q_OBJECT
+ Q_INTERFACES(Phonon::AudioOutputInterface)
+
+ public:
+ AudioOutput(QObject *parent = 0);
+ ~AudioOutput();
+
+ qreal volume() const;
+ void setVolume(qreal);
+ int outputDevice() const;
+ bool setOutputDevice(int);
+
+ signals:
+ void volumeChanged(qreal newVolume);
+ void audioDeviceFailed();
+
+ protected:
+ void mediaNodeEvent(const MediaNodeEvent *event);
+
+ private:
+ AudioOutputAudioPart *m_audioOutput;
+ int m_device;
+ bool m_redirectToMovie;
+ };
+
+}} //namespace Phonon::QT7
+
+QT_END_NAMESPACE
+#endif // Phonon_QT7_AUDIOOUTPUT_H
diff --git a/src/3rdparty/phonon/qt7/audiooutput.mm b/src/3rdparty/phonon/qt7/audiooutput.mm
new file mode 100644
index 0000000000..38066d50c1
--- /dev/null
+++ b/src/3rdparty/phonon/qt7/audiooutput.mm
@@ -0,0 +1,168 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "audiooutput.h"
+#include "audiograph.h"
+#include "audiodevice.h"
+#include "mediaobject.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace QT7
+{
+
+AudioOutputAudioPart::AudioOutputAudioPart() : AudioNode(1, 0)
+{
+ m_audioDevice = AudioDevice::defaultDevice(AudioDevice::Out);
+ m_volume = 1;
+}
+
+ComponentDescription AudioOutputAudioPart::getAudioNodeDescription() const
+{
+ ComponentDescription description;
+ description.componentType = kAudioUnitType_Output;
+ description.componentSubType = kAudioUnitSubType_DefaultOutput;
+ description.componentManufacturer = kAudioUnitManufacturer_Apple;
+ description.componentFlags = 0;
+ description.componentFlagsMask = 0;
+ return description;
+}
+
+void AudioOutputAudioPart::initializeAudioUnit()
+{
+ setAudioDevice(m_audioDevice);
+ setVolume(m_volume);
+}
+
+void AudioOutputAudioPart::setAudioDevice(AudioDeviceID device)
+{
+ m_audioDevice = device;
+ if (!m_audioDevice)
+ return;
+ if (!m_audioUnit)
+ return;
+ bool ok = AudioDevice::setDevice(m_audioUnit, m_audioDevice, AudioDevice::Out);
+ if (!ok)
+ emit audioDeviceFailed();
+}
+
+void AudioOutputAudioPart::setVolume(float volume)
+{
+ if (volume < 0)
+ m_volume = 0;
+ if (volume > 1)
+ m_volume = 1;
+ else
+ m_volume = volume;
+
+ if (m_audioUnit){
+ float db = volume;//20.0 * log10(volume); // convert to db
+ OSStatus err = AudioUnitSetParameter(m_audioUnit, kHALOutputParam_Volume, kAudioUnitScope_Input, 0, db, 0);
+ BACKEND_ASSERT2(err == noErr, "Could not set volume on output audio unit.", FATAL_ERROR)
+ emit volumeChanged(qreal(db));
+ }
+}
+
+float AudioOutputAudioPart::volume()
+{
+ return m_volume;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+
+AudioOutput::AudioOutput(QObject *parent) : MediaNode(AudioSink, parent)
+{
+ m_audioOutput = new AudioOutputAudioPart();
+ setAudioNode(m_audioOutput);
+ connect(m_audioOutput, SIGNAL(volumeChanged(qreal)), this, SIGNAL(volumeChanged(qreal)));
+ connect(m_audioOutput, SIGNAL(audioDeviceFailed()), this, SIGNAL(audioDeviceFailed()));
+ m_redirectToMovie = false;
+}
+
+AudioOutput::~AudioOutput()
+{
+}
+
+void AudioOutput::setVolume(qreal volume)
+{
+ IMPLEMENTED;
+ m_audioOutput->setVolume(float(volume));
+ if (m_owningMediaObject)
+ m_owningMediaObject->setVolumeOnMovie(volume);
+
+ emit volumeChanged(m_audioOutput->volume());
+}
+
+qreal AudioOutput::volume() const
+{
+ IMPLEMENTED;
+ return qreal(m_audioOutput->volume());
+}
+
+bool AudioOutput::setOutputDevice(int device)
+{
+ IMPLEMENTED;
+ if (device == -1)
+ return false;
+
+ if (m_owningMediaObject){
+ bool ok = m_owningMediaObject->setAudioDeviceOnMovie(device);
+ if (!ok)
+ return false;
+ }
+
+ if (m_audioGraph){
+ MediaNodeEvent event1(MediaNodeEvent::AboutToRestartAudioStream, this);
+ m_audioGraph->notify(&event1);
+ }
+
+ m_audioOutput->setAudioDevice(device);
+
+ if (m_audioGraph){
+ MediaNodeEvent event2(MediaNodeEvent::RestartAudioStreamRequest, this);
+ m_audioGraph->notify(&event2);
+ }
+ return true;
+}
+
+int AudioOutput::outputDevice() const
+{
+ IMPLEMENTED;
+ return m_audioOutput->m_audioDevice;
+}
+
+void AudioOutput::mediaNodeEvent(const MediaNodeEvent *event)
+{
+ switch (event->type()){
+ case MediaNodeEvent::SetMediaObject:
+ if (static_cast<MediaObject *>(event->data())){
+ setVolume(volume());
+ setOutputDevice(outputDevice());
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+}} //namespace Phonon::QT7
+
+QT_END_NAMESPACE
+
+#include "moc_audiooutput.cpp"
diff --git a/src/3rdparty/phonon/qt7/audiopartoutput.h b/src/3rdparty/phonon/qt7/audiopartoutput.h
new file mode 100644
index 0000000000..0ccdfb676d
--- /dev/null
+++ b/src/3rdparty/phonon/qt7/audiopartoutput.h
@@ -0,0 +1,47 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef Phonon_QT7_AUDIOPARTOUTPUT_H
+#define Phonon_QT7_AUDIOPARTOUTPUT_H
+
+#include <AudioToolbox/AudioToolbox.h>
+#include <AudioUnit/AudioUnit.h>
+#include "audionode.h"
+#include <QtCore/qnamespace.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace QT7
+{
+ class AudioPartOutput : public AudioNode
+ {
+ public:
+ AudioPartOutput();
+ virtual ~AudioPartOutput();
+
+ private:
+ ComponentDescription getAudioNodeDescription() const;
+ void initializeAudioUnit(AudioNode *source);
+ };
+
+}} // namespace Phonon::QT7
+
+QT_END_NAMESPACE
+
+#endif // Phonon_QT7_AUDIOPARTOUTPUT_H
diff --git a/src/3rdparty/phonon/qt7/audiopartoutput.mm b/src/3rdparty/phonon/qt7/audiopartoutput.mm
new file mode 100644
index 0000000000..b985e69742
--- /dev/null
+++ b/src/3rdparty/phonon/qt7/audiopartoutput.mm
@@ -0,0 +1,69 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "audiopartoutput.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace QT7
+{
+
+AudioPartOutput::AudioPartOutput()
+ : AudioNode()
+{
+}
+
+AudioPartOutput::~AudioPartOutput()
+{
+}
+
+ComponentDescription AudioPartOutput::getAudioNodeDescription() const
+{
+ ComponentDescription description;
+ description.componentType = kAudioUnitType_Output;
+ description.componentSubType = kAudioUnitSubType_DefaultOutput;
+ description.componentManufacturer = kAudioUnitManufacturer_Apple;
+ description.componentFlags = 0;
+ description.componentFlagsMask = 0;
+ return description;
+}
+
+void AudioPartOutput::initializeAudioUnit(AudioNode *source)
+{
+ m_audioStreamDescription = source->outputStreamDescription();
+ m_audioChannelLayout = source->outputChannelLayout();
+ m_audioChannelLayoutSize = source->outputChannelLayoutSize();
+
+ // Specify the stream format:
+ OSStatus err;
+ err = AudioUnitSetProperty(m_audioUnit,
+ kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input,
+ 0, m_audioStreamDescription, sizeof(AudioStreamBasicDescription));
+ BACKEND_ASSERT2(err == noErr, "Could not set stream format on audio output unit.", FATAL_ERROR)
+
+ // Set the channel layout:
+ err = AudioUnitSetProperty(m_audioUnit,
+ kAudioUnitProperty_AudioChannelLayout, kAudioUnitScope_Input,
+ 0, m_audioChannelLayout, m_audioChannelLayoutSize);
+ BACKEND_ASSERT2(err == noErr, "Could not set channel layout on audio output unit.", FATAL_ERROR)
+}
+
+}} // namespace Phonon::QT7
+
+QT_END_NAMESPACE
diff --git a/src/3rdparty/phonon/qt7/audiosplitter.h b/src/3rdparty/phonon/qt7/audiosplitter.h
new file mode 100644
index 0000000000..ed6101f0de
--- /dev/null
+++ b/src/3rdparty/phonon/qt7/audiosplitter.h
@@ -0,0 +1,50 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef Phonon_QT7_AUDIOSPLITTER_H
+#define Phonon_QT7_AUDIOSPLITTER_H
+
+#include <QtCore/QFile>
+
+#include "medianode.h"
+#include "audionode.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace QT7
+{
+ class AudioNodeSplitter : public AudioNode
+ {
+ public:
+ AudioNodeSplitter();
+ ComponentDescription getAudioNodeDescription() const;
+ };
+
+ class AudioSplitter : public MediaNode
+ {
+ public:
+ AudioSplitter(QObject *parent = 0);
+ ~AudioSplitter();
+ };
+
+}} //namespace Phonon::QT7
+
+QT_END_NAMESPACE
+
+#endif // Phonon_QT7_AUDIOSPLITTER_H
diff --git a/src/3rdparty/phonon/qt7/audiosplitter.mm b/src/3rdparty/phonon/qt7/audiosplitter.mm
new file mode 100644
index 0000000000..685ea1262b
--- /dev/null
+++ b/src/3rdparty/phonon/qt7/audiosplitter.mm
@@ -0,0 +1,52 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "audiosplitter.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace QT7
+{
+
+AudioNodeSplitter::AudioNodeSplitter() : AudioNode(1, 2)
+{
+}
+
+ComponentDescription AudioNodeSplitter::getAudioNodeDescription() const
+{
+ ComponentDescription description;
+ description.componentType = kAudioUnitType_FormatConverter;
+ description.componentSubType = kAudioUnitSubType_Splitter;
+ description.componentManufacturer = kAudioUnitManufacturer_Apple;
+ description.componentFlags = 0;
+ description.componentFlagsMask = 0;
+ return description;
+}
+
+AudioSplitter::AudioSplitter(QObject *parent) : MediaNode(AudioSink | AudioSource, new AudioNodeSplitter(), parent)
+{
+}
+
+AudioSplitter::~AudioSplitter()
+{
+}
+
+}} //namespace Phonon::QT7
+
+QT_END_NAMESPACE
diff --git a/src/3rdparty/phonon/qt7/backend.h b/src/3rdparty/phonon/qt7/backend.h
new file mode 100644
index 0000000000..287fcec4f3
--- /dev/null
+++ b/src/3rdparty/phonon/qt7/backend.h
@@ -0,0 +1,61 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef Phonon_QT7_BACKEND_H
+#define Phonon_QT7_BACKEND_H
+
+#include <QtCore/QList>
+#include <QtCore/QPointer>
+#include <QtCore/QStringList>
+#include <phonon/backendinterface.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace QT7
+{
+ class Backend : public QObject, public BackendInterface
+ {
+ Q_OBJECT
+ Q_INTERFACES(Phonon::BackendInterface)
+
+ public:
+ Backend();
+ Backend(QObject *parent, const QStringList &args);
+ virtual ~Backend();
+
+ QObject *createObject(BackendInterface::Class, QObject *parent, const QList<QVariant> &args);
+ QStringList availableMimeTypes() const;
+ QList<int> objectDescriptionIndexes(ObjectDescriptionType type) const;
+ QHash<QByteArray, QVariant> objectDescriptionProperties(ObjectDescriptionType type, int index) const;
+
+ bool startConnectionChange(QSet<QObject *> nodes);
+ bool connectNodes(QObject *source, QObject *sink);
+ bool disconnectNodes(QObject *source, QObject *sink);
+ bool endConnectionChange(QSet<QObject *> nodes);
+
+ Q_SIGNALS:
+ void objectDescriptionChanged(ObjectDescriptionType);
+
+ private:
+ bool quickTime7Available();
+ };
+}} // namespace Phonon::QT7
+
+QT_END_NAMESPACE
+#endif // Phonon_QT7_BACKEND_H
diff --git a/src/3rdparty/phonon/qt7/backend.mm b/src/3rdparty/phonon/qt7/backend.mm
new file mode 100644
index 0000000000..327ddd7703
--- /dev/null
+++ b/src/3rdparty/phonon/qt7/backend.mm
@@ -0,0 +1,276 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "backend.h"
+#include <QtCore/QDebug>
+#include <QtCore/QSet>
+#include <QtCore/QVariant>
+#include <QtCore/QtPlugin>
+
+#include "backendheader.h"
+
+#include "videowidget.h"
+#include "audiooutput.h"
+#include "mediaobject.h"
+#include "videoeffect.h"
+#include "medianode.h"
+#include "audiodevice.h"
+#include "audiomixer.h"
+#include "backendinfo.h"
+#include "quicktimeaudioplayer.h"
+
+#include "audiograph.h"
+#include "audiomixer.h"
+#include "audiooutput.h"
+#include "audiosplitter.h"
+#include "audioeffects.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace QT7
+{
+
+Backend::Backend()
+{
+ IMPLEMENTED << "Creating backend QT7";
+}
+
+Backend::Backend(QObject *parent, const QStringList &) : QObject(parent)
+{
+ IMPLEMENTED << "Creating backend QT7";
+ setProperty("identifier", QLatin1String("Mac OS X/QuickTime7"));
+ setProperty("backendName", QLatin1String("Mac OS X/QuickTime7"));
+ setProperty("backendComment", QLatin1String("Developed by Trolltech"));
+ setProperty("backendVersion", QLatin1String("0.1"));
+ setProperty("backendIcon", QLatin1String(""));
+ setProperty("backendWebsite", QLatin1String("http://qtsoftware.com/"));
+}
+
+Backend::~Backend()
+{
+}
+
+bool Backend::quickTime7Available()
+{
+ static bool ok = BackendInfo::isQuickTimeVersionAvailable(0x0700);
+ if (!ok){
+ static bool messageWritten = false;
+ if (!messageWritten && qgetenv("PHONON_DEBUG") == "1"){
+ messageWritten = true;
+ QString str("WARNING: Phonon backend plugin need QuickTime 7 or newer to work.");
+ str += " This computer has version "
+ + BackendInfo::quickTimeVersionString()
+ + " installed.";
+ qWarning(str.toAscii().data());
+ }
+ return false;
+ }
+ return true;
+}
+
+QObject *Backend::createObject(BackendInterface::Class c, QObject *parent, const QList<QVariant> &args)
+{
+ if (!quickTime7Available())
+ return 0;
+
+ switch (c) {
+ case MediaObjectClass:
+ IMPLEMENTED << "Creating new MediaObjectClass.";
+ return new MediaObject(parent);
+ break;
+ case VolumeFaderEffectClass:
+ IMPLEMENTED << "Creating new VolumeFaderEffectClass.";
+ return new AudioMixer(parent);
+ break;
+ case AudioOutputClass:
+ IMPLEMENTED << "Creating new AudioOutputClass.";
+ return new AudioOutput(parent);
+ break;
+ case AudioDataOutputClass:
+ NOT_IMPLEMENTED << "Creating new AudioDataOutputClass.";
+ break;
+ case VisualizationClass:
+ NOT_IMPLEMENTED << "Creating new VisualizationClass.";
+ break;
+ case VideoDataOutputClass:
+ NOT_IMPLEMENTED << "Creating new VideoDataOutputClass.";
+ break;
+ case EffectClass:
+ IMPLEMENTED << "Creating new EffectClass.";
+ return new AudioEffect(args[0].toInt());
+ break;
+ case VideoWidgetClass:
+ IMPLEMENTED << "Creating new VideoWidget.";
+ return new VideoWidget(parent);
+ break;
+ default:
+ return 0;
+ }
+ return 0;
+}
+
+bool Backend::startConnectionChange(QSet<QObject *> objects)
+{
+ IMPLEMENTED;
+ QList<AudioGraph *> notifiedGraphs;
+ for (int i=0; i<objects.size(); i++){
+ MediaNode *node = qobject_cast<MediaNode*>(objects.values()[i]);
+ if (node && node->m_audioGraph && !notifiedGraphs.contains(node->m_audioGraph)){
+ MediaNodeEvent event(MediaNodeEvent::StartConnectionChange);
+ node->m_audioGraph->notify(&event);
+ notifiedGraphs << node->m_audioGraph;
+ }
+ }
+ return true;
+}
+
+bool Backend::endConnectionChange(QSet<QObject *> objects)
+{
+ IMPLEMENTED;
+ QList<AudioGraph *> notifiedGraphs;
+ for (int i=0; i<objects.size(); i++){
+ MediaNode *node = qobject_cast<MediaNode*>(objects.values()[i]);
+ if (node && node->m_audioGraph && !notifiedGraphs.contains(node->m_audioGraph)){
+ MediaNodeEvent event(MediaNodeEvent::EndConnectionChange);
+ node->m_audioGraph->notify(&event);
+ notifiedGraphs << node->m_audioGraph;
+ }
+ }
+ return true;
+}
+
+bool Backend::connectNodes(QObject *aSource, QObject *aSink)
+{
+ IMPLEMENTED;
+ MediaNode *source = qobject_cast<MediaNode*>(aSource);
+ if (!source) return false;
+ MediaNode *sink = qobject_cast<MediaNode*>(aSink);
+ if (!sink) return false;
+
+ return source->connectToSink(sink);
+}
+
+
+bool Backend::disconnectNodes(QObject *aSource, QObject *aSink)
+{
+ IMPLEMENTED;
+ MediaNode *source = qobject_cast<MediaNode*>(aSource);
+ if (!source) return false;
+ MediaNode *sink = qobject_cast<MediaNode*>(aSink);
+ if (!sink) return false;
+
+ return source->disconnectToSink(sink);
+}
+
+
+QStringList Backend::availableMimeTypes() const
+{
+ IMPLEMENTED;
+ return BackendInfo::quickTimeMimeTypes(BackendInfo::In);
+}
+
+/**
+* Returns a set of indexes that acts as identifiers for the various properties
+* this backend supports for the given ObjectDescriptionType.
+* More information for a given property/index can be
+* looked up in Backend::objectDescriptionProperties(...).
+*/
+QList<int> Backend::objectDescriptionIndexes(ObjectDescriptionType type) const
+{
+ QList<int> ret;
+
+ switch (type){
+ case AudioOutputDeviceType:{
+ IMPLEMENTED_SILENT << "Creating index set for type: AudioOutputDeviceType";
+ QList<AudioDeviceID> devices = AudioDevice::devices(AudioDevice::Out);
+ for (int i=0; i<devices.size(); i++)
+ ret << int(devices[i]);
+ break; }
+ case EffectType:{
+ IMPLEMENTED_SILENT << "Creating index set for type: EffectType";
+ if (QuickTimeAudioPlayer::soundPlayerIsAwailable())
+ ret = AudioEffect::effectList();
+ break; }
+
+#if 0 // will be awailable in a later version of phonon.
+ case AudioCaptureDeviceType:{
+ IMPLEMENTED_SILENT << "Creating index set for type: AudioCaptureDeviceType";
+ QList<AudioDeviceID> devices = AudioDevice::devices(AudioDevice::In).keys();
+ for (int i=0; i<devices.size(); i++)
+ ret <<int(devices[i]);
+ break; }
+ case VideoEffectType:{
+ // Just count the number of filters awailable (c), and
+ // add return a set with the numbers 1..c inserted:
+ IMPLEMENTED_SILENT << "Creating index set for type: VideoEffectType";
+ QList<QtCore/QString> filters = objc_getCiFilterInfo()->filterDisplayNames;
+ for (int i=0; i<filters.size(); i++)
+ ret << insert(i);
+ break; }
+#endif
+ default:
+ NOT_IMPLEMENTED;
+ break;
+ }
+ return ret;
+}
+
+QHash<QByteArray, QVariant> Backend::objectDescriptionProperties(ObjectDescriptionType type, int index) const
+{
+ QHash<QByteArray, QVariant> ret;
+
+ switch (type){
+ case AudioOutputDeviceType:{
+ IMPLEMENTED_SILENT << "Creating description hash for type: AudioOutputDeviceType";
+ ret.insert("name", AudioDevice::deviceSourceNameElseDeviceName(index));
+ ret.insert("description", AudioDevice::deviceNameElseDeviceSourceName(index));
+ break; }
+ case EffectType:{
+ AudioEffect e(index);
+ ret.insert("name", e.name());
+ ret.insert("description", e.description());
+ break; }
+
+#if 0 // will be awailable in a later version of phonon.
+ case VideoEffectType:{
+ // Get list of effects, pick out filter at index, and return its name:
+ IMPLEMENTED_SILENT << "Creating description hash for type: VideoEffectType";
+ QList<QtCore/QString> filters = objc_getCiFilterInfo()->filterDisplayNames;
+ ret.insert("name", filters[index]);
+ case AudioCaptureDeviceType:{
+ IMPLEMENTED_SILENT << "Creating description hash for type: AudioCaptureDeviceType";
+ QMap<AudioDeviceID, QString> devices = AudioDevice::devices(AudioDevice::In);
+ ret.insert("name", devices.value(index));
+ break; }
+#endif
+ default:
+ NOT_IMPLEMENTED;
+ break;
+ }
+
+ return ret;
+}
+
+Q_EXPORT_PLUGIN2(phonon_qt7, Backend)
+}}
+
+QT_END_NAMESPACE
+
+#include "moc_backend.cpp"
+
diff --git a/src/3rdparty/phonon/qt7/backendheader.h b/src/3rdparty/phonon/qt7/backendheader.h
new file mode 100644
index 0000000000..fd0d892c0a
--- /dev/null
+++ b/src/3rdparty/phonon/qt7/backendheader.h
@@ -0,0 +1,184 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef Phonon_QT7_BACKENDHEADER_H
+#define Phonon_QT7_BACKENDHEADER_H
+
+#include <QtCore/QString>
+#import <Foundation/NSAutoreleasePool.h>
+#include <CoreFoundation/CFBase.h>
+
+#ifndef Q_WS_MAC64
+#define QUICKTIME_C_API_AVAILABLE
+#endif
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace QT7
+{
+
+// Implemented in error.cpp:
+void gSetErrorString(const QString &errorString);
+QString gGetErrorString();
+void gSetErrorLocation(const QString &errorLocation);
+void gSetErrorType(int type);
+int gGetErrorType();
+void gClearError();
+
+#define NO_ERROR 0
+#define NORMAL_ERROR 1
+#define FATAL_ERROR 2
+
+#define ERROR_LOCATION \
+ QLatin1String("Function: ") + QLatin1String(__FUNCTION__) \
+ + QLatin1String(", File: ") + QLatin1String(__FILE__) \
+ + QLatin1String(", Line: ") + QString::number(__LINE__)
+
+#define SET_ERROR(string, type){ \
+ Phonon::QT7::gSetErrorString(string); \
+ Phonon::QT7::gSetErrorType(type); \
+ Phonon::QT7::gSetErrorLocation(ERROR_LOCATION); }
+
+#define BACKEND_ASSERT(test, string, type) \
+ bool fail = !test; \
+ if (fail) \
+ SET_ERROR(QLatin1String(string), type) \
+ if (fail)
+
+#define BACKEND_ASSERT2(test, string, type) \
+ if (!(test)) { \
+ SET_ERROR(QLatin1String(string), type) \
+ return; \
+ }
+
+#define BACKEND_ASSERT3(test, string, type, ret) \
+ if (!(test)) { \
+ SET_ERROR(QLatin1String(string), type) \
+ return ret; \
+ }
+
+#define ARGUMENT_UNSUPPORTED(a, x, type, ret) \
+ if ((a) == (x)) { \
+ SET_ERROR("Argument value not supported: "#a" == "#x, type); \
+ return ret; \
+ }
+
+#define CASE_UNSUPPORTED(string, type) SET_ERROR(string, type)
+
+#ifdef SET_DEBUG_IMPLEMENTED
+#define IMPLEMENTED qDebug() << "QT7:" << __FUNCTION__ << "(" << __FILE__ << "):"
+#else
+#define IMPLEMENTED if (1); else qDebug()
+#endif
+
+#ifdef SET_DEBUG_HALF_IMPLEMENTED
+#define HALF_IMPLEMENTED qDebug() << "QT7: --- HALF IMPLEMENTED:" << __FUNCTION__ << "(" << __FILE__ << "," << __LINE__ << "):"
+#else
+#define HALF_IMPLEMENTED if (1); else qDebug()
+#endif
+
+#ifdef SET_DEBUG_NOT_IMPLEMENTED
+#define NOT_IMPLEMENTED qDebug() << "QT7: *** NOT IMPLEMENTED:" << __FUNCTION__ << "(" << __FILE__ << "," << __LINE__ << "):"
+#else
+#define NOT_IMPLEMENTED if (1); else qDebug()
+#endif
+
+#ifdef SET_DEBUG_IMPLEMENTED_SILENT
+#define IMPLEMENTED_SILENT qDebug() << "QT7: (silent)" << __FUNCTION__ << "(" << __FILE__ << "," << __LINE__ << "):"
+#else
+#define IMPLEMENTED_SILENT if (1); else qDebug()
+#endif
+
+#ifdef SET_DEBUG_AUDIO_GRAPH
+#define DEBUG_AUDIO_GRAPH(x) qDebug() << "QT7 DEBUG GRAPH:" << x;
+#else
+#define DEBUG_AUDIO_GRAPH(x) {}
+#endif
+
+#ifdef SET_DEBUG_AUDIO_STREAM
+#define DEBUG_AUDIO_STREAM(x) qDebug() << "QT7 DEBUG STREAM:" << x;
+#else
+#define DEBUG_AUDIO_STREAM(x) {}
+#endif
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+class PhononAutoReleasePool
+{
+private:
+ void *pool;
+public:
+ PhononAutoReleasePool();
+ ~PhononAutoReleasePool();
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+template <typename T>
+class PhononCFType
+{
+public:
+ inline PhononCFType(const T &t = 0) : type(t) {}
+ inline PhononCFType(const PhononCFType &helper) : type(helper.type) { if (type) CFRetain(type); }
+ inline ~PhononCFType() { if (type) CFRelease(type); }
+ inline operator T() { return type; }
+ inline PhononCFType operator =(const PhononCFType &helper)
+ {
+ if (helper.type)
+ CFRetain(helper.type);
+ CFTypeRef type2 = type;
+ type = helper.type;
+ if (type2)
+ CFRelease(type2);
+ return *this;
+ }
+ inline T *operator&() { return &type; }
+ static PhononCFType constructFromGet(const T &t)
+ {
+ CFRetain(t);
+ return PhononCFType<T>(t);
+ }
+protected:
+ T type;
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+class PhononCFString : public PhononCFType<CFStringRef>
+{
+public:
+ inline PhononCFString(const QString &str) : PhononCFType<CFStringRef>(0), string(str) {}
+ inline PhononCFString(const CFStringRef cfstr = 0) : PhononCFType<CFStringRef>(cfstr) {}
+ inline PhononCFString(const PhononCFType<CFStringRef> &other) : PhononCFType<CFStringRef>(other) {}
+ operator QString() const;
+ operator CFStringRef() const;
+ static QString toQString(CFStringRef cfstr);
+ static CFStringRef toCFStringRef(const QString &str);
+private:
+ QString string;
+};
+}} //namespace Phonon::QT7
+
+QT_END_NAMESPACE
+
+#ifdef Q_CC_INTEL
+#pragma warning (disable : 1899) // mute icc warning for the use of 4cc
+#endif
+
+#endif // Phonon_QT7_BACKENDHEADER_H
diff --git a/src/3rdparty/phonon/qt7/backendheader.mm b/src/3rdparty/phonon/qt7/backendheader.mm
new file mode 100644
index 0000000000..3a733890ef
--- /dev/null
+++ b/src/3rdparty/phonon/qt7/backendheader.mm
@@ -0,0 +1,127 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "backendheader.h"
+#include <QtCore/QString>
+#include <QtCore/QDebug>
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <QVarLengthArray>
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace QT7
+{
+
+Q_GLOBAL_STATIC(QString, gErrorString)
+int gErrorType = NO_ERROR;
+
+void gSetErrorString(const QString &errorString)
+{
+ if (qgetenv("PHONON_DEBUG") == "1"){
+ qDebug() << "Error:" << errorString;
+ }
+
+ if (!gErrorString()->isEmpty())
+ return; // not yet caught.
+
+ *gErrorString() = errorString;
+}
+
+QString gGetErrorString()
+{
+ return *gErrorString();
+}
+
+void gSetErrorLocation(const QString &errorLocation)
+{
+ if (qgetenv("PHONON_DEBUG") == "1"){
+ qDebug() << "Location:" << errorLocation;
+ }
+}
+
+void gSetErrorType(int errorType)
+{
+ if (gErrorType != NO_ERROR)
+ return; // not yet caught.
+ gErrorType = errorType;
+}
+
+int gGetErrorType()
+{
+ return gErrorType;
+}
+
+void gClearError()
+{
+ gErrorString()->clear();
+ gErrorType = NO_ERROR;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+PhononAutoReleasePool::PhononAutoReleasePool()
+{
+ pool = (void*)[[NSAutoreleasePool alloc] init];
+}
+
+PhononAutoReleasePool::~PhononAutoReleasePool()
+{
+ [(NSAutoreleasePool*)pool release];
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+QString PhononCFString::toQString(CFStringRef str)
+{
+ if(!str)
+ return QString();
+ CFIndex length = CFStringGetLength(str);
+ const UniChar *chars = CFStringGetCharactersPtr(str);
+ if (chars)
+ return QString(reinterpret_cast<const QChar *>(chars), length);
+
+ QVarLengthArray<UniChar> buffer(length);
+ CFStringGetCharacters(str, CFRangeMake(0, length), buffer.data());
+ return QString(reinterpret_cast<const QChar *>(buffer.constData()), length);
+}
+
+PhononCFString::operator QString() const
+{
+ if (string.isEmpty() && type)
+ const_cast<PhononCFString*>(this)->string = toQString(type);
+ return string;
+}
+
+CFStringRef PhononCFString::toCFStringRef(const QString &string)
+{
+ return CFStringCreateWithCharacters(0, reinterpret_cast<const UniChar *>(string.unicode()),
+ string.length());
+}
+
+PhononCFString::operator CFStringRef() const
+{
+ if (!type)
+ const_cast<PhononCFString*>(this)->type = toCFStringRef(string);
+ return type;
+}
+
+}}
+
+QT_END_NAMESPACE
diff --git a/src/3rdparty/phonon/qt7/backendinfo.h b/src/3rdparty/phonon/qt7/backendinfo.h
new file mode 100644
index 0000000000..c30cda34ae
--- /dev/null
+++ b/src/3rdparty/phonon/qt7/backendinfo.h
@@ -0,0 +1,48 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef Phonon_QT7_BACKENDINFO_H
+#define Phonon_QT7_BACKENDINFO_H
+
+#include <phonon/mediasource.h>
+#include <Carbon/Carbon.h>
+#include <QtCore/QStringList>
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace QT7
+{
+ class BackendInfo
+ {
+ public:
+ enum Scope {In, Out};
+
+ static QString quickTimeVersionString();
+ static bool isQuickTimeVersionAvailable(int minHexVersion);
+ static QStringList quickTimeMimeTypes(Scope scope);
+ static QStringList quickTimeCompressionFormats();
+ static QStringList coreAudioCodecs(Scope scope);
+ static QStringList coreAudioFileTypes(Scope scope);
+ };
+
+}} // namespace Phonon::QT7
+
+QT_END_NAMESPACE
+
+#endif // Phonon_QT7_BACKENDINFO_H
diff --git a/src/3rdparty/phonon/qt7/backendinfo.mm b/src/3rdparty/phonon/qt7/backendinfo.mm
new file mode 100644
index 0000000000..e173f052a9
--- /dev/null
+++ b/src/3rdparty/phonon/qt7/backendinfo.mm
@@ -0,0 +1,311 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "backendinfo.h"
+#include "backendheader.h"
+
+#include <AudioToolbox/AudioToolbox.h>
+#include <AudioUnit/AudioUnit.h>
+#include <CoreServices/CoreServices.h>
+
+#import <QTKit/QTMovie.h>
+
+#ifdef QUICKTIME_C_API_AVAILABLE
+ #include <QuickTime/QuickTime.h>
+ #undef check // avoid name clash;
+#endif
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace QT7
+{
+
+QString BackendInfo::quickTimeVersionString()
+{
+ SInt32 version;
+ OSStatus err = Gestalt(gestaltQuickTimeVersion, &version);
+ if (err != noErr)
+ return QString("00.0.0.0000");
+ QString versionString = QString("%1%2.%3.%4.%5%6%7%8")
+ .arg((version >> (7*4)) & 0xF)
+ .arg((version >> (6*4)) & 0xF)
+ .arg((version >> (5*4)) & 0xF)
+ .arg((version >> (4*4)) & 0xF)
+ .arg((version >> (3*4)) & 0xF)
+ .arg((version >> (2*4)) & 0xF)
+ .arg((version >> (1*4)) & 0xF)
+ .arg((version >> (0*4)) & 0xF);
+ return versionString;
+}
+
+bool BackendInfo::isQuickTimeVersionAvailable(int minHexVersion)
+{
+ // minHexVersion == 0x0741 means version 7.4.1
+ SInt32 qtHexVersion;
+ OSStatus err = Gestalt(gestaltQuickTimeVersion, &qtHexVersion);
+ return (err == noErr) ? ((qtHexVersion >> 16) >= minHexVersion) : 0;
+}
+
+#ifdef QUICKTIME_C_API_AVAILABLE
+static QString getMimeTypeTag(QTAtomContainer mimeList, int index, OSType type)
+{
+ QTAtom mimeAtom = QTFindChildByIndex(mimeList, kParentAtomIsContainer, type, index, 0);
+ char mimeCharArray[256];
+ long length;
+ OSStatus err = QTCopyAtomDataToPtr(mimeList, mimeAtom, true, sizeof(mimeCharArray)-1, mimeCharArray, &length);
+ if (err == noErr)
+ return QString::fromAscii(mimeCharArray, length);
+ return QString();
+}
+#endif // QUICKTIME_C_API_AVAILABLE
+
+#ifdef QUICKTIME_C_API_AVAILABLE
+QStringList BackendInfo::quickTimeMimeTypes(Scope scope)
+{
+ QStringList mimeTypes;
+ ARGUMENT_UNSUPPORTED(scope, Out, NORMAL_ERROR, mimeTypes)
+
+ ComponentDescription description;
+ description.componentType = MovieImportType;
+ description.componentSubType = 0;
+ description.componentManufacturer = 0;
+ description.componentFlags = hasMovieImportMIMEList | canMovieImportFiles;
+ description.componentFlagsMask = canMovieImportFiles | movieImportSubTypeIsFileExtension | hasMovieImportMIMEList;
+ Component component = FindNextComponent(0, &description);
+
+ while (component) {
+ QTAtomContainer mimeList = 0;
+ OSStatus err = MovieImportGetMIMETypeList((MovieImportComponent)component, &mimeList);
+ if (err == noErr){
+ int count = QTCountChildrenOfType(mimeList, kParentAtomIsContainer, 0);
+ for (int i=1; i<=count; ++i){
+ QString mimeType = getMimeTypeTag(mimeList, i, kMimeInfoMimeTypeTag);
+ if (mimeType.startsWith(QLatin1String("audio")) || mimeType.startsWith(QLatin1String("video"))){
+ if (err == noErr && !mimeType.isEmpty())
+ mimeTypes << mimeType;
+ }
+ }
+ }
+ QTDisposeAtomContainer(mimeList);
+ component = FindNextComponent(component, &description);
+ }
+ mimeTypes.sort();
+ return mimeTypes;
+}
+
+#else // QUICKTIME_C_API_AVAILABLE == false
+
+QString mimeForExtensionAudio(const QString &ext)
+{
+ if (ext == "3g2") return QLatin1String("audio/3g2");
+ if (ext == "3gp") return QLatin1String("audio/3gp");
+ if (ext == "aac") return QLatin1String("audio/aac");
+ if (ext == "ac3") return QLatin1String("audio/ac3");
+ if (ext == "aif") return QLatin1String("audio/aif");
+ if (ext == "aifc") return QLatin1String("audio/aifc");
+ if (ext == "aiff") return QLatin1String("audio/aiff");
+ if (ext == "amr") return QLatin1String("audio/amr");
+ if (ext == "au") return QLatin1String("audio/au");
+ if (ext == "bwf") return QLatin1String("audio/bwf");
+ if (ext == "caf") return QLatin1String("audio/caf");
+ if (ext == "cdda") return QLatin1String("audio/cdda");
+ if (ext == "gsm") return QLatin1String("audio/gsm");
+ if (ext == "kar") return QLatin1String("audio/kar");
+ if (ext == "m1a") return QLatin1String("audio/m1a");
+ if (ext == "m1s") return QLatin1String("audio/m1s");
+ if (ext == "m3u") return QLatin1String("audio/m3u");
+ if (ext == "m3url") return QLatin1String("audio/m3url");
+ if (ext == "mid") return QLatin1String("audio/mid");
+ if (ext == "midi") return QLatin1String("audio/midi");
+ if (ext == "mka") return QLatin1String("audio/mka");
+ if (ext == "mp3") return QLatin1String("audio/mp3");
+ if (ext == "mp4") return QLatin1String("audio/mp4");
+ if (ext == "mpa") return QLatin1String("audio/mpa");
+ if (ext == "mpeg") return QLatin1String("audio/mpeg");
+ if (ext == "mpg") return QLatin1String("audio/mpg");
+ if (ext == "mpg4") return QLatin1String("audio/mpg4");
+ if (ext == "mpm") return QLatin1String("audio/mpm");
+ if (ext == "qcp") return QLatin1String("audio/qcp");
+ if (ext == "sd2") return QLatin1String("audio/sd2");
+ if (ext == "smf") return QLatin1String("audio/smf");
+ if (ext == "snd") return QLatin1String("audio/snd");
+ if (ext == "ulw") return QLatin1String("audio/ulw");
+ if (ext == "wav") return QLatin1String("audio/wav");
+ if (ext == "wax") return QLatin1String("audio/wax");
+ if (ext == "wma") return QLatin1String("audio/wma");
+ return QString();
+}
+
+QString mimeForExtensionVideo(const QString &ext)
+{
+ if (ext == "3g2") return QLatin1String("video/3g2");
+ if (ext == "3gp") return QLatin1String("video/3gp");
+ if (ext == "asf") return QLatin1String("video/asf");
+ if (ext == "asx") return QLatin1String("video/asx");
+ if (ext == "avi") return QLatin1String("video/avi");
+ if (ext == "dif") return QLatin1String("video/dif");
+ if (ext == "dv") return QLatin1String("video/dv");
+ if (ext == "flc") return QLatin1String("video/flc");
+ if (ext == "fli") return QLatin1String("video/fli");
+ if (ext == "m15") return QLatin1String("video/m15");
+ if (ext == "m1a") return QLatin1String("video/m1a");
+ if (ext == "m1s") return QLatin1String("video/m1s");
+ if (ext == "m1v") return QLatin1String("video/m1v");
+ if (ext == "m75") return QLatin1String("video/m75");
+ if (ext == "mkv") return QLatin1String("video/mkv");
+ if (ext == "mp4") return QLatin1String("video/mp4");
+ if (ext == "mpa") return QLatin1String("video/mpa");
+ if (ext == "mpeg") return QLatin1String("video/mpeg");
+ if (ext == "mpg") return QLatin1String("video/mpg");
+ if (ext == "mpg4") return QLatin1String("video/mpg4");
+ if (ext == "mpm") return QLatin1String("video/mpm");
+ if (ext == "mpv") return QLatin1String("video/mpv");
+ if (ext == "vfw") return QLatin1String("video/vfw");
+ if (ext == "wm") return QLatin1String("video/wm");
+ if (ext == "wmv") return QLatin1String("video/wmv");
+ if (ext == "wmx") return QLatin1String("video/wmx");
+ if (ext == "wvx") return QLatin1String("video/wvx");
+ return QString();
+}
+
+QStringList BackendInfo::quickTimeMimeTypes(Scope scope)
+{
+ QStringList mimeTypes;
+ QStringList fileExtensions;
+ ARGUMENT_UNSUPPORTED(scope, Out, NORMAL_ERROR, mimeTypes)
+
+ PhononAutoReleasePool pool;
+ NSArray *fileTypes = [QTMovie movieFileTypes:QTIncludeAllTypes];
+ for (NSString *type in fileTypes){
+ QString formattedType = QString::fromUtf8([type UTF8String]);
+ formattedType = formattedType.remove('\'').remove('.').toLower();
+ QString audioMime = mimeForExtensionAudio(formattedType);
+ QString videoMime = mimeForExtensionVideo(formattedType);
+ if (!audioMime.isEmpty())
+ mimeTypes << audioMime;
+ if (!videoMime.isEmpty())
+ mimeTypes << videoMime;
+ if (audioMime.isEmpty() && videoMime.isEmpty())
+ fileExtensions << QLatin1String("application/x-qt-") + formattedType;
+ }
+ mimeTypes.sort();
+ fileExtensions.sort();
+ return mimeTypes + fileExtensions;
+}
+#endif // QUICKTIME_C_API_AVAILABLE
+
+QStringList BackendInfo::quickTimeCompressionFormats()
+{
+ QStringList result;
+
+#ifdef QUICKTIME_C_API_AVAILABLE
+
+ ComponentInstance component = 0;
+ OSStatus err = OpenADefaultComponent(StandardCompressionType, StandardCompressionSubTypeAudio, &component);
+ BACKEND_ASSERT3(err == noErr, "Could not open component for retrieving awailable compression formats", NORMAL_ERROR, result)
+
+ UInt32 size;
+ err = QTGetComponentPropertyInfo(component, kQTPropertyClass_SCAudio, kQTSCAudioPropertyID_AvailableCompressionFormatNamesList, 0, &size,0);
+ BACKEND_ASSERT3(err == noErr, "Could not get awailable compression formats", NORMAL_ERROR, result)
+
+ CFArrayRef formats[size];
+ err = QTGetComponentProperty(component, kQTPropertyClass_SCAudio, kQTSCAudioPropertyID_AvailableCompressionFormatNamesList, size, &formats, &size);
+ BACKEND_ASSERT3(err == noErr, "Could not get awailable compression formats", NORMAL_ERROR, result)
+
+ CFIndex count = CFArrayGetCount(*formats);
+ for (CFIndex i=0; i<count; ++i){
+ const CFStringRef name = (const struct __CFString *) CFArrayGetValueAtIndex(*formats, i);
+ result << PhononCFString::toQString(name);
+ }
+
+#endif // QUICKTIME_C_API_AVAILABLE
+ return result;
+}
+
+
+QStringList BackendInfo::coreAudioCodecs(Scope scope)
+{
+ QStringList result;
+ UInt32 size;
+ OSStatus err;
+ OSType *formatIDs;
+
+ OSType encodersOrDecoders = (scope == In)
+ ? kAudioFormatProperty_EncodeFormatIDs : kAudioFormatProperty_DecodeFormatIDs;
+
+ err = AudioFormatGetPropertyInfo(encodersOrDecoders, 0, NULL, &size);
+ BACKEND_ASSERT3(err == noErr, "Could not get awailable decoders/encoders", NORMAL_ERROR, result)
+
+ formatIDs = (OSType*)malloc(size);
+ UInt32 numFormats = size / sizeof(OSType);
+ err = AudioFormatGetProperty(encodersOrDecoders, 0, NULL, &size, formatIDs);
+ BACKEND_ASSERT(err == noErr, "Could not get awailable decoders/encoders", NORMAL_ERROR){
+ free(formatIDs);
+ return result;
+ }
+
+ for (UInt32 i=0; i<numFormats; ++i){
+ AudioStreamBasicDescription absd;
+ memset(&absd, 0, sizeof(absd));
+ absd.mFormatID = formatIDs[i];
+
+ CFStringRef name;
+ size = sizeof(CFStringRef);
+ err = AudioFormatGetProperty(kAudioFormatProperty_FormatName, sizeof(absd), &absd, &size, &name);
+ BACKEND_ASSERT(err == noErr, "Could not get awailable decoder/encoder names", NORMAL_ERROR){
+ free(formatIDs);
+ return result;
+ }
+ result << PhononCFString::toQString(name);
+ }
+ free(formatIDs);
+ return result;
+}
+
+QStringList BackendInfo::coreAudioFileTypes(Scope scope)
+{
+ QStringList result;
+ OSStatus err;
+ UInt32 propertySize;
+
+ OSType readOrwrite = (scope == In)
+ ? kAudioFileGlobalInfo_ReadableTypes : kAudioFileGlobalInfo_WritableTypes;
+
+ err = AudioFileGetGlobalInfoSize(readOrwrite, 0, NULL, &propertySize);
+ BACKEND_ASSERT3(err == noErr, "Could not get core audio file types", NORMAL_ERROR, result)
+
+ OSType *types = (OSType*)malloc(propertySize);
+ err = AudioFileGetGlobalInfo(readOrwrite, 0, NULL, &propertySize, types);
+ BACKEND_ASSERT3(err == noErr, "Could not get core audio file types", NORMAL_ERROR, result)
+
+ UInt32 numTypes = propertySize / sizeof(OSType);
+ for (UInt32 i=0; i<numTypes; ++i){
+ CFStringRef name;
+ UInt32 outSize = sizeof(name);
+ err = AudioFileGetGlobalInfo(kAudioFileGlobalInfo_FileTypeName, sizeof(OSType), types+i, &outSize, &name);
+ BACKEND_ASSERT3(err == noErr, "Could not get core audio file type names", NORMAL_ERROR, result)
+ result << PhononCFString::toQString(name);
+ }
+ return result;
+}
+
+}}
+
+QT_END_NAMESPACE
+
diff --git a/src/3rdparty/phonon/qt7/lgpl-2.1.txt b/src/3rdparty/phonon/qt7/lgpl-2.1.txt
new file mode 100644
index 0000000000..5ab7695ab8
--- /dev/null
+++ b/src/3rdparty/phonon/qt7/lgpl-2.1.txt
@@ -0,0 +1,504 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library 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; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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 library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/src/3rdparty/phonon/qt7/lgpl-3.txt b/src/3rdparty/phonon/qt7/lgpl-3.txt
new file mode 100644
index 0000000000..fc8a5de7ed
--- /dev/null
+++ b/src/3rdparty/phonon/qt7/lgpl-3.txt
@@ -0,0 +1,165 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+ This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+ 0. Additional Definitions.
+
+ As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+ "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+ An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+ A "Combined Work" is a work produced by combining or linking an
+Application with the Library. The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+ The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+ The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+ 1. Exception to Section 3 of the GNU GPL.
+
+ You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+ 2. Conveying Modified Versions.
+
+ If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+ a) under this License, provided that you make a good faith effort to
+ ensure that, in the event an Application does not supply the
+ function or data, the facility still operates, and performs
+ whatever part of its purpose remains meaningful, or
+
+ b) under the GNU GPL, with none of the additional permissions of
+ this License applicable to that copy.
+
+ 3. Object Code Incorporating Material from Library Header Files.
+
+ The object code form of an Application may incorporate material from
+a header file that is part of the Library. You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+ a) Give prominent notice with each copy of the object code that the
+ Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the object code with a copy of the GNU GPL and this license
+ document.
+
+ 4. Combined Works.
+
+ You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+ a) Give prominent notice with each copy of the Combined Work that
+ the Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
+ document.
+
+ c) For a Combined Work that displays copyright notices during
+ execution, include the copyright notice for the Library among
+ these notices, as well as a reference directing the user to the
+ copies of the GNU GPL and this license document.
+
+ d) Do one of the following:
+
+ 0) Convey the Minimal Corresponding Source under the terms of this
+ License, and the Corresponding Application Code in a form
+ suitable for, and under terms that permit, the user to
+ recombine or relink the Application with a modified version of
+ the Linked Version to produce a modified Combined Work, in the
+ manner specified by section 6 of the GNU GPL for conveying
+ Corresponding Source.
+
+ 1) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (a) uses at run time
+ a copy of the Library already present on the user's computer
+ system, and (b) will operate properly with a modified version
+ of the Library that is interface-compatible with the Linked
+ Version.
+
+ e) Provide Installation Information, but only if you would otherwise
+ be required to provide such information under section 6 of the
+ GNU GPL, and only to the extent that such information is
+ necessary to install and execute a modified version of the
+ Combined Work produced by recombining or relinking the
+ Application with a modified version of the Linked Version. (If
+ you use option 4d0, the Installation Information must accompany
+ the Minimal Corresponding Source and Corresponding Application
+ Code. If you use option 4d1, you must provide the Installation
+ Information in the manner specified by section 6 of the GNU GPL
+ for conveying Corresponding Source.)
+
+ 5. Combined Libraries.
+
+ You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+ a) Accompany the combined library with a copy of the same work based
+ on the Library, uncombined with any other library facilities,
+ conveyed under the terms of this License.
+
+ b) Give prominent notice with the combined library that part of it
+ is a work based on the Library, and explaining where to find the
+ accompanying uncombined form of the same work.
+
+ 6. Revised Versions of the GNU Lesser General Public License.
+
+ The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+ If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
diff --git a/src/3rdparty/phonon/qt7/medianode.h b/src/3rdparty/phonon/qt7/medianode.h
new file mode 100644
index 0000000000..595e4daa0a
--- /dev/null
+++ b/src/3rdparty/phonon/qt7/medianode.h
@@ -0,0 +1,85 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef Phonon_QT7_MediaNode_H
+#define Phonon_QT7_MediaNode_H
+
+#include <QtCore/QObject>
+#include "backendheader.h"
+#include "medianodeevent.h"
+#include "audioconnection.h"
+#include "videoframe.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace QT7
+{
+ class AudioNode;
+ class AudioGraph;
+ class MediaObject;
+ class AudioConnection;
+
+ class MediaNode : public QObject
+ {
+ Q_OBJECT
+
+ public:
+ enum NodeDescriptionEnum {
+ AudioSource = 1,
+ AudioSink = 2,
+ VideoSource = 4,
+ VideoSink = 8,
+ AudioGraphNode = 16
+ };
+ Q_DECLARE_FLAGS(NodeDescription, NodeDescriptionEnum);
+
+ MediaNode(NodeDescription description, QObject *parent);
+ MediaNode(NodeDescription description, AudioNode *audioPart, QObject *parent);
+ virtual ~MediaNode();
+
+ void setAudioNode(AudioNode *audioPart);
+ bool connectToSink(MediaNode *sink);
+ bool disconnectToSink(MediaNode *sink);
+ AudioConnection *getAudioConnectionToSink(MediaNode *sink);
+
+ void notify(const MediaNodeEvent *event, bool propagate = true);
+ void sendEventToSinks(const MediaNodeEvent *event);
+ virtual void mediaNodeEvent(const MediaNodeEvent *event);
+
+ virtual void updateVideo(VideoFrame &frame);
+ AudioGraph *m_audioGraph;
+
+ AudioNode *m_audioNode;
+ QList<AudioConnection *> m_audioSinkList;
+ QList<AudioConnection *> m_audioSourceList;
+ QList<MediaNode *> m_videoSinkList;
+
+ int availableAudioInputBus();
+ int availableAudioOutputBus();
+
+ NodeDescription m_description;
+ MediaObject *m_owningMediaObject;
+ };
+
+ Q_DECLARE_OPERATORS_FOR_FLAGS(MediaNode::NodeDescription);
+
+}} // namespace Phonon::QT7
+
+QT_END_NAMESPACE
+#endif // Phonon_QT7_MediaNode_H
diff --git a/src/3rdparty/phonon/qt7/medianode.mm b/src/3rdparty/phonon/qt7/medianode.mm
new file mode 100644
index 0000000000..00f8340ded
--- /dev/null
+++ b/src/3rdparty/phonon/qt7/medianode.mm
@@ -0,0 +1,261 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "medianode.h"
+#include "audiograph.h"
+#include "audionode.h"
+#include "backendheader.h"
+
+#include "mediaobject.h"
+#include "audiooutput.h"
+#include "quicktimevideoplayer.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace QT7
+{
+
+MediaNode::MediaNode(NodeDescription description, QObject *parent)
+ : QObject(parent), m_audioGraph(0), m_audioNode(0), m_description(description), m_owningMediaObject(0)
+{
+}
+
+MediaNode::MediaNode(NodeDescription description, AudioNode *audioPart, QObject *parent)
+ : QObject(parent), m_audioGraph(0), m_audioNode(audioPart), m_description(description)
+{
+}
+
+void MediaNode::setAudioNode(AudioNode *audioPart)
+{
+ if (m_audioNode)
+ delete m_audioNode;
+ m_audioNode = audioPart;
+}
+
+MediaNode::~MediaNode()
+{
+ delete m_audioNode;
+ qDeleteAll(m_audioSinkList);
+}
+
+AudioConnection *MediaNode::getAudioConnectionToSink(MediaNode *sink)
+{
+ AudioConnection *connection = 0;
+ for (int i=0; i<m_audioSinkList.size(); ++i){
+ if (m_audioSinkList[i]->isBetween(this, sink)){
+ connection = m_audioSinkList[i];
+ break;
+ }
+ }
+ return connection;
+}
+
+bool MediaNode::connectToSink(MediaNode *sink)
+{
+ if ((m_description & AudioSource) && (sink->m_description & AudioSink)){
+ // Check that they don't belong to different graphs. If they do, but
+ // sink is not connected to any source, accept it:
+ if (m_owningMediaObject && sink->m_owningMediaObject
+ && m_owningMediaObject != sink->m_owningMediaObject
+ && !sink->m_audioSourceList.isEmpty()){
+ return false;
+ }
+
+ // Check that the connection doesn't already exists:
+ AudioConnection *connection = getAudioConnectionToSink(sink);
+ if (connection)
+ return true;
+
+ // Check that there are awailable input/output busses:
+ int inputBus = sink->availableAudioInputBus();
+ int outputBus = availableAudioOutputBus();
+ if (inputBus >= sink->m_audioNode->m_maxInputBusses || outputBus >= m_audioNode->m_maxOutputBusses)
+ return false;
+
+ // All OK. Create connection:
+ connection = new AudioConnection(this, outputBus, sink, inputBus);
+ m_audioSinkList << connection;
+ sink->m_audioSourceList << connection;
+
+ if (m_audioNode->m_audioGraph)
+ m_audioNode->m_audioGraph->connectLate(connection);
+
+ MediaNodeEvent event1(MediaNodeEvent::AudioSinkAdded, connection);
+ notify(&event1, false);
+ MediaNodeEvent event2(MediaNodeEvent::AudioSourceAdded, connection);
+ sink->notify(&event2, false);
+ return true;
+ }
+
+ if ((m_description & VideoSource) && (sink->m_description & VideoSink)){
+ // Check that the connection doesn't already exists:
+ if (m_videoSinkList.contains(sink))
+ return true;
+
+ m_videoSinkList << sink;
+ MediaNodeEvent event1(MediaNodeEvent::VideoSinkAdded, sink);
+ notify(&event1, false);
+ MediaNodeEvent event2(MediaNodeEvent::VideoSourceAdded, this);
+ sink->notify(&event2, false);
+ return true;
+ }
+
+ return false;
+}
+
+bool MediaNode::disconnectToSink(MediaNode *sink)
+{
+ if ((m_description & AudioSource) && (sink->m_description & AudioSink)){
+ AudioConnection *connection = getAudioConnectionToSink(sink);
+ if (!connection)
+ return false;
+
+ m_audioSinkList.removeOne(connection);
+ sink->m_audioSourceList.removeOne(connection);
+
+ if (m_audioNode->m_audioGraph)
+ m_audioNode->m_audioGraph->disconnectLate(connection);
+
+ MediaNodeEvent event1(MediaNodeEvent::AudioSinkRemoved, connection);
+ notify(&event1, false);
+ MediaNodeEvent event2(MediaNodeEvent::AudioSourceRemoved, connection);
+ sink->notify(&event2, false);
+
+ delete connection;
+ return true;
+ }
+
+ if ((m_description & VideoSource) && (sink->m_description & VideoSink)){
+ m_videoSinkList.removeOne(sink);
+
+ MediaNodeEvent event1(MediaNodeEvent::VideoSinkRemoved, sink);
+ notify(&event1, false);
+ MediaNodeEvent event2(MediaNodeEvent::VideoSourceRemoved, this);
+ sink->notify(&event2, false);
+ return true;
+ }
+
+ return false;
+}
+
+int MediaNode::availableAudioInputBus()
+{
+ // Scan through all the connection <u>in</u> to this
+ // node, and find an awailable index:
+ int index = -1;
+ bool available = false;
+
+ while (!available){
+ ++index;
+ available = true;
+ for (int i=0; i<m_audioSourceList.size(); ++i){
+ if (m_audioSourceList[i]->m_sinkInputBus == index){
+ available = false;
+ break;
+ }
+ }
+ }
+ return index;
+}
+
+int MediaNode::availableAudioOutputBus()
+{
+ // Scan through all the connection <u>out</u> from this
+ // node, and find an awailable index:
+ int bus = -1;
+ bool available = false;
+
+ while (!available){
+ ++bus;
+ available = true;
+ for (int i=0; i<m_audioSinkList.size(); ++i){
+ if (m_audioSinkList[i]->m_sourceOutputBus == bus){
+ available = false;
+ break;
+ }
+ }
+ }
+ return bus;
+}
+
+void MediaNode::notify(const MediaNodeEvent *event, bool propagate)
+{
+ // Let subclass handle the event first:
+ mediaNodeEvent(event);
+
+ switch(event->type()){
+ case MediaNodeEvent::AudioGraphAboutToBeDeleted:
+ if (m_audioNode){
+ foreach(AudioConnection *connection, m_audioSinkList)
+ connection->invalidate();
+ }
+ break;
+ case MediaNodeEvent::NewAudioGraph:
+ m_audioGraph = static_cast<AudioGraph *>(event->data());
+ break;
+ case MediaNodeEvent::AudioSinkAdded:
+ case MediaNodeEvent::VideoSinkAdded:
+ if (m_owningMediaObject){
+ MediaNodeEvent e1(MediaNodeEvent::SetMediaObject, m_owningMediaObject);
+ sendEventToSinks(&e1);
+ QRect videoRect = m_owningMediaObject->videoPlayer()->videoRect();
+ MediaNodeEvent e2(MediaNodeEvent::VideoFrameSizeChanged, &videoRect);
+ sendEventToSinks(&e2);
+ }
+ break;
+ case MediaNodeEvent::SetMediaObject:
+ m_owningMediaObject = static_cast<MediaObject *>(event->data());
+ break;
+ default:
+ break;
+ }
+
+ // Inform the audio node as well:
+ if (m_audioNode)
+ m_audioNode->notify(event);
+
+ // And perhaps the sinks:
+ if (propagate)
+ sendEventToSinks(event);
+}
+
+void MediaNode::sendEventToSinks(const MediaNodeEvent *event)
+{
+ for (int i=0; i<m_audioSinkList.size(); ++i)
+ m_audioSinkList[i]->m_sink->notify(event);
+ for (int i=0; i<m_videoSinkList.size(); ++i)
+ m_videoSinkList[i]->notify(event);
+}
+
+void MediaNode::updateVideo(VideoFrame &frame){
+ for (int i=0; i<m_videoSinkList.size(); ++i)
+ m_videoSinkList[i]->updateVideo(frame);
+}
+
+void MediaNode::mediaNodeEvent(const MediaNodeEvent */*event*/)
+{
+ // Override if needed.
+}
+
+}} //namespace Phonon::QT7
+
+QT_END_NAMESPACE
+
+#include "moc_medianode.cpp"
+
diff --git a/src/3rdparty/phonon/qt7/medianodeevent.h b/src/3rdparty/phonon/qt7/medianodeevent.h
new file mode 100644
index 0000000000..ad6e2123f1
--- /dev/null
+++ b/src/3rdparty/phonon/qt7/medianodeevent.h
@@ -0,0 +1,71 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef Phonon_QT7_MEDIANODEEVENT_H
+#define Phonon_QT7_MEDIANODEEVENT_H
+
+#include <QtCore/qnamespace.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace QT7
+{
+ class QuickTimeVideoPlayer;
+
+ class MediaNodeEvent
+ {
+ public:
+ enum Type {
+ AudioGraphAboutToBeDeleted,
+ NewAudioGraph,
+ AudioGraphInitialized,
+ AudioGraphCannotPlay,
+ AboutToRestartAudioStream,
+ RestartAudioStreamRequest,
+ VideoSinkAdded,
+ VideoSinkRemoved,
+ AudioSinkAdded,
+ AudioSinkRemoved,
+ VideoSourceAdded,
+ VideoSourceRemoved,
+ AudioSourceAdded,
+ AudioSourceRemoved,
+ VideoOutputCountChanged,
+ VideoFrameSizeChanged,
+ SetMediaObject,
+ StartConnectionChange,
+ EndConnectionChange,
+ MediaPlaying
+ };
+
+ MediaNodeEvent(Type type, void *data = 0);
+ virtual ~MediaNodeEvent();
+ inline Type type() const{ return eventType; };
+ inline void* data() const { return eventData; };
+
+ private:
+ Type eventType;
+ void *eventData;
+ };
+
+}} // namespace Phonon::QT7
+
+QT_END_NAMESPACE
+
+#endif // Phonon_QT7_MEDIANODEEVENT_H
diff --git a/src/3rdparty/phonon/qt7/medianodeevent.mm b/src/3rdparty/phonon/qt7/medianodeevent.mm
new file mode 100644
index 0000000000..664fbbc22c
--- /dev/null
+++ b/src/3rdparty/phonon/qt7/medianodeevent.mm
@@ -0,0 +1,37 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "medianodeevent.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace QT7
+{
+
+MediaNodeEvent::MediaNodeEvent(Type type, void *data) : eventType(type), eventData(data)
+{
+}
+
+MediaNodeEvent::~MediaNodeEvent()
+{
+}
+
+}} // namespace Phonon::QT7
+
+QT_END_NAMESPACE
diff --git a/src/3rdparty/phonon/qt7/medianodevideopart.h b/src/3rdparty/phonon/qt7/medianodevideopart.h
new file mode 100644
index 0000000000..fb1f89ce86
--- /dev/null
+++ b/src/3rdparty/phonon/qt7/medianodevideopart.h
@@ -0,0 +1,42 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef Phonon_QT7_MEDIANODEVIDEOPART_H
+#define Phonon_QT7_MEDIANODEVIDEOPART_H
+
+#include <QtCore/qnamespace.h>
+#include "backendheader.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace QT7
+{
+ class MediaNodeVideoPart
+ {
+ public:
+ MediaNodeVideoPart();
+ virtual ~MediaNodeVideoPart();
+ virtual void updateVideo(void *ciImage) = 0;
+ };
+
+}} // namespace Phonon::QT7
+
+QT_END_NAMESPACE
+
+#endif // Phonon_QT7_MEDIANODEVIDEOPART_H
diff --git a/src/3rdparty/phonon/qt7/medianodevideopart.mm b/src/3rdparty/phonon/qt7/medianodevideopart.mm
new file mode 100644
index 0000000000..da060da8f2
--- /dev/null
+++ b/src/3rdparty/phonon/qt7/medianodevideopart.mm
@@ -0,0 +1,37 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "medianodevideopart.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace QT7
+{
+
+MediaNodeVideoPart::MediaNodeVideoPart()
+{
+}
+
+MediaNodeVideoPart::~MediaNodeVideoPart()
+{
+}
+
+}}
+
+QT_END_NAMESPACE
diff --git a/src/3rdparty/phonon/qt7/mediaobject.h b/src/3rdparty/phonon/qt7/mediaobject.h
new file mode 100644
index 0000000000..27949ec756
--- /dev/null
+++ b/src/3rdparty/phonon/qt7/mediaobject.h
@@ -0,0 +1,171 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef Phonon_QT7_MEDIAOBJECT_H
+#define Phonon_QT7_MEDIAOBJECT_H
+
+#include <QtCore/QStringList>
+#include <QtCore/QTime>
+#include <phonon/mediaobjectinterface.h>
+#include <phonon/addoninterface.h>
+
+#include "medianode.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace QT7
+{
+ class QuickTimeVideoPlayer;
+ class QuickTimeAudioPlayer;
+ class QuickTimeMetaData;
+ class AudioGraph;
+ class MediaObjectAudioNode;
+
+ class MediaObject : public MediaNode,
+ public Phonon::MediaObjectInterface, public Phonon::AddonInterface
+ {
+ Q_OBJECT
+ Q_INTERFACES(Phonon::MediaObjectInterface Phonon::AddonInterface)
+
+ public:
+ MediaObject(QObject *parent);
+ ~MediaObject();
+
+ QStringList availableAudioStreams() const;
+ QStringList availableVideoStreams() const;
+ QStringList availableSubtitleStreams() const;
+ QString currentAudioStream(const QObject *audioPath) const;
+ QString currentVideoStream(const QObject *videoPath) const;
+ QString currentSubtitleStream(const QObject *videoPath) const;
+
+ void setCurrentAudioStream(const QString &streamName,const QObject *audioPath);
+ void setCurrentVideoStream(const QString &streamName,const QObject *videoPath);
+ void setCurrentSubtitleStream(const QString &streamName,const QObject *videoPath);
+
+ void play();
+ void pause();
+ void stop();
+ void seek(qint64 milliseconds);
+
+ qint32 tickInterval() const;
+ void setTickInterval(qint32 interval);
+ bool hasVideo() const;
+ bool isSeekable() const;
+ qint64 currentTime() const;
+ Phonon::State state() const;
+
+ QString errorString() const;
+ Phonon::ErrorType errorType() const;
+
+ qint64 totalTime() const;
+ MediaSource source() const;
+ void setSource(const MediaSource &);
+ void setNextSource(const MediaSource &source);
+ qint32 prefinishMark() const;
+ void setPrefinishMark(qint32);
+ qint32 transitionTime() const;
+ void setTransitionTime(qint32);
+ bool hasInterface(Interface interface) const;
+ QVariant interfaceCall(Interface interface, int command, const QList<QVariant> &arguments = QList<QVariant>());
+
+ QuickTimeVideoPlayer* videoPlayer() const;
+ QuickTimeAudioPlayer* audioPlayer() const;
+
+ void setVolumeOnMovie(float volume);
+ bool setAudioDeviceOnMovie(int id);
+
+ int videoOutputCount();
+
+ signals:
+ void stateChanged(Phonon::State,Phonon::State);
+ void tick(qint64);
+ void seekableChanged(bool);
+ void hasVideoChanged(bool);
+ void bufferStatus(int);
+ void finished();
+ void aboutToFinish();
+ void prefinishMarkReached(qint32);
+ void totalTimeChanged(qint64);
+ void metaDataChanged(QMultiMap<QString,QString>);
+ void currentSourceChanged(const MediaSource &newSource);
+
+ protected:
+ void mediaNodeEvent(const MediaNodeEvent *event);
+ bool event(QEvent *event);
+
+ private:
+ enum AudioSystem {AS_Unset, AS_Video, AS_Graph, AS_Silent} m_audioSystem;
+ Phonon::State m_state;
+
+ QuickTimeVideoPlayer *m_videoPlayer;
+ QuickTimeAudioPlayer *m_audioPlayer;
+ QuickTimeVideoPlayer *m_nextVideoPlayer;
+ QuickTimeAudioPlayer *m_nextAudioPlayer;
+ MediaObjectAudioNode *m_mediaObjectAudioNode;
+ QuickTimeMetaData *m_metaData;
+
+ qint32 m_tickInterval;
+ qint32 m_transitionTime;
+ quint32 m_prefinishMark;
+ quint32 m_currentTime;
+ float m_percentageLoaded;
+
+ int m_tickTimer;
+ int m_bufferTimer;
+ int m_rapidTimer;
+
+ bool m_waitNextSwap;
+ int m_swapTimeLeft;
+ QTime m_swapTime;
+
+ void synchAudioVideo();
+ void updateCurrentTime();
+ void swapCurrentWithNext(qint32 transitionTime);
+ bool setState(Phonon::State state);
+ void pause_internal();
+ void play_internal();
+ void setupAudioSystem();
+ void updateTimer(int &timer, int interval);
+ void bufferAudioVideo();
+ void updateRapidly();
+ void updateCrossFade();
+ void updateAudioBuffers();
+ void updateLipSynch(int allowedOffset);
+ void updateVideoFrames();
+ void updateBufferStatus();
+ void setMute(bool mute);
+ void inspectAudioGraphRecursive(AudioConnection *connection, int &effectCount, int &outputCount);
+ void inspectVideoGraphRecursive(MediaNode *node, int &effectCount, int &outputCount);
+ void inspectGraph();
+ bool isCrossFading();
+
+ QString m_errorString;
+ Phonon::ErrorType m_errorType;
+ bool checkForError();
+
+ int m_audioEffectCount;
+ int m_audioOutputCount;
+ int m_videoEffectCount;
+ int m_videoOutputCount;
+ };
+
+}} //namespace Phonon::QT7
+
+QT_END_NAMESPACE
+#endif // Phonon_QT7_MEDIAOBJECT_H
diff --git a/src/3rdparty/phonon/qt7/mediaobject.mm b/src/3rdparty/phonon/qt7/mediaobject.mm
new file mode 100644
index 0000000000..002c33753b
--- /dev/null
+++ b/src/3rdparty/phonon/qt7/mediaobject.mm
@@ -0,0 +1,852 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <QtCore/QEvent>
+#include "mediaobject.h"
+#include "backendheader.h"
+#include "videowidget.h"
+#include "videoframe.h"
+#include "audiooutput.h"
+#include "quicktimevideoplayer.h"
+#include "quicktimemetadata.h"
+#include "audiograph.h"
+#include "mediaobjectaudionode.h"
+#include "quicktimeaudioplayer.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace QT7
+{
+
+MediaObject::MediaObject(QObject *parent) : MediaNode(AudioSource | VideoSource, parent)
+{
+ m_owningMediaObject = this;
+ m_state = Phonon::LoadingState;
+
+ m_videoPlayer = new QuickTimeVideoPlayer();
+ m_audioPlayer = new QuickTimeAudioPlayer();
+ m_nextVideoPlayer = new QuickTimeVideoPlayer();
+ m_nextAudioPlayer = new QuickTimeAudioPlayer();
+ m_mediaObjectAudioNode = new MediaObjectAudioNode(m_audioPlayer, m_nextAudioPlayer);
+ setAudioNode(m_mediaObjectAudioNode);
+
+ m_metaData = new QuickTimeMetaData();
+ m_audioGraph = new AudioGraph(this);
+
+ m_tickInterval = 0;
+ m_prefinishMark = 0;
+ m_currentTime = 0;
+ m_transitionTime = 0;
+ m_percentageLoaded = 0;
+ m_waitNextSwap = false;
+ m_audioEffectCount = 0;
+ m_audioOutputCount = 0;
+ m_videoEffectCount = 0;
+ m_videoOutputCount = 0;
+ m_audioSystem = AS_Unset;
+ m_errorType = Phonon::NoError;
+
+ m_tickTimer = 0;
+ m_bufferTimer = 0;
+ m_rapidTimer = 0;
+
+ checkForError();
+}
+
+MediaObject::~MediaObject()
+{
+ // m_mediaObjectAudioNode is owned by super class.
+ m_audioPlayer->unsetVideoPlayer();
+ m_nextAudioPlayer->unsetVideoPlayer();
+ delete m_videoPlayer;
+ delete m_nextVideoPlayer;
+ delete m_metaData;
+ checkForError();
+}
+
+bool MediaObject::setState(Phonon::State state)
+{
+ Phonon::State prevState = m_state;
+ m_state = state;
+ if (prevState != m_state){
+ emit stateChanged(m_state, prevState);
+ if (m_state != state){
+ // End-application did something
+ // upon receiving the signal.
+ return false;
+ }
+ }
+ return true;
+}
+
+void MediaObject::inspectAudioGraphRecursive(AudioConnection *connection, int &effectCount, int &outputCount)
+{
+ if ((connection->m_sink->m_description & (AudioSource | AudioSink)) == (AudioSource | AudioSink))
+ ++effectCount;
+ else if (connection->m_sink->m_description & AudioSink)
+ ++outputCount;
+
+ for (int i=0; i<connection->m_sink->m_audioSinkList.size(); ++i)
+ inspectAudioGraphRecursive(connection->m_sink->m_audioSinkList[i], effectCount, outputCount);
+}
+
+void MediaObject::inspectVideoGraphRecursive(MediaNode *node, int &effectCount, int &outputCount)
+{
+ if ((node->m_description & (VideoSource | VideoSink)) == (VideoSource | VideoSink))
+ ++effectCount;
+ else if (node->m_description & VideoSink)
+ ++outputCount;
+
+ for (int i=0; i<node->m_videoSinkList.size(); ++i)
+ inspectVideoGraphRecursive(node->m_videoSinkList[i], effectCount, outputCount);
+}
+
+void MediaObject::inspectGraph()
+{
+ // Inspect the graph to check wether there are any
+ // effects or outputs connected. This will have
+ // influence on the audio system and video system that ends up beeing used:
+ int prevVideoOutputCount = m_videoOutputCount;
+ m_audioEffectCount = 0;
+ m_audioOutputCount = 0;
+ m_videoEffectCount = 0;
+ m_videoOutputCount = 0;
+ AudioConnection rootConnection(this);
+ inspectAudioGraphRecursive(&rootConnection, m_audioEffectCount, m_audioOutputCount);
+ inspectVideoGraphRecursive(this, m_videoEffectCount, m_videoOutputCount);
+
+ if (m_videoOutputCount != prevVideoOutputCount){
+ MediaNodeEvent e1(MediaNodeEvent::VideoOutputCountChanged, &m_videoOutputCount);
+ notify(&e1);
+ }
+}
+
+void MediaObject::setupAudioSystem()
+{
+ // Select which audio system to use:
+ AudioSystem newAudioSystem = AS_Unset;
+ if (!m_audioOutputCount || !m_videoPlayer->canPlayMedia()){
+ newAudioSystem = AS_Silent;
+ } else if (m_audioEffectCount == 0){
+ newAudioSystem = AS_Video;
+ } else if (QSysInfo::MacintoshVersion < QSysInfo::MV_10_4){
+ newAudioSystem = AS_Video;
+ SET_ERROR("Audio effects are not supported for Mac OS 10.3 and below", NORMAL_ERROR);
+ } else if (m_videoPlayer->isDrmProtected()){
+ newAudioSystem = AS_Video;
+ SET_ERROR("Audio effects are not supported for DRM protected media", NORMAL_ERROR);
+ } else if (m_audioGraph->graphCannotPlay()){
+ newAudioSystem = AS_Video;
+ SET_ERROR("Audio effects are not supported for the current codec", NORMAL_ERROR);
+#ifdef QUICKTIME_C_API_AVAILABLE
+ } else {
+ newAudioSystem = AS_Graph;
+ }
+#else
+ } else {
+ newAudioSystem = AS_Video;
+ SET_ERROR("Audio effects are not supported for the 64-bit version of the Phonon QT7 backend", NORMAL_ERROR);
+ }
+#endif
+
+ if (newAudioSystem == m_audioSystem)
+ return;
+
+ // Enable selected audio system:
+ m_audioSystem = newAudioSystem;
+ switch (newAudioSystem){
+ case AS_Silent:
+ m_audioGraph->stop();
+ m_videoPlayer->enableAudio(false);
+ m_nextVideoPlayer->enableAudio(false);
+ m_audioPlayer->enableAudio(false);
+ m_nextAudioPlayer->enableAudio(false);
+ break;
+ case AS_Graph:
+ if (m_state == Phonon::PausedState)
+ m_audioGraph->prepare();
+ else
+ m_audioGraph->start();
+ // Starting the graph can lead to a recursive call
+ // telling us that we must direct audio through
+ // video. If that has happened, we must not proceed:
+ if (m_audioSystem != AS_Graph)
+ return;
+ m_videoPlayer->enableAudio(false);
+ m_nextVideoPlayer->enableAudio(false);
+ m_audioPlayer->enableAudio(true);
+ m_audioPlayer->seek(m_videoPlayer->currentTime());
+ m_nextAudioPlayer->enableAudio(true);
+ m_audioPlayer->seek(m_videoPlayer->currentTime());
+ m_nextAudioPlayer->seek(m_nextVideoPlayer->currentTime());
+ break;
+ case AS_Video:
+ case AS_Unset:
+ m_audioGraph->stop();
+ m_videoPlayer->enableAudio(true);
+ m_nextVideoPlayer->enableAudio(true);
+ m_audioPlayer->enableAudio(false);
+ m_nextAudioPlayer->enableAudio(false);
+ m_videoPlayer->seek(m_audioPlayer->currentTime());
+ m_nextVideoPlayer->seek(m_nextAudioPlayer->currentTime());
+ break;
+ }
+}
+
+void MediaObject::setSource(const MediaSource &source)
+{
+ IMPLEMENTED;
+ PhononAutoReleasePool pool;
+ setState(Phonon::LoadingState);
+
+ // Save current state for event/signal handling below:
+ bool prevHasVideo = m_videoPlayer->hasVideo();
+ qint64 prevTotalTime = totalTime();
+ m_waitNextSwap = false;
+
+ // Cancel cross-fade if any:
+ m_nextVideoPlayer->pause();
+ m_nextAudioPlayer->pause();
+ m_mediaObjectAudioNode->cancelCrossFade();
+
+ // Set new source:
+ m_audioPlayer->unsetVideoPlayer();
+ m_videoPlayer->setMediaSource(source);
+ m_audioPlayer->setVideoPlayer(m_videoPlayer);
+ m_metaData->setVideo(m_videoPlayer);
+
+ m_audioGraph->updateStreamSpecifications();
+ m_nextAudioPlayer->unsetVideoPlayer();
+ m_nextVideoPlayer->unsetVideo();
+ m_currentTime = 0;
+
+ // Emit/notify information about the new source:
+ QRect videoRect = m_videoPlayer->videoRect();
+ MediaNodeEvent e1(MediaNodeEvent::VideoFrameSizeChanged, &videoRect);
+ notify(&e1);
+
+ // Clear video widgets:
+ VideoFrame emptyFrame;
+ updateVideo(emptyFrame);
+
+ emit currentSourceChanged(source);
+ emit metaDataChanged(m_metaData->metaData());
+
+ if (prevHasVideo != m_videoPlayer->hasVideo())
+ emit hasVideoChanged(m_videoPlayer->hasVideo());
+ if (prevTotalTime != totalTime())
+ emit totalTimeChanged(totalTime());
+ if (checkForError())
+ return;
+ if (!m_videoPlayer->isDrmAuthorized())
+ SET_ERROR("This computer is not authorized to play current media (DRM protected).", FATAL_ERROR)
+ if (checkForError())
+ return;
+ if (!m_videoPlayer->canPlayMedia())
+ SET_ERROR("Cannot play media.", FATAL_ERROR)
+
+ // The state might have changed from LoadingState
+ // as a response to an error state change. So we
+ // need to check it before stopping:
+ if (m_state == Phonon::LoadingState)
+ stop();
+
+ setupAudioSystem();
+ checkForError();
+}
+
+void MediaObject::setNextSource(const MediaSource &source)
+{
+ IMPLEMENTED;
+ m_nextAudioPlayer->unsetVideoPlayer();
+ m_nextVideoPlayer->setMediaSource(source);
+ m_nextAudioPlayer->setVideoPlayer(m_nextVideoPlayer);
+ checkForError();
+}
+
+void MediaObject::swapCurrentWithNext(qint32 transitionTime)
+{
+ PhononAutoReleasePool pool;
+ setState(Phonon::LoadingState);
+ // Save current state for event/signal handling below:
+ bool prevHasVideo = m_videoPlayer->hasVideo();
+ qint64 prevTotalTime = totalTime();
+
+ qSwap(m_audioPlayer, m_nextAudioPlayer);
+ qSwap(m_videoPlayer, m_nextVideoPlayer);
+ m_mediaObjectAudioNode->startCrossFade(transitionTime);
+ m_audioGraph->updateStreamSpecifications();
+ m_metaData->setVideo(m_videoPlayer);
+
+ m_waitNextSwap = false;
+ m_currentTime = 0;
+
+ // Emit/notify information about the new source:
+ QRect videoRect = m_videoPlayer->videoRect();
+ MediaNodeEvent e1(MediaNodeEvent::VideoFrameSizeChanged, &videoRect);
+ notify(&e1);
+
+ emit currentSourceChanged(m_videoPlayer->mediaSource());
+ emit metaDataChanged(m_metaData->metaData());
+
+ if (prevHasVideo != m_videoPlayer->hasVideo())
+ emit hasVideoChanged(m_videoPlayer->hasVideo());
+ if (prevTotalTime != totalTime())
+ emit totalTimeChanged(totalTime());
+ if (checkForError())
+ return;
+ if (!m_videoPlayer->isDrmAuthorized())
+ SET_ERROR("This computer is not authorized to play current media (DRM protected).", FATAL_ERROR)
+ if (checkForError())
+ return;
+ if (!m_videoPlayer->canPlayMedia())
+ SET_ERROR("Cannot play next media.", FATAL_ERROR)
+
+ setupAudioSystem();
+ checkForError();
+ if (m_state == Phonon::LoadingState){
+ if (setState(Phonon::PlayingState))
+ play_internal();
+ checkForError();
+ }
+}
+
+void MediaObject::updateTimer(int &timer, int interval)
+{
+ if (timer)
+ killTimer(timer);
+ timer = 0;
+ if (interval >= 0)
+ timer = startTimer(interval);
+}
+
+void MediaObject::play_internal()
+{
+ // Play main audio/video:
+ m_videoPlayer->play();
+ m_audioPlayer->play();
+ updateLipSynch(0);
+ // Play old audio/video to finish cross-fade:
+ if (m_nextVideoPlayer->currentTime() > 0){
+ m_nextVideoPlayer->play();
+ m_nextAudioPlayer->play();
+ }
+ bufferAudioVideo();
+ updateTimer(m_rapidTimer, 100);
+}
+
+void MediaObject::pause_internal()
+{
+ m_audioGraph->stop();
+ m_audioPlayer->pause();
+ m_nextAudioPlayer->pause();
+ m_videoPlayer->pause();
+ m_nextVideoPlayer->pause();
+ updateTimer(m_rapidTimer, -1);
+ updateTimer(m_bufferTimer, -1);
+
+ if (m_waitNextSwap)
+ m_swapTimeLeft = m_swapTime.msecsTo(QTime::currentTime());
+}
+
+void MediaObject::play()
+{
+ IMPLEMENTED;
+ if (m_state == Phonon::PlayingState)
+ return;
+ if (m_waitNextSwap){
+ // update swap time after pause:
+ m_swapTime = QTime::currentTime();
+ m_swapTime.addMSecs(m_swapTimeLeft);
+ setState(Phonon::PlayingState);
+ return;
+ }
+ if (m_currentTime == m_videoPlayer->duration())
+ return;
+ if (!m_videoPlayer->canPlayMedia())
+ return;
+ if (!setState(Phonon::PlayingState))
+ return;
+ if (m_audioSystem == AS_Graph){
+ m_audioGraph->start();
+ m_mediaObjectAudioNode->setMute(true);
+ }
+ // Inform the graph that we are about to play:
+ bool playing = true;
+ MediaNodeEvent e1(MediaNodeEvent::MediaPlaying, &playing);
+ notify(&e1);
+ // Start to play:
+ play_internal();
+ m_mediaObjectAudioNode->setMute(false);
+ checkForError();
+}
+
+void MediaObject::pause()
+{
+ IMPLEMENTED;
+ if (m_state == Phonon::PausedState)
+ return;
+ if (!setState(Phonon::PausedState))
+ return;
+ pause_internal();
+ // Inform the graph that we are no longer playing:
+ bool playing = false;
+ MediaNodeEvent e1(MediaNodeEvent::MediaPlaying, &playing);
+ notify(&e1);
+ // But be prepared:
+ if (m_audioSystem == AS_Graph)
+ m_audioGraph->prepare();
+ checkForError();
+}
+
+void MediaObject::stop()
+{
+ IMPLEMENTED;
+ if (m_state == Phonon::StoppedState)
+ return;
+ if (!setState(Phonon::StoppedState))
+ return;
+ m_waitNextSwap = false;
+ m_nextVideoPlayer->unsetVideo();
+ m_nextAudioPlayer->unsetVideoPlayer();
+ pause_internal();
+ seek(0);
+ checkForError();
+}
+
+void MediaObject::seek(qint64 milliseconds)
+{
+ IMPLEMENTED;
+ if (m_state == Phonon::ErrorState)
+ return;
+
+ // Stop cross-fade if any:
+ m_nextVideoPlayer->unsetVideo();
+ m_nextAudioPlayer->unsetVideoPlayer();
+ m_mediaObjectAudioNode->cancelCrossFade();
+
+ // Seek to new position:
+ m_mediaObjectAudioNode->setMute(true);
+ m_videoPlayer->seek(milliseconds);
+ m_audioPlayer->seek(m_videoPlayer->currentTime());
+ m_mediaObjectAudioNode->setMute(false);
+
+ // Update time and cancel pending swap:
+ if (m_currentTime < m_videoPlayer->duration())
+ m_waitNextSwap = false;
+
+ updateCurrentTime();
+ if (m_state != Phonon::PlayingState)
+ updateVideoFrames();
+ checkForError();
+}
+
+QStringList MediaObject::availableAudioStreams() const
+{
+ NOT_IMPLEMENTED;
+ return QStringList();
+}
+
+QStringList MediaObject::availableVideoStreams() const
+{
+ NOT_IMPLEMENTED;
+ return QStringList();
+}
+
+QStringList MediaObject::availableSubtitleStreams() const
+{
+ NOT_IMPLEMENTED;
+ return QStringList();
+}
+
+QString MediaObject::currentAudioStream(const QObject */*audioPath*/) const
+{
+ NOT_IMPLEMENTED;
+ return QString();
+}
+
+QString MediaObject::currentVideoStream(const QObject */*videoPath*/) const
+{
+ NOT_IMPLEMENTED;
+ return QString();
+}
+
+QString MediaObject::currentSubtitleStream(const QObject */*videoPath*/) const
+{
+ NOT_IMPLEMENTED;
+ return QString();
+}
+
+void MediaObject::setCurrentAudioStream(const QString &/*streamName*/,const QObject */*audioPath*/)
+{
+ NOT_IMPLEMENTED;
+}
+
+void MediaObject::setCurrentVideoStream(const QString &/*streamName*/,const QObject */*videoPath*/)
+{
+ NOT_IMPLEMENTED;
+}
+
+void MediaObject::setCurrentSubtitleStream(const QString &/*streamName*/,const QObject */*videoPath*/)
+{
+ NOT_IMPLEMENTED;
+}
+
+int MediaObject::videoOutputCount()
+{
+ return m_videoOutputCount;
+}
+
+void MediaObject::synchAudioVideo()
+{
+ if (m_state != Phonon::PlayingState)
+ return;
+ if (m_videoSinkList.isEmpty() || m_audioSinkList.isEmpty())
+ return;
+
+ seek(m_currentTime);
+ checkForError();
+}
+
+qint32 MediaObject::tickInterval() const
+{
+ IMPLEMENTED;
+ return m_tickInterval;
+}
+
+void MediaObject::setTickInterval(qint32 interval)
+{
+ IMPLEMENTED;
+ m_tickInterval = interval;
+ if (m_tickInterval > 0)
+ m_tickTimer = startTimer(m_tickInterval);
+ else{
+ killTimer(m_tickTimer);
+ m_tickTimer = 0;
+ }
+}
+
+bool MediaObject::hasVideo() const
+{
+ IMPLEMENTED;
+ return m_videoPlayer ? m_videoPlayer->hasVideo() : false;
+}
+
+bool MediaObject::isSeekable() const
+{
+ IMPLEMENTED;
+ return m_videoPlayer ? m_videoPlayer->isSeekable() : false;
+}
+
+qint64 MediaObject::currentTime() const
+{
+ IMPLEMENTED_SILENT;
+ const_cast<MediaObject *>(this)->updateCurrentTime();
+ return m_currentTime;
+}
+
+void MediaObject::updateCurrentTime()
+{
+ quint64 lastUpdateTime = m_currentTime;
+ m_currentTime = (m_audioSystem == AS_Graph) ? m_audioPlayer->currentTime() : m_videoPlayer->currentTime();
+ quint64 total = m_videoPlayer->duration();
+
+ // Check if it's time to emit aboutToFinish:
+ quint32 mark = qMax(quint64(0), qMin(total, total + m_transitionTime - 2000));
+ if (lastUpdateTime < mark && mark <= m_currentTime)
+ emit aboutToFinish();
+
+ // Check if it's time to emit prefinishMarkReached:
+ mark = qMax(quint64(0), total - m_prefinishMark);
+ if (lastUpdateTime < mark && mark <= m_currentTime)
+ emit prefinishMarkReached(total - m_currentTime);
+
+ if (m_nextVideoPlayer->state() == QuickTimeVideoPlayer::NoMedia){
+ // There is no next source in que.
+ // Check if it's time to emit finished:
+ if (lastUpdateTime < m_currentTime && m_currentTime == total){
+ emit finished();
+ m_currentTime = (m_audioSystem == AS_Graph) ? m_audioPlayer->currentTime() : m_videoPlayer->currentTime();
+ if (m_state == Phonon::PlayingState && m_currentTime == total)
+ pause();
+ }
+ } else {
+ // We have a next source.
+ // Check if it's time to swap to next source:
+ mark = qMax(quint64(0), total + m_transitionTime);
+ if (m_waitNextSwap && m_state == Phonon::PlayingState &&
+ m_transitionTime < m_swapTime.msecsTo(QTime::currentTime())){
+ swapCurrentWithNext(0);
+ } else if (mark >= total){
+ if (lastUpdateTime < total && total == m_currentTime){
+ m_swapTime = QTime::currentTime();
+ m_swapTime.addMSecs(mark - total);
+ m_waitNextSwap = true;
+ }
+ } else if (lastUpdateTime < mark && mark <= m_currentTime){
+ swapCurrentWithNext(total - m_currentTime);
+ }
+ }
+}
+
+qint64 MediaObject::totalTime() const
+{
+ IMPLEMENTED_SILENT;
+ return m_videoPlayer->duration();
+}
+
+Phonon::State MediaObject::state() const
+{
+ IMPLEMENTED;
+ return m_state;
+}
+
+QString MediaObject::errorString() const
+{
+ IMPLEMENTED;
+ return m_errorString;
+}
+
+Phonon::ErrorType MediaObject::errorType() const
+{
+ IMPLEMENTED;
+ return m_errorType;
+}
+
+bool MediaObject::checkForError()
+{
+ int type = gGetErrorType();
+ if (type == NO_ERROR)
+ return false;
+
+ m_errorType = (type == NORMAL_ERROR) ? Phonon::NormalError : Phonon::FatalError;
+ m_errorString = gGetErrorString();
+ pause_internal();
+ gClearError();
+ setState(Phonon::ErrorState);
+ return true;
+}
+
+QuickTimeVideoPlayer* MediaObject::videoPlayer() const
+{
+ return m_videoPlayer;
+}
+
+MediaSource MediaObject::source() const
+{
+ IMPLEMENTED;
+ return m_videoPlayer->mediaSource();
+}
+
+qint32 MediaObject::prefinishMark() const
+{
+ IMPLEMENTED;
+ return m_prefinishMark;
+}
+
+void MediaObject::setPrefinishMark(qint32 mark)
+{
+ IMPLEMENTED;
+ m_prefinishMark = mark;
+}
+
+qint32 MediaObject::transitionTime() const
+{
+ IMPLEMENTED;
+ return m_transitionTime;
+}
+
+void MediaObject::setTransitionTime(qint32 transitionTime)
+{
+ IMPLEMENTED;
+ m_transitionTime = transitionTime;
+}
+
+void MediaObject::setVolumeOnMovie(float volume)
+{
+ m_videoPlayer->setMasterVolume(volume);
+ m_nextVideoPlayer->setMasterVolume(volume);
+}
+
+bool MediaObject::setAudioDeviceOnMovie(int id)
+{
+ m_nextVideoPlayer->setAudioDevice(id);
+ return m_videoPlayer->setAudioDevice(id);
+}
+
+void MediaObject::updateCrossFade()
+{
+ m_mediaObjectAudioNode->updateCrossFade(m_currentTime);
+ // Clean-up previous movie if done fading:
+ if (m_mediaObjectAudioNode->m_fadeDuration == 0){
+ if (m_nextVideoPlayer->isPlaying() || m_nextAudioPlayer->isPlaying()){
+ m_nextVideoPlayer->unsetVideo();
+ m_nextAudioPlayer->unsetVideoPlayer();
+ }
+ }
+}
+
+void MediaObject::updateBufferStatus()
+{
+ float percent = m_videoPlayer->percentageLoaded();
+ if (percent != m_percentageLoaded){
+ m_percentageLoaded = percent;
+ emit bufferStatus(m_percentageLoaded * 100);
+ }
+}
+
+void MediaObject::updateAudioBuffers()
+{
+ // Schedule audio slices:
+ m_audioPlayer->scheduleAudioToGraph();
+ m_nextAudioPlayer->scheduleAudioToGraph();
+}
+
+bool MediaObject::isCrossFading()
+{
+ return m_mediaObjectAudioNode->isCrossFading();
+}
+
+void MediaObject::updateVideoFrames()
+{
+ // Draw next frame if awailable:
+ if (m_videoPlayer->videoFrameChanged()){
+ updateLipSynch(50);
+ VideoFrame frame(m_videoPlayer);
+ if (m_nextVideoPlayer->isPlaying()
+ && m_nextVideoPlayer->hasVideo()
+ && isCrossFading()){
+ VideoFrame bgFrame(m_nextVideoPlayer);
+ frame.setBackgroundFrame(bgFrame);
+ frame.setBaseOpacity(m_mediaObjectAudioNode->m_volume1);
+ }
+
+ // Send the frame through the graph:
+ updateVideo(frame);
+ checkForError();
+ }
+}
+
+void MediaObject::updateLipSynch(int allowedOffset)
+{
+ if (m_audioSystem != AS_Graph || !m_audioGraph->isRunning())
+ return;
+ if (m_videoSinkList.isEmpty() || m_audioSinkList.isEmpty())
+ return;
+
+ if (m_videoPlayer->hasVideo()){
+ qint64 diff = m_audioPlayer->currentTime() - m_videoPlayer->currentTime();
+ if (-allowedOffset > diff || diff > allowedOffset)
+ m_audioPlayer->seek(m_videoPlayer->currentTime());
+ }
+
+ if (isCrossFading() && m_nextVideoPlayer->hasVideo()){
+ qint64 diff = m_nextAudioPlayer->currentTime() - m_nextVideoPlayer->currentTime();
+ if (-(allowedOffset*2) > diff || diff > (allowedOffset*2))
+ m_nextAudioPlayer->seek(m_nextVideoPlayer->currentTime());
+ }
+}
+
+void MediaObject::bufferAudioVideo()
+{
+ long nextVideoUpdate = m_videoPlayer->hasVideo() ? 30 : INT_MAX;
+ long nextAudioUpdate = m_audioPlayer->regularTaskFrequency();
+ updateAudioBuffers();
+ updateVideoFrames();
+ if (m_state == Phonon::PlayingState)
+ updateTimer(m_bufferTimer, qMin(nextVideoUpdate, nextAudioUpdate));
+}
+
+void MediaObject::updateRapidly()
+{
+ updateCurrentTime();
+ updateCrossFade();
+ updateBufferStatus();
+}
+
+void MediaObject::setMute(bool mute)
+{
+ m_mediaObjectAudioNode->setMute(mute);
+ m_videoPlayer->setMute(mute);
+ m_nextVideoPlayer->setMute(mute);
+}
+
+void MediaObject::mediaNodeEvent(const MediaNodeEvent *event)
+{
+ switch (event->type()){
+ case MediaNodeEvent::EndConnectionChange:
+ m_mediaObjectAudioNode->setMute(true);
+ inspectGraph();
+ setupAudioSystem();
+ synchAudioVideo();
+ checkForError();
+ m_mediaObjectAudioNode->setMute(false);
+ if (m_state == Phonon::PlayingState)
+ bufferAudioVideo();
+ break;
+ case MediaNodeEvent::AudioGraphCannotPlay:
+ case MediaNodeEvent::AudioGraphInitialized:
+ if (m_state != Phonon::LoadingState){
+ m_mediaObjectAudioNode->setMute(true);
+ setupAudioSystem();
+ updateLipSynch(0);
+ checkForError();
+ m_mediaObjectAudioNode->setMute(false);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+bool MediaObject::event(QEvent *event)
+{
+ switch (event->type()){
+ case QEvent::Timer: {
+ QTimerEvent *timerEvent = static_cast<QTimerEvent *>(event);
+ if (timerEvent->timerId() == m_rapidTimer)
+ updateRapidly();
+ else if (timerEvent->timerId() == m_tickTimer)
+ emit tick(currentTime());
+ else if (timerEvent->timerId() == m_bufferTimer)
+ bufferAudioVideo();
+ }
+ break;
+ default:
+ break;
+ }
+ return QObject::event(event);
+}
+
+bool MediaObject::hasInterface(Interface /*interface*/) const
+{
+ return false;
+}
+
+QVariant MediaObject::interfaceCall(Interface /*interface*/, int /*command*/, const QList<QVariant> &/*arguments*/)
+{
+ return QVariant();
+}
+
+}} // namespace Phonon::QT7
+
+QT_END_NAMESPACE
+
+#include "moc_mediaobject.cpp"
+
diff --git a/src/3rdparty/phonon/qt7/mediaobjectaudionode.h b/src/3rdparty/phonon/qt7/mediaobjectaudionode.h
new file mode 100644
index 0000000000..7939aaa96d
--- /dev/null
+++ b/src/3rdparty/phonon/qt7/mediaobjectaudionode.h
@@ -0,0 +1,75 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef Phonon_QT7_MEDIAOBJECTAUDIONODE_H
+#define Phonon_QT7_MEDIAOBJECTAUDIONODE_H
+
+#include <QtCore/qnamespace.h>
+#include "audionode.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace QT7
+{
+ class QuickTimeAudioPlayer;
+ class AudioMixerAudioNode;
+ class AudioConnection;
+
+ class MediaObjectAudioNode : public AudioNode
+ {
+ public:
+ MediaObjectAudioNode(QuickTimeAudioPlayer *player1, QuickTimeAudioPlayer *player2);
+ ~MediaObjectAudioNode();
+
+ // Overridden section from AudioNode:
+ void createAndConnectAUNodes();
+ void createAudioUnits();
+ void setGraph(AudioGraph *audioGraph);
+ AUNode getOutputAUNode();
+ bool fillInStreamSpecification(AudioConnection *connection, ConnectionSide side);
+ bool setStreamSpecification(AudioConnection *connection, ConnectionSide side);
+
+ void startCrossFade(qint64 duration);
+ void updateCrossFade(qint64 currentTime);
+ void cancelCrossFade();
+ void setMute(bool mute);
+ bool isCrossFading();
+
+ QuickTimeAudioPlayer *m_player1;
+ QuickTimeAudioPlayer *m_player2;
+ AudioMixerAudioNode *m_mixer;
+
+ AudioConnection *m_connection1;
+ AudioConnection *m_connection2;
+
+ float m_fadeDuration;
+ float m_volume1;
+ float m_volume2;
+ float m_mute;
+
+ float applyCurve(float volume);
+ void updateVolume();
+
+ void mediaNodeEvent(const MediaNodeEvent *event);
+ };
+
+}} //namespace Phonon::QT7
+
+QT_END_NAMESPACE
+#endif // Phonon_QT7_MEDIAOBJECTAUDIONODE_H
diff --git a/src/3rdparty/phonon/qt7/mediaobjectaudionode.mm b/src/3rdparty/phonon/qt7/mediaobjectaudionode.mm
new file mode 100644
index 0000000000..66d6041514
--- /dev/null
+++ b/src/3rdparty/phonon/qt7/mediaobjectaudionode.mm
@@ -0,0 +1,207 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "mediaobjectaudionode.h"
+#include "quicktimeaudioplayer.h"
+#include "quicktimevideoplayer.h"
+#include "audiomixer.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace QT7
+{
+
+MediaObjectAudioNode::MediaObjectAudioNode(QuickTimeAudioPlayer *player1, QuickTimeAudioPlayer *player2) : AudioNode(0, 1)
+{
+ m_mute = false;
+ m_player1 = player1;
+ m_player2 = player2;
+ m_mixer = new AudioMixerAudioNode();
+
+ m_connection1 = new AudioConnection(m_player1, 0, m_mixer, 0);
+ m_connection2 = new AudioConnection(m_player2, 0, m_mixer, 1);
+
+ m_fadeDuration = 0;
+}
+
+MediaObjectAudioNode::~MediaObjectAudioNode()
+{
+ setGraph(0);
+ delete m_player1;
+ delete m_player2;
+ delete m_mixer;
+ delete m_connection1;
+ delete m_connection2;
+}
+
+void MediaObjectAudioNode::createAndConnectAUNodes()
+{
+ DEBUG_AUDIO_GRAPH("(MediaObjectAudioNode" << int(this) << "createAndConnectAUNodes called)" )
+ m_player1->createAndConnectAUNodes();
+ m_player2->createAndConnectAUNodes();
+ m_mixer->createAndConnectAUNodes();
+
+ m_connection1->connect(m_audioGraph);
+ m_connection2->connect(m_audioGraph);
+}
+
+void MediaObjectAudioNode::createAudioUnits()
+{
+ DEBUG_AUDIO_GRAPH("(MediaObjectAudioNode" << int(this) << "createAudioUnits called)" )
+ m_player1->createAudioUnits();
+ m_player2->createAudioUnits();
+ m_mixer->createAudioUnits();
+}
+
+void MediaObjectAudioNode::setGraph(AudioGraph *audioGraph)
+{
+ DEBUG_AUDIO_GRAPH("MediaObjectAudioNode" << int(this) << "is setting graph:" << int(audioGraph))
+ m_audioGraph = audioGraph;
+ m_player1->setGraph(audioGraph);
+ m_player2->setGraph(audioGraph);
+ m_mixer->setGraph(audioGraph);
+}
+
+AUNode MediaObjectAudioNode::getOutputAUNode()
+{
+ return m_mixer->getOutputAUNode();
+}
+
+bool MediaObjectAudioNode::fillInStreamSpecification(AudioConnection *connection, ConnectionSide side)
+{
+ if (side == Source){
+ DEBUG_AUDIO_STREAM("(MediaObjectAudioNode" << int(this) << "fillInStreamSpecification called, role = source)")
+ return m_mixer->fillInStreamSpecification(connection, side);
+ } else {
+ DEBUG_AUDIO_STREAM("(MediaObjectAudioNode" << int(this) << "fillInStreamSpecification called, role = sink)")
+ return (m_connection2->updateStreamSpecification() && m_connection1->updateStreamSpecification());
+ }
+}
+
+bool MediaObjectAudioNode::setStreamSpecification(AudioConnection *connection, ConnectionSide side)
+{
+ if (side == Source){
+ DEBUG_AUDIO_STREAM("(MediaObjectAudioNode" << int(this) << "setStreamSpecification called, role = source)")
+ return m_mixer->setStreamSpecification(connection, side);
+ }
+ return true;
+}
+
+void MediaObjectAudioNode::setMute(bool mute)
+{
+ m_mute = mute;
+ m_mixer->setVolume(m_mute ? 0 : m_volume1, m_connection1->m_sinkInputBus);
+ m_mixer->setVolume(m_mute ? 0 : m_volume2, m_connection2->m_sinkInputBus);
+}
+
+void MediaObjectAudioNode::updateVolume()
+{
+ if (m_mute)
+ return;
+
+ QuickTimeVideoPlayer *player1 = static_cast<QuickTimeAudioPlayer *>(m_connection1->m_sourceAudioNode)->videoPlayer();
+ QuickTimeVideoPlayer *player2 = static_cast<QuickTimeAudioPlayer *>(m_connection2->m_sourceAudioNode)->videoPlayer();
+ if (player1)
+ player1->setRelativeVolume(m_volume1);
+ if (player2)
+ player2->setRelativeVolume(m_volume2);
+
+ m_mixer->setVolume(m_volume1, m_connection1->m_sinkInputBus);
+ m_mixer->setVolume(m_volume2, m_connection2->m_sinkInputBus);
+}
+
+void MediaObjectAudioNode::startCrossFade(qint64 duration)
+{
+ m_fadeDuration = duration;
+
+ // Swap:
+ AudioConnection *tmp = m_connection1;
+ m_connection1 = m_connection2;
+ m_connection2 = tmp;
+
+ // Init volume:
+ if (m_fadeDuration > 0){
+ m_volume1 = 0;
+ m_volume2 = 1;
+ } else {
+ m_volume1 = 1;
+ m_volume2 = 0;
+ }
+ updateVolume();
+}
+
+float MediaObjectAudioNode::applyCurve(float volume)
+{
+ float newValue = 0;
+ if (volume > 0)
+ newValue = float(0.5f * (2 + log10(volume)));
+ return newValue;
+}
+
+void MediaObjectAudioNode::updateCrossFade(qint64 currentTime)
+{
+ // Assume that currentTime starts at 0 and progress.
+ if (m_fadeDuration > 0){
+ float volume = float(currentTime) / float(m_fadeDuration);
+ if (volume >= 1){
+ volume = 1;
+ m_fadeDuration = 0;
+ }
+ m_volume1 = applyCurve(volume);
+ m_volume2 = 1 - volume;
+ updateVolume();
+ }
+}
+
+bool MediaObjectAudioNode::isCrossFading()
+{
+ return (m_fadeDuration > 0);
+}
+
+void MediaObjectAudioNode::cancelCrossFade()
+{
+ m_fadeDuration = 0;
+ m_volume1 = 1;
+ m_volume2 = 0;
+ updateVolume();
+}
+
+void MediaObjectAudioNode::mediaNodeEvent(const MediaNodeEvent *event)
+{
+ switch (event->type()){
+ case MediaNodeEvent::AudioGraphAboutToBeDeleted:
+ m_connection1->invalidate();
+ m_connection2->invalidate();
+ break;
+ case MediaNodeEvent::AudioGraphCannotPlay:
+ case MediaNodeEvent::AudioGraphInitialized:
+ updateVolume();
+ break;
+ default:
+ break;
+ }
+
+ m_player1->mediaNodeEvent(event);
+ m_player2->mediaNodeEvent(event);
+ m_mixer->mediaNodeEvent(event);
+}
+
+}} //namespace Phonon::QT7
+
+QT_END_NAMESPACE
diff --git a/src/3rdparty/phonon/qt7/quicktimeaudioplayer.h b/src/3rdparty/phonon/qt7/quicktimeaudioplayer.h
new file mode 100644
index 0000000000..25ddb5e890
--- /dev/null
+++ b/src/3rdparty/phonon/qt7/quicktimeaudioplayer.h
@@ -0,0 +1,112 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef Phonon_QT7_QUICKTIMEAUDIOPLAYER_H
+#define Phonon_QT7_QUICKTIMEAUDIOPLAYER_H
+
+#include "backendheader.h"
+
+#ifdef QUICKTIME_C_API_AVAILABLE
+ #include <QuickTime/QuickTime.h>
+ #undef check // avoid name clash;
+#endif
+
+#include <phonon/mediasource.h>
+#include <Carbon/Carbon.h>
+#include <QtCore/QString>
+#include "audionode.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace QT7
+{
+ class AudioGraph;
+ class MediaNodeEvent;
+ class QuickTimeVideoPlayer;
+
+ class QuickTimeAudioPlayer : public AudioNode
+ {
+ public:
+ enum State {Playing, Paused, NoMedia, NoState};
+
+ QuickTimeAudioPlayer();
+ virtual ~QuickTimeAudioPlayer();
+
+ void play();
+ void pause();
+ void seek(quint64 milliseconds);
+ void enableAudio(bool enable);
+ bool audioEnabled();
+ void flush();
+
+ void setVideoPlayer(QuickTimeVideoPlayer *videoPlayer);
+ void unsetVideoPlayer();
+
+ bool hasAudio();
+ bool isPlaying();
+ void scheduleAudioToGraph();
+ long regularTaskFrequency();
+ quint64 currentTime();
+ QString currentTimeString();
+ QuickTimeVideoPlayer *videoPlayer();
+
+ ComponentDescription getAudioNodeDescription() const;
+ void initializeAudioUnit();
+ bool fillInStreamSpecification(AudioConnection *connection, ConnectionSide side);
+ void mediaNodeEvent(const MediaNodeEvent *event);
+
+ static bool soundPlayerIsAwailable();
+
+ private:
+ void initSoundExtraction();
+ void newGraphNotification();
+ void allocateSoundSlices();
+ void scheduleSoundSlices();
+
+ State m_state;
+ QuickTimeVideoPlayer *m_videoPlayer;
+
+#ifdef QUICKTIME_C_API_AVAILABLE
+ MovieAudioExtractionRef m_audioExtractionRef;
+#endif
+
+ ScheduledAudioSlice *m_sliceList;
+ AudioChannelLayout *m_audioChannelLayout;
+ UInt32 m_audioChannelLayoutSize;
+ AudioStreamBasicDescription m_audioStreamDescription;
+
+ bool m_discrete;
+ bool m_playerUnitStarted;
+ bool m_audioExtractionComplete;
+ bool m_audioEnabled;
+ bool m_audioUnitIsReset;
+
+ long m_samplesRemaining;
+ int m_sliceCount;
+ int m_maxExtractionPacketCount;
+
+ Float64 m_sampleTimeStamp;
+ quint64 m_startTime;
+ };
+
+}} // namespace Phonon::QT7
+
+QT_END_NAMESPACE
+
+#endif // Phonon_QT7_QUICKTIMEAUDIOPLAYER_H
diff --git a/src/3rdparty/phonon/qt7/quicktimeaudioplayer.mm b/src/3rdparty/phonon/qt7/quicktimeaudioplayer.mm
new file mode 100644
index 0000000000..61c97ccde8
--- /dev/null
+++ b/src/3rdparty/phonon/qt7/quicktimeaudioplayer.mm
@@ -0,0 +1,491 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "quicktimeaudioplayer.h"
+#include "quicktimevideoplayer.h"
+#include "audiograph.h"
+#include "medianodeevent.h"
+#include "medianode.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace QT7
+{
+
+QuickTimeAudioPlayer::QuickTimeAudioPlayer() : AudioNode(0, 1)
+{
+ m_state = NoMedia;
+ m_videoPlayer = 0;
+ m_audioChannelLayout = 0;
+ m_sliceList = 0;
+ m_sliceCount = 30;
+ m_maxExtractionPacketCount = 4096;
+ m_audioExtractionComplete = false;
+ m_audioEnabled = true;
+ m_samplesRemaining = -1;
+ m_startTime = 0;
+ m_sampleTimeStamp = 0;
+ m_audioUnitIsReset = true;
+
+#ifdef QUICKTIME_C_API_AVAILABLE
+ m_audioExtractionRef = 0;
+#endif
+}
+
+QuickTimeAudioPlayer::~QuickTimeAudioPlayer()
+{
+ unsetVideoPlayer();
+}
+
+void QuickTimeAudioPlayer::unsetVideoPlayer()
+{
+ if (m_audioUnit){
+ OSStatus err = AudioUnitReset(m_audioUnit, kAudioUnitScope_Global, 0);
+ BACKEND_ASSERT2(err == noErr, "Could not reset audio player unit when unsetting movie", FATAL_ERROR)
+ }
+
+#ifdef QUICKTIME_C_API_AVAILABLE
+ if (m_audioExtractionRef && m_videoPlayer && m_videoPlayer->hasMovie())
+ MovieAudioExtractionEnd(m_audioExtractionRef);
+ m_audioExtractionRef = 0;
+#endif
+
+ if (m_audioChannelLayout){
+ free(m_audioChannelLayout);
+ m_audioChannelLayout = 0;
+ }
+
+ if (m_sliceList){
+ for (int i=0; i<m_sliceCount; i++)
+ free(m_sliceList[i].mBufferList);
+ free(m_sliceList);
+ m_sliceList = 0;
+ }
+
+ m_videoPlayer = 0;
+ m_audioExtractionComplete = false;
+ m_samplesRemaining = -1;
+ m_sampleTimeStamp = 0;
+ m_state = NoMedia;
+}
+
+void QuickTimeAudioPlayer::enableAudio(bool enable)
+{
+ // Remember to seek after enabling audio.
+ if (enable == m_audioEnabled)
+ return;
+
+ m_audioEnabled = enable;
+ if (!enable)
+ flush();
+}
+
+bool QuickTimeAudioPlayer::audioEnabled()
+{
+ return m_audioEnabled;
+}
+
+void QuickTimeAudioPlayer::setVideoPlayer(QuickTimeVideoPlayer *videoPlayer)
+{
+ unsetVideoPlayer();
+ if (videoPlayer && videoPlayer->hasMovie()){
+ m_videoPlayer = videoPlayer;
+ initSoundExtraction();
+ allocateSoundSlices();
+ m_state = Paused;
+ seek(0);
+ }
+}
+
+QuickTimeVideoPlayer *QuickTimeAudioPlayer::videoPlayer()
+{
+ return m_videoPlayer;
+}
+
+void QuickTimeAudioPlayer::scheduleAudioToGraph()
+{
+ if (!m_videoPlayer || !m_audioEnabled || m_audioExtractionComplete || m_state != Playing)
+ return;
+
+ // Schedule audio slices, and detect if everything went OK.
+ // If not, flag the need for another audio system, but let
+ // the end app know about it:
+ gClearError();
+ scheduleSoundSlices();
+ if (gGetErrorType() != NO_ERROR){
+ gClearError();
+ if (m_audioGraph)
+ m_audioGraph->setStatusCannotPlay();
+ }
+}
+
+void QuickTimeAudioPlayer::flush()
+{
+ // Empty scheduled audio data, so playback
+ // will stop. Call seek to refill data again.
+ if (m_audioUnit){
+ m_startTime = currentTime();
+ OSStatus err = AudioUnitReset(m_audioUnit, kAudioUnitScope_Global, 0);
+ BACKEND_ASSERT2(err == noErr, "Could not reset audio player unit on pause", FATAL_ERROR)
+ m_audioUnitIsReset = true;
+ }
+}
+
+void QuickTimeAudioPlayer::pause()
+{
+ m_state = Paused;
+ flush();
+}
+
+void QuickTimeAudioPlayer::play()
+{
+ m_state = Playing;
+ if (!m_audioEnabled)
+ return;
+ if (m_audioUnitIsReset)
+ seek(m_startTime);
+ else
+ scheduleAudioToGraph();
+}
+
+bool QuickTimeAudioPlayer::isPlaying()
+{
+ return m_videoPlayer && m_state == Playing;
+}
+
+void QuickTimeAudioPlayer::seek(quint64 milliseconds)
+{
+ if (!m_videoPlayer || !m_videoPlayer->hasMovie())
+ return;
+ if (milliseconds > m_videoPlayer->duration())
+ milliseconds = m_videoPlayer->duration();
+ if (!m_audioUnitIsReset && milliseconds == currentTime())
+ return;
+
+ m_startTime = milliseconds;
+
+ // Since the graph may be running (advancing time), there is
+ // no point in seeking if were not going to play immidiatly:
+ if (m_state != Playing)
+ return;
+ if (!m_audioUnit)
+ return;
+ if (!m_audioEnabled || !m_videoPlayer->isSeekable())
+ return;
+
+ // Reset (and stop playing):
+ OSStatus err;
+ if (!m_audioUnitIsReset){
+ err = AudioUnitReset(m_audioUnit, kAudioUnitScope_Global, 0);
+ BACKEND_ASSERT2(err == noErr, "Could not reset audio player unit before seek", FATAL_ERROR)
+ }
+ m_sampleTimeStamp = 0;
+ for (int i = 0; i < m_sliceCount; i++)
+ m_sliceList[i].mFlags = kScheduledAudioSliceFlag_Complete;
+
+ // Start to play again immidiatly:
+ AudioTimeStamp timeStamp;
+ memset(&timeStamp, 0, sizeof(timeStamp));
+ timeStamp.mFlags = kAudioTimeStampSampleTimeValid;
+ timeStamp.mSampleTime = -1;
+ err = AudioUnitSetProperty(m_audioUnit,
+ kAudioUnitProperty_ScheduleStartTimeStamp, kAudioUnitScope_Global,
+ 0, &timeStamp, sizeof(timeStamp));
+ BACKEND_ASSERT2(err == noErr, "Could not set schedule start time stamp on audio player unit", FATAL_ERROR)
+
+ // Seek back to 'now' in the movie:
+ TimeRecord timeRec;
+ timeRec.scale = m_videoPlayer->timeScale();
+ timeRec.base = 0;
+ timeRec.value.hi = 0;
+ timeRec.value.lo = (milliseconds / 1000.0f) * timeRec.scale;
+
+#ifdef QUICKTIME_C_API_AVAILABLE
+ err = MovieAudioExtractionSetProperty(m_audioExtractionRef,
+ kQTPropertyClass_MovieAudioExtraction_Movie,
+ kQTMovieAudioExtractionMoviePropertyID_CurrentTime,
+ sizeof(TimeRecord), &timeRec);
+ BACKEND_ASSERT2(err == noErr, "Could not set current time on audio player unit", FATAL_ERROR)
+#endif
+
+ float durationLeftSec = float(m_videoPlayer->duration() - milliseconds) / 1000.0f;
+ m_samplesRemaining = (durationLeftSec > 0) ? (durationLeftSec * m_audioStreamDescription.mSampleRate) : -1;
+ m_audioExtractionComplete = false;
+ m_audioUnitIsReset = false;
+ scheduleAudioToGraph();
+
+}
+
+quint64 QuickTimeAudioPlayer::currentTime()
+{
+ if (!m_audioUnit){
+ if (m_videoPlayer)
+ return m_videoPlayer->currentTime();
+ else
+ return m_startTime;
+ }
+
+ Float64 currentUnitTime = getTimeInSamples(kAudioUnitProperty_CurrentPlayTime);
+ if (currentUnitTime == -1)
+ currentUnitTime = 0;
+
+ quint64 cTime = quint64(m_startTime +
+ float(currentUnitTime / float(m_audioStreamDescription.mSampleRate)) * 1000.0f);
+ return (m_videoPlayer && cTime > m_videoPlayer->duration()) ? m_videoPlayer->duration() : cTime;
+}
+
+QString QuickTimeAudioPlayer::currentTimeString()
+{
+ return QuickTimeVideoPlayer::timeToString(currentTime());
+}
+
+bool QuickTimeAudioPlayer::hasAudio()
+{
+ if (!m_videoPlayer)
+ return false;
+
+ return m_videoPlayer->hasAudio();
+}
+
+bool QuickTimeAudioPlayer::soundPlayerIsAwailable()
+{
+ QuickTimeAudioPlayer player;
+ ComponentDescription d = player.getAudioNodeDescription();
+ return FindNextComponent(0, &d);
+}
+
+ComponentDescription QuickTimeAudioPlayer::getAudioNodeDescription() const
+{
+ ComponentDescription description;
+ description.componentType = kAudioUnitType_Generator;
+ description.componentSubType = kAudioUnitSubType_ScheduledSoundPlayer;
+ description.componentManufacturer = kAudioUnitManufacturer_Apple;
+ description.componentFlags = 0;
+ description.componentFlagsMask = 0;
+ return description;
+}
+
+void QuickTimeAudioPlayer::initializeAudioUnit()
+{
+}
+
+bool QuickTimeAudioPlayer::fillInStreamSpecification(AudioConnection *connection, ConnectionSide side)
+{
+ if (!m_videoPlayer){
+ if (side == Source)
+ DEBUG_AUDIO_STREAM("QuickTimeAudioPlayer" << int(this) << "is source, but has no movie to use for stream spec fill.")
+ return true;
+ }
+
+ if (side == Source){
+ DEBUG_AUDIO_STREAM("QuickTimeAudioPlayer" << int(this) << "is source, and fills in stream spec from movie.")
+ connection->m_sourceStreamDescription = m_audioStreamDescription;
+ connection->m_sourceChannelLayout = (AudioChannelLayout *) malloc(m_audioChannelLayoutSize);
+ memcpy(connection->m_sourceChannelLayout, m_audioChannelLayout, m_audioChannelLayoutSize);
+ connection->m_sourceChannelLayoutSize = m_audioChannelLayoutSize;
+ connection->m_hasSourceSpecification = true;
+ }
+ return true;
+}
+
+long QuickTimeAudioPlayer::regularTaskFrequency(){
+ if (!m_audioEnabled || !m_audioUnit || (m_audioGraph && m_audioGraph->graphCannotPlay()))
+ return INT_MAX;
+
+ // Calculate how much audio in
+ // milliseconds our slices can hold:
+ int packetNeedPerSecond = m_audioStreamDescription.mSampleRate / m_maxExtractionPacketCount;
+ long bufferTimeLengthSec = float(m_sliceCount) / float(packetNeedPerSecond);
+ // Make sure we also get some time to fill the
+ // buffer, so divide the time by two:
+ return (bufferTimeLengthSec * (1000 / 2));
+}
+
+void QuickTimeAudioPlayer::initSoundExtraction()
+{
+#ifdef QUICKTIME_C_API_AVAILABLE
+
+ // Initilize the extraction:
+ OSStatus err = noErr;
+ err = MovieAudioExtractionBegin([m_videoPlayer->qtMovie() quickTimeMovie], 0, &m_audioExtractionRef);
+ BACKEND_ASSERT2(err == noErr, "Could not start audio extraction on audio player unit", FATAL_ERROR)
+ m_discrete = false;
+#if 0
+ // Extract all channels as descrete:
+ err = MovieAudioExtractionSetProperty(audioExtractionRef,
+ kQTPropertyClass_MovieAudioExtraction_Movie,
+ kQTMovieAudioExtractionMoviePropertyID_AllChannelsDiscrete,
+ sizeof (discrete),
+ &discrete);
+ BACKEND_ASSERT2(err == noErr, "Could not set channels discrete on audio player unit", FATAL_ERROR)
+#endif
+
+ // Get the size of the audio channel layout (may include offset):
+ err = MovieAudioExtractionGetPropertyInfo(m_audioExtractionRef,
+ kQTPropertyClass_MovieAudioExtraction_Audio,
+ kQTMovieAudioExtractionAudioPropertyID_AudioChannelLayout,
+ 0, &m_audioChannelLayoutSize, 0);
+ BACKEND_ASSERT2(err == noErr, "Could not get channel layout size from audio extraction", FATAL_ERROR)
+
+ // Allocate memory for the layout
+ m_audioChannelLayout = (AudioChannelLayout *) calloc(1, m_audioChannelLayoutSize);
+ BACKEND_ASSERT2(m_audioChannelLayout, "Could not allocate memory for channel layout on audio player unit", FATAL_ERROR)
+
+ // Get the layout:
+ err = MovieAudioExtractionGetProperty(m_audioExtractionRef,
+ kQTPropertyClass_MovieAudioExtraction_Audio,
+ kQTMovieAudioExtractionAudioPropertyID_AudioChannelLayout,
+ m_audioChannelLayoutSize, m_audioChannelLayout, 0);
+ BACKEND_ASSERT2(err == noErr, "Could not get channel layout from audio extraction", FATAL_ERROR)
+
+ // Get audio stream description:
+ err = MovieAudioExtractionGetProperty(m_audioExtractionRef,
+ kQTPropertyClass_MovieAudioExtraction_Audio,
+ kQTMovieAudioExtractionAudioPropertyID_AudioStreamBasicDescription,
+ sizeof(m_audioStreamDescription), &m_audioStreamDescription, 0);
+ BACKEND_ASSERT2(err == noErr, "Could not get audio stream description from audio extraction", FATAL_ERROR)
+
+#endif // QUICKTIME_C_API_AVAILABLE
+}
+
+void QuickTimeAudioPlayer::allocateSoundSlices()
+{
+#ifdef QUICKTIME_C_API_AVAILABLE
+
+ // m_sliceList will contain a specified number of ScheduledAudioSlice-s that each can
+ // carry audio from extraction, and be scheduled for playback at an audio unit.
+ // Each ScheduledAudioSlice will contain several audio buffers, one for each sound channel.
+ // Each buffer will carry (at most) a specified number of sound packets, and each packet can
+ // contain one or more frames.
+
+ // Create a list of ScheduledAudioSlices:
+ m_sliceList = (ScheduledAudioSlice *) calloc(m_sliceCount, sizeof(ScheduledAudioSlice));
+ BACKEND_ASSERT2(m_sliceList, "Could not allocate memory for audio slices", FATAL_ERROR)
+ bzero(m_sliceList, m_sliceCount * sizeof(ScheduledAudioSlice));
+
+ // Calculate the size of the different structures needed:
+ int packetsBufferSize = m_maxExtractionPacketCount * m_audioStreamDescription.mBytesPerPacket;
+ int channels = m_audioStreamDescription.mChannelsPerFrame;
+ int audioBufferListSize = int(sizeof(AudioBufferList) + (channels-1) * sizeof(AudioBuffer));
+ int mallocSize = audioBufferListSize + (packetsBufferSize * m_audioStreamDescription.mChannelsPerFrame);
+
+ // Round off to Altivec sizes:
+ packetsBufferSize = int(((packetsBufferSize + 15) / 16) * 16);
+ audioBufferListSize = int(((audioBufferListSize + 15) / 16) * 16);
+
+ for (int sliceIndex = 0; sliceIndex < m_sliceCount; ++sliceIndex){
+ // Create the memory chunk for this audio slice:
+ AudioBufferList *audioBufferList = (AudioBufferList*) calloc(1, mallocSize);
+ BACKEND_ASSERT2(audioBufferList, "Could not allocate memory for audio buffer list", FATAL_ERROR)
+
+ // The AudioBufferList contains an AudioBuffer for each channel in the audio stream:
+ audioBufferList->mNumberBuffers = m_audioStreamDescription.mChannelsPerFrame;
+ for (uint i = 0; i < audioBufferList->mNumberBuffers; ++i){
+ audioBufferList->mBuffers[i].mNumberChannels = 1;
+ audioBufferList->mBuffers[i].mData = (char *) audioBufferList + audioBufferListSize + (i * packetsBufferSize);
+ audioBufferList->mBuffers[i].mDataByteSize = packetsBufferSize;
+ }
+
+ m_sliceList[sliceIndex].mBufferList = audioBufferList;
+ m_sliceList[sliceIndex].mNumberFrames = m_maxExtractionPacketCount;
+ m_sliceList[sliceIndex].mTimeStamp.mFlags = kAudioTimeStampSampleTimeValid;
+ m_sliceList[sliceIndex].mCompletionProcUserData = 0;
+ m_sliceList[sliceIndex].mCompletionProc = 0;
+ m_sliceList[sliceIndex].mFlags = kScheduledAudioSliceFlag_Complete;
+ m_sliceList[sliceIndex].mReserved = 0;
+ }
+
+#endif // QUICKTIME_C_API_AVAILABLE
+}
+
+void QuickTimeAudioPlayer::scheduleSoundSlices()
+{
+#ifdef QUICKTIME_C_API_AVAILABLE
+
+ PhononAutoReleasePool pool;
+ // For each completed (or never used) slice, fill and schedule it.
+ for (int sliceIndex = 0; sliceIndex < m_sliceCount; ++sliceIndex){
+ if (m_sliceList[sliceIndex].mFlags & kScheduledAudioSliceFlag_Complete){
+ if (m_samplesRemaining == 0)
+ m_audioExtractionComplete = true;
+
+ if (!m_audioExtractionComplete){
+ // Determine how many samples to read:
+ int samplesCount = m_samplesRemaining;
+ if ((samplesCount > m_maxExtractionPacketCount) || (samplesCount == -1))
+ samplesCount = m_maxExtractionPacketCount;
+ m_sliceList[sliceIndex].mTimeStamp.mSampleTime = m_sampleTimeStamp;
+
+ // Reset buffer sizes:
+ int byteSize = samplesCount * m_audioStreamDescription.mBytesPerPacket;
+ for (uint i = 0; i < m_sliceList[sliceIndex].mBufferList->mNumberBuffers; ++i)
+ m_sliceList[sliceIndex].mBufferList->mBuffers[i].mDataByteSize = byteSize;
+
+ // Do the extraction:
+ UInt32 flags = 0;
+ UInt32 samplesRead = samplesCount;
+ OSStatus err = MovieAudioExtractionFillBuffer(
+ m_audioExtractionRef, &samplesRead, m_sliceList[sliceIndex].mBufferList, &flags);
+ BACKEND_ASSERT2(err == noErr, "Could not fill audio buffers from audio extraction", FATAL_ERROR)
+ m_audioExtractionComplete = (flags & kQTMovieAudioExtractionComplete);
+
+ // Play the slice:
+ if (samplesRead != 0 && m_audioUnit != 0){
+ m_sliceList[sliceIndex].mNumberFrames = samplesRead;
+ err = AudioUnitSetProperty(m_audioUnit,
+ kAudioUnitProperty_ScheduleAudioSlice, kAudioUnitScope_Global,
+ 0, &m_sliceList[sliceIndex], sizeof(ScheduledAudioSlice));
+ BACKEND_ASSERT2(err == noErr, "Could not schedule audio buffers on audio unit", FATAL_ERROR)
+ } else
+ m_sliceList[sliceIndex].mFlags = kScheduledAudioSliceFlag_Complete;
+
+ // Move the window:
+ m_sampleTimeStamp += samplesRead;
+ if (m_samplesRemaining != -1)
+ m_samplesRemaining -= samplesRead;
+ }
+ }
+ }
+
+#endif // QUICKTIME_C_API_AVAILABLE
+}
+
+void QuickTimeAudioPlayer::mediaNodeEvent(const MediaNodeEvent *event)
+{
+ switch (event->type()){
+ case MediaNodeEvent::AudioGraphAboutToBeDeleted:
+ case MediaNodeEvent::AboutToRestartAudioStream:
+ case MediaNodeEvent::StartConnectionChange:
+ m_startTime = currentTime();
+ break;
+ case MediaNodeEvent::AudioGraphInitialized:
+ case MediaNodeEvent::RestartAudioStreamRequest:
+ case MediaNodeEvent::EndConnectionChange:
+ if (m_state == Playing)
+ seek(m_startTime);
+ break;
+ default:
+ break;
+ }
+}
+
+}}
+
+QT_END_NAMESPACE
+
diff --git a/src/3rdparty/phonon/qt7/quicktimemetadata.h b/src/3rdparty/phonon/qt7/quicktimemetadata.h
new file mode 100644
index 0000000000..d5241832d8
--- /dev/null
+++ b/src/3rdparty/phonon/qt7/quicktimemetadata.h
@@ -0,0 +1,67 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef Phonon_QT7_QUICKTIMEMETADATA_H
+#define Phonon_QT7_QUICKTIMEMETADATA_H
+
+#include "backendheader.h"
+#include <phonon/mediasource.h>
+#include <Carbon/Carbon.h>
+#include <QtCore/QString>
+
+#ifdef QUICKTIME_C_API_AVAILABLE
+ #include <QuickTime/QuickTime.h>
+ #undef check // avoid name clash;
+#endif
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace QT7
+{
+ class QuickTimeVideoPlayer;
+ class QuickTimeMetaData
+ {
+ public:
+ QuickTimeMetaData();
+ virtual ~QuickTimeMetaData();
+
+ void setVideo(QuickTimeVideoPlayer *videoPlayer);
+ QMultiMap<QString, QString> metaData();
+
+ private:
+ QMultiMap<QString, QString> m_metaData;
+ bool m_movieChanged;
+ QuickTimeVideoPlayer *m_videoPlayer;
+ void readMetaData();
+
+#ifdef QUICKTIME_C_API_AVAILABLE
+ QString stripCopyRightSymbol(const QString &key);
+ QString convertQuickTimeKeyToUserKey(const QString &key);
+ OSStatus readMetaValue(QTMetaDataRef, QTMetaDataItem, QTPropertyClass, QTPropertyID, QTPropertyValuePtr *, ByteCount *);
+ UInt32 getMetaType(QTMetaDataRef metaDataRef, QTMetaDataItem item);
+ QString getMetaValue(QTMetaDataRef metaDataRef, QTMetaDataItem item, SInt32 id);
+ void readFormattedData(QTMetaDataRef metaDataRef, OSType format, QMultiMap<QString, QString> &result);
+#endif // QUICKTIME_C_API_AVAILABLE
+ };
+
+}} // namespace Phonon::QT7
+
+QT_END_NAMESPACE
+
+#endif // Phonon_QT7_QUICKTIMEMETADATA_H
diff --git a/src/3rdparty/phonon/qt7/quicktimemetadata.mm b/src/3rdparty/phonon/qt7/quicktimemetadata.mm
new file mode 100644
index 0000000000..851e7077b7
--- /dev/null
+++ b/src/3rdparty/phonon/qt7/quicktimemetadata.mm
@@ -0,0 +1,185 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "quicktimemetadata.h"
+#include "quicktimevideoplayer.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace QT7
+{
+
+QuickTimeMetaData::QuickTimeMetaData()
+{
+ m_videoPlayer = 0;
+ m_movieChanged = false;
+}
+
+QuickTimeMetaData::~QuickTimeMetaData()
+{
+}
+
+void QuickTimeMetaData::setVideo(QuickTimeVideoPlayer *videoPlayer)
+{
+ m_videoPlayer = videoPlayer;
+ m_movieChanged = true;
+ m_metaData.clear();
+}
+
+#ifdef QUICKTIME_C_API_AVAILABLE
+
+QString QuickTimeMetaData::stripCopyRightSymbol(const QString &key)
+{
+ return key.right(key.length()-1);
+}
+
+QString QuickTimeMetaData::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("???");
+}
+
+OSStatus QuickTimeMetaData::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);
+ BACKEND_ASSERT3(err == noErr, "Could not read meta data value size", NORMAL_ERROR, err)
+
+ *value = malloc(propSize);
+
+ err = QTMetaDataGetItemProperty(metaDataRef, item, propClass, id, propSize, *value, size);
+ BACKEND_ASSERT3(err == noErr, "Could not read meta data value", NORMAL_ERROR, err)
+
+ if (type == 'code' || type == 'itsk' || type == 'itlk') {
+ // convert from native endian to big endian
+ OSTypePtr pType = (OSTypePtr)*value;
+ *pType = EndianU32_NtoB(*pType);
+ }
+
+ return err;
+}
+
+UInt32 QuickTimeMetaData::getMetaType(QTMetaDataRef metaDataRef, QTMetaDataItem item)
+{
+ QTPropertyValuePtr value = 0;
+ ByteCount ignore = 0;
+ OSStatus err = readMetaValue(
+ metaDataRef, item, kPropertyClass_MetaDataItem, kQTMetaDataItemPropertyID_DataType, &value, &ignore);
+ BACKEND_ASSERT3(err == noErr, "Could not read meta data type", NORMAL_ERROR, 0)
+ UInt32 type = *((UInt32 *) value);
+ if (value)
+ free(value);
+ return type;
+}
+
+QString QuickTimeMetaData::getMetaValue(QTMetaDataRef metaDataRef, QTMetaDataItem item, SInt32 id)
+{
+ QTPropertyValuePtr value = 0;
+ ByteCount size = 0;
+ OSStatus err = readMetaValue(metaDataRef, item, kPropertyClass_MetaDataItem, id, &value, &size);
+ BACKEND_ASSERT3(err == noErr, "Could not read meta data item", NORMAL_ERROR, QString())
+ BACKEND_ASSERT3(value != 0, "Could not read meta data item", NORMAL_ERROR, QString())
+
+ QString string;
+ UInt32 dataType = getMetaType(metaDataRef, item);
+ switch (dataType){
+ case kQTMetaDataTypeUTF8:
+ case kQTMetaDataTypeMacEncodedText:
+ string = PhononCFString::toQString(CFStringCreateWithBytes(0, (UInt8*)value, size, kCFStringEncodingUTF8, false));
+ break;
+ case kQTMetaDataTypeUTF16BE:
+ string = PhononCFString::toQString(CFStringCreateWithBytes(0, (UInt8*)value, size, kCFStringEncodingUTF16BE, false));
+ break;
+ default:
+ break;
+ }
+
+ if (value)
+ free(value);
+ return string;
+}
+
+void QuickTimeMetaData::readFormattedData(QTMetaDataRef metaDataRef, OSType format, QMultiMap<QString, QString> &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 // QUICKTIME_C_API_AVAILABLE
+
+void QuickTimeMetaData::readMetaData()
+{
+ if (!m_videoPlayer)
+ return;
+ QMultiMap<QString, QString> metaMap;
+
+#ifdef QUICKTIME_C_API_AVAILABLE
+ QTMetaDataRef metaDataRef;
+ OSStatus err = QTCopyMovieMetaData([m_videoPlayer->qtMovie() quickTimeMovie], &metaDataRef);
+ BACKEND_ASSERT2(err == noErr, "Could not read QuickTime meta data", NORMAL_ERROR)
+
+ readFormattedData(metaDataRef, kQTMetaDataStorageFormatUserData, metaMap);
+ readFormattedData(metaDataRef, kQTMetaDataStorageFormatQuickTime, metaMap);
+ readFormattedData(metaDataRef, kQTMetaDataStorageFormatiTunes, metaMap);
+#else
+ NSString *name = [m_videoPlayer->qtMovie() attributeForKey:@"QTMovieDisplayNameAttribute"];
+ metaMap.insert(QLatin1String("nam"), QString::fromUtf8([name UTF8String]));
+#endif // QUICKTIME_C_API_AVAILABLE
+
+ m_metaData.insert(QLatin1String("ARTIST"), metaMap.value(QLatin1String("ART")));
+ m_metaData.insert(QLatin1String("ALBUM"), metaMap.value(QLatin1String("alb")));
+ m_metaData.insert(QLatin1String("TITLE"), metaMap.value(QLatin1String("nam")));
+ m_metaData.insert(QLatin1String("DATE"), metaMap.value(QLatin1String("day")));
+ m_metaData.insert(QLatin1String("GENRE"), metaMap.value(QLatin1String("gnre")));
+ m_metaData.insert(QLatin1String("TRACKNUMBER"), metaMap.value(QLatin1String("trk")));
+ m_metaData.insert(QLatin1String("DESCRIPTION"), metaMap.value(QLatin1String("des")));
+}
+
+QMultiMap<QString, QString> QuickTimeMetaData::metaData()
+{
+ if (m_videoPlayer && m_videoPlayer->hasMovie() && m_movieChanged)
+ readMetaData();
+ return m_metaData;
+}
+
+}}
+
+QT_END_NAMESPACE
diff --git a/src/3rdparty/phonon/qt7/quicktimestreamreader.h b/src/3rdparty/phonon/qt7/quicktimestreamreader.h
new file mode 100644
index 0000000000..0e7590cd58
--- /dev/null
+++ b/src/3rdparty/phonon/qt7/quicktimestreamreader.h
@@ -0,0 +1,71 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef Phonon_QT7_QUICKTIMESTREAMREADER_H
+#define Phonon_QT7_QUICKTIMESTREAMREADER_H
+
+#include <phonon/mediasource.h>
+#include <phonon/streaminterface.h>
+#include <QtCore/QReadWriteLock>
+
+#ifndef QT_MAC_USE_COCOA
+#include <QuickTime/Movies.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace QT7
+{
+ class QuickTimeStreamReader : public QObject, Phonon::StreamInterface
+ {
+ Q_OBJECT
+ Q_INTERFACES(Phonon::StreamInterface)
+
+ public:
+ QuickTimeStreamReader(const Phonon::MediaSource &source);
+ ~QuickTimeStreamReader();
+
+ int readData(long offset, long size, void *data);
+ bool readAllData();
+ QByteArray *pointerToData();
+ void writeData(const QByteArray &data);
+ void endOfData();
+ void setStreamSize(qint64 newSize);
+ qint64 streamSize() const;
+ void setStreamSeekable(bool s);
+ bool streamSeekable() const;
+ void setCurrentPos(qint64 pos);
+ qint64 currentPos() const;
+ int currentBufferSize() const;
+#ifndef QT_MAC_USE_COCOA
+ Movie movieRef();
+#endif
+
+ QByteArray m_buffer;
+ mutable QReadWriteLock m_lock;
+ bool m_seekable;
+ qint64 m_pos;
+ qint64 m_size;
+ };
+
+}} //namespace Phonon::QT7
+
+QT_END_NAMESPACE
+
+#endif // Phonon_QT7_QUICKTIMESTREAMREADER_H
diff --git a/src/3rdparty/phonon/qt7/quicktimestreamreader.mm b/src/3rdparty/phonon/qt7/quicktimestreamreader.mm
new file mode 100644
index 0000000000..7131616a4f
--- /dev/null
+++ b/src/3rdparty/phonon/qt7/quicktimestreamreader.mm
@@ -0,0 +1,137 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "backendheader.h"
+#include "quicktimestreamreader.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace QT7
+{
+
+QuickTimeStreamReader::QuickTimeStreamReader(const Phonon::MediaSource &source)
+{
+ connectToSource(source);
+}
+
+QuickTimeStreamReader::~QuickTimeStreamReader()
+{
+}
+
+bool QuickTimeStreamReader::readAllData()
+{
+ int oldSize = m_buffer.size();
+ while (m_buffer.size() < m_size){
+ needData();
+ if (oldSize == currentBufferSize())
+ BACKEND_ASSERT3(oldSize != currentBufferSize(),
+ "Could not create new movie from IO stream. Not enough free memory to preload the whole movie.",
+ FATAL_ERROR, false)
+ oldSize = m_buffer.size();
+ }
+ return true;
+}
+
+QByteArray *QuickTimeStreamReader::pointerToData()
+{
+ return &m_buffer;
+}
+
+int QuickTimeStreamReader::readData(long offset, long size, void *data)
+{
+// QReadLocker readLocker(&m_lock);
+ if (streamSize() != 1 && offset + size > streamSize()){
+ size = streamSize() - offset;
+ }
+
+ if (currentPos() - currentBufferSize() != offset)
+ setCurrentPos(offset);
+
+ int oldSize = currentBufferSize();
+ while (currentBufferSize() < int(size)) {
+ needData();
+ if (oldSize == currentBufferSize())
+ break;
+ oldSize = currentBufferSize();
+ }
+
+ int bytesRead = qMin(currentBufferSize(), int(size));
+// QWriteLocker writeLocker(&m_lock);
+ qMemCopy(data, m_buffer.data(), bytesRead);
+ m_buffer = m_buffer.mid(bytesRead);
+
+ return bytesRead;
+}
+
+void QuickTimeStreamReader::writeData(const QByteArray &data)
+{
+ QWriteLocker locker(&m_lock);
+ m_pos += data.size();
+ m_buffer += data;
+}
+
+void QuickTimeStreamReader::endOfData()
+{
+}
+
+void QuickTimeStreamReader::setStreamSize(qint64 newSize)
+{
+ m_size = newSize;
+}
+
+qint64 QuickTimeStreamReader::streamSize() const
+{
+ return m_size;
+}
+
+void QuickTimeStreamReader::setStreamSeekable(bool s)
+{
+ m_seekable = s;
+}
+
+bool QuickTimeStreamReader::streamSeekable() const
+{
+ return m_seekable;
+}
+
+void QuickTimeStreamReader::setCurrentPos(qint64 pos)
+{
+ QWriteLocker locker(&m_lock);
+ m_pos = pos;
+ seekStream(pos);
+ m_buffer.clear();
+}
+
+qint64 QuickTimeStreamReader::currentPos() const
+{
+ return m_pos;
+}
+
+int QuickTimeStreamReader::currentBufferSize() const
+{
+ QReadLocker locker(&m_lock);
+ return m_buffer.size();
+}
+
+}} //namespace Phonon::QT7
+
+QT_END_NAMESPACE
+
+#include "moc_quicktimestreamreader.cpp"
+
diff --git a/src/3rdparty/phonon/qt7/quicktimevideoplayer.h b/src/3rdparty/phonon/qt7/quicktimevideoplayer.h
new file mode 100644
index 0000000000..0b3aec221b
--- /dev/null
+++ b/src/3rdparty/phonon/qt7/quicktimevideoplayer.h
@@ -0,0 +1,167 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef Phonon_QT7_QUICKTIMEVIDEOPLAYER_H
+#define Phonon_QT7_QUICKTIMEVIDEOPLAYER_H
+
+#include "backendheader.h"
+
+#import <QTKit/QTDataReference.h>
+#import <QTKit/QTMovie.h>
+
+#include <phonon/mediasource.h>
+#include <Carbon/Carbon.h>
+#include <QtCore/QString>
+#include <QtOpenGL/QGLPixelBuffer>
+#include "videoframe.h"
+
+QT_BEGIN_NAMESPACE
+
+class QGLContext;
+
+namespace Phonon
+{
+namespace QT7
+{
+ class QuickTimeStreamReader;
+ class VideoRenderWidgetQTMovieView;
+
+ class QuickTimeVideoPlayer : QObject
+ {
+ public:
+ enum StateEnum {
+ Playing = 0x1,
+ Paused = 0x2,
+ NoMedia = 0x4,
+ };
+ Q_DECLARE_FLAGS(State, StateEnum);
+
+ QuickTimeVideoPlayer();
+ virtual ~QuickTimeVideoPlayer();
+
+ void setMediaSource(const MediaSource &source);
+ MediaSource mediaSource() const;
+ void unsetVideo();
+
+ void play();
+ void pause();
+ void seek(quint64 milliseconds);
+
+ bool videoFrameChanged();
+ CVOpenGLTextureRef currentFrameAsCVTexture();
+ GLuint currentFrameAsGLTexture();
+ void *currentFrameAsCIImage();
+ QImage currentFrameAsQImage();
+ QRect videoRect() const;
+
+ quint64 duration() const;
+ quint64 currentTime() const;
+ long timeScale() const;
+ QString currentTimeString();
+
+ void setColors(qreal brightness = 0, qreal contrast = 1, qreal hue = 0, qreal saturation = 1);
+ void setMasterVolume(float volume);
+ void setRelativeVolume(float volume);
+ void setVolume(float masterVolume, float relativeVolume);
+ void setMute(bool mute);
+ void enableAudio(bool enable);
+ bool audioEnabled();
+ bool setAudioDevice(int id);
+ void setPlaybackRate(float rate);
+ QTMovie *qtMovie() const;
+
+ float playbackRate() const;
+ float prefferedPlaybackRate() const;
+
+ QuickTimeVideoPlayer::State state() const;
+
+ bool hasAudio() const;
+ bool hasVideo() const;
+ bool hasMovie() const;
+ bool canPlayMedia() const;
+ bool isPlaying() const;
+ bool isSeekable() const;
+ bool isDrmProtected() const;
+ bool isDrmAuthorized() const;
+
+ bool preRollMovie(qint64 startTime = 0);
+ float percentageLoaded();
+ quint64 timeLoaded();
+
+ static QString timeToString(quint64 ms);
+
+ // Help functions when drawing to more that one widget in cocoa 64:
+ void *m_primaryRenderingTarget;
+ void setPrimaryRenderingTarget(NSObject *target);
+
+ void *primaryRenderingCIImage();
+ void setPrimaryRenderingCIImage(void *ciImage);
+
+ private:
+ QTMovie *m_QTMovie;
+ State m_state;
+ QGLPixelBuffer *m_QImagePixelBuffer;
+
+ bool m_playbackRateSat;
+ bool m_isDrmProtected;
+ bool m_isDrmAuthorized;
+ bool m_mute;
+ bool m_audioEnabled;
+ bool m_hasVideo;
+ float m_masterVolume;
+ float m_relativeVolume;
+ float m_playbackRate;
+ quint64 m_currentTime;
+ MediaSource m_mediaSource;
+ void *m_primaryRenderingCIImage;
+ qreal m_brightness;
+ qreal m_contrast;
+ qreal m_hue;
+ qreal m_saturation;
+
+#ifdef QUICKTIME_C_API_AVAILABLE
+ QTVisualContextRef m_visualContext;
+#endif
+ VideoFrame m_currentFrame;
+ QuickTimeStreamReader *m_streamReader;
+
+ void createVisualContext();
+ void openMovieFromCurrentMediaSource();
+ void openMovieFromDataRef(QTDataReference *dataRef);
+ void openMovieFromFile();
+ void openMovieFromUrl();
+ void openMovieFromStream();
+ void openMovieFromData(QByteArray *data, char *fileType);
+ void openMovieFromDataGuessType(QByteArray *data);
+ QString mediaSourcePath();
+ bool codecExistsAccordingToSuffix(const QString &fileName);
+
+ void setError(NSError *error);
+ bool errorOccured();
+ void readProtection();
+ void checkIfVideoAwailable();
+ bool movieNotLoaded();
+ void waitStatePlayable();
+ };
+
+ Q_DECLARE_OPERATORS_FOR_FLAGS(QuickTimeVideoPlayer::State);
+
+}} // namespace Phonon::QT7
+
+QT_END_NAMESPACE
+
+#endif // Phonon_QT7_QUICKTIMEVIDEOPLAYER_H
diff --git a/src/3rdparty/phonon/qt7/quicktimevideoplayer.mm b/src/3rdparty/phonon/qt7/quicktimevideoplayer.mm
new file mode 100644
index 0000000000..3f76132f1e
--- /dev/null
+++ b/src/3rdparty/phonon/qt7/quicktimevideoplayer.mm
@@ -0,0 +1,955 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "quicktimevideoplayer.h"
+#include "mediaobject.h"
+#include "videowidget.h"
+#include "audiodevice.h"
+#include "quicktimestreamreader.h"
+
+#include <QtCore/QCoreApplication>
+#include <QtCore/QEventLoop>
+#include <QtCore/QFileInfo>
+#include <QtCore/QUrl>
+#include <QtOpenGL/QGLContext>
+
+#import <QTKit/QTTrack.h>
+#import <QTKit/QTMedia.h>
+#import <QuartzCore/CIContext.h>
+#import <QuartzCore/CIFilter.h>
+
+#ifdef QUICKTIME_C_API_AVAILABLE
+ #include <QuickTime/QuickTime.h>
+ #undef check // avoid name clash;
+ #include <AGL/agl.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace QT7
+{
+
+// Defined in videowidget.cpp:
+QGLWidget *PhononSharedQGLWidget();
+
+QuickTimeVideoPlayer::QuickTimeVideoPlayer() : QObject(0)
+{
+ m_state = NoMedia;
+ m_mediaSource = MediaSource();
+ m_QTMovie = 0;
+ m_streamReader = 0;
+ m_playbackRate = 1.0f;
+ m_masterVolume = 1.0f;
+ m_relativeVolume = 1.0f;
+ m_currentTime = 0;
+ m_mute = false;
+ m_audioEnabled = false;
+ m_hasVideo = false;
+ m_playbackRateSat = false;
+ m_isDrmProtected = false;
+ m_isDrmAuthorized = true;
+ m_primaryRenderingTarget = 0;
+ m_primaryRenderingCIImage = 0;
+ m_QImagePixelBuffer = 0;
+
+#ifdef QUICKTIME_C_API_AVAILABLE
+ OSStatus err = EnterMovies();
+ BACKEND_ASSERT2(err == noErr, "Could not initialize QuickTime", FATAL_ERROR)
+ createVisualContext();
+#endif
+}
+
+QuickTimeVideoPlayer::~QuickTimeVideoPlayer()
+{
+ unsetVideo();
+ [(NSObject*)m_primaryRenderingTarget release];
+ m_primaryRenderingTarget = 0;
+#ifdef QUICKTIME_C_API_AVAILABLE
+ if (m_visualContext)
+ CFRelease(m_visualContext);
+#endif
+}
+
+void QuickTimeVideoPlayer::createVisualContext()
+{
+#ifdef QUICKTIME_C_API_AVAILABLE
+ PhononSharedQGLWidget()->makeCurrent();
+
+ PhononAutoReleasePool pool;
+ CGLContextObj cglContext = CGLGetCurrentContext();
+ NSOpenGLPixelFormat *nsglPixelFormat = [NSOpenGLView defaultPixelFormat];
+ CGLPixelFormatObj cglPixelFormat = static_cast<CGLPixelFormatObj>([nsglPixelFormat CGLPixelFormatObj]);
+ BACKEND_ASSERT2(cglContext, "Could not get current CoreVideo GL context (OpenGL)", FATAL_ERROR)
+ BACKEND_ASSERT2(cglPixelFormat, "Could not get current CoreVideo pixel format (OpenGL)", FATAL_ERROR)
+
+ CFTypeRef keys[] = { kQTVisualContextWorkingColorSpaceKey };
+ CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
+ CFDictionaryRef textureContextAttributes = CFDictionaryCreate(kCFAllocatorDefault,
+ (const void **)keys,
+ (const void **)&colorSpace, 1,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+
+ OSStatus err = QTOpenGLTextureContextCreate(kCFAllocatorDefault, cglContext,
+ cglPixelFormat, textureContextAttributes, &m_visualContext);
+ CFRelease(textureContextAttributes);
+ BACKEND_ASSERT2(err == noErr, "Could not create visual context (OpenGL)", FATAL_ERROR)
+#endif // QUICKTIME_C_API_AVAILABLE
+}
+
+bool QuickTimeVideoPlayer::videoFrameChanged()
+{
+ if (!m_QTMovie || !m_hasVideo)
+ return false;
+
+#ifdef QUICKTIME_C_API_AVAILABLE
+ if (m_primaryRenderingTarget)
+ return true;
+ if (!m_visualContext)
+ return false;
+
+ QTVisualContextTask(m_visualContext);
+ return QTVisualContextIsNewImageAvailable(m_visualContext, 0);
+
+#elif defined(QT_MAC_USE_COCOA)
+ return true;
+
+#else
+ return false;
+#endif
+}
+
+CVOpenGLTextureRef QuickTimeVideoPlayer::currentFrameAsCVTexture()
+{
+#ifdef QUICKTIME_C_API_AVAILABLE
+ if (!m_visualContext)
+ return 0;
+ CVOpenGLTextureRef texture = 0;
+ OSStatus err = QTVisualContextCopyImageForTime(m_visualContext, 0, 0, &texture);
+ BACKEND_ASSERT3(err == noErr, "Could not copy image for time in QuickTime player", FATAL_ERROR, 0)
+ return texture;
+
+#else
+ return 0;
+#endif
+}
+
+QImage QuickTimeVideoPlayer::currentFrameAsQImage()
+{
+#ifdef QUICKTIME_C_API_AVAILABLE
+ QGLContext *prevContext = const_cast<QGLContext *>(QGLContext::currentContext());
+ CVOpenGLTextureRef texture = currentFrameAsCVTexture();
+ GLenum target = CVOpenGLTextureGetTarget(texture);
+ GLfloat lowerLeft[2], lowerRight[2], upperRight[2], upperLeft[2];
+
+ if (!m_QImagePixelBuffer){
+ m_QImagePixelBuffer = new QGLPixelBuffer(videoRect().size(), QGLFormat::defaultFormat(), PhononSharedQGLWidget());
+ m_QImagePixelBuffer->makeCurrent();
+ glEnable(target);
+ glDisable(GL_BLEND);
+ glDisable(GL_CULL_FACE);
+ } else {
+ m_QImagePixelBuffer->makeCurrent();
+ }
+
+ CVOpenGLTextureGetCleanTexCoords(texture, upperLeft, upperRight, lowerRight, lowerLeft);
+ glBindTexture(target, CVOpenGLTextureGetName(texture));
+ glBegin(GL_QUADS);
+ glTexCoord2f(lowerLeft[0], lowerLeft[1]);
+ glVertex2i(-1, 1);
+ glTexCoord2f(lowerRight[0], lowerRight[1]);
+ glVertex2i(1, 1);
+ glTexCoord2f(upperRight[0], upperRight[1]);
+ glVertex2i(1, -1);
+ glTexCoord2f(upperLeft[0], upperLeft[1]);
+ glVertex2i(-1, -1);
+ glEnd();
+
+ QImage image = m_QImagePixelBuffer->toImage();
+ CVOpenGLTextureRelease(texture);
+ // Because of QuickTime, m_QImagePixelBuffer->doneCurrent() will fail.
+ // So we store, and restore, the context our selves:
+ prevContext->makeCurrent();
+ return image;
+#else
+ CIImage *img = (CIImage *)currentFrameAsCIImage();
+ if (!img)
+ return QImage();
+
+ NSBitmapImageRep* bitmap = [[NSBitmapImageRep alloc] initWithCIImage:img];
+ CGRect bounds = [img extent];
+ QImage qImg([bitmap bitmapData], bounds.size.width, bounds.size.height, QImage::Format_ARGB32);
+ QImage swapped = qImg.rgbSwapped();
+ [bitmap release];
+ [img release];
+ return swapped;
+#endif
+}
+
+void QuickTimeVideoPlayer::setPrimaryRenderingCIImage(void *ciImage)
+{
+ [(CIImage *)m_primaryRenderingCIImage release];
+ m_primaryRenderingCIImage = ciImage;
+ [(CIImage *)m_primaryRenderingCIImage retain];
+}
+
+void QuickTimeVideoPlayer::setPrimaryRenderingTarget(NSObject *target)
+{
+ [(NSObject*)m_primaryRenderingTarget release];
+ m_primaryRenderingTarget = target;
+ [(NSObject*)m_primaryRenderingTarget retain];
+}
+
+void *QuickTimeVideoPlayer::primaryRenderingCIImage()
+{
+ return m_primaryRenderingCIImage;
+}
+
+void *QuickTimeVideoPlayer::currentFrameAsCIImage()
+{
+ if (!m_QTMovie)
+ return 0;
+
+#if defined(QT_MAC_USE_COCOA)
+ if (m_primaryRenderingCIImage){
+ CIImage *img = (CIImage *)m_primaryRenderingCIImage;
+ if (m_brightness || m_contrast || m_saturation){
+ 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 retain];
+ }
+#endif
+
+#ifdef QUICKTIME_C_API_AVAILABLE
+ CVOpenGLTextureRef cvImg = currentFrameAsCVTexture();
+ CIImage *img = [[CIImage alloc] initWithCVImageBuffer:cvImg];
+ CVOpenGLTextureRelease(cvImg);
+ return img;
+#else
+ return 0;
+#endif
+}
+
+GLuint QuickTimeVideoPlayer::currentFrameAsGLTexture()
+{
+ CIImage *img = (CIImage *)currentFrameAsCIImage();
+ if (!img)
+ return 0;
+
+ NSBitmapImageRep* bitmap = [[NSBitmapImageRep alloc] initWithCIImage:img];
+ GLuint texName = 0;
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, [bitmap pixelsWide]);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ glGenTextures(1, &texName);
+ glBindTexture(GL_TEXTURE_RECTANGLE_EXT, texName);
+ glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+
+ int samplesPerPixel = [bitmap samplesPerPixel];
+ if (![bitmap isPlanar] && (samplesPerPixel == 3 || samplesPerPixel == 4)){
+ glTexImage2D(GL_TEXTURE_RECTANGLE_EXT, 0,
+ samplesPerPixel == 4 ? GL_RGBA8 : GL_RGB8,
+ [bitmap pixelsWide], [bitmap pixelsHigh],
+ 0, samplesPerPixel == 4 ? GL_RGBA : GL_RGB,
+ GL_UNSIGNED_BYTE, [bitmap bitmapData]);
+ } else {
+ // Handle other bitmap formats.
+ }
+
+ [bitmap release];
+ [img release];
+ return texName;
+}
+
+void QuickTimeVideoPlayer::setMasterVolume(float volume)
+{
+ setVolume(volume, m_relativeVolume);
+}
+
+void QuickTimeVideoPlayer::setRelativeVolume(float volume)
+{
+ setVolume(m_masterVolume, volume);
+}
+
+void QuickTimeVideoPlayer::setVolume(float masterVolume, float relativeVolume)
+{
+ m_masterVolume = masterVolume;
+ m_relativeVolume = relativeVolume;
+ if (!m_QTMovie || !m_audioEnabled || m_mute)
+ return;
+ [m_QTMovie setVolume:(m_masterVolume * m_relativeVolume)];
+}
+
+void QuickTimeVideoPlayer::setMute(bool mute)
+{
+ m_mute = mute;
+ if (!m_QTMovie || m_state != Playing || !m_audioEnabled)
+ return;
+
+ // Work-around bug that happends if you set/unset mute
+ // before movie is playing, and audio is not played
+ // through graph. Then audio is delayed.
+ [m_QTMovie setMuted:mute];
+ [m_QTMovie setVolume:(mute ? 0 : m_masterVolume * m_relativeVolume)];
+}
+
+void QuickTimeVideoPlayer::enableAudio(bool enable)
+{
+ m_audioEnabled = enable;
+ if (!m_QTMovie || m_state != Playing)
+ return;
+
+ // Work-around bug that happends if you set/unset mute
+ // before movie is playing, and audio is not played
+ // through graph. Then audio is delayed.
+ [m_QTMovie setMuted:(!enable || m_mute)];
+ [m_QTMovie setVolume:((!enable || m_mute) ? 0 : m_masterVolume * m_relativeVolume)];
+}
+
+bool QuickTimeVideoPlayer::audioEnabled()
+{
+ return m_audioEnabled;
+}
+
+bool QuickTimeVideoPlayer::setAudioDevice(int id)
+{
+ if (!m_QTMovie)
+ return false;
+
+#ifdef QUICKTIME_C_API_AVAILABLE
+ // The following code will not work for some media codecs that
+ // typically mingle audio/video frames (e.g mpeg).
+ CFStringRef idString = PhononCFString::toCFStringRef(AudioDevice::deviceUID(id));
+ QTAudioContextRef context;
+ QTAudioContextCreateForAudioDevice(kCFAllocatorDefault, idString, 0, &context);
+ OSStatus err = SetMovieAudioContext([m_QTMovie quickTimeMovie], context);
+ CFRelease(context);
+ if (err != noErr)
+ return false;
+ return true;
+#else
+ Q_UNUSED(id);
+ return false;
+#endif
+}
+
+void QuickTimeVideoPlayer::setColors(qreal brightness, qreal contrast, qreal hue, qreal saturation)
+{
+ if (!m_QTMovie)
+ return;
+
+ // 0 is default value for the colors
+ // in phonon, so adjust scale:
+ contrast += 1;
+ saturation += 1;
+
+ m_brightness = brightness;
+ m_contrast = contrast;
+ m_hue = hue;
+ m_saturation = saturation;
+
+#ifdef QUICKTIME_C_API_AVAILABLE
+ Float32 value;
+ value = brightness;
+ SetMovieVisualBrightness([m_QTMovie quickTimeMovie], value, 0);
+ value = contrast;
+ SetMovieVisualContrast([m_QTMovie quickTimeMovie], value, 0);
+ value = hue;
+ SetMovieVisualHue([m_QTMovie quickTimeMovie], value, 0);
+ value = saturation;
+ SetMovieVisualSaturation([m_QTMovie quickTimeMovie], value, 0);
+#endif
+}
+
+QRect QuickTimeVideoPlayer::videoRect() const
+{
+ if (!m_QTMovie)
+ return QRect();
+
+ PhononAutoReleasePool pool;
+ NSSize size = [[m_QTMovie attributeForKey:@"QTMovieCurrentSizeAttribute"] sizeValue];
+ return QRect(0, 0, size.width, size.height);
+}
+
+void QuickTimeVideoPlayer::unsetVideo()
+{
+ if (!m_QTMovie)
+ return;
+
+ [m_QTMovie release];
+ m_QTMovie = 0;
+ delete m_streamReader;
+ m_streamReader = 0;
+ m_currentTime = 0;
+ m_state = NoMedia;
+ m_isDrmProtected = false;
+ m_isDrmAuthorized = true;
+ m_mediaSource = MediaSource();
+ [(CIImage *)m_primaryRenderingCIImage release];
+ m_primaryRenderingCIImage = 0;
+ delete m_QImagePixelBuffer;
+ m_QImagePixelBuffer = 0;
+}
+
+QuickTimeVideoPlayer::State QuickTimeVideoPlayer::state() const
+{
+ return m_state;
+}
+
+quint64 QuickTimeVideoPlayer::timeLoaded()
+{
+ if (!m_QTMovie)
+ return 0;
+#ifdef QUICKTIME_C_API_AVAILABLE
+ TimeValue value;
+ GetMaxLoadedTimeInMovie([m_QTMovie quickTimeMovie], &value);
+ quint64 loaded = static_cast<quint64>(float(value) / float(GetMovieTimeScale([m_QTMovie quickTimeMovie])) * 1000.0f);
+ return (loaded == INT_MAX) ? 0 : loaded;
+#else
+ return 0;
+#endif
+}
+
+float QuickTimeVideoPlayer::percentageLoaded()
+{
+ if (!m_QTMovie || !isSeekable())
+ return 0;
+#ifdef QUICKTIME_C_API_AVAILABLE
+ TimeValue loaded;
+ GetMaxLoadedTimeInMovie([m_QTMovie quickTimeMovie], &loaded);
+ float duration = GetMovieDuration([m_QTMovie quickTimeMovie]);
+ return duration ? float(loaded) / duration : 0;
+#else
+ return 0;
+#endif
+}
+
+void QuickTimeVideoPlayer::waitStatePlayable()
+{
+#if defined(QT_MAC_USE_COCOA)
+ long state = [[m_QTMovie attributeForKey:@"QTMovieLoadStateAttribute"] longValue];
+ while (state != QTMovieLoadStateError && state < QTMovieLoadStatePlayable)
+ state = [[m_QTMovie attributeForKey:@"QTMovieLoadStateAttribute"] longValue];
+#elif defined(QUICKTIME_C_API_AVAILABLE)
+ long state = GetMovieLoadState([m_QTMovie quickTimeMovie]);
+ while (state != kMovieLoadStateError && state < kMovieLoadStatePlayable){
+ MoviesTask(0, 0);
+ state = GetMovieLoadState([m_QTMovie quickTimeMovie]);
+ }
+#endif
+}
+
+bool QuickTimeVideoPlayer::movieNotLoaded()
+{
+ if (!m_QTMovie)
+ return true;
+
+#if defined(QT_MAC_USE_COCOA)
+ long state = [[m_QTMovie attributeForKey:@"QTMovieLoadStateAttribute"] longValue];
+ return state == QTMovieLoadStateError;
+#elif defined(QUICKTIME_C_API_AVAILABLE)
+ long state = GetMovieLoadState([m_QTMovie quickTimeMovie]);
+ return state == kMovieLoadStateError;
+#endif
+}
+
+void QuickTimeVideoPlayer::setError(NSError *error)
+{
+ if (!error)
+ return;
+ QString desc = QString::fromUtf8([[error localizedDescription] UTF8String]);
+ if (desc == "The file is not a movie file.")
+ desc = QLatin1String("Could not decode media source.");
+ else if (desc == "A necessary data reference could not be resolved."){
+ if (codecExistsAccordingToSuffix(mediaSourcePath()))
+ desc = QLatin1String("Could not locate media source.");
+ else
+ desc = QLatin1String("Could not decode media source.");
+ } else if (desc == "You do not have sufficient permissions for this operation.")
+ desc = QLatin1String("Could not open media source.");
+ SET_ERROR(desc, FATAL_ERROR)
+}
+
+bool QuickTimeVideoPlayer::errorOccured()
+{
+ if (gGetErrorType() != NO_ERROR){
+ return true;
+ } else if (movieNotLoaded()){
+ SET_ERROR("Could not open media source.", FATAL_ERROR)
+ return true;
+ }
+ return false;
+}
+
+bool QuickTimeVideoPlayer::codecExistsAccordingToSuffix(const QString &fileName)
+{
+ PhononAutoReleasePool pool;
+ NSArray *fileTypes = [QTMovie movieFileTypes:QTIncludeAllTypes];
+ for (uint i=0; i<[fileTypes count]; ++i){
+ NSString *type = [fileTypes objectAtIndex:i];
+ QString formattedType = QString::fromUtf8([type UTF8String]);
+ formattedType.remove('\'').remove('.');
+ if (fileName.endsWith(QChar('.') + formattedType, Qt::CaseInsensitive))
+ return true;
+ }
+ return false;
+}
+
+void QuickTimeVideoPlayer::setMediaSource(const MediaSource &mediaSource)
+{
+ PhononAutoReleasePool pool;
+ unsetVideo();
+ m_mediaSource = mediaSource;
+ if (mediaSource.type() == MediaSource::Empty || mediaSource.type() == MediaSource::Invalid){
+ m_state = NoMedia;
+ return;
+ }
+ openMovieFromCurrentMediaSource();
+ if (errorOccured()){
+ unsetVideo();
+ return;
+ }
+
+#ifdef QUICKTIME_C_API_AVAILABLE
+ if (m_visualContext)
+ SetMovieVisualContext([m_QTMovie quickTimeMovie], m_visualContext);
+#endif
+
+ waitStatePlayable();
+ if (errorOccured()){
+ unsetVideo();
+ return;
+ }
+
+ readProtection();
+ preRollMovie();
+ if (errorOccured()){
+ unsetVideo();
+ return;
+ }
+
+ if (!m_playbackRateSat)
+ m_playbackRate = prefferedPlaybackRate();
+ checkIfVideoAwailable();
+ enableAudio(m_audioEnabled);
+ setMute(m_mute);
+ setVolume(m_masterVolume, m_relativeVolume);
+ pause();
+}
+
+void QuickTimeVideoPlayer::openMovieFromCurrentMediaSource()
+{
+ switch (m_mediaSource.type()){
+ case MediaSource::LocalFile:
+ openMovieFromFile();
+ break;
+ case MediaSource::Url:
+ openMovieFromUrl();
+ break;
+ case MediaSource::Disc:
+ CASE_UNSUPPORTED("Could not open media source.", FATAL_ERROR)
+ break;
+ case MediaSource::Stream:
+ openMovieFromStream();
+ break;
+ case MediaSource::Empty:
+ case MediaSource::Invalid:
+ break;
+ }
+}
+
+QString QuickTimeVideoPlayer::mediaSourcePath()
+{
+ switch (m_mediaSource.type()){
+ case MediaSource::LocalFile:{
+ QFileInfo fileInfo(m_mediaSource.fileName());
+ return fileInfo.isSymLink() ? fileInfo.symLinkTarget() : fileInfo.canonicalFilePath();
+ break;}
+ case MediaSource::Url:
+ return m_mediaSource.url().toEncoded();
+ break;
+ default:
+ break;
+ }
+ return QString();
+}
+
+void QuickTimeVideoPlayer::openMovieFromDataRef(QTDataReference *dataRef)
+{
+ PhononAutoReleasePool pool;
+ NSDictionary *attr = [NSDictionary dictionaryWithObjectsAndKeys:
+ dataRef, QTMovieDataReferenceAttribute,
+ [NSNumber numberWithBool:YES], QTMovieOpenAsyncOKAttribute,
+ [NSNumber numberWithBool:YES], QTMovieIsActiveAttribute,
+ [NSNumber numberWithBool:YES], QTMovieResolveDataRefsAttribute,
+ [NSNumber numberWithBool:YES], QTMovieDontInteractWithUserAttribute,
+ nil];
+
+ NSError *err = 0;
+ m_QTMovie = [[QTMovie movieWithAttributes:attr error:&err] retain];
+ if (err){
+ [m_QTMovie release];
+ m_QTMovie = 0;
+ setError(err);
+ }
+}
+
+void QuickTimeVideoPlayer::openMovieFromData(QByteArray *data, char *fileType)
+{
+ PhononAutoReleasePool pool;
+ NSString *type = [NSString stringWithUTF8String:fileType];
+ NSData *nsData = [NSData dataWithBytesNoCopy:data->data() length:data->size() freeWhenDone:NO];
+ QTDataReference *dataRef = [QTDataReference dataReferenceWithReferenceToData:nsData name:type MIMEType:@""];
+ openMovieFromDataRef(dataRef);
+}
+
+void QuickTimeVideoPlayer::openMovieFromDataGuessType(QByteArray *data)
+{
+ // It turns out to be better to just try the standard file types rather
+ // than using e.g [QTMovie movieFileTypes:QTIncludeCommonTypes]. Some
+ // codecs *think* they can decode the stream, and crash...
+#define TryOpenMovieWithCodec(type) gClearError(); \
+ openMovieFromData(data, "."type); \
+ if (m_QTMovie) return;
+
+ TryOpenMovieWithCodec("avi");
+ TryOpenMovieWithCodec("mp4");
+ TryOpenMovieWithCodec("m4p");
+ TryOpenMovieWithCodec("m1s");
+ TryOpenMovieWithCodec("mp3");
+ TryOpenMovieWithCodec("mpeg");
+ TryOpenMovieWithCodec("mov");
+ TryOpenMovieWithCodec("ogg");
+ TryOpenMovieWithCodec("wav");
+ TryOpenMovieWithCodec("wmv");
+#undef TryOpenMovieWithCodec(type)
+}
+
+void QuickTimeVideoPlayer::openMovieFromFile()
+{
+ NSString *nsFilename = (NSString *)PhononCFString::toCFStringRef(mediaSourcePath());
+ QTDataReference *dataRef = [QTDataReference dataReferenceWithReferenceToFile:nsFilename];
+ openMovieFromDataRef(dataRef);
+}
+
+void QuickTimeVideoPlayer::openMovieFromUrl()
+{
+ PhononAutoReleasePool pool;
+ NSString *urlString = (NSString *)PhononCFString::toCFStringRef(mediaSourcePath());
+ NSURL *url = [NSURL URLWithString: urlString];
+ QTDataReference *dataRef = [QTDataReference dataReferenceWithReferenceToURL:url];
+ openMovieFromDataRef(dataRef);
+}
+
+void QuickTimeVideoPlayer::openMovieFromStream()
+{
+ m_streamReader = new QuickTimeStreamReader(m_mediaSource);
+ if (!m_streamReader->readAllData())
+ return;
+ openMovieFromDataGuessType(m_streamReader->pointerToData());
+}
+
+MediaSource QuickTimeVideoPlayer::mediaSource() const
+{
+ return m_mediaSource;
+}
+
+QTMovie *QuickTimeVideoPlayer::qtMovie() const
+{
+ return m_QTMovie;
+}
+
+void QuickTimeVideoPlayer::setPlaybackRate(float rate)
+{
+ PhononAutoReleasePool pool;
+ m_playbackRateSat = true;
+ m_playbackRate = rate;
+ if (m_QTMovie)
+ [m_QTMovie setRate:m_playbackRate];
+}
+
+float QuickTimeVideoPlayer::playbackRate() const
+{
+ return m_playbackRate;
+}
+
+quint64 QuickTimeVideoPlayer::currentTime() const
+{
+ if (!m_QTMovie || m_state == Paused)
+ return m_currentTime;
+
+ PhononAutoReleasePool pool;
+ QTTime qtTime = [m_QTMovie currentTime];
+ quint64 t = static_cast<quint64>(float(qtTime.timeValue) / float(qtTime.timeScale) * 1000.0f);
+ const_cast<QuickTimeVideoPlayer *>(this)->m_currentTime = t;
+ return m_currentTime;
+}
+
+long QuickTimeVideoPlayer::timeScale() const
+{
+ if (!m_QTMovie)
+ return 0;
+
+ PhononAutoReleasePool pool;
+ return [[m_QTMovie attributeForKey:@"QTMovieTimeScaleAttribute"] longValue];
+}
+
+QString QuickTimeVideoPlayer::timeToString(quint64 ms)
+{
+ int sec = ms/1000;
+ int min = sec/60;
+ int hour = min/60;
+ return QString(QLatin1String("%1:%2:%3:%4")).arg(hour%60).arg(min%60).arg(sec%60).arg(ms%1000);
+}
+
+QString QuickTimeVideoPlayer::currentTimeString()
+{
+ return timeToString(currentTime());
+}
+
+quint64 QuickTimeVideoPlayer::duration() const
+{
+ if (!m_QTMovie)
+ return 0;
+
+ PhononAutoReleasePool pool;
+ QTTime qtTime = [m_QTMovie duration];
+ return static_cast<quint64>(float(qtTime.timeValue) / float(qtTime.timeScale) * 1000.0f);
+}
+
+void QuickTimeVideoPlayer::play()
+{
+ if (!canPlayMedia())
+ return;
+
+ PhononAutoReleasePool pool;
+ m_state = Playing;
+ enableAudio(m_audioEnabled);
+ setMute(m_mute);
+ [m_QTMovie setRate:m_playbackRate];
+}
+
+void QuickTimeVideoPlayer::pause()
+{
+ if (!canPlayMedia())
+ return;
+
+ PhononAutoReleasePool pool;
+ currentTime();
+ m_state = Paused;
+
+ if (isSeekable())
+ [m_QTMovie setRate:0];
+ else // pretend to be paused:
+ [m_QTMovie setMuted:0];
+}
+
+void QuickTimeVideoPlayer::seek(quint64 milliseconds)
+{
+ if (!canPlayMedia() || !isSeekable() || milliseconds == currentTime())
+ return;
+ if (milliseconds > duration())
+ milliseconds = duration();
+
+ PhononAutoReleasePool pool;
+ QTTime newQTTime = [m_QTMovie currentTime];
+ newQTTime.timeValue = (milliseconds / 1000.0f) * newQTTime.timeScale;
+ [m_QTMovie setCurrentTime:newQTTime];
+
+ // The movie might not have been able to seek
+ // to the exact point we told it to. So set
+ // the current time according to what the movie says:
+ newQTTime = [m_QTMovie currentTime];
+ m_currentTime = static_cast<quint64>
+ (float(newQTTime.timeValue) / float(newQTTime.timeScale) * 1000.0f);
+
+ if (m_state == Paused){
+ // We need (for reasons unknown) to task
+ // the movie twize to make sure that
+ // a subsequent call to frameAsCvTexture
+ // returns the correct frame:
+#ifdef QUICKTIME_C_API_AVAILABLE
+ MoviesTask(0, 0);
+ MoviesTask(0, 0);
+#elif defined(QT_MAC_USE_COCOA)
+ qApp->processEvents(QEventLoop::ExcludeUserInputEvents | QEventLoop::ExcludeSocketNotifiers);
+#endif
+ }
+}
+
+bool QuickTimeVideoPlayer::canPlayMedia() const
+{
+ if (!m_QTMovie)
+ return false;
+ return m_isDrmAuthorized;
+}
+
+bool QuickTimeVideoPlayer::isPlaying() const
+{
+ return m_state == Playing;
+}
+
+bool QuickTimeVideoPlayer::isSeekable() const
+{
+ return canPlayMedia() && (duration()-1) != INT_MAX;
+}
+
+float QuickTimeVideoPlayer::prefferedPlaybackRate() const
+{
+ if (!m_QTMovie)
+ return 0;
+
+ PhononAutoReleasePool pool;
+ return [[m_QTMovie attributeForKey:@"QTMoviePreferredRateAttribute"] floatValue];
+}
+
+#ifdef QUICKTIME_C_API_AVAILABLE
+void MoviePrePrerollCompleteCallBack(Movie /*theMovie*/, OSErr /*thePrerollErr*/, void * /*userData*/)
+{
+ // QuickTimeVideoPlayer *player = static_cast<QuickTimeVideoPlayer *>(userData);
+}
+#endif
+
+bool QuickTimeVideoPlayer::preRollMovie(qint64 startTime)
+{
+ if (!canPlayMedia())
+ return false;
+
+#ifdef QUICKTIME_C_API_AVAILABLE
+ if (PrePrerollMovie([m_QTMovie quickTimeMovie], startTime, FloatToFixed(m_playbackRate),
+ 0 /*MoviePrePrerollCompleteCallBack*/, this) != noErr) // No callback means wait (synch)
+ return false;
+
+ if (PrerollMovie([m_QTMovie quickTimeMovie], startTime, FloatToFixed(m_playbackRate)) != noErr)
+ return false;
+
+ return true;
+#else
+ Q_UNUSED(startTime);
+ return false;
+#endif
+}
+
+bool QuickTimeVideoPlayer::hasAudio() const
+{
+ if (!m_QTMovie)
+ return false;
+
+ PhononAutoReleasePool pool;
+ return [[m_QTMovie attributeForKey:@"QTMovieHasAudioAttribute"] boolValue] == YES;
+}
+
+bool QuickTimeVideoPlayer::hasVideo() const
+{
+ return m_hasVideo;
+}
+
+bool QuickTimeVideoPlayer::hasMovie() const
+{
+ return m_QTMovie != 0;
+}
+
+void QuickTimeVideoPlayer::checkIfVideoAwailable()
+{
+ PhononAutoReleasePool pool;
+ m_hasVideo = [[m_QTMovie attributeForKey:@"QTMovieHasVideoAttribute"] boolValue] == YES;
+}
+
+bool QuickTimeVideoPlayer::isDrmProtected() const
+{
+ return m_isDrmProtected;
+}
+
+bool QuickTimeVideoPlayer::isDrmAuthorized() const
+{
+ return m_isDrmAuthorized;
+}
+/*
+void QuickTimeVideoPlayer::movieCodecIsMPEG()
+{
+ NSArray *tracks = [m_QTMovie tracks];
+ for (QTTrack *track in tracks)
+ if ([[track media] hasCharacteristic:QTMediaTypeMPEG])
+ return true;
+ return false;
+}
+*/
+
+static void QtGetTrackProtection(QTTrack *track, bool &isDrmProtected, bool &isDrmAuthorized)
+{
+ isDrmProtected = false;
+ isDrmAuthorized = true;
+
+#ifdef QUICKTIME_C_API_AVAILABLE
+ QTMedia *media = [track media];
+ MediaHandler mediaHandler = GetMediaHandler([media quickTimeMedia]);
+ if (mediaHandler){
+ // Regardless, skip message boxes pointing to iTunes regarding DRM:
+ Boolean boolFalse = false;
+ QTSetComponentProperty(mediaHandler,
+ kQTPropertyClass_DRM, kQTDRMPropertyID_InteractWithUser,
+ sizeof(boolFalse), &boolFalse);
+
+ // Check track:
+ Boolean value;
+ OSStatus err = QTGetComponentProperty(mediaHandler,
+ kQTPropertyClass_DRM, kQTDRMPropertyID_IsProtected,
+ sizeof(value), &value, 0);
+ isDrmProtected = (err == noErr) ? bool(value) : false;
+ err = QTGetComponentProperty(mediaHandler,
+ kQTPropertyClass_DRM, kQTDRMPropertyID_IsAuthorized,
+ sizeof(value), &value, 0);
+ isDrmAuthorized = (err == noErr) ? bool(value) : true;
+ }
+#else
+ Q_UNUSED(track);
+#endif // QUICKTIME_C_API_AVAILABLE
+}
+
+void QuickTimeVideoPlayer::readProtection()
+{
+ m_isDrmProtected = false;
+ m_isDrmAuthorized = true;
+
+ NSArray *tracks = [m_QTMovie tracks];
+ for (uint i=0; i<[tracks count]; ++i){
+ QTTrack *track = [tracks objectAtIndex:i];
+ bool isDrmProtected = false;
+ bool isDrmAuthorized = true;
+ QtGetTrackProtection(track, isDrmProtected, isDrmAuthorized);
+ if (isDrmProtected)
+ m_isDrmProtected = true;
+ if (!isDrmAuthorized)
+ m_isDrmAuthorized = false;
+ }
+}
+
+}}
+
+QT_END_NAMESPACE
diff --git a/src/3rdparty/phonon/qt7/videoeffect.h b/src/3rdparty/phonon/qt7/videoeffect.h
new file mode 100644
index 0000000000..9189a6a03a
--- /dev/null
+++ b/src/3rdparty/phonon/qt7/videoeffect.h
@@ -0,0 +1,63 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef Phonon_QT7_VIDEOEFFECT_H
+#define Phonon_QT7_VIDEOEFFECT_H
+
+#include <QtCore/QList>
+#include <QtCore/QString>
+#include <phonon/effectinterface.h>
+#include "medianode.h"
+#include "videoframe.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+ class EffectParameter;
+
+namespace QT7
+{
+ class MediaNodeEvent;
+
+ class VideoEffect : public MediaNode, public Phonon::EffectInterface
+ {
+ Q_OBJECT
+ Q_INTERFACES(Phonon::EffectInterface)
+
+ public:
+ VideoEffect(int effectId, QObject *parent);
+ virtual ~VideoEffect();
+
+ QList<EffectParameter> parameters() const;
+ QVariant parameterValue(const EffectParameter &) const;
+ void setParameterValue(const EffectParameter &, const QVariant &newValue);
+
+ void updateVideo(VideoFrame &frame);
+
+ protected:
+ void mediaNodeEvent(const MediaNodeEvent *event);
+
+ private:
+ int effectId;
+ void *ciFilter;
+ QString filterName;
+ };
+}} // namespace Phonon::QT7
+
+QT_END_NAMESPACE
+#endif // Phonon_QT7_VIDEOEFFECT_H
diff --git a/src/3rdparty/phonon/qt7/videoeffect.mm b/src/3rdparty/phonon/qt7/videoeffect.mm
new file mode 100644
index 0000000000..c33a9196db
--- /dev/null
+++ b/src/3rdparty/phonon/qt7/videoeffect.mm
@@ -0,0 +1,76 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "videoeffect.h"
+#include "backendheader.h"
+#include "objc_help.h"
+#include <phonon/effect.h>
+#include <phonon/effectparameter.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace QT7
+{
+
+VideoEffect::VideoEffect(int effectId, QObject *parent) : MediaNode(VideoSink | VideoSource, 0, parent), effectId(effectId)
+{
+ ciFilter = objc_createCiFilter(effectId);
+ if (ciFilter)
+ filterName = objc_getCiFilterInfo()->filterDisplayNames[effectId];
+}
+
+VideoEffect::~VideoEffect()
+{
+ if (ciFilter)
+ objc_releaseCiFilter(ciFilter);
+}
+
+QList<EffectParameter> VideoEffect::parameters() const
+{
+ IMPLEMENTED;
+ return objc_getCiFilterParameterInfo(ciFilter).parameters;
+}
+
+QVariant VideoEffect::parameterValue(const EffectParameter &parameter) const
+{
+ IMPLEMENTED;
+ return objc_getCiFilterParameter(ciFilter, parameter.id());
+}
+
+void VideoEffect::setParameterValue(const EffectParameter &parameter, const QVariant &newValue)
+{
+ IMPLEMENTED;
+ objc_setCiFilterParameter(ciFilter, parameter.id(), newValue);
+}
+
+void VideoEffect::mediaNodeEvent(const MediaNodeEvent */*event*/)
+{
+}
+
+void VideoEffect::updateVideo(VideoFrame &frame){
+ frame.applyCoreImageFilter(ciFilter);
+ MediaNode::updateVideo(frame);
+}
+
+}}
+
+QT_END_NAMESPACE
+
+#include "moc_videoeffect.cpp"
+
diff --git a/src/3rdparty/phonon/qt7/videoframe.h b/src/3rdparty/phonon/qt7/videoframe.h
new file mode 100644
index 0000000000..506960728f
--- /dev/null
+++ b/src/3rdparty/phonon/qt7/videoframe.h
@@ -0,0 +1,98 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef Phonon_QT7_VIDEOFRAME_H
+#define Phonon_QT7_VIDEOFRAME_H
+
+#import <QuartzCore/CVOpenGLTexture.h>
+#import <AppKit/NSImage.h>
+#undef check // avoid name clash;
+
+#include <QtCore/QRect>
+#include <QtGui/QPainter>
+#include <QtGui/QImage>
+
+QT_BEGIN_NAMESPACE
+
+class QGLContext;
+
+namespace Phonon
+{
+namespace QT7
+{
+ class QuickTimeVideoPlayer;
+ class QNSBitmapImage;
+
+ class VideoFrame
+ {
+ public:
+ VideoFrame();
+ VideoFrame(QuickTimeVideoPlayer *videoPlayer);
+ VideoFrame(const VideoFrame& frame);
+ void operator=(const VideoFrame& frame);
+ ~VideoFrame();
+
+
+ CVOpenGLTextureRef cachedCVTexture() const;
+ void *cachedCIImage() const;
+ GLuint glTextureRef() const;
+
+ void drawQImage(QPainter *p, const QRect &rect) const;
+ void drawCIImage(const CGRect &rect, float opacity = 1.0f) const;
+ void drawCIImage(const QRect &rect, float opacity = 1.0f) const;
+ void drawCVTexture(const QRect &rect, float opacity = 1.0f) const;
+ void drawGLTexture(const QRect &rect, float opacity = 1.0f) const;
+
+ void applyCoreImageFilter(void *filter);
+ void setColors(qreal brightness, qreal contrast, qreal hue, qreal saturation);
+ bool hasColorAdjustments();
+ void setBaseOpacity(qreal opacity);
+ void setBackgroundFrame(const VideoFrame &frame);
+
+ bool isEmpty();
+ QRect frameRect() const;
+ QuickTimeVideoPlayer *videoPlayer();
+
+ void retain() const;
+ void release() const;
+
+ static CGRect QRectToCGRect(const QRect & qrect);
+
+ private:
+ CVOpenGLTextureRef m_cachedCVTextureRef;
+ void *m_cachedCIImage;
+ QImage m_cachedQImage;
+ NSBitmapImageRep *m_cachedNSBitmap;
+
+ QuickTimeVideoPlayer *m_videoPlayer;
+ VideoFrame *m_backgroundFrame;
+
+ qreal m_brightness;
+ qreal m_contrast;
+ qreal m_hue;
+ qreal m_saturation;
+ qreal m_opacity;
+
+ void initMembers();
+ void copyMembers(const VideoFrame& frame);
+ void invalidateImage() const;
+ };
+
+}} //namespace Phonon::QT7
+
+QT_END_NAMESPACE
+#endif // Phonon_QT7_VIDEOFRAME_H
diff --git a/src/3rdparty/phonon/qt7/videoframe.mm b/src/3rdparty/phonon/qt7/videoframe.mm
new file mode 100644
index 0000000000..92a3cd5181
--- /dev/null
+++ b/src/3rdparty/phonon/qt7/videoframe.mm
@@ -0,0 +1,378 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "videoframe.h"
+#include "quicktimevideoplayer.h"
+#import <QuartzCore/CIFilter.h>
+#import <QuartzCore/CIContext.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace QT7
+{
+
+ VideoFrame::VideoFrame()
+ {
+ initMembers();
+ }
+
+ VideoFrame::VideoFrame(QuickTimeVideoPlayer *videoPlayer)
+ {
+ initMembers();
+ m_videoPlayer = videoPlayer;
+ }
+
+ VideoFrame::VideoFrame(const VideoFrame& frame)
+ {
+ copyMembers(frame);
+ retain();
+ }
+
+ void VideoFrame::operator=(const VideoFrame& frame)
+ {
+ if (this == &frame)
+ return;
+
+ release();
+ copyMembers(frame);
+ retain();
+ }
+
+ void VideoFrame::initMembers()
+ {
+ m_cachedCVTextureRef = 0;
+ m_cachedCIImage = 0;
+ m_cachedNSBitmap = 0;
+ m_videoPlayer = 0;
+ m_brightness = 0;
+ m_contrast = 0;
+ m_hue = 0;
+ m_saturation = 0;
+ m_opacity = 1;
+ m_backgroundFrame = 0;
+ }
+
+ void VideoFrame::copyMembers(const VideoFrame& frame)
+ {
+ m_cachedCVTextureRef = frame.m_cachedCVTextureRef;
+ m_cachedCIImage = frame.m_cachedCIImage;
+ m_cachedQImage = frame.m_cachedQImage;
+ m_cachedNSBitmap = frame.m_cachedNSBitmap;
+ m_videoPlayer = frame.m_videoPlayer;
+ m_brightness = frame.m_brightness;
+ m_contrast = frame.m_contrast;
+ m_hue = frame.m_hue;
+ m_saturation = frame.m_saturation;
+ m_opacity = frame.m_opacity;
+ m_backgroundFrame = frame.m_backgroundFrame;
+ }
+
+ VideoFrame::~VideoFrame()
+ {
+ release();
+ }
+
+ QuickTimeVideoPlayer *VideoFrame::videoPlayer()
+ {
+ return m_videoPlayer;
+ }
+
+ void VideoFrame::setBackgroundFrame(const VideoFrame &frame)
+ {
+ m_backgroundFrame = new VideoFrame(frame);
+ }
+
+ QRect VideoFrame::frameRect() const
+ {
+ return m_videoPlayer->videoRect();
+ }
+
+ CVOpenGLTextureRef VideoFrame::cachedCVTexture() const
+ {
+ if (!m_cachedCVTextureRef && m_videoPlayer){
+ m_videoPlayer->setColors(m_brightness, m_contrast, m_hue, m_saturation);
+ (const_cast<VideoFrame *>(this))->m_cachedCVTextureRef = m_videoPlayer->currentFrameAsCVTexture();
+ }
+ return m_cachedCVTextureRef;
+ }
+
+ void *VideoFrame::cachedCIImage() const
+ {
+ if (!m_cachedCIImage && m_videoPlayer){
+ m_videoPlayer->setColors(m_brightness, m_contrast, m_hue, m_saturation);
+ (const_cast<VideoFrame *>(this))->m_cachedCIImage = m_videoPlayer->currentFrameAsCIImage();
+ }
+ return m_cachedCIImage;
+ }
+
+ GLuint VideoFrame::glTextureRef() const
+ {
+ return CVOpenGLTextureGetName(cachedCVTexture());
+ }
+
+ void VideoFrame::setColors(qreal brightness, qreal contrast, qreal hue, qreal saturation)
+ {
+ if (m_backgroundFrame)
+ m_backgroundFrame->setColors(brightness, contrast, hue, saturation);
+ if (m_brightness == brightness
+ && m_contrast == contrast
+ && m_hue == hue
+ && m_saturation == saturation)
+ return;
+
+ m_brightness = brightness;
+ m_contrast = contrast;
+ m_hue = hue;
+ m_saturation = saturation;
+
+ invalidateImage();
+ }
+
+ CGRect VideoFrame::QRectToCGRect(const QRect & qrect)
+ {
+ CGRect cgrect;
+ cgrect.origin.x = qrect.x();
+ cgrect.origin.y = qrect.y() + qrect.height();
+ cgrect.size.width = qrect.width();
+ cgrect.size.height = -qrect.height();
+ return cgrect;
+ }
+
+ bool VideoFrame::hasColorAdjustments()
+ {
+ return (m_brightness || m_contrast || m_saturation || m_hue);
+ }
+
+ void VideoFrame::setBaseOpacity(qreal opacity)
+ {
+ m_opacity = opacity;
+ }
+
+ void VideoFrame::drawQImage(QPainter *p, const QRect &rect) const
+ {
+ if (!m_videoPlayer)
+ return;
+#ifdef QUICKTIME_C_API_AVAILABLE
+ if (m_cachedQImage.isNull()){
+ m_videoPlayer->setColors(m_brightness, m_contrast, m_hue, m_saturation);
+ (const_cast<VideoFrame *>(this))->m_cachedQImage = m_videoPlayer->currentFrameAsQImage();
+ }
+#else
+ // Since cocoa-64 doesn't give us OpenGL textures directly, the process of converting
+ // CIImges into QImages takes time. We could still call m_videoPlayer->currentFrameAsQImage(),
+ // but because of bitmap memory management issues, and the fact that we need to swap red and
+ // blue, we can optimize the process a bit here since we are going to draw immidiatly:
+ CIImage *img = (CIImage*)cachedCIImage();
+ if (!img)
+ return;
+
+ if (!m_cachedNSBitmap){
+ (const_cast<VideoFrame *>(this))->m_cachedNSBitmap =
+ [[NSBitmapImageRep alloc] initWithCIImage:img];
+ CGRect bounds = [img extent];
+ int w = bounds.size.width;
+ int h = bounds.size.height;
+ (const_cast<VideoFrame *>(this))->m_cachedQImage =
+ QImage([m_cachedNSBitmap bitmapData], w, h, QImage::Format_ARGB32);
+ // Swap red and blue (same as QImage::rgbSwapped, but without copy)
+ for (int i=0; i<h; ++i) {
+ uint *p = (uint*) m_cachedQImage.scanLine(i);
+ uint *end = p + w;
+ while (p < end) {
+ *p = ((*p << 16) & 0xff0000) | ((*p >> 16) & 0xff) | (*p & 0xff00ff00);
+ p++;
+ }
+ }
+ }
+#endif
+ p->drawImage(rect, m_cachedQImage);
+ }
+
+ void VideoFrame::drawCIImage(const QRect &rect, float opacity) const
+ {
+ drawCIImage(QRectToCGRect(rect), opacity);
+ }
+
+ void VideoFrame::drawCIImage(const CGRect &rect, float opacity) const
+ {
+ Q_UNUSED(opacity);
+ CIImage *img = (CIImage *) cachedCIImage();
+ if (!img)
+ return;
+
+ CIContext* ciContext = [[NSGraphicsContext currentContext] CIContext];
+ [ciContext drawImage:img inRect:rect fromRect:[img extent]];
+ }
+
+ void VideoFrame::drawCVTexture(const QRect &rect, float opacity) const
+ {
+ if (!m_videoPlayer)
+ return;
+ if (m_backgroundFrame)
+ m_backgroundFrame->drawCVTexture(rect, opacity);
+
+ CVOpenGLTextureRef texRef = cachedCVTexture();
+ if (!texRef)
+ return;
+
+ glPushMatrix();
+ glDisable(GL_CULL_FACE);
+ GLenum target = CVOpenGLTextureGetTarget(texRef);
+ glEnable(target);
+
+ opacity *= m_opacity;
+ if (opacity < 1){
+ glEnable(GL_BLEND);
+ glColor4f(1, 1, 1, opacity);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ } else {
+ glColor3f(1, 1, 1);
+ glDisable(GL_BLEND);
+ }
+
+ glBindTexture(target, CVOpenGLTextureGetName(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(texRef, lowerLeft, lowerRight, upperRight, upperLeft);
+
+ glBegin(GL_QUADS);
+ 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 VideoFrame::drawGLTexture(const QRect &rect, float opacity) const
+ {
+ if (!m_videoPlayer)
+ return;
+ if (m_backgroundFrame)
+ m_backgroundFrame->drawGLTexture(rect, opacity);
+
+ GLuint texture = m_videoPlayer->currentFrameAsGLTexture();
+ if (!texture)
+ return;
+
+ glPushMatrix();
+ glDisable(GL_CULL_FACE);
+ glEnable(GL_TEXTURE_RECTANGLE_EXT);
+
+ opacity *= m_opacity;
+ if (opacity < 1){
+ glEnable(GL_BLEND);
+ glColor4f(1, 1, 1, opacity);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ } else {
+ glColor3f(1, 1, 1);
+ glDisable(GL_BLEND);
+ }
+
+ glBindTexture(GL_TEXTURE_RECTANGLE_EXT, texture);
+ glTexParameterf(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameterf(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+ QRect videoRect = m_videoPlayer->videoRect();
+ GLfloat lowerLeft[2], lowerRight[2], upperRight[2], upperLeft[2];
+ lowerLeft[0] = 0;
+ lowerLeft[1] = videoRect.height();
+ lowerRight[0] = videoRect.width();
+ lowerRight[1] = videoRect.height();
+ upperRight[0] = videoRect.width();
+ upperRight[1] = 0;
+ upperLeft[0] = 0;
+ upperLeft[1] = 0;
+
+ glBegin(GL_QUADS);
+ 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();
+
+
+ // FOR NOW. FREE THE TEXTURE:
+ glDeleteTextures(1, &texture);
+ }
+
+ bool VideoFrame::isEmpty()
+ {
+ return (m_videoPlayer == 0);
+ }
+
+ void VideoFrame::invalidateImage() const
+ {
+ if (m_cachedCVTextureRef){
+ CVOpenGLTextureRelease(m_cachedCVTextureRef);
+ (const_cast<VideoFrame *>(this))->m_cachedCVTextureRef = 0;
+ }
+ if (m_cachedCIImage){
+ [(CIImage *) m_cachedCIImage release];
+ (const_cast<VideoFrame *>(this))->m_cachedCIImage = 0;
+ }
+ if (m_cachedNSBitmap){
+ [m_cachedNSBitmap release];
+ (const_cast<VideoFrame *>(this))->m_cachedNSBitmap = 0;
+ }
+ (const_cast<VideoFrame *>(this))-> m_cachedQImage = QImage();
+ }
+
+ void VideoFrame::retain() const
+ {
+ if (m_cachedCVTextureRef)
+ CVOpenGLTextureRetain(m_cachedCVTextureRef);
+ if (m_cachedCIImage)
+ [(CIImage *) m_cachedCIImage retain];
+ if (m_backgroundFrame)
+ m_backgroundFrame->retain();
+ if (m_cachedNSBitmap)
+ [m_cachedNSBitmap retain];
+ }
+
+ void VideoFrame::release() const
+ {
+ if (m_cachedCVTextureRef)
+ CVOpenGLTextureRelease(m_cachedCVTextureRef);
+ if (m_cachedCIImage)
+ [(CIImage *) m_cachedCIImage release];
+ if (m_backgroundFrame)
+ m_backgroundFrame->release();
+ if (m_cachedNSBitmap)
+ [m_cachedNSBitmap release];
+
+ (const_cast<VideoFrame *>(this))->m_backgroundFrame = 0;
+ (const_cast<VideoFrame *>(this))->m_cachedCVTextureRef = 0;
+ (const_cast<VideoFrame *>(this))->m_cachedCIImage = 0;
+ (const_cast<VideoFrame *>(this))->m_cachedNSBitmap = 0;
+ }
+
+}} //namespace Phonon::QT7
+
+QT_END_NAMESPACE
diff --git a/src/3rdparty/phonon/qt7/videowidget.h b/src/3rdparty/phonon/qt7/videowidget.h
new file mode 100644
index 0000000000..8d084ec368
--- /dev/null
+++ b/src/3rdparty/phonon/qt7/videowidget.h
@@ -0,0 +1,71 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef Phonon_QT7_VIDEOWIDGET_H
+#define Phonon_QT7_VIDEOWIDGET_H
+
+#include <QtGui/QPaintEngine>
+#include <phonon/videowidgetinterface.h>
+#include "medianode.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace QT7
+{
+ class MediaNodeEvent;
+ class VideoRenderWidget;
+
+ class VideoWidget : public MediaNode, public Phonon::VideoWidgetInterface
+ {
+ Q_OBJECT
+ Q_INTERFACES(Phonon::VideoWidgetInterface)
+
+ public:
+ VideoWidget(QObject *parent);
+ virtual ~VideoWidget();
+
+ Phonon::VideoWidget::AspectRatio aspectRatio() const;
+ void setAspectRatio(Phonon::VideoWidget::AspectRatio aspectRatio);
+ qreal brightness() const;
+ void setBrightness(qreal);
+ Phonon::VideoWidget::ScaleMode scaleMode() const;
+ void setScaleMode(Phonon::VideoWidget::ScaleMode scaleMode);
+ qreal contrast() const;
+ void setContrast(qreal);
+ qreal hue() const;
+ void setHue(qreal);
+ qreal saturation() const;
+ void setSaturation(qreal);
+
+ QWidget *widget();
+
+ void updateVideo(VideoFrame &frame);
+
+ protected:
+ void mediaNodeEvent(const MediaNodeEvent *event);
+
+ private:
+ VideoRenderWidget *m_videoRenderWidget;
+ };
+
+}} // namespace Phonon::QT7
+
+QT_END_NAMESPACE
+
+#endif // Phonon_QT7_VIDEOWIDGET_H
diff --git a/src/3rdparty/phonon/qt7/videowidget.mm b/src/3rdparty/phonon/qt7/videowidget.mm
new file mode 100644
index 0000000000..736dcdf846
--- /dev/null
+++ b/src/3rdparty/phonon/qt7/videowidget.mm
@@ -0,0 +1,883 @@
+/* This file is part of the KDE project.
+
+ Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+ This library 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, either version 2.1 or 3 of the License.
+
+ This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <QtCore/qglobal.h>
+#ifdef QT_MAC_USE_COCOA
+#import <QTKit/QTMovieLayer.h>
+#endif
+
+#include "videowidget.h"
+#include "backendheader.h"
+#include "quicktimevideoplayer.h"
+#include "medianode.h"
+#include "medianodeevent.h"
+#include "mediaobject.h"
+
+#include <QtOpenGL/QGLWidget>
+#include <QtCore/QTime>
+#include <QtCore/QEvent>
+#include <QtCore/QCoreApplication>
+
+#import <AppKit/NSImage.h>
+#import <QTKit/QTMovieView.h>
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef QT_MAC_USE_COCOA // Rendering to a QTMovieView can only be done in Cocoa
+
+#define VIDEO_TRANSPARENT(m) -(void)m:(NSEvent *)e{[[self superview] m:e];}
+
+@interface SharedQTMovieView : QTMovieView
+{
+@private
+ Phonon::QT7::QuickTimeVideoPlayer *m_player;
+ QList<QWidget *> *m_parents;
+ QWidget *m_window;
+ QRect *m_drawRect;
+ bool m_newImageReady;
+ bool m_usingWindow;
+}
+
+- (SharedQTMovieView *) init;
+- (void) registerParent:(QWidget *)parent;
+- (void) unregisterParent:(QWidget *)parent;
+- (void) setDrawRect:(QRect &)rect;
+- (void) drawVideoFrame:(Phonon::QT7::VideoFrame &)frame forWidget:(QWidget *)widget shareImages:(bool)share;
+- (void) useOffscreenWindow:(bool)offscreen;
+- (void) applyDrawRectOnSelf;
+@end
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+@implementation SharedQTMovieView
+
+- (SharedQTMovieView *) init
+{
+ self = [super initWithFrame:NSZeroRect];
+ if (self){
+ [self setControllerVisible:NO];
+ m_parents = new QList<QWidget *>();
+ m_drawRect = new QRect(0, 0, 1, 1);
+ [self applyDrawRectOnSelf];
+ m_usingWindow = false;
+ }
+ return self;
+}
+
+- (void) dealloc
+{
+ Phonon::QT7::PhononAutoReleasePool pool;
+ delete m_window;
+ delete m_drawRect;
+ delete m_parents;
+ [super dealloc];
+}
+
+- (void) applyDrawRectOnSelf
+{
+ 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];
+}
+
+- (void) setDrawRect:(QRect &)rect
+{
+ *m_drawRect = rect;
+ if (!m_usingWindow)
+ [self applyDrawRectOnSelf];
+}
+
+- (void) waitForFrame
+{
+ if (m_usingWindow){
+ QTMovie *movie = [self movie];
+ if (movie){
+ // CIImages are expected, but not received.
+ // Try to wait a couple of seconds for them:
+ m_newImageReady = false;
+ float rate = [movie rate];
+ if (!rate)
+ [movie setRate:1];
+ QTime t; t.start();
+ while (!m_newImageReady && t.elapsed() < 2000)
+ ;
+ [movie setRate:rate];
+ }
+ }
+}
+
+- (void) useOffscreenWindow:(bool)offscreen
+{
+ if (offscreen == m_usingWindow)
+ return;
+ if (offscreen){
+ if (!m_window){
+ m_window = new QWidget;
+ m_window->setWindowOpacity(0.0);
+ m_window->show();
+ m_window->hide();
+ }
+ m_usingWindow = true;
+ [self setDelegate:self];
+ [self waitForFrame];
+ foreach(QWidget *w, *m_parents)
+ w->repaint();
+ qApp->processEvents();
+ [self removeFromSuperview];
+ [(NSView *)m_window->winId() addSubview:self];
+ } else if (!m_parents->isEmpty()){
+ m_usingWindow = false;
+ [self removeFromSuperview];
+ [(NSView*)m_parents->first()->winId() addSubview:self];
+ [self setDelegate:0];
+ [self setDrawRect:*m_drawRect];
+ }
+}
+
+- (void) drawVideoFrame:(Phonon::QT7::VideoFrame &)frame forWidget:(QWidget *)widget shareImages:(bool)share;
+{
+ // Detect if the video that produces the frame has changed:
+ Phonon::QT7::QuickTimeVideoPlayer *player = frame.videoPlayer();
+ if (player && player->qtMovie() != [self movie]){
+ m_player = player;
+ [self setMovie:player->qtMovie()];
+ [self waitForFrame];
+ }
+
+ [self useOffscreenWindow:(share || m_parents->size() > 1)];
+ if (m_usingWindow)
+ widget->update();
+}
+
+// Override this method so that the movie doesn't stop if
+// the window becomes invisible
+- (void)viewWillMoveToWindow:(NSWindow *)newWindow
+{
+ Q_UNUSED(newWindow);
+}
+
+- (CIImage *) view:(QTMovieView *)view willDisplayImage:(CIImage *)img
+{
+ // This method is called from QTMovieView just
+ // before the image will be drawn.
+ Q_UNUSED(view);
+ m_player->setPrimaryRenderingCIImage(img);
+ m_newImageReady = true;
+ return img;
+}
+
+- (void) registerParent:(QWidget *)parent
+{
+ if (m_parents->contains(parent))
+ return;
+ m_parents->append(parent);
+ if (m_parents->size() == 1){
+ Phonon::QT7::PhononAutoReleasePool pool;
+ m_usingWindow = true;
+ [self applyDrawRectOnSelf];
+ [self useOffscreenWindow:NO];
+ }
+}
+
+- (void) unregisterParent:(QWidget *)parent
+{
+ m_parents->removeAll(parent);
+ if (m_parents->size() == 1)
+ [self applyDrawRectOnSelf];
+}
+
+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
+
+#endif // QT_MAC_USE_COCOA
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+namespace QT7
+{
+
+class IVideoRenderDrawWidget
+{
+public:
+ virtual ~IVideoRenderDrawWidget(){}
+ virtual void setVideoFrame(VideoFrame &) = 0;
+ virtual void setDrawFrameRect(const QRect &) = 0;
+ virtual void updateVideoOutputCount(int){}
+ virtual void setMovieIsPaused(bool){}
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+QGLWidget *PhononSharedQGLWidget(){
+ static QGLWidget *glWidget = 0;
+ if (!glWidget)
+ glWidget = new QGLWidget();
+ return glWidget;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+class RenderOpenGL : public QGLWidget, public IVideoRenderDrawWidget
+{
+public:
+ VideoFrame m_currentFrame;
+ QRect m_drawFrameRect;
+
+ RenderOpenGL(QWidget *parent, const QGLFormat &format, const QSize &size) : QGLWidget(format, parent, PhononSharedQGLWidget())
+ {
+ resize(size);
+ setAutoFillBackground(false);
+ show();
+ }
+
+ void initializeGL()
+ {
+ glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
+ }
+
+ 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);
+ m_currentFrame.drawCVTexture(m_drawFrameRect);
+ }
+
+ void setVideoFrame(VideoFrame &frame)
+ {
+ m_currentFrame = frame;
+ makeCurrent();
+ paintGL();
+ swapBuffers();
+ }
+
+ void setDrawFrameRect(const QRect &rect)
+ {
+ m_drawFrameRect = rect;
+ }
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+class RenderQTMovieView : public QWidget, public IVideoRenderDrawWidget
+{
+public:
+#if defined(QT_MAC_USE_COCOA)
+ QRect m_drawRect;
+ VideoFrame m_videoFrame;
+ SharedQTMovieView *m_currentView;
+ bool m_setDrawRectPending;
+ bool m_share;
+
+ RenderQTMovieView(bool share, QWidget *parent, const QSize &size=QSize()) : QWidget(parent), m_currentView(0)
+ {
+ m_setDrawRectPending = true;
+ m_share = share;
+ setAutoFillBackground(false);
+ if (share){
+ // In 'share' mode, this widget will only make sure
+ // that CIIImages are produced, and not actually
+ // draw anything:
+ hide();
+ } else {
+ resize(size);
+ show();
+ }
+ }
+
+ ~RenderQTMovieView()
+ {
+ [m_currentView unregisterParent:this];
+ }
+
+ void showEvent(QShowEvent *)
+ {
+ if (m_share)
+ return;
+ [m_currentView registerParent:this];
+ }
+
+ void hideEvent(QHideEvent *)
+ {
+ if (m_share)
+ return;
+ [m_currentView unregisterParent:this];
+ }
+
+ void paintEvent(QPaintEvent *)
+ {
+ if (m_share)
+ return;
+ QPainter p(this);
+ p.fillRect(rect(), Qt::black);
+ m_videoFrame.drawCIImage(m_drawRect);
+ }
+
+ void updateVideoOutputCount(int count)
+ {
+ Q_UNUSED(count);
+ }
+
+ void setMovieIsPaused(bool paused)
+ {
+ Q_UNUSED(paused);
+ }
+
+ void setVideoFrame(VideoFrame &frame)
+ {
+ m_videoFrame = frame;
+
+ if (!m_videoFrame.isEmpty()){
+ Phonon::QT7::QuickTimeVideoPlayer *player = m_videoFrame.videoPlayer();
+ if (!player->m_primaryRenderingTarget){
+ // First movie view. Create the shared resource:
+ SharedQTMovieView *view = [[[SharedQTMovieView alloc] init] autorelease];
+ player->setPrimaryRenderingTarget(view);
+ }
+
+ SharedQTMovieView *view = static_cast<SharedQTMovieView *>(player->m_primaryRenderingTarget);
+ if (!m_share && view != m_currentView){
+ [m_currentView unregisterParent:this];
+ m_currentView = view;
+ [m_currentView registerParent:this];
+ }
+
+ [view drawVideoFrame:m_videoFrame forWidget:this shareImages:m_share || m_videoFrame.hasColorAdjustments()];
+
+ if (m_setDrawRectPending){
+ m_setDrawRectPending = false;
+ [view setDrawRect:m_drawRect];
+ }
+ }
+ }
+
+ void setDrawFrameRect(const QRect &rect)
+ {
+ m_drawRect = rect;
+ Phonon::QT7::QuickTimeVideoPlayer *player = m_videoFrame.videoPlayer();
+ if (player && player->m_primaryRenderingTarget){
+ SharedQTMovieView *view = static_cast<SharedQTMovieView *>(player->m_primaryRenderingTarget);
+ [view setDrawRect:m_drawRect];
+ } else
+ m_setDrawRectPending = true;
+ }
+
+#else // QT_MAC_USE_COCOA == false
+ RenderQTMovieView(bool, QWidget *, const QSize& = QSize()){}
+ void setVideoFrame(VideoFrame &){}
+ void setDrawFrameRect(const QRect &){}
+#endif
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+class RenderQTMovieLayer : public QWidget, public IVideoRenderDrawWidget
+{
+public:
+#ifdef QT_MAC_USE_COCOA
+ QTMovieLayer *m_movieLayer;
+
+ RenderQTMovieLayer(QWidget *parent, const QSize&) : QWidget(parent)
+ {
+ PhononAutoReleasePool pool;
+ setAutoFillBackground(false);
+ m_movieLayer = 0;
+ [(NSView *)winId() setWantsLayer:YES];
+ }
+
+ void setVideoFrame(VideoFrame &frame)
+ {
+ QuickTimeVideoPlayer *player = frame.videoPlayer();
+ if (!player || player->qtMovie() == [m_movieLayer movie])
+ return;
+
+ if (m_movieLayer)
+ [m_movieLayer setMovie:player->qtMovie()];
+ else {
+ m_movieLayer = [QTMovieLayer layerWithMovie:player->qtMovie()];
+ [(NSView *)winId() setLayer:m_movieLayer];
+ }
+ }
+
+ void setDrawFrameRect(const QRect &rect)
+ {
+ m_movieLayer.frame.origin.x = rect.x();
+ m_movieLayer.frame.origin.y = rect.y();
+ m_movieLayer.frame.size.width = rect.width();
+ m_movieLayer.frame.size.height = rect.height();
+ }
+
+#else // QT_MAC_USE_COCOA == false
+ RenderQTMovieLayer(QWidget *, const QSize&){}
+ void setVideoFrame(VideoFrame &){}
+ void setDrawFrameRect(const QRect &){}
+#endif
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+class VideoRenderWidget : public QWidget
+{
+public:
+ enum RenderSystem { RS_NoRendering = 0,
+ RS_QGLWidget = 1,
+ RS_QPainter = 2,
+ RS_CIImage = 3,
+ RS_CVTexture = 4,
+ RS_QImage = 5,
+ RS_QTMovieView = 6,
+ RS_QTMovieLayer = 7
+ } m_renderSystem;
+
+ VideoFrame m_currentFrame;
+ QRect m_movieFrameRect;
+ QRect m_drawFrameRect;
+ Phonon::VideoWidget::ScaleMode m_scaleMode;
+ Phonon::VideoWidget::AspectRatio m_aspect;
+ IVideoRenderDrawWidget *m_renderDrawWidget;
+
+ qreal m_brightness;
+ qreal m_contrast;
+ qreal m_hue;
+ qreal m_saturation;
+ qreal m_opacity;
+
+ VideoRenderWidget() : QWidget(0),
+ m_scaleMode(Phonon::VideoWidget::FitInView), m_aspect(Phonon::VideoWidget::AspectRatioAuto)
+ {
+ PhononAutoReleasePool pool;
+ m_brightness = 0;
+ m_contrast = 0;
+ m_hue = 0;
+ m_saturation = 0;
+ m_opacity = 1;
+ m_renderDrawWidget = 0;
+ m_renderSystem = RS_NoRendering;
+
+ setAutoFillBackground(false);
+ updateDrawFrameRect();
+ }
+
+ RenderSystem selectBestRenderSystem(){
+ if (!isVisible())
+ return RS_NoRendering;
+ else if (window() && window()->testAttribute(Qt::WA_DontShowOnScreen))
+ return RS_QPainter;
+ else {
+#ifdef QUICKTIME_C_API_AVAILABLE
+ return RS_QGLWidget;
+#else
+ return RS_QTMovieView;
+#endif
+ }
+ }
+
+ void setRenderSystem(RenderSystem renderSystem){
+ PhononAutoReleasePool pool;
+ static QString userSystem = qgetenv("PHONON_RENDER_SYSTEM");
+ if (!userSystem.isEmpty())
+ renderSystem = RenderSystem(userSystem.toInt());
+
+ if (m_renderSystem == renderSystem)
+ return;
+
+ m_renderSystem = renderSystem;
+ if (m_renderDrawWidget){
+ delete m_renderDrawWidget;
+ m_renderDrawWidget = 0;
+ }
+
+ switch (m_renderSystem){
+ case RS_QGLWidget:{
+ QGLFormat format = QGLFormat::defaultFormat();
+ format.setSwapInterval(1); // Vertical sync (avoid tearing)
+ m_renderDrawWidget = new RenderOpenGL(this, format, size());
+ break;}
+ case RS_QTMovieView:{
+ m_renderDrawWidget = new RenderQTMovieView(false, this, size());
+ break;}
+ case RS_QTMovieLayer:{
+ m_renderDrawWidget = new RenderQTMovieLayer(this, size());
+ break;}
+ case RS_QPainter:
+ case RS_CIImage:
+ case RS_CVTexture:
+ case RS_QImage:
+#ifndef QUICKTIME_C_API_AVAILABLE
+ // On cocoa-64, let QTMovieView produce
+ // video frames for us:
+ m_renderDrawWidget = new RenderQTMovieView(true, this);
+#endif
+ break;
+ case RS_NoRendering:
+ break;
+ }
+
+ if (m_renderDrawWidget){
+ m_renderDrawWidget->setVideoFrame(m_currentFrame);
+ m_renderDrawWidget->setDrawFrameRect(m_drawFrameRect);
+ }
+ }
+
+ QSize sizeHint() const
+ {
+ return m_movieFrameRect.size();
+ }
+
+ bool event(QEvent *event)
+ {
+ switch (event->type()){
+ // Try to detect if one of this objects
+ // anchestors might have changed:
+ case QEvent::Resize:{
+ PhononAutoReleasePool pool;
+ updateDrawFrameRect();
+ if (m_renderDrawWidget)
+ dynamic_cast<QWidget *>(m_renderDrawWidget)->resize(size());
+ break; }
+ case QEvent::Paint:{
+ PhononAutoReleasePool pool;
+ float opacity = parentWidget() ? parentWidget()->windowOpacity() : 1;
+ switch (m_renderSystem){
+ case RS_QPainter:{
+ QPainter p(this);
+ p.fillRect(rect(), Qt::black);
+ if (p.paintEngine()->type() == QPaintEngine::OpenGL)
+ m_currentFrame.drawCVTexture(m_drawFrameRect, opacity);
+ else
+ m_currentFrame.drawQImage(&p, m_drawFrameRect);
+ break; }
+ case RS_CIImage:
+ m_currentFrame.drawCIImage(m_drawFrameRect, opacity);
+ break;
+ case RS_CVTexture:
+ m_currentFrame.drawCVTexture(m_drawFrameRect, opacity);
+ break;
+ case RS_QImage:{
+ QPainter p(this);
+ p.fillRect(rect(), Qt::black);
+ m_currentFrame.drawQImage(&p, m_drawFrameRect);
+ break; }
+ case RS_QGLWidget:
+ case RS_QTMovieView:
+ case RS_QTMovieLayer:
+ // draw in separate widget
+ break;
+ case RS_NoRendering:
+ QPainter p(this);
+ p.fillRect(rect(), Qt::black);
+ break;
+ }
+ break; }
+ default:
+ break;
+ }
+
+ return QWidget::event(event);
+ }
+
+ void setVideoFrame(VideoFrame &frame)
+ {
+ PhononAutoReleasePool pool;
+ m_currentFrame = frame;
+ m_currentFrame.setColors(m_brightness, m_contrast, m_hue, m_saturation);
+
+ if (m_renderDrawWidget)
+ m_renderDrawWidget->setVideoFrame(m_currentFrame);
+
+ setRenderSystem(selectBestRenderSystem());
+ switch (m_renderSystem){
+ case RS_QGLWidget:
+ case RS_QTMovieView:
+ case RS_QTMovieLayer:
+ case RS_NoRendering:
+ break;
+ case RS_CIImage:
+ case RS_CVTexture:
+ case RS_QImage:
+ case RS_QPainter:
+ repaint();
+ break;
+ }
+ }
+
+ void updateVideoFrame()
+ {
+ setVideoFrame(m_currentFrame);
+ }
+
+ void setMovieRect(const QRect &mrect)
+ {
+ if (mrect == m_movieFrameRect)
+ return;
+ m_movieFrameRect = mrect;
+ updateDrawFrameRect();
+ updateGeometry();
+ if (isVisible())
+ qApp->processEvents(QEventLoop::ExcludeUserInputEvents | QEventLoop::ExcludeSocketNotifiers);
+ }
+
+ void setScaleMode(Phonon::VideoWidget::ScaleMode scaleMode)
+ {
+ m_scaleMode = scaleMode;
+ updateDrawFrameRect();
+ updateVideoFrame();
+ repaint();
+ }
+
+ void setAspectRatio(Phonon::VideoWidget::AspectRatio aspect)
+ {
+ m_aspect = aspect;
+ updateDrawFrameRect();
+ updateVideoFrame();
+ repaint();
+ }
+
+ void updateVideoOutputCount(int count)
+ {
+ if (m_renderDrawWidget)
+ m_renderDrawWidget->updateVideoOutputCount(count);
+ }
+
+ void setMovieIsPaused(bool paused)
+ {
+ if (m_renderDrawWidget)
+ m_renderDrawWidget->setMovieIsPaused(paused);
+ }
+
+ void updateDrawFrameRect()
+ {
+ if (m_movieFrameRect.width() <= 0 || m_movieFrameRect.height() <= 0)
+ m_movieFrameRect = QRect(0, 0, 640, 480);
+
+ // Set m_drawFrameRect to be the size of the smallest possible
+ // rect conforming to the aspect and containing the whole frame:
+ switch(m_aspect){
+ case Phonon::VideoWidget::AspectRatioWidget:
+ m_drawFrameRect = rect();
+ break;
+ case Phonon::VideoWidget::AspectRatio4_3:
+ m_drawFrameRect = scaleToAspect(m_movieFrameRect, 4, 3);
+ break;
+ case Phonon::VideoWidget::AspectRatio16_9:
+ m_drawFrameRect = scaleToAspect(m_movieFrameRect, 16, 9);
+ break;
+ case Phonon::VideoWidget::AspectRatioAuto:
+ default:
+ m_drawFrameRect = m_movieFrameRect;
+ break;
+ }
+
+ // Scale m_drawFrameRect to fill the widget
+ // without breaking aspect:
+ int widgetWidth = rect().width();
+ int widgetHeight = rect().height();
+ int frameWidth = widgetWidth;
+ int frameHeight = m_drawFrameRect.height() * float(widgetWidth) / float(m_drawFrameRect.width());
+
+ switch(m_scaleMode){
+ case Phonon::VideoWidget::ScaleAndCrop:
+ if (frameHeight < widgetHeight){
+ frameWidth *= float(widgetHeight) / float(frameHeight);
+ frameHeight = widgetHeight;
+ }
+ break;
+ case Phonon::VideoWidget::FitInView:
+ default:
+ if (frameHeight > widgetHeight){
+ frameWidth *= float(widgetHeight) / float(frameHeight);
+ frameHeight = widgetHeight;
+ }
+ break;
+ }
+
+ m_drawFrameRect.setSize(QSize(frameWidth, frameHeight));
+ m_drawFrameRect.moveTo((widgetWidth - frameWidth) / 2.0f, (widgetHeight - frameHeight) / 2.0f);
+
+ if (m_renderDrawWidget)
+ m_renderDrawWidget->setDrawFrameRect(m_drawFrameRect);
+ }
+
+ QRect scaleToAspect(QRect srcRect, int w, int h)
+ {
+ int width = srcRect.width();
+ int height = srcRect.width() * (float(h) / float(w));
+ if (height > srcRect.height()){
+ height = srcRect.height();
+ width = srcRect.height() * (float(w) / float(h));
+ }
+ return QRect(0, 0, width, height);
+ }
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+VideoWidget::VideoWidget(QObject *parent) : MediaNode(VideoSink, parent)
+{
+ m_videoRenderWidget = new VideoRenderWidget();
+}
+
+VideoWidget::~VideoWidget()
+{
+ delete m_videoRenderWidget;
+}
+
+QWidget *VideoWidget::widget()
+{
+ IMPLEMENTED;
+ return m_videoRenderWidget;
+}
+
+Phonon::VideoWidget::AspectRatio VideoWidget::aspectRatio() const
+{
+ IMPLEMENTED;
+ return m_videoRenderWidget->m_aspect;
+}
+
+void VideoWidget::setAspectRatio(Phonon::VideoWidget::AspectRatio aspect)
+{
+ IMPLEMENTED;
+ m_videoRenderWidget->setAspectRatio(aspect);
+}
+
+Phonon::VideoWidget::ScaleMode VideoWidget::scaleMode() const
+{
+ IMPLEMENTED;
+ return m_videoRenderWidget->m_scaleMode;
+}
+
+void VideoWidget::setScaleMode(Phonon::VideoWidget::ScaleMode scaleMode)
+{
+ IMPLEMENTED;
+ m_videoRenderWidget->setScaleMode(scaleMode);
+}
+
+qreal VideoWidget::brightness() const
+{
+ IMPLEMENTED;
+ return m_videoRenderWidget->m_brightness;
+}
+
+void VideoWidget::setBrightness(qreal value)
+{
+ IMPLEMENTED;
+ m_videoRenderWidget->m_brightness = value;
+ if (m_owningMediaObject && m_owningMediaObject->state() == Phonon::PausedState)
+ m_videoRenderWidget->updateVideoFrame();
+}
+
+qreal VideoWidget::contrast() const
+{
+ IMPLEMENTED;
+ return m_videoRenderWidget->m_contrast;
+}
+
+void VideoWidget::setContrast(qreal value)
+{
+ IMPLEMENTED;
+ m_videoRenderWidget->m_contrast = value;
+ if (m_owningMediaObject && m_owningMediaObject->state() == Phonon::PausedState)
+ m_videoRenderWidget->updateVideoFrame();
+}
+
+qreal VideoWidget::hue() const
+{
+ IMPLEMENTED;
+ return m_videoRenderWidget->m_hue;
+}
+
+void VideoWidget::setHue(qreal value)
+{
+ IMPLEMENTED;
+ m_videoRenderWidget->m_hue = value;
+ if (m_owningMediaObject && m_owningMediaObject->state() == Phonon::PausedState)
+ m_videoRenderWidget->updateVideoFrame();
+}
+
+qreal VideoWidget::saturation() const
+{
+ IMPLEMENTED;
+ return m_videoRenderWidget->m_saturation;
+}
+
+void VideoWidget::setSaturation(qreal value)
+{
+ IMPLEMENTED;
+ m_videoRenderWidget->m_saturation = value;
+ if (m_owningMediaObject && m_owningMediaObject->state() == Phonon::PausedState)
+ m_videoRenderWidget->updateVideoFrame();
+}
+
+void VideoWidget::mediaNodeEvent(const MediaNodeEvent *event)
+{
+ switch (event->type()){
+ case MediaNodeEvent::VideoFrameSizeChanged:
+ m_videoRenderWidget->setMovieRect(*static_cast<QRect *>(event->data()));
+ break;
+ case MediaNodeEvent::VideoOutputCountChanged:
+ m_videoRenderWidget->updateVideoOutputCount(*static_cast<int *>(event->data()));
+ break;
+ case MediaNodeEvent::MediaPlaying:
+ m_videoRenderWidget->setMovieIsPaused(!(*static_cast<bool *>(event->data())));
+ break;
+ default:
+ break;
+ }
+}
+
+void VideoWidget::updateVideo(VideoFrame &frame){
+ PhononAutoReleasePool pool;
+ m_videoRenderWidget->setVideoFrame(frame);
+ MediaNode::updateVideo(frame);
+}
+
+}} // namespace Phonon::QT7
+
+QT_END_NAMESPACE
+
+#include "moc_videowidget.cpp"
diff --git a/src/3rdparty/phonon/waveout/audiooutput.cpp b/src/3rdparty/phonon/waveout/audiooutput.cpp
new file mode 100644
index 0000000000..f842dc9d0a
--- /dev/null
+++ b/src/3rdparty/phonon/waveout/audiooutput.cpp
@@ -0,0 +1,78 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library 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, either version 2.1 or 3 of the License.
+
+This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "audiooutput.h"
+#include "mediaobject.h"
+
+#include <QtCore/QVector>
+
+#include <cmath>
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+ namespace WaveOut
+ {
+ AudioOutput::AudioOutput(Backend *, QObject *parent)
+ {
+ setParent(parent);
+ m_volume = 0xffff;
+ }
+
+ AudioOutput::~AudioOutput()
+ {
+ }
+
+ int AudioOutput::outputDevice() const
+ {
+ return 0;
+ }
+
+ void AudioOutput::setVolume(qreal newVolume)
+ {
+ m_volume = newVolume;
+ emit volumeChanged(newVolume);
+ }
+
+ void AudioOutput::setCrossFadingProgress(short currentIndex, qreal progress)
+ {
+ Q_UNUSED(currentIndex);
+ Q_UNUSED(progress);
+ }
+
+ bool AudioOutput::setOutputDevice(const AudioOutputDevice & newDevice)
+ {
+ return setOutputDevice(newDevice.index());
+ }
+
+ qreal AudioOutput::volume() const
+ {
+ return m_volume;
+ }
+
+ bool AudioOutput::setOutputDevice(int newDevice)
+ {
+
+ return (newDevice == 0);
+ }
+
+ }
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/3rdparty/phonon/waveout/audiooutput.h b/src/3rdparty/phonon/waveout/audiooutput.h
new file mode 100644
index 0000000000..43f8222cf3
--- /dev/null
+++ b/src/3rdparty/phonon/waveout/audiooutput.h
@@ -0,0 +1,65 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library 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, either version 2.1 or 3 of the License.
+
+This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef PHONON_AUDIOOUTPUT_H
+#define PHONON_AUDIOOUTPUT_H
+
+#include <QtCore/QFile>
+#include <phonon/audiooutputinterface.h>
+
+#include "backend.h"
+
+struct IBaseFilter;
+struct IBasicAudio;
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+ namespace WaveOut
+ {
+ class AudioOutput : public QObject, public Phonon::AudioOutputInterface
+ {
+ Q_OBJECT
+
+ Q_INTERFACES(Phonon::AudioOutputInterface)
+ public:
+ AudioOutput(Backend *back, QObject *parent);
+ ~AudioOutput();
+
+ // Attributes Getters:
+ qreal volume() const;
+ int outputDevice() const;
+ void setVolume(qreal newVolume);
+ bool setOutputDevice(int newDevice);
+ bool setOutputDevice(const AudioOutputDevice & newDevice);
+ void setCrossFadingProgress(short currentIndex, qreal progress);
+
+ Q_SIGNALS:
+ void audioDeviceFailed();
+ void volumeChanged(qreal);
+ private:
+ unsigned int m_volume;
+
+
+ };
+ }
+}
+
+QT_END_NAMESPACE
+
+#endif // PHONON_AUDIOOUTPUT_H
diff --git a/src/3rdparty/phonon/waveout/backend.cpp b/src/3rdparty/phonon/waveout/backend.cpp
new file mode 100644
index 0000000000..8faa26ee3c
--- /dev/null
+++ b/src/3rdparty/phonon/waveout/backend.cpp
@@ -0,0 +1,131 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library 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, either version 2.1 or 3 of the License.
+
+This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "backend.h"
+
+
+#include "audiooutput.h"
+#include "mediaobject.h"
+
+
+
+#include <QtCore/QSettings>
+#include <QtCore/QSet>
+#include <QtCore/QVariant>
+#include <QtCore/QStringList>
+
+#include <QtCore/QtPlugin>
+
+
+QT_BEGIN_NAMESPACE
+
+// export as Qt/KDE factory as required
+
+Q_EXPORT_PLUGIN2(phonon_waveout, Phonon::WaveOut::Backend);
+
+namespace Phonon
+{
+ namespace WaveOut
+ {
+
+ Backend::Backend(QObject *parent, const QVariantList &)
+ : QObject(parent)
+ {
+ }
+
+ Backend::~Backend()
+ {
+ }
+
+ QObject *Backend::createObject(BackendInterface::Class c, QObject *parent, const QList<QVariant> &args)
+ {
+ Q_UNUSED(args);
+ switch (c)
+ {
+ case MediaObjectClass:
+ return new MediaObject(parent);
+ case AudioOutputClass:
+ return new AudioOutput(this, parent);
+ default:
+ return 0;
+ }
+ }
+
+ bool Backend::supportsVideo() const
+ {
+ return false;
+ }
+
+ QStringList Backend::availableMimeTypes() const
+ {
+ QStringList ret;
+ return ret;
+ }
+
+
+ QList<int> Backend::objectDescriptionIndexes(Phonon::ObjectDescriptionType type) const
+ {
+ QList<int> r;
+ if (type == Phonon::AudioOutputDeviceType)
+ r.append(0);
+ return r;
+ }
+
+ QHash<QByteArray, QVariant> Backend::objectDescriptionProperties(Phonon::ObjectDescriptionType type, int index) const
+ {
+ Q_UNUSED(index);
+ QHash<QByteArray, QVariant> r;
+ if (type == Phonon::AudioOutputDeviceType)
+ r["name"] = QLatin1String("default audio device");
+ return r;
+ }
+
+
+ bool Backend::connectNodes(QObject *node1, QObject *node2)
+ {
+ MediaObject *mediaObject = qobject_cast<MediaObject*> (node1);
+ AudioOutput *audioOutput = qobject_cast<AudioOutput*> (node2);
+
+ if (mediaObject && audioOutput)
+ mediaObject->setAudioOutput(audioOutput);
+ return true;
+ }
+
+ bool Backend::disconnectNodes(QObject *node1, QObject *node2)
+ {
+ Q_UNUSED(node1);
+ Q_UNUSED(node2);
+ return true;
+ }
+
+ //transaction management
+ bool Backend::startConnectionChange(QSet<QObject *>)
+ {
+ return true;
+ }
+
+ bool Backend::endConnectionChange(QSet<QObject *>)
+ {
+ return true;
+ }
+
+ }
+}
+
+QT_END_NAMESPACE
+
+#include "moc_backend.cpp"
diff --git a/src/3rdparty/phonon/waveout/backend.h b/src/3rdparty/phonon/waveout/backend.h
new file mode 100644
index 0000000000..060d853798
--- /dev/null
+++ b/src/3rdparty/phonon/waveout/backend.h
@@ -0,0 +1,69 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library 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, either version 2.1 or 3 of the License.
+
+This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef PHONON_BACKEND_H
+#define PHONON_BACKEND_H
+
+#include <phonon/backendinterface.h>
+#include <phonon/phononnamespace.h>
+
+#include <QtCore/QList>
+
+
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+ namespace WaveOut
+ {
+ class AudioOutput;
+ class MediaObject;
+
+ class Backend : public QObject, public Phonon::BackendInterface
+ {
+ Q_OBJECT
+ Q_INTERFACES(Phonon::BackendInterface)
+ public:
+ Backend(QObject *parent = 0, const QVariantList & = QVariantList());
+ virtual ~Backend();
+
+ QObject *createObject(Phonon::BackendInterface::Class, QObject *parent, const QList<QVariant> &args);
+
+ bool supportsVideo() const;
+ QStringList availableMimeTypes() const;
+
+ QList<int> objectDescriptionIndexes(Phonon::ObjectDescriptionType type) const;
+ QHash<QByteArray, QVariant> objectDescriptionProperties(Phonon::ObjectDescriptionType type, int index) const;
+
+ bool connectNodes(QObject *, QObject *);
+ bool disconnectNodes(QObject *, QObject *);
+
+ //transaction management
+ bool startConnectionChange(QSet<QObject *>);
+ bool endConnectionChange(QSet<QObject *>);
+
+ Q_SIGNALS:
+ void objectDescriptionChanged(ObjectDescriptionType);
+
+ };
+ }
+}
+
+QT_END_NAMESPACE
+
+#endif // PHONON_BACKEND_H
diff --git a/src/3rdparty/phonon/waveout/mediaobject.cpp b/src/3rdparty/phonon/waveout/mediaobject.cpp
new file mode 100644
index 0000000000..35d9e0b3d2
--- /dev/null
+++ b/src/3rdparty/phonon/waveout/mediaobject.cpp
@@ -0,0 +1,686 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library 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, either version 2.1 or 3 of the License.
+
+This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "mediaobject.h"
+#include "audiooutput.h"
+
+#include <QtCore/QVector>
+#include <QtCore/QTimerEvent>
+#include <QtCore/QTimer>
+#include <QtCore/QTime>
+#include <QtCore/QLibrary>
+#include <QtCore/QUrl>
+#include <QtCore/QWriteLocker>
+
+#include <phonon/streaminterface.h>
+
+
+#define WAVEHEADER_OFFSET_FORMATTAG 20
+#define WAVEHEADER_OFFSET_CHANNELS 22
+#define WAVEHEADER_OFFSET_SAMPLESPERSEC 24
+#define WAVEHEADER_OFFSET_AVGBYTESPERSEC 28
+#define WAVEHEADER_OFFSET_BLOCKALIGN 32
+#define WAVEHEADER_OFFSET_BITSPERSAMPLE 34
+#define WAVEHEADER_OFFSET_DATA 44
+#define WAVEHEADER_SIZE WAVEHEADER_OFFSET_DATA
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+ namespace WaveOut
+ {
+ static unsigned int buffer_size = (16 * 1024 * 4);
+
+ QString getErrorText(MMRESULT error)
+ {
+ ushort b[256];
+ waveOutGetErrorText(error, (LPWSTR)b, 256);
+ return QString::fromUtf16(b);
+ }
+
+ class WorkerThread : public QThread
+ {
+ Q_OBJECT
+ public slots:
+ void stream(QIODevice *file, QByteArray *buffer, bool *finished);
+ };
+
+ void WorkerThread::stream(QIODevice *ioStream, QByteArray *buffer, bool *finished)
+ {
+ (*finished) = false;
+ memset((void*) buffer->data(), 0, buffer->size());
+ qint64 i = ioStream->read(buffer->data(), buffer_size);
+ buffer->resize(i);
+ (*finished) = true;
+ }
+
+
+ void CALLBACK MediaObject::WaveOutCallBack(HWAVEOUT m_hWaveOut, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2)
+ {
+ Q_UNUSED(m_hWaveOut);
+ Q_UNUSED(dwInstance);
+ Q_UNUSED(dwParam2);
+
+ switch(uMsg)
+ {
+ case WOM_OPEN:
+ break;
+ case WOM_DONE:
+ {
+ WAVEHDR *waveHeader = (WAVEHDR*)dwParam1;
+ MediaObject* mediaObject = reinterpret_cast<MediaObject *>(waveHeader->dwUser);
+ if (mediaObject) {
+ mediaObject->swapBuffers();
+ }
+ }
+ break;
+ case WOM_CLOSE:
+ break;
+ }
+ }
+
+ class StreamReader : public Phonon::StreamInterface
+ {
+ public:
+ StreamReader(QObject *parent, const Phonon::MediaSource &source) :
+ m_seekable(false), m_pos(0), m_size(-1)
+ {
+ Q_UNUSED(parent);
+ connectToSource(source);
+ }
+
+ //for Phonon::StreamInterface
+ void writeData(const QByteArray &data)
+ {
+ QWriteLocker locker(&m_lock);
+ m_pos += data.size();
+ m_buffer += data;
+ }
+
+ void endOfData()
+ {
+ }
+
+ void setStreamSize(qint64 newSize)
+ {
+ QWriteLocker locker(&m_lock);
+ m_size = newSize;
+ }
+
+ qint64 streamSize() const
+ {
+ QReadLocker locker(&m_lock);
+ return m_size;
+ }
+
+ void setStreamSeekable(bool s)
+ {
+ QWriteLocker locker(&m_lock);
+ m_seekable = s;
+ }
+
+ bool streamSeekable() const
+ {
+ QReadLocker locker(&m_lock);
+ return m_seekable;
+ }
+
+ void setCurrentPos(qint64 pos)
+ {
+ QWriteLocker locker(&m_lock);
+ m_pos = pos;
+ seekStream(pos);
+ m_buffer.clear();
+ }
+
+ qint64 currentPos() const
+ {
+ QReadLocker locker(&m_lock);
+ return m_pos;
+ }
+
+ int currentBufferSize() const
+ {
+ QReadLocker locker(&m_lock);
+ return m_buffer.size();
+ }
+
+ //for Phonon::StreamInterface
+ QByteArray m_buffer;
+ bool m_seekable;
+ qint64 m_pos;
+ qint64 m_size;
+ mutable QReadWriteLock m_lock;
+ };
+
+ class IOWrapper : public QIODevice {
+ public:
+ IOWrapper(QObject *parent, const Phonon::MediaSource &source) : m_streamReader(this, source)
+ {
+ Q_UNUSED(parent);
+ setOpenMode(QIODevice::ReadOnly);
+ }
+ bool seek(qint64 pos);
+ qint64 size() const;
+ qint64 pos();
+ bool isReadable() const;
+ protected:
+ qint64 readData (char * data, qint64 maxSize);
+ qint64 writeData(const char *,qint64);
+ private:
+ StreamReader m_streamReader;
+ };
+
+ bool IOWrapper::isReadable () const
+ {
+ return true;
+ }
+
+ qint64 IOWrapper::pos()
+ {
+ return (m_streamReader.streamSeekable() ? m_streamReader.currentPos() : 0);
+ }
+
+ bool IOWrapper::seek( qint64 pos)
+ {
+ if (!m_streamReader.streamSeekable())
+ return false;
+ m_streamReader.setCurrentPos(pos);
+ return true;
+ }
+
+ qint64 IOWrapper::size() const
+ {
+ return m_streamReader.streamSize();
+ }
+
+ qint64 IOWrapper::readData(char * data, qint64 maxSize)
+ {
+ int oldSize = m_streamReader.currentBufferSize();
+ while (m_streamReader.currentBufferSize() < maxSize) {
+ m_streamReader.needData();
+ if (oldSize == m_streamReader.currentBufferSize()) {
+ break; //we didn't get any data
+ }
+ oldSize = m_streamReader.currentBufferSize();
+ }
+
+ qint64 bytesRead = qMin(qint64(m_streamReader.currentBufferSize()), maxSize);
+ {
+ QWriteLocker locker(&m_streamReader.m_lock);
+ qMemCopy(data, m_streamReader.m_buffer.data(), bytesRead);
+ //truncate the buffer
+ m_streamReader.m_buffer = m_streamReader.m_buffer.mid(bytesRead);
+ }
+ return bytesRead;
+ }
+
+ qint64 IOWrapper::writeData(const char *,qint64)
+ {
+ return 0;
+ }
+
+ MediaObject::MediaObject(QObject *parent) : m_file(0), m_stream(0),
+ m_hWaveOut(0), m_nextBufferIndex(1),
+ m_mediaSize(-1), m_bufferingFinished(0),
+ m_paused(0), m_tickInterval(0),
+ m_hasNextSource(0), m_hasSource(0),
+ m_sourceIsValid(0), m_errorType(Phonon::NoError),
+ m_currentTime(0), m_transitionTime(0),
+ m_tick(0), m_volume(100), m_prefinishMark(0),
+ m_tickIntervalResolution(0), m_bufferPrepared(0),
+ m_stopped(0)
+ {
+ m_thread = new WorkerThread();
+ connect(this, SIGNAL(outOfData(QIODevice*, QByteArray*, bool*)), m_thread, SLOT(stream(QIODevice*, QByteArray*, bool*)));
+ m_thread->start();
+ m_soundBuffer1.waveHeader = new WAVEHDR;
+ m_soundBuffer2.waveHeader = new WAVEHDR;
+ setParent(parent);
+ setState(Phonon::LoadingState);
+ }
+
+ MediaObject::~MediaObject()
+ {
+ stop();
+ disconnect(this, SIGNAL(outOfData(QIODevice*, QByteArray*, bool*)), m_thread, SLOT(stream(QIODevice*, QByteArray*, bool*)));
+ do { //The event loop of m_thread might not be started, yet
+ m_thread->quit(); //If the event loop is not started yet quit() does nothing
+ m_thread->wait(100);
+ } while (m_thread->isRunning());
+ delete m_thread;
+ deleteValidWaveOutDevice();
+ delete m_soundBuffer1.waveHeader;
+ delete m_soundBuffer2.waveHeader;
+ }
+
+ Phonon::State MediaObject::state() const
+ {
+ return m_state;
+ }
+
+ bool MediaObject::hasVideo() const
+ {
+ return false;
+ }
+
+ bool MediaObject::isSeekable() const
+ {
+ if (!m_stream)
+ return false;
+ return !m_stream->isSequential();
+ }
+
+ qint64 MediaObject::totalTime() const
+ {
+ return m_totalTime;
+ }
+
+ qint64 MediaObject::currentTime() const
+ {
+ //this handles inaccuracy when stopping on a title
+ return m_currentTime;
+ }
+
+ qint32 MediaObject::tickInterval() const
+ {
+ return m_tickInterval * m_tickIntervalResolution;
+ }
+
+ void MediaObject::setTickInterval(qint32 newTickInterval)
+ {
+ if ((m_tickIntervalResolution == 0) || (newTickInterval == 0))
+ return;
+ m_tickInterval = newTickInterval / m_tickIntervalResolution;
+ if ((newTickInterval > 0) && (m_tickInterval == 0))
+ m_tickInterval = 1;
+ }
+
+ void MediaObject::pause()
+ {
+ if (!m_paused) {
+ m_paused = true;
+ setState(Phonon::PausedState);
+ if (!(waveOutPause(m_hWaveOut) == MMSYSERR_NOERROR))
+ {
+ setError(Phonon::NormalError, QLatin1String("cannot pause (system error)"));
+ }
+ }
+ }
+
+ void MediaObject::stop()
+ {
+ setState(Phonon::StoppedState);
+ m_stopped = true;
+ m_paused = false;
+ seek(0);
+ if (!(waveOutReset(m_hWaveOut) == MMSYSERR_NOERROR))
+ setError(Phonon::NormalError, QLatin1String("cannot stop (system error)"));
+ }
+
+ void MediaObject::play()
+ {
+ if ((m_state == Phonon::PlayingState) && !m_paused && !m_stopped)
+ return;
+ if ((m_state == Phonon::LoadingState) ||
+ (m_state == Phonon::BufferingState) ||
+ (m_state == Phonon::ErrorState)) {
+ setError(Phonon::FatalError, QLatin1String("illegale state for playback"));
+ return;
+ }
+
+ if (m_state == Phonon::StoppedState)
+ stop();
+ if (m_sourceIsValid) {
+ setState(Phonon::PlayingState);
+ if (!m_paused) {
+ m_nextBufferIndex = true;
+ m_stopped = false;
+ playBuffer(m_soundBuffer1.waveHeader);
+ playBuffer(m_soundBuffer2.waveHeader);
+ } else {
+ if (!(waveOutRestart(m_hWaveOut) == MMSYSERR_NOERROR))
+ setError(Phonon::NormalError, QLatin1String("cannot resume (system)"));
+ }
+ } else {
+ setError(Phonon::FatalError, QLatin1String("cannot playback invalid source"));
+ }
+ m_paused = false;
+ }
+
+ QString MediaObject::errorString() const
+ {
+
+ return m_errorString;
+ }
+
+ Phonon::ErrorType MediaObject::errorType() const
+ {
+ return Phonon::ErrorType();
+ }
+
+ qint32 MediaObject::prefinishMark() const
+ {
+ return m_prefinishMark;
+ }
+
+ void MediaObject::setPrefinishMark(qint32 newPrefinishMark)
+ {
+ m_prefinishMark = newPrefinishMark;
+ }
+
+ qint32 MediaObject::transitionTime() const
+ {
+ return m_transitionTime;
+ }
+
+ void MediaObject::setTransitionTime(qint32 time)
+ {
+ m_transitionTime = time;
+ }
+
+ qint64 MediaObject::remainingTime() const
+ {
+ return m_totalTime - m_currentTime;
+ }
+
+ Phonon::MediaSource MediaObject::source() const
+ {
+ return Phonon::MediaSource();
+ }
+
+ void MediaObject::setNextSource(const Phonon::MediaSource &source)
+ {
+ m_nextSource = source;
+ m_hasNextSource = true;
+ }
+
+ void MediaObject::setSource(const Phonon::MediaSource &source)
+ {
+ if (m_state == Phonon::PlayingState)
+ {
+ setError(Phonon::NormalError, QLatin1String("source changed while playing"));
+ stop();
+ }
+
+ m_source = source;
+ m_hasSource = true;
+ m_sourceIsValid = false;
+
+ emit currentSourceChanged(source);
+
+ if (source.type() == Phonon::MediaSource::LocalFile) {
+ if (!openWaveFile(source.fileName())) {
+ setError(Phonon::FatalError, QLatin1String("cannot open media file"));
+ return ;
+ }
+ } else if (source.type() == Phonon::MediaSource::Stream) {
+ if (m_stream)
+ delete m_stream;
+ m_stream = new IOWrapper(this, source);
+ m_mediaSize = m_stream->size();
+ } else if (source.type() == Phonon::MediaSource::Url) {
+ if (!openWaveFile(source.url().toLocalFile())) {
+ setError(Phonon::FatalError, QLatin1String("cannot open media file"));
+ return ;
+ }
+ } else {
+ setError(Phonon::FatalError, QLatin1String("type of source not supported"));
+ return ;
+ }
+ setState(Phonon::LoadingState);
+
+ if (!readHeader())
+ setError(Phonon::FatalError, QLatin1String("invalid header"));
+ else if (!getWaveOutDevice())
+ setError(Phonon::FatalError, QLatin1String("No waveOut device available"));
+ else if (!fillBuffers())
+ setError(Phonon::FatalError, QLatin1String("no data for buffering"));
+ else if (!prepareBuffers())
+ setError(Phonon::FatalError, QLatin1String("cannot prepare buffers"));
+ else
+ m_sourceIsValid = true;
+
+ if (m_sourceIsValid)
+ setState(Phonon::StoppedState);
+ }
+
+ void MediaObject::seek(qint64 time)
+ {
+ if (!m_sourceIsValid) {
+ setError(Phonon::NormalError, QLatin1String("source is not valid"));
+ return;
+ }
+ if ((time >= 0) && (time < m_totalTime)) {
+ int counter = 0;
+ while (!m_bufferingFinished && (counter < 200)) {
+ Sleep(20);
+ counter ++;
+ }
+ if (counter >= 200) {
+ setError(Phonon::NormalError, QLatin1String("buffering timed out"));
+ return;
+ }
+
+ m_stream->seek(WAVEHEADER_SIZE + time * m_waveFormatEx.nSamplesPerSec * m_waveFormatEx.wBitsPerSample * m_waveFormatEx.nChannels / 8 / 1000);
+ m_currentTime = time;
+ if (m_state == Phonon::PlayingState)
+ play();
+ } else {
+ setError(Phonon::NormalError, QLatin1String("seeking out of range"));
+ }
+ }
+
+ void MediaObject::unPrepareBuffers()
+ {
+ if (m_bufferPrepared) {
+ DWORD err1 = waveOutUnprepareHeader(m_hWaveOut, m_soundBuffer1.waveHeader, sizeof(WAVEHDR));
+ DWORD err2 = waveOutUnprepareHeader(m_hWaveOut, m_soundBuffer2.waveHeader, sizeof(WAVEHDR));
+ if (!(err1 == MMSYSERR_NOERROR) || !(err2 == MMSYSERR_NOERROR))
+ setError(Phonon::NormalError, QLatin1String("cannot unprepare buffer") + getErrorText(err1) + getErrorText(err2));
+ }
+ m_bufferPrepared = false;
+ }
+
+ bool MediaObject::prepareBuffers()
+ {
+ memset((void*)m_soundBuffer1.waveHeader, 0, sizeof(WAVEHDR));
+ m_soundBuffer1.waveHeader->lpData = m_soundBuffer1.data.data();
+ m_soundBuffer1.waveHeader->dwBufferLength = m_soundBuffer1.data.size();
+ m_soundBuffer1.waveHeader->dwUser = (DWORD_PTR) this;
+
+ ZeroMemory((void*)m_soundBuffer2.waveHeader, sizeof(WAVEHDR));
+ m_soundBuffer2.waveHeader->lpData = m_soundBuffer2.data.data();
+ m_soundBuffer2.waveHeader->dwBufferLength = m_soundBuffer1.data.size();
+ m_soundBuffer2.waveHeader->dwUser = (DWORD_PTR) this;
+
+ m_bufferPrepared = (waveOutPrepareHeader(m_hWaveOut, m_soundBuffer1.waveHeader, sizeof(WAVEHDR)) == MMSYSERR_NOERROR)
+ && (waveOutPrepareHeader(m_hWaveOut, m_soundBuffer2.waveHeader, sizeof(WAVEHDR)) == MMSYSERR_NOERROR);
+ return m_bufferPrepared;
+ }
+
+ void MediaObject::deleteValidWaveOutDevice()
+ {
+ if (m_hWaveOut) {
+ unPrepareBuffers();
+ if (!(waveOutClose(m_hWaveOut) == MMSYSERR_NOERROR))
+ setError(Phonon::NormalError, QLatin1String("cannot close wave device"));
+ }
+ }
+
+ bool MediaObject::getWaveOutDevice()
+ {
+ deleteValidWaveOutDevice();
+
+ for(UINT deviceId = 0; deviceId < waveOutGetNumDevs(); deviceId++)
+ {
+ if(deviceId == waveOutGetNumDevs())
+ return false;
+ if(waveOutOpen(&m_hWaveOut, WAVE_MAPPER, &m_waveFormatEx, (DWORD)WaveOutCallBack, 0, CALLBACK_FUNCTION) == MMSYSERR_NOERROR)
+ return m_hWaveOut; //m_hWaveOut !=0;
+ }
+ return false;
+ }
+
+ bool MediaObject::openWaveFile(QString fileName)
+ {
+ if (m_file)
+ delete m_file;
+ m_file = new QFile(fileName);
+ m_file->setParent(this);
+ m_stream = m_file;
+ m_mediaSize = m_file->size();
+ return (m_file->open(QIODevice::ReadOnly));
+ }
+
+ bool MediaObject::readHeader()
+ {
+ QByteArray header = m_stream->read(WAVEHEADER_SIZE);
+
+ if (header.size() == WAVEHEADER_SIZE) {
+
+ m_waveFormatEx.wFormatTag = *((WORD* )(header.data() + WAVEHEADER_OFFSET_FORMATTAG ));
+ m_waveFormatEx.nChannels = *((WORD* )(header.data() + WAVEHEADER_OFFSET_CHANNELS ));
+ m_waveFormatEx.nSamplesPerSec = *((DWORD*)(header.data() + WAVEHEADER_OFFSET_SAMPLESPERSEC ));
+ m_waveFormatEx.nAvgBytesPerSec = *((DWORD*)(header.data() + WAVEHEADER_OFFSET_AVGBYTESPERSEC));
+ m_waveFormatEx.nBlockAlign = *((WORD* )(header.data() + WAVEHEADER_OFFSET_BLOCKALIGN ));
+ m_waveFormatEx.wBitsPerSample = *((WORD* )(header.data() + WAVEHEADER_OFFSET_BITSPERSAMPLE ));
+
+ m_tickIntervalResolution = (qint64(buffer_size) * 8 * 1000) / m_waveFormatEx.nSamplesPerSec / m_waveFormatEx.wBitsPerSample / m_waveFormatEx.nChannels;
+ if (m_mediaSize > 0)
+ m_totalTime = ((m_mediaSize - WAVEHEADER_SIZE) * 8 * 1000) / m_waveFormatEx.nSamplesPerSec / m_waveFormatEx.wBitsPerSample / m_waveFormatEx.nChannels;
+ else
+ m_totalTime = -1;
+ emit totalTimeChanged(m_totalTime);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ bool MediaObject::fillBuffers()
+ {
+
+ m_soundBuffer1.data = m_stream->read(buffer_size);
+ m_soundBuffer2.data = m_stream->read(buffer_size);
+
+ m_bufferingFinished = true;
+
+ if (!(m_soundBuffer1.data.size() > 0))
+ setError(Phonon::NormalError, QLatin1String("cannot read source"));
+ return true;
+ }
+
+ void MediaObject::setState(Phonon::State newState)
+ {
+ if (m_state == newState)
+ return;
+ emit stateChanged(newState, m_state);
+ m_state = newState;
+ }
+
+ void MediaObject::setError(ErrorType errorType, QString errorMessage)
+ {
+ m_errorType = errorType;
+ setState(Phonon::ErrorState);
+ m_errorString = errorMessage;
+ }
+
+ void MediaObject::setAudioOutput(QObject *audioOutput)
+ {
+ m_audioOutput = qobject_cast<AudioOutput*>(audioOutput);
+
+ if (m_audioOutput) {
+ m_volume = m_audioOutput->volume();
+ connect(m_audioOutput, SIGNAL(volumeChanged(qreal)), this, SLOT(setVolume(qreal)));
+ }
+ }
+
+ void MediaObject::setVolume(qreal newVolume)
+ {
+ m_volume = newVolume;
+ }
+
+ void MediaObject::swapBuffers()
+ {
+ if (m_stopped || m_paused)
+ return;
+
+ m_currentTime += m_tickIntervalResolution;
+ if (m_tickInterval) {
+ m_tick ++;
+ if (m_tick > (m_tickInterval - 1)) {
+ emit tick(m_currentTime);
+ m_tick = 0;
+ }
+ }
+ if ((m_prefinishMark > 0)&& (m_prefinishMark < m_currentTime))
+ emit prefinishMarkReached(m_totalTime - m_currentTime);
+
+ while (!m_bufferingFinished) {
+ setState(Phonon::BufferingState);
+ qWarning() << QLatin1String("buffer underun");
+ Sleep(20);
+ }
+
+ setState(Phonon::PlayingState);
+
+ //if size == o then stop...
+ if (m_nextBufferIndex) {
+ int size = m_soundBuffer1.waveHeader->dwBufferLength = m_soundBuffer1.data.size();
+ if (size == buffer_size) {
+ playBuffer(m_soundBuffer1.waveHeader);
+ emit outOfData(m_stream, &m_soundBuffer1.data, &m_bufferingFinished);
+ } else {
+ playBuffer(m_soundBuffer1.waveHeader);
+ m_stopped = true;
+ setState(Phonon::StoppedState);
+ emit finished();
+ seek(0);
+ }
+ } else {
+ int size = m_soundBuffer2.waveHeader->dwBufferLength = m_soundBuffer2.data.size();
+ if (size == buffer_size) {
+ playBuffer(m_soundBuffer2.waveHeader);
+ emit outOfData(m_stream, &m_soundBuffer2.data, &m_bufferingFinished);
+ } else {
+ playBuffer(m_soundBuffer2.waveHeader);
+ m_stopped = true;
+ setState(Phonon::StoppedState);
+ emit finished();
+ seek(0);
+ }
+ }
+ m_nextBufferIndex =! m_nextBufferIndex;
+ }
+
+
+ void MediaObject::playBuffer(WAVEHDR *waveHeader)
+ {
+ DWORD err = waveOutWrite(m_hWaveOut, waveHeader, sizeof(WAVEHDR));
+ if (!err == MMSYSERR_NOERROR) {
+ setError(Phonon::FatalError, QLatin1String("cannot play sound buffer (system) ") + getErrorText(err));
+ m_stopped = true;
+ }
+ }
+ }
+}
+
+QT_END_NAMESPACE
+
+#include "mediaobject.moc"
diff --git a/src/3rdparty/phonon/waveout/mediaobject.h b/src/3rdparty/phonon/waveout/mediaobject.h
new file mode 100644
index 0000000000..dd6b24bc6c
--- /dev/null
+++ b/src/3rdparty/phonon/waveout/mediaobject.h
@@ -0,0 +1,162 @@
+/* This file is part of the KDE project.
+
+Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+
+This library 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, either version 2.1 or 3 of the License.
+
+This library 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 library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef PHONON_MEDIAOBJECT_H
+#define PHONON_MEDIAOBJECT_H
+
+#include <phonon/mediaobjectinterface.h>
+
+#include <QtCore/QHash>
+#include <QtCore/QObject>
+#include <QtCore/QQueue>
+#include <QtCore/QBasicTimer>
+#include <QtCore/QWaitCondition>
+#include <QtCore/QMutex>
+#include <QtCore/QThread>
+#include <QFile>
+#include <QIODevice>
+
+#include <windows.h>
+
+
+QT_BEGIN_NAMESPACE
+
+namespace Phonon
+{
+ class MediaSource;
+
+ namespace WaveOut
+ {
+ class WorkerThread;
+ class AudioOutput;
+
+ class MediaObject : public QObject, public Phonon::MediaObjectInterface
+ {
+ Q_OBJECT
+ Q_INTERFACES(Phonon::MediaObjectInterface)
+
+ public:
+ MediaObject(QObject *parent);
+ ~MediaObject();
+ Phonon::State state() const;
+ bool hasVideo() const;
+ bool isSeekable() const;
+ qint64 currentTime() const;
+ qint32 tickInterval() const;
+
+ void setTickInterval(qint32 newTickInterval);
+ void play();
+ void pause();
+ void stop();
+ void seek(qint64 time);
+
+ QString errorString() const;
+ Phonon::ErrorType errorType() const;
+ qint64 totalTime() const;
+ qint32 prefinishMark() const;
+ void setPrefinishMark(qint32 newPrefinishMark);
+ qint32 transitionTime() const;
+ void setTransitionTime(qint32);
+ qint64 remainingTime() const;
+ MediaSource source() const;
+ void setSource(const MediaSource &source);
+ void setNextSource(const MediaSource &source);
+
+
+ Q_SIGNALS:
+ void stateChanged(Phonon::State newstate, Phonon::State oldstate);
+ void tick(qint64 time);
+ void metaDataChanged(QMultiMap<QString, QString>);
+ void seekableChanged(bool);
+ void hasVideoChanged(bool);
+ void bufferStatus(int);
+ void finished();
+ void prefinishMarkReached(qint32);
+ void aboutToFinish();
+ void totalTimeChanged(qint64 length) const;
+ void currentSourceChanged(const MediaSource &);
+ void outOfData(QIODevice *ioStream, QByteArray *buffer, bool *m_bufferingFinshed);
+
+ protected:
+ void setAudioOutput(QObject *audioOutput);
+
+ private Q_SLOTS:
+ void setVolume(qreal newVolume);
+
+ private:
+ bool m_nextBufferIndex;
+ bool prepareBuffers();
+ void unPrepareBuffers();
+ bool getWaveOutDevice();
+ bool openWaveFile(QString fileName);
+ bool readHeader();
+ bool boolUpdateBuffer();
+ bool fillBuffers();
+ void swapBuffers();
+ void setState(Phonon::State newState);
+ void setError(ErrorType errorType, QString errorMessage);
+ void deleteValidWaveOutDevice();
+ void playBuffer(WAVEHDR *waveHeader);
+
+ static void CALLBACK WaveOutCallBack(HWAVEOUT hWaveOut, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2);
+
+ struct {
+ WAVEHDR *waveHeader;
+ QByteArray data;
+ } m_soundBuffer1, m_soundBuffer2;
+
+ WAVEFORMATEX m_waveFormatEx;
+ HWAVEOUT m_hWaveOut;
+
+ QFile *m_file;
+ QIODevice *m_stream;
+ QString m_errorString;
+
+ WorkerThread *m_thread;
+
+ MediaSource m_source;
+ MediaSource m_nextSource;
+ AudioOutput *m_audioOutput;
+ ErrorType m_errorType;
+
+ qreal m_volume;
+ qint64 m_mediaSize;
+ qint64 m_totalTime;
+ qint64 m_currentTime;
+ qint64 m_transitionTime;
+ qint64 m_prefinishMark;
+ qint64 m_tickIntervalResolution;
+ qint32 m_tickInterval;
+ qint32 m_tick;
+ Phonon::State m_state;
+
+ bool m_bufferingFinished;
+ bool m_paused;
+ bool m_stopped;
+ bool m_hasNextSource;
+ bool m_hasSource;
+ bool m_sourceIsValid;
+ bool m_bufferPrepared;
+
+ friend class Backend;
+ };
+ }
+}
+
+QT_END_NAMESPACE
+
+#endif // PHONON_MEDIAOBJECT_H