| /* 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 |
| { |
| None, |
| Render, |
| Seek, |
| ChangeState, |
| ReplaceGraph //just updates recalls WaitForMultipleObject |
| }; |
| |
| struct Work |
| { |
| Work() : task(None), id(0), time(0) { } |
| 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 |
| }; |
| void handleTask(); |
| |
| Work m_currentWork; |
| QQueue<Work> m_queue; |
| bool m_finished; |
| quint16 m_currentWorkId; |
| QWinWaitCondition m_waitCondition; |
| QMutex m_mutex; // mutex for the m_queue, m_finished and m_currentWorkId |
| |
| //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> ¶ms); |
| #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 |