1
/*  This file is part of the KDE project.
2
3
Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4
5
This library is free software: you can redistribute it and/or modify
6
it under the terms of the GNU Lesser General Public License as published by
7
the Free Software Foundation, either version 2.1 or 3 of the License.
8
9
This library is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
GNU Lesser General Public License for more details.
13
14
You should have received a copy of the GNU Lesser General Public License
15
along with this library.  If not, see <http://www.gnu.org/licenses/>.
16
*/
17
18
#ifndef PHONON_MEDIAOBJECT_H
19
#define PHONON_MEDIAOBJECT_H
20
21
#include <phonon/mediaobjectinterface.h>
22
#include <phonon/addoninterface.h>
23
24
#include <QtCore/QHash>
25
#include <QtCore/QObject>
26
#include <QtCore/QQueue>
27
#include <QtCore/QBasicTimer>
28
#include <QtCore/QMutex>
29
#include <QtCore/QThread>
30
31
#include "backendnode.h"
32
#include "mediagraph.h"
33
34
QT_BEGIN_NAMESPACE
35
36
namespace Phonon
37
{
38
    class MediaSource;
39
40
    namespace DS9
41
    {
42
        class VideoWidget;
43
        class AudioOutput;
44
45
        class QWinWaitCondition
46
        {
47
        public:
48
            QWinWaitCondition() : m_handle(::CreateEvent(0,0,0,0))
49
            {
50
            }
51
52
            ~QWinWaitCondition()
53
            {
54
                ::CloseHandle(m_handle);
55
            }
56
57
            void reset()
58
            {
59
                //will block
60
                ::ResetEvent(m_handle);
61
            }
62
63
            void set()
64
            {
65
                //will unblock
66
                ::SetEvent(m_handle);
67
            }
68
69
            operator HANDLE()
70
            {
71
                return m_handle;
72
            }
73
74
            operator HEVENT()
75
            {
76
                return reinterpret_cast<HEVENT>(m_handle);
77
            }
78
79
80
        private:
81
            HANDLE m_handle;
82
        };
83
84
        class WorkerThread : public QThread
85
        {
86
            Q_OBJECT
87
        public:
88
            WorkerThread();
89
            ~WorkerThread();
90
91
            virtual void run();
92
93
            //wants to know as soon as the state is set
94
            void addStateChangeRequest(Graph graph, OAFilterState, QList<Filter> = QList<Filter>());
95
96
            quint16 addSeekRequest(Graph graph, qint64 time);
97
            quint16 addUrlToRender(const QString &url);
98
            quint16 addFilterToRender(const Filter &filter);
99
100
            void replaceGraphForEventManagement(Graph newGraph, Graph oldGraph);
101
102
    		void abortCurrentRender(qint16 renderId);
103
104
            //tells the thread to stop processing
105
            void signalStop();
106
107
        Q_SIGNALS:
108
            void asyncRenderFinished(quint16, HRESULT, Graph);
109
            void asyncSeekingFinished(quint16, qint64);
110
            void stateReady(Graph, Phonon::State);
111
            void eventReady(Graph, long eventCode, long param1);
112
113
        private:
114
115
            enum Task
116
            {
117
                None,
118
                Render,
119
                Seek,
120
                ChangeState,
121
                ReplaceGraph //just updates recalls WaitForMultipleObject
122
            };
123
124
            struct Work
125
            {
126
                Work() : task(None), id(0), time(0) { }
127
                Task task;
128
                quint16 id;
129
                Graph graph;
130
                Graph oldGraph;
131
                Filter filter;
132
                QString url;
133
                union
134
                {
135
                    qint64 time;
136
                    OAFilterState state;
137
                };
138
                QList<Filter> decoders; //for the state change requests
139
            };
140
            void handleTask();
141
142
            Work m_currentWork;
143
            QQueue<Work> m_queue;
144
            bool m_finished;
145
            quint16 m_currentWorkId;
146
            QWinWaitCondition m_waitCondition;
147
            QMutex m_mutex; // mutex for the m_queue, m_finished and m_currentWorkId
148
149
            //this is for WaitForMultipleObjects
150
            struct
151
            {
152
                Graph graph;
153
                HANDLE handle;
154
            } m_graphHandle[FILTER_COUNT];
155
        };
156
157
158
        class MediaObject : public BackendNode, public Phonon::MediaObjectInterface
159
#ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
160
            , public Phonon::AddonInterface
161
#endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
162
        {
163
            friend class Stream;
164
            Q_OBJECT
165
                Q_INTERFACES(Phonon::MediaObjectInterface 
166
#ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
167
                    Phonon::AddonInterface
168
#endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
169
                    )
170
        public:
171
            MediaObject(QObject *parent);
172
            ~MediaObject();
173
            Phonon::State state() const;
174
            bool hasVideo() const;
175
            bool isSeekable() const;
176
            qint64 currentTime() const;
177
            qint32 tickInterval() const;
178
179
            void setTickInterval(qint32 newTickInterval);
180
            void play();
181
            void pause();
182
            void stop();
183
            void ensureStopped();
184
            void seek(qint64 time);
185
186
            QString errorString() const;
187
            Phonon::ErrorType errorType() const;
188
189
#ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
190
            bool hasInterface(Interface) const;
191
            QVariant interfaceCall(Interface iface, int command, const QList<QVariant> &params);
192
#endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
193
194
            qint64 totalTime() const;
195
            qint32 prefinishMark() const;
196
            void setPrefinishMark(qint32 newPrefinishMark);
197
198
            qint32 transitionTime() const;
199
            void setTransitionTime(qint32);
200
201
            qint64 remainingTime() const;
202
203
            MediaSource source() const;
204
            void setSource(const MediaSource &source);
205
            void setNextSource(const MediaSource &source);
206
207
208
            //COM error management
209
            bool catchComError(HRESULT hr);
210
211
            void grabNode(BackendNode *node);
212
            bool connectNodes(BackendNode *source, BackendNode *sink);
213
            bool disconnectNodes(BackendNode *source, BackendNode *sink);
214
215
            void switchFilters(int index, Filter oldFilter, Filter newFilter);
216
217
            WorkerThread *workerThread();
218
            void loadingFinished(MediaGraph *mg);
219
            void seekingFinished(MediaGraph *mg);
220
            MediaGraph *currentGraph() const;
221
222
            //this is used by the backend only
223
            Phonon::State transactionState;
224
225
         private Q_SLOTS:
226
            void switchToNextSource();
227
            void slotStateReady(Graph, Phonon::State);
228
            void handleEvents(Graph, long eventCode, long param1);
229
            void finishLoading(quint16 workId, HRESULT hr, Graph);
230
            void finishSeeking(quint16 workId, qint64 time);
231
232
         Q_SIGNALS:
233
            void stateChanged(Phonon::State newstate, Phonon::State oldstate);
234
            void tick(qint64 time);
235
            void metaDataChanged(QMultiMap<QString, QString>);
236
            void seekableChanged(bool);
237
            void hasVideoChanged(bool);
238
            void bufferStatus(int);
239
240
            // AddonInterface:
241
            void titleChanged(int);
242
            void availableTitlesChanged(int);
243
            void chapterChanged(int);
244
            void availableChaptersChanged(int);
245
            void angleChanged(int);
246
            void availableAnglesChanged(int);
247
248
            void finished();
249
            void prefinishMarkReached(qint32);
250
            void aboutToFinish();
251
            void totalTimeChanged(qint64 length) const;
252
            void currentSourceChanged(const MediaSource &);
253
254
        protected:
255
            void setState(Phonon::State);
256
            void timerEvent(QTimerEvent *e);
257
258
        private:
259
#ifndef QT_NO_PHONON_VIDEO
260
            void updateVideoGeometry();
261
#endif // QT_NO_PHONON_VIDEO
262
            void handleComplete(IGraphBuilder *graph);
263
            MediaGraph *nextGraph() const;
264
265
            void updateTargetTick();
266
            void updateStopPosition();
267
268
            mutable QString m_errorString;
269
            mutable Phonon::ErrorType m_errorType;
270
271
            Phonon::State m_state;
272
            Phonon::State m_nextState;
273
            qint32 m_transitionTime;
274
275
            qint32 m_prefinishMark;
276
277
            QBasicTimer m_tickTimer;
278
            qint32 m_tickInterval;
279
280
            //the graph(s)
281
            MediaGraph* m_graphs[FILTER_COUNT];
282
283
            //...the videowidgets in the graph
284
            QList<VideoWidget*> m_videoWidgets;
285
            QList<AudioOutput*> m_audioOutputs;
286
287
            bool m_buffering:1;
288
            bool m_oldHasVideo:1;
289
            bool m_prefinishMarkSent:1;
290
            bool m_aboutToFinishSent:1;
291
            bool m_nextSourceReadyToStart:1;
292
293
            //for TitleInterface (and commands)
294
#ifndef QT_NO_PHONON_MEDIACONTROLLER
295
            bool m_autoplayTitles:1;
296
            QList<qint64> m_titles;
297
            int m_currentTitle;
298
            int _iface_availableTitles() const;
299
            int _iface_currentTitle() const;
300
            void _iface_setCurrentTitle(int title, bool bseek = true);
301
            void setTitles(const QList<qint64> &titles);
302
            qint64 titleAbsolutePosition(int title) const;
303
#endif //QT_NO_PHONON_MEDIACONTROLLER
304
            qint64 m_targetTick;
305
306
            WorkerThread m_thread;
307
        };
308
    }
309
}
310
311
QT_END_NAMESPACE
312
313
#endif // PHONON_MEDIAOBJECT_H