[prev in list] [next in list] [prev in thread] [next in thread]
List: kde-commits
Subject: extragear/multimedia/amarok/src/engine/phonon/directshow
From: Shane King <kde () dontletsstart ! com>
Date: 2007-12-06 13:40:16
Message-ID: 1196948416.050642.28708.nullmailer () svn ! kde ! org
[Download RAW message or body]
SVN commit 745583 by shakes:
Implementation of an audio backend for windows using DirectShow. Should mostly work, \
at least well enough to play a few tunes from the collection.
Amarok is now somewhat usable under windows! :)
TODO:
* Code needs more documentation.
* Some methods are left unimplementation because Amarok doesn't currently make use of \
them but probably will before release (eg cross fading).
* Doesn't do streaming, only local files.
M +8 -1 CMakeLists.txt
AM ComPtr.h [License: GPL (v2+)]
AM ComVariant.h [License: GPL (v2+)]
D DirectShow.h
M +12 -6 DirectShowAudioOutput.cpp
M +15 -0 DirectShowAudioOutput.h
M +170 -12 DirectShowBackend.cpp
M +25 -0 DirectShowBackend.h
AM DirectShowGraph.cpp [License: GPL (v2+)]
A DirectShowGraph.h DirectShow.h#745115 [License: GPL (v2+)]
M +42 -9 DirectShowMediaObject.cpp
M +24 -0 DirectShowMediaObject.h
--- trunk/extragear/multimedia/amarok/src/engine/phonon/directshow/CMakeLists.txt \
#745582:745583 @@ -1,11 +1,18 @@
set(phonon_amarok_directshow_PART_SRCS
DirectShowAudioOutput.cpp
DirectShowBackend.cpp
+ DirectShowGraph.cpp
DirectShowMediaObject.cpp
)
+include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/../../..
+ ${KDE4_INCLUDE_DIR}
+ ${QT_INCLUDES} )
+
+add_definitions( -DUNICODE -DWINVER=0x0500 )
+
kde4_add_plugin(phonon_amarok_directshow ${phonon_amarok_directshow_PART_SRCS})
-target_link_libraries(phonon_amarok_directshow ${KDE4_KDECORE_LIBS} \
${KDE4_PHONON_LIBS} Strmiids.lib Ole32.lib) \
+target_link_libraries(phonon_amarok_directshow ${KDE4_KDECORE_LIBS} \
${KDE4_PHONON_LIBS} amaroklib Strmiids.lib Ole32.lib Oleaut32.lib uuid.lib)
install(TARGETS phonon_amarok_directshow DESTINATION ${PLUGIN_INSTALL_DIR})
install(FILES amarok_directshow.desktop DESTINATION \
${SERVICES_INSTALL_DIR}/phononbackends)
** trunk/extragear/multimedia/amarok/src/engine/phonon/directshow/ComPtr.h #property \
svn:eol-style + native
** trunk/extragear/multimedia/amarok/src/engine/phonon/directshow/ComVariant.h \
#property svn:eol-style + native
--- trunk/extragear/multimedia/amarok/src/engine/phonon/directshow/DirectShowAudioOutput.cpp \
#745582:745583 @@ -14,7 +14,9 @@
DirectShowAudioOutput::DirectShowAudioOutput(QObject *parent)
- : QObject(parent)
+ : QObject( parent ),
+ m_device( 0 ),
+ m_volume( 0 )
{
}
@@ -27,25 +29,29 @@
qreal
DirectShowAudioOutput::volume() const
{
- return 0;
+ return m_volume;
}
void
-DirectShowAudioOutput::setVolume(qreal)
+DirectShowAudioOutput::setVolume(qreal volume)
{
+ m_volume = volume;
+ emit volumeChanged(m_volume);
}
int
DirectShowAudioOutput::outputDevice() const
{
- return 0;
+ return m_device;
}
bool
-DirectShowAudioOutput::setOutputDevice(int)
+DirectShowAudioOutput::setOutputDevice( int device )
{
- return false;
+ m_device = device;
+ emit outputDeviceChanged( device );
+ return true;
}
--- trunk/extragear/multimedia/amarok/src/engine/phonon/directshow/DirectShowAudioOutput.h \
#745582:745583 @@ -13,6 +13,11 @@
#include <phonon/audiooutputinterface.h>
+class DirectShowBackend;
+class DirectShowGraph;
+
+// Phonon AudioOutput implementation.
+// Mostly just emits signals which attached graphs use.
class DirectShowAudioOutput : public QObject, public Phonon::AudioOutputInterface
{
Q_OBJECT
@@ -27,6 +32,16 @@
int outputDevice() const;
bool setOutputDevice(int);
+
+ signals:
+ void volumeChanged(qreal newVolume);
+ void audioDeviceFailed();
+
+ void outputDeviceChanged( int device );
+
+ private:
+ int m_device;
+ qreal m_volume;
};
#endif // AMAROK_DIRECTSHOWAUDIOOUTPUT_H
--- trunk/extragear/multimedia/amarok/src/engine/phonon/directshow/DirectShowBackend.cpp \
#745582:745583 @@ -10,15 +10,22 @@
#define DEBUG_PREFIX "phonon-directshow"
-#include "DirectShow.h"
-
#include "DirectShowBackend.h"
+#include "DirectShowAudioOutput.h"
+#include "DirectShowGraph.h"
#include "DirectShowMediaObject.h"
-#include "DirectShowAudioOutput.h"
+#include "ComVariant.h"
+#include "debug.h"
+
#include <kpluginfactory.h>
+#include <QtGui>
+#include <dshow.h>
+#include <ocidl.h>
+
+
K_PLUGIN_FACTORY(DirectShowBackendFactory, registerPlugin<DirectShowBackend>();)
K_EXPORT_PLUGIN(DirectShowBackendFactory("amarokdirectshowbackend"))
@@ -26,24 +33,29 @@
DirectShowBackend::DirectShowBackend(QObject *parent, const QVariantList &args)
: QObject(parent)
{
+ m_initialized = createMessageWindow() && loadAudioDevices();
}
DirectShowBackend::~DirectShowBackend()
{
+ destroyMessageWindow();
}
QObject *
DirectShowBackend::createObject(BackendInterface::Class objectClass, QObject \
*parent, const QList<QVariant> &args) {
- switch( objectClass )
+ if( m_initialized )
{
- case BackendInterface::MediaObjectClass:
- return new DirectShowMediaObject(parent);
+ switch( objectClass )
+ {
+ case BackendInterface::MediaObjectClass:
+ return new DirectShowMediaObject(parent);
- case BackendInterface::AudioOutputClass:
- return new DirectShowAudioOutput(parent);
+ case BackendInterface::AudioOutputClass:
+ return new DirectShowAudioOutput(parent);
+ }
}
return 0;
}
@@ -52,14 +64,52 @@
QList<int>
DirectShowBackend::objectDescriptionIndexes(Phonon::ObjectDescriptionType type) \
const {
- return QList<int>();
+ QList<int> result;
+
+ if( type == Phonon::AudioOutputDeviceType )
+ {
+ for( int i = 0; i < m_audioDevices.size(); ++i )
+ {
+ result.push_back( i );
+ }
+ }
+
+ return result;
}
QHash<QByteArray, QVariant>
DirectShowBackend::objectDescriptionProperties(Phonon::ObjectDescriptionType type, \
int index) const {
- return QHash<QByteArray, QVariant>();
+ QHash<QByteArray, QVariant> result;
+
+ if( type == Phonon::AudioOutputDeviceType )
+ {
+ ComPtr<IMoniker> moniker = m_audioDevices[ index ];
+
+ HResult hr;
+ ComPtr<IPropertyBag> propBag;
+ hr = moniker->BindToStorage( 0, 0, IID_IPropertyBag, reinterpret_cast<void \
**>( &propBag ) ); + if( SUCCEEDED( hr ) )
+ {
+ ComVariant name;
+ hr = propBag->Read(L"FriendlyName", &name, 0);
+ if( SUCCEEDED( hr ) )
+ {
+ result.insert( "name", name.AsString() );
+ }
+ else
+ {
+ debug() << "Failed to get FriendlyName: " << hr;
+ }
+ }
+ else
+ {
+ debug() << "Failed to get properties for audio device: " << hr;
+ }
+ }
+
+ return result;
}
@@ -71,15 +121,34 @@
bool
-DirectShowBackend::connectNodes(QObject *, QObject *)
+DirectShowBackend::connectNodes(QObject *source, QObject *sink)
{
+ DirectShowMediaObject *mediaObject = qobject_cast<DirectShowMediaObject *>( \
source ); + DirectShowAudioOutput *audioOutput = \
qobject_cast<DirectShowAudioOutput *>( sink ); + if( mediaObject && audioOutput )
+ {
+ if( mediaObject->getGraph() )
+ debug() << "Can't connect multiple outputs to a media object";
+ else
+ return ( new DirectShowGraph( this, mediaObject, audioOutput ) \
)->initialized(); + }
+ else
+ {
+ debug() << "Can't connect nodes: mediaObject = " << (mediaObject == 0) << " \
audioOutput = " << (audioOutput == 0); + }
return false;
}
bool
-DirectShowBackend::disconnectNodes(QObject *, QObject *)
+DirectShowBackend::disconnectNodes(QObject *source, QObject *sink)
{
+ DirectShowMediaObject *mediaObject = qobject_cast<DirectShowMediaObject *>( \
source ); + DirectShowAudioOutput *audioOutput = \
qobject_cast<DirectShowAudioOutput *>( sink ); +
+ delete mediaObject->getGraph();
+ mediaObject->setGraph( 0 );
+
return false;
}
@@ -94,5 +163,94 @@
QStringList
DirectShowBackend::availableMimeTypes() const
{
+ // no way to get a list from DirectShow here :(
return QStringList();
}
+
+
+extern "C" LRESULT CALLBACK WndProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM \
lParam ) +{
+ if( uMsg == DirectShowBackend::WM_GRAPH_EVENT )
+ {
+ return reinterpret_cast<DirectShowGraph *>( lParam )->onEvent() ? 0 : -1;
+ }
+ return DefWindowProc( hwnd, uMsg, wParam, lParam );
+}
+
+
+static const wchar_t * WINDOW_CLASS = L"PhononAmarokDirectShow";
+const int DirectShowBackend::WM_GRAPH_EVENT = WM_APP + 1;
+
+bool
+DirectShowBackend::createMessageWindow()
+{
+ WNDCLASS cls;
+ cls.style = 0;
+ cls.lpfnWndProc = WndProc;
+ cls.cbClsExtra = 0;
+ cls.cbWndExtra = 0;
+ cls.hInstance = qWinAppInst();
+ cls.hIcon = 0;
+ cls.hCursor = 0;
+ cls.hbrBackground = 0;
+ cls.lpszMenuName = 0;
+ cls.lpszClassName = WINDOW_CLASS;
+
+ if( RegisterClass(&cls) )
+ {
+ m_window = CreateWindowEx( 0, WINDOW_CLASS,
+ L"PhononAmarokDirectShowWindow",0 ,0 ,0 ,0 ,0 ,HWND_MESSAGE,0, \
cls.hInstance, 0); + if(m_window)
+ return true;
+ else
+ debug() << "Failed to create message window";
+ }
+ else
+ {
+ debug() << "Failed to register window class";
+ }
+ return false;
+}
+
+
+void
+DirectShowBackend::destroyMessageWindow()
+{
+ DestroyWindow(m_window);
+ UnregisterClass(WINDOW_CLASS, qWinAppInst());
+}
+
+
+bool
+DirectShowBackend::loadAudioDevices()
+{
+ // Create the System Device Enumerator.
+ HResult hr;
+ ComPtr<ICreateDevEnum> sysDevEnum;
+ hr = sysDevEnum.CreateInstance(CLSID_SystemDeviceEnum, IID_ICreateDevEnum);
+ if ( SUCCEEDED( hr ) )
+ {
+ ComPtr<IEnumMoniker> enumCat;
+ hr = sysDevEnum->CreateClassEnumerator(CLSID_AudioRendererCategory, \
&enumCat, 0); + if ( SUCCEEDED( hr ) && enumCat )
+ {
+ ComPtr<IMoniker> moniker;
+ unsigned long fetched;
+ int i = 1;
+ while( enumCat->Next( 1, &moniker, &fetched ) == S_OK )
+ {
+ m_audioDevices.push_back( moniker );
+ }
+ return true;
+ }
+ else
+ {
+ debug() << "Failure enumerating device: " << hr;
+ }
+ }
+ else
+ {
+ debug() << "Failed to create system device enumerator: " << hr;
+ }
+ return false;
+}
--- trunk/extragear/multimedia/amarok/src/engine/phonon/directshow/DirectShowBackend.h \
#745582:745583 @@ -11,8 +11,19 @@
#ifndef AMAROK_DIRECTSHOWBACKEND_H
#define AMAROK_DIRECTSHOWBACKEND_H
+#include "ComPtr.h"
+
#include <phonon/backendinterface.h>
+#include <windows.h>
+#include <objidl.h>
+
+class DirectShowGraph;
+
+// Phonon backend class.
+// Does basic initialization of what we need for DirectShow
+// including setup up a (non-UI) "window" to handle events
+// which are dispatched to the appropriate graph object.
class DirectShowBackend : public QObject, public Phonon::BackendInterface
{
Q_OBJECT
@@ -30,6 +41,20 @@
bool disconnectNodes(QObject *, QObject *);
bool endConnectionChange(QSet<QObject *>);
QStringList availableMimeTypes() const;
+
+ ComPtr< IMoniker > getDevice( int index ) const { return m_audioDevices.at( \
index ); } + HWND window() { return m_window; }
+
+ static const int WM_GRAPH_EVENT;
+
+ private:
+ bool createMessageWindow();
+ void destroyMessageWindow();
+ bool loadAudioDevices();
+
+ bool m_initialized;
+ HWND m_window;
+ QList< ComPtr<IMoniker> > m_audioDevices;
};
#endif // AMAROK_DIRECTSHOWBACKEND_H
** trunk/extragear/multimedia/amarok/src/engine/phonon/directshow/DirectShowGraph.cpp \
#property svn:eol-style + native
--- trunk/extragear/multimedia/amarok/src/engine/phonon/directshow/DirectShowMediaObject.cpp \
#745582:745583 @@ -11,12 +11,14 @@
#define DEBUG_PREFIX "phonon-directshow"
#include "DirectShowMediaObject.h"
+#include "DirectShowGraph.h"
#include <kpluginfactory.h>
DirectShowMediaObject::DirectShowMediaObject(QObject *parent)
- : QObject(parent)
+ : QObject( parent ),
+ m_graph( 0 )
{
}
@@ -29,24 +31,32 @@
void
DirectShowMediaObject::play()
{
+ if( m_graph )
+ m_graph->play();
}
void
DirectShowMediaObject::pause()
{
+ if( m_graph )
+ m_graph->pause();
}
void
DirectShowMediaObject::stop()
{
+ if( m_graph )
+ m_graph->stop();
}
void
DirectShowMediaObject::seek(qint64 milliseconds)
{
+ if( m_graph )
+ m_graph->seek( milliseconds );
}
@@ -72,55 +82,57 @@
bool
DirectShowMediaObject::isSeekable() const
{
- return false;
+ return m_graph && m_graph->isSeekable();
}
qint64
DirectShowMediaObject::currentTime() const
{
- return 0;
+ return m_graph ? m_graph->currentTime() : 0;
}
Phonon::State
DirectShowMediaObject::state() const
{
- return Phonon::StoppedState;
+ return m_graph ? m_graph->state() : Phonon::StoppedState;
}
qint64
DirectShowMediaObject::totalTime() const
{
- return 0;
+ return m_graph ? m_graph->totalTime() : 0;
}
QString
DirectShowMediaObject::errorString() const
{
- return "";
+ return m_graph ? m_graph->errorString() : "";
}
Phonon::ErrorType
DirectShowMediaObject::errorType() const
{
- return Phonon::NoError;
+ return m_graph ? m_graph->errorType() : Phonon::NoError;
}
Phonon::MediaSource
DirectShowMediaObject::source() const
{
- return Phonon::MediaSource();
+ return m_graph->source();
}
void
-DirectShowMediaObject::setSource(const Phonon::MediaSource &)
+DirectShowMediaObject::setSource(const Phonon::MediaSource &source)
{
+ if( m_graph )
+ m_graph->setSource( source );
}
@@ -129,6 +141,7 @@
{
}
+
qint32
DirectShowMediaObject::prefinishMark() const
{
@@ -153,3 +166,23 @@
DirectShowMediaObject::setTransitionTime(qint32)
{
}
+
+
+void
+DirectShowMediaObject::setGraph( DirectShowGraph *graph )
+{
+ m_graph = graph;
+
+ connect( m_graph, SIGNAL( aboutToFinish() ), SIGNAL( aboutToFinish() ) );
+ connect( m_graph, SIGNAL( finished() ), SIGNAL( finished() ) );
+ connect( m_graph, SIGNAL( prefinishMarkReached(qint32) ), SIGNAL( \
prefinishMarkReached(qint32) ) ); + connect( m_graph, SIGNAL( \
totalTimeChanged(qint64) ), SIGNAL( prefinishMarkReached(qint32) ) ); + connect( \
m_graph, SIGNAL( currentSourceChanged(const Phonon::MediaSource &) ), SIGNAL( \
currentSourceChanged(const Phonon::MediaSource &) ) ); +
+ connect( m_graph, SIGNAL( stateChanged( Phonon::State, Phonon::State ) ), \
SIGNAL( stateChanged( Phonon::State, Phonon::State ) ) ); + connect( m_graph, \
SIGNAL( tick(qint64) ), SIGNAL( tick(qint64) ) ); + connect( m_graph, SIGNAL( \
metaDataChanged(const QMultiMap<QString, QString> &) ), SIGNAL( metaDataChanged(const \
QMultiMap<QString, QString> &) ) ); + connect( m_graph, SIGNAL( \
seekableChanged(bool) ), SIGNAL( seekableChanged(bool) ) ); + connect( m_graph, \
SIGNAL( hasVideoChanged(bool) ), SIGNAL( hasVideoChanged(bool) ) ); + connect( \
m_graph, SIGNAL( bufferStatus(int) ), SIGNAL( bufferStatus(int) ) ); +}
--- trunk/extragear/multimedia/amarok/src/engine/phonon/directshow/DirectShowMediaObject.h \
#745582:745583 @@ -13,6 +13,10 @@
#include <phonon/mediaobjectinterface.h>
+class DirectShowGraph;
+
+// Phonon MediaObject implementation.
+// Mostly just forwards everything on to its associated graph object.
class DirectShowMediaObject : public QObject, public Phonon::MediaObjectInterface
{
Q_OBJECT
@@ -49,6 +53,26 @@
qint32 transitionTime() const;
void setTransitionTime(qint32);
+
+ void setGraph( DirectShowGraph *graph );
+ DirectShowGraph *getGraph() { return m_graph; }
+
+ signals:
+ void aboutToFinish();
+ void finished();
+ void prefinishMarkReached(qint32 msec);
+ void totalTimeChanged(qint64 length);
+ void currentSourceChanged(const Phonon::MediaSource &);
+
+ void stateChanged(Phonon::State newstate, Phonon::State oldstate);
+ void tick(qint64 time);
+ void metaDataChanged(const QMultiMap<QString, QString> &);
+ void seekableChanged(bool);
+ void hasVideoChanged(bool);
+ void bufferStatus(int);
+
+ private:
+ DirectShowGraph *m_graph;
};
#endif // AMAROK_DIRECTSHOWMEDIAOBJECT_H
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic