1 | /* |
2 | Copyright (C) 2007-2008 Tanguy Krotoff <tkrotoff@gmail.com> |
3 | Copyright (C) 2008 Lukas Durfina <lukas.durfina@gmail.com> |
4 | Copyright (C) 2009 Fathi Boudra <fabo@kde.org> |
5 | Copyright (C) 2009-2011 vlc-phonon AUTHORS <kde-multimedia@kde.org> |
6 | Copyright (C) 2010-2011 Harald Sitter <sitter@kde.org> |
7 | |
8 | This library is free software; you can redistribute it and/or |
9 | modify it under the terms of the GNU Lesser General Public |
10 | License as published by the Free Software Foundation; either |
11 | version 2.1 of the License, or (at your option) any later version. |
12 | |
13 | This library is distributed in the hope that it will be useful, |
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
16 | Lesser General Public License for more details. |
17 | |
18 | You should have received a copy of the GNU Lesser General Public |
19 | License along with this library. If not, see <http://www.gnu.org/licenses/>. |
20 | */ |
21 | |
22 | #ifndef PHONON_VLC_MEDIAOBJECT_H |
23 | #define PHONON_VLC_MEDIAOBJECT_H |
24 | |
25 | #include <QtCore/QObject> |
26 | #include <QtCore/QTimer> |
27 | |
28 | #include <phonon/mediaobjectinterface.h> |
29 | #include <phonon/addoninterface.h> |
30 | |
31 | #include "mediacontroller.h" |
32 | #include "mediaplayer.h" |
33 | |
34 | namespace Phonon |
35 | { |
36 | namespace VLC |
37 | { |
38 | |
39 | class Media; |
40 | class SinkNode; |
41 | class StreamReader; |
42 | |
43 | /** \brief Implementation for the most important class in Phonon |
44 | * |
45 | * The MediaObject class is the workhorse for Phonon. It handles what is needed |
46 | * to play media. It has a media source object used to configure what media to |
47 | * play. |
48 | * |
49 | * It provides the essential methods setSource(), play(), seek() and additional |
50 | * methods to configure the next media source, the transition between sources, |
51 | * transition times, ticks, other. |
52 | * |
53 | * There are numerous signals that provide information about the state of the media |
54 | * and of the playing process. The aboutToFinish() and finished() signals are used |
55 | * to see when the current media is finished. |
56 | * |
57 | * This class does not contain methods directly involved with libVLC. This part is |
58 | * handled by the VLCMediaObject class. There are protected methods and slots |
59 | * inherited by that class, like playInternal(), seekInternal(). |
60 | * These methods have no implementation here. |
61 | * |
62 | * For documentation regarding the methods implemented for MediaObjectInterface, see |
63 | * the Phonon documentation. |
64 | * |
65 | * \see Phonon::MediaObjectInterface |
66 | * \see VLCMediaObject |
67 | */ |
68 | class MediaObject : public QObject, public MediaObjectInterface, public MediaController |
69 | { |
70 | Q_OBJECT |
71 | Q_INTERFACES(Phonon::MediaObjectInterface Phonon::AddonInterface) |
72 | friend class SinkNode; |
73 | |
74 | public: |
75 | /** |
76 | * Initializes the members, connects the private slots to their corresponding signals, |
77 | * sets the next media source to an empty media source. |
78 | * |
79 | * \param parent A parent for the QObject |
80 | */ |
81 | explicit MediaObject(QObject *parent); |
82 | ~MediaObject(); |
83 | |
84 | /** |
85 | * Reset members (those that need resetting anyway). |
86 | * Should always be called before going to a new source. |
87 | */ |
88 | void resetMembers(); |
89 | |
90 | /** |
91 | * If the current state is paused, it resumes playing. Else, the playback |
92 | * is commenced. |
93 | */ |
94 | void play() override; |
95 | |
96 | /// Pauses the playback for the media player. |
97 | void pause() override; |
98 | |
99 | /// Sets the next media source to an empty one and stops playback. |
100 | void stop() override; |
101 | |
102 | /// \returns \c true when there is a video available, \c false otherwise |
103 | bool hasVideo() const override; |
104 | |
105 | /// \returns \c true when the MediaObject is seekable, \c false otherwise |
106 | bool isSeekable() const override; |
107 | |
108 | /// \returns total time (length, duration) of the current MediaSource (-1 if unknown) |
109 | qint64 totalTime() const override; |
110 | |
111 | /// \returns An error message with the last libVLC error. |
112 | QString errorString() const override; |
113 | |
114 | /** |
115 | * Adds a sink for this media object. During playInternal(), all the sinks |
116 | * will have their addToMedia() called. |
117 | * |
118 | * \see playInternal() |
119 | * \see SinkNode::addToMedia() |
120 | */ |
121 | void addSink(SinkNode *node); |
122 | |
123 | /// Removes a sink from this media object. |
124 | void removeSink(SinkNode *node); |
125 | |
126 | /** |
127 | * Pushes a seek command to the SeekStack for this media object. The SeekStack then |
128 | * calls seekInternal() when it's popped. |
129 | */ |
130 | void seek(qint64 milliseconds) override; |
131 | |
132 | /** |
133 | * \return The interval between successive tick() signals. If set to 0, the emission |
134 | * of these signals is disabled. |
135 | */ |
136 | qint32 tickInterval() const override; |
137 | |
138 | /** |
139 | * Sets the interval between successive tick() signals. If set to 0, it disables the |
140 | * emission of these signals. |
141 | */ |
142 | void setTickInterval(qint32 tickInterval) override; |
143 | |
144 | /** |
145 | * \return The current time of the media, depending on the current state. |
146 | * If the current state is stopped or loading, 0 is returned. |
147 | * If the current state is error or unknown, -1 is returned. |
148 | */ |
149 | qint64 currentTime() const override; |
150 | |
151 | /// \return The current state for this media object. |
152 | Phonon::State state() const override; |
153 | |
154 | /// All errors are categorized as normal errors. |
155 | Phonon::ErrorType errorType() const override; |
156 | |
157 | /// \return The current media source for this media object. |
158 | MediaSource source() const override; |
159 | |
160 | /** |
161 | * Sets the current media source for this media object. Depending on the source type, |
162 | * the media object loads the specified media. The MRL is passed to loadMedia(), if the media |
163 | * is not a stream. The currentSourceChanged() signal |
164 | * is emitted. |
165 | * |
166 | * Supported media source types: |
167 | * \li local files |
168 | * \li URL |
169 | * \li discs (CD, DVD, VCD) |
170 | * \li capture devices (V4L) |
171 | * \li streams |
172 | * |
173 | * \param source The media source that will become the current source. |
174 | * |
175 | * \see loadMedia() |
176 | */ |
177 | void setSource(const MediaSource &source) override; |
178 | |
179 | /// Sets the media source that will replace the current one, after the playback for it finishes. |
180 | void setNextSource(const MediaSource &source) override; |
181 | |
182 | qint32 prefinishMark() const override; |
183 | void setPrefinishMark(qint32 msecToEnd) override; |
184 | |
185 | qint32 transitionTime() const override; |
186 | void setTransitionTime(qint32) override; |
187 | |
188 | void emitAboutToFinish(); |
189 | |
190 | Q_SIGNALS: |
191 | // MediaController signals |
192 | void availableSubtitlesChanged(); |
193 | void availableAudioChannelsChanged(); |
194 | |
195 | void availableChaptersChanged(int); |
196 | void availableTitlesChanged(int); |
197 | |
198 | void chapterChanged(int chapterNumber); |
199 | void titleChanged(int titleNumber); |
200 | void durationChanged(qint64 newDuration); |
201 | |
202 | /** |
203 | * New widget size computed by VLC. |
204 | * |
205 | * It should be applied to the widget that contains the VLC video. |
206 | */ |
207 | void videoWidgetSizeChanged(int i_width, int i_height); |
208 | |
209 | void aboutToFinish(); |
210 | void bufferStatus(int percentFilled); |
211 | void currentSourceChanged(const MediaSource &newSource); |
212 | void finished(); |
213 | void hasVideoChanged(bool b_has_video); |
214 | void metaDataChanged(const QMultiMap<QString, QString> & metaData); |
215 | void prefinishMarkReached(qint32 msecToEnd); |
216 | void seekableChanged(bool seekable); |
217 | void stateChanged(Phonon::State newState, Phonon::State oldState); |
218 | void tick(qint64 time); |
219 | void totalTimeChanged(qint64 newTotalTime); |
220 | |
221 | void moveToNext(); |
222 | |
223 | private Q_SLOTS: |
224 | /** |
225 | * If the new state is different from the current state, the current state is |
226 | * changed and the corresponding signal is emitted. |
227 | */ |
228 | void changeState(Phonon::State newState); |
229 | |
230 | /** |
231 | * Checks when the tick(), prefinishMarkReached(), aboutToFinish() signals need to |
232 | * be emitted and emits them if necessary. |
233 | * |
234 | * \param currentTime The current play time for the media, in milliseconds. |
235 | */ |
236 | void timeChanged(qint64 time); |
237 | void emitTick(qint64 time); |
238 | |
239 | /** |
240 | * If the next media source is valid, the current source is replaced and playback is commenced. |
241 | * The next source is set to an empty source. |
242 | * |
243 | * \see setNextSource() |
244 | */ |
245 | void moveToNextSource(); |
246 | |
247 | /*** Update media duration time - see comment in CPP */ |
248 | void updateDuration(qint64 newDuration); |
249 | |
250 | /** Retrieve meta data of a file (i.e ARTIST, TITLE, ALBUM, etc...). */ |
251 | void updateMetaData(); |
252 | void updateState(MediaPlayer::State state); |
253 | |
254 | /** Called when the availability of video output changed */ |
255 | void onHasVideoChanged(bool hasVideo); |
256 | |
257 | void setBufferStatus(int percent); |
258 | |
259 | /** Refreshes all MediaController descriptors if Video is present. */ |
260 | void refreshDescriptors(); |
261 | |
262 | private: |
263 | /** |
264 | * This method actually calls the functions needed to begin playing the media. |
265 | * If another media is already playing, it is discarded. The new media filename is set |
266 | * with loadMediaInternal(). A new VLC Media is created and set into the VLC Media Player. |
267 | * All the connected sink nodes are connected to the new media. It connects the media object |
268 | * to the events for the VLC Media, updates the meta-data, sets up the video widget id, and |
269 | * starts playing. |
270 | * |
271 | * \see loadMediaInternal() |
272 | * \see connectToMediaVLCEvents() |
273 | * \see updateMetaData() |
274 | * \see setVLCWidgetId() |
275 | */ |
276 | void setupMedia(); |
277 | |
278 | /** |
279 | * Seeks to the required position. If the state is not playing, the seek position is remembered. |
280 | */ |
281 | void seekInternal(qint64 milliseconds); |
282 | |
283 | bool hasNextTrack(); |
284 | |
285 | /** |
286 | * Changes the current state to buffering and sets the new current file. |
287 | * |
288 | * \param filename The MRL of the media source |
289 | */ |
290 | void loadMedia(const QByteArray &mrl); |
291 | |
292 | /** |
293 | * Overload for loadMedia, converting a QString to a QByteArray. |
294 | * |
295 | * \param filename The MRL of the media source |
296 | * |
297 | * \see loadMedia |
298 | */ |
299 | void loadMedia(const QString &mrl); |
300 | |
301 | /** |
302 | * Uninitializes the media |
303 | */ |
304 | void unloadMedia(); |
305 | |
306 | MediaSource m_nextSource; |
307 | |
308 | MediaSource m_mediaSource; |
309 | StreamReader *m_streamReader; |
310 | Phonon::State m_state; |
311 | |
312 | qint32 m_prefinishMark; |
313 | bool m_prefinishEmitted; |
314 | |
315 | bool m_aboutToFinishEmitted; |
316 | |
317 | qint32 m_tickInterval; |
318 | qint64 m_lastTick; |
319 | qint32 m_transitionTime; |
320 | |
321 | Media *m_media; |
322 | |
323 | qint64 m_totalTime; |
324 | QByteArray m_mrl; |
325 | QMultiMap<QString, QString> m_vlcMetaData; |
326 | QList<SinkNode *> m_sinks; |
327 | |
328 | bool m_hasVideo; |
329 | bool m_isScreen; |
330 | |
331 | /** |
332 | * Workaround for being able to seek before VLC goes to playing state. |
333 | * Seeks before playing are stored in this var, and processed on state change |
334 | * to Playing. |
335 | */ |
336 | qint64 m_seekpoint; |
337 | |
338 | int m_timesVideoChecked; |
339 | |
340 | bool m_buffering; |
341 | Phonon::State m_stateAfterBuffering; |
342 | }; |
343 | |
344 | } // namespace VLC |
345 | } // namespace Phonon |
346 | |
347 | #endif // PHONON_VLC_MEDIAOBJECT_H |
348 | |