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
34namespace Phonon
35{
36namespace VLC
37{
38
39class Media;
40class SinkNode;
41class 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 */
68class MediaObject : public QObject, public MediaObjectInterface, public MediaController
69{
70 Q_OBJECT
71 Q_INTERFACES(Phonon::MediaObjectInterface Phonon::AddonInterface)
72 friend class SinkNode;
73
74public:
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
190Q_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
223private 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
262private:
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

source code of phonon-vlc/src/mediaobject.h