File indexing completed on 2024-12-01 04:21:26

0001 /*
0002     Copyright (C) 2007-2008 Tanguy Krotoff <tkrotoff@gmail.com>
0003     Copyright (C) 2008 Lukas Durfina <lukas.durfina@gmail.com>
0004     Copyright (C) 2009 Fathi Boudra <fabo@kde.org>
0005     Copyright (C) 2009-2011 vlc-phonon AUTHORS <kde-multimedia@kde.org>
0006     Copyright (C) 2010-2011 Harald Sitter <sitter@kde.org>
0007 
0008     This library is free software; you can redistribute it and/or
0009     modify it under the terms of the GNU Lesser General Public
0010     License as published by the Free Software Foundation; either
0011     version 2.1 of the License, or (at your option) any later version.
0012 
0013     This library is distributed in the hope that it will be useful,
0014     but WITHOUT ANY WARRANTY; without even the implied warranty of
0015     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0016     Lesser General Public License for more details.
0017 
0018     You should have received a copy of the GNU Lesser General Public
0019     License along with this library.  If not, see <http://www.gnu.org/licenses/>.
0020 */
0021 
0022 #ifndef PHONON_VLC_MEDIAOBJECT_H
0023 #define PHONON_VLC_MEDIAOBJECT_H
0024 
0025 #include <QtCore/QObject>
0026 #include <QtCore/QTimer>
0027 
0028 #include <phonon/mediaobjectinterface.h>
0029 #include <phonon/addoninterface.h>
0030 
0031 #include "mediacontroller.h"
0032 #include "mediaplayer.h"
0033 
0034 namespace Phonon
0035 {
0036 namespace VLC
0037 {
0038 
0039 class Media;
0040 class SinkNode;
0041 class StreamReader;
0042 
0043 /** \brief Implementation for the most important class in Phonon
0044  *
0045  * The MediaObject class is the workhorse for Phonon. It handles what is needed
0046  * to play media. It has a media source object used to configure what media to
0047  * play.
0048  *
0049  * It provides the essential methods setSource(), play(), seek() and additional
0050  * methods to configure the next media source, the transition between sources,
0051  * transition times, ticks, other.
0052  *
0053  * There are numerous signals that provide information about the state of the media
0054  * and of the playing process. The aboutToFinish() and finished() signals are used
0055  * to see when the current media is finished.
0056  *
0057  * This class does not contain methods directly involved with libVLC. This part is
0058  * handled by the VLCMediaObject class. There are protected methods and slots
0059  * inherited by that class, like playInternal(), seekInternal().
0060  * These methods have no implementation here.
0061  *
0062  * For documentation regarding the methods implemented for MediaObjectInterface, see
0063  * the Phonon documentation.
0064  *
0065  * \see Phonon::MediaObjectInterface
0066  * \see VLCMediaObject
0067  */
0068 class MediaObject : public QObject, public MediaObjectInterface, public MediaController
0069 {
0070     Q_OBJECT
0071     Q_INTERFACES(Phonon::MediaObjectInterface Phonon::AddonInterface)
0072     friend class SinkNode;
0073 
0074 public:
0075     /**
0076      * Initializes the members, connects the private slots to their corresponding signals,
0077      * sets the next media source to an empty media source.
0078      *
0079      * \param parent A parent for the QObject
0080      */
0081     explicit MediaObject(QObject *parent);
0082     ~MediaObject();
0083 
0084     /**
0085      * Reset members (those that need resetting anyway).
0086      * Should always be called before going to a new source.
0087      */
0088     void resetMembers();
0089 
0090     /**
0091      * If the current state is paused, it resumes playing. Else, the playback
0092      * is commenced.
0093      */
0094     void play() override;
0095 
0096     /// Pauses the playback for the media player.
0097     void pause() override;
0098 
0099     /// Sets the next media source to an empty one and stops playback.
0100     void stop() override;
0101 
0102     /// \returns \c true when there is a video available, \c false otherwise
0103     bool hasVideo() const override;
0104 
0105     /// \returns \c true when the MediaObject is seekable, \c false otherwise
0106     bool isSeekable() const override;
0107 
0108     /// \returns total time (length, duration) of the current MediaSource (-1 if unknown)
0109     qint64 totalTime() const override;
0110 
0111     /// \returns An error message with the last libVLC error.
0112     QString errorString() const override;
0113 
0114     /**
0115      * Adds a sink for this media object. During playInternal(), all the sinks
0116      * will have their addToMedia() called.
0117      *
0118      * \see playInternal()
0119      * \see SinkNode::addToMedia()
0120      */
0121     void addSink(SinkNode *node);
0122 
0123     /// Removes a sink from this media object.
0124     void removeSink(SinkNode *node);
0125 
0126     /**
0127      * Pushes a seek command to the SeekStack for this media object. The SeekStack then
0128      * calls seekInternal() when it's popped.
0129      */
0130     void seek(qint64 milliseconds) override;
0131 
0132     /**
0133      * \return The interval between successive tick() signals. If set to 0, the emission
0134      * of these signals is disabled.
0135      */
0136     qint32 tickInterval() const override;
0137 
0138     /**
0139      * Sets the interval between successive tick() signals. If set to 0, it disables the
0140      * emission of these signals.
0141      */
0142     void setTickInterval(qint32 tickInterval) override;
0143 
0144     /**
0145      * \return The current time of the media, depending on the current state.
0146      * If the current state is stopped or loading, 0 is returned.
0147      * If the current state is error or unknown, -1 is returned.
0148      */
0149     qint64 currentTime() const override;
0150 
0151     /// \return The current state for this media object.
0152     Phonon::State state() const override;
0153 
0154     /// All errors are categorized as normal errors.
0155     Phonon::ErrorType errorType() const override;
0156 
0157     /// \return The current media source for this media object.
0158     MediaSource source() const override;
0159 
0160     /**
0161      * Sets the current media source for this media object. Depending on the source type,
0162      * the media object loads the specified media. The MRL is passed to loadMedia(), if the media
0163      * is not a stream. The currentSourceChanged() signal
0164      * is emitted.
0165      *
0166      * Supported media source types:
0167      * \li local files
0168      * \li URL
0169      * \li discs (CD, DVD, VCD)
0170      * \li capture devices (V4L)
0171      * \li streams
0172      *
0173      * \param source The media source that will become the current source.
0174      *
0175      * \see loadMedia()
0176      */
0177     void setSource(const MediaSource &source) override;
0178 
0179     /// Sets the media source that will replace the current one, after the playback for it finishes.
0180     void setNextSource(const MediaSource &source) override;
0181 
0182     qint32 prefinishMark() const override;
0183     void setPrefinishMark(qint32 msecToEnd) override;
0184 
0185     qint32 transitionTime() const override;
0186     void setTransitionTime(qint32) override;
0187 
0188     void emitAboutToFinish();
0189 
0190 Q_SIGNALS:
0191     // MediaController signals
0192     void availableSubtitlesChanged();
0193     void availableAudioChannelsChanged();
0194 
0195     void availableChaptersChanged(int);
0196     void availableTitlesChanged(int);
0197 
0198     void chapterChanged(int chapterNumber);
0199     void titleChanged(int titleNumber);
0200     void durationChanged(qint64 newDuration);
0201 
0202     /**
0203      * New widget size computed by VLC.
0204      *
0205      * It should be applied to the widget that contains the VLC video.
0206      */
0207     void videoWidgetSizeChanged(int i_width, int i_height);
0208 
0209     void aboutToFinish();
0210     void bufferStatus(int percentFilled);
0211     void currentSourceChanged(const MediaSource &newSource);
0212     void finished();
0213     void hasVideoChanged(bool b_has_video);
0214     void metaDataChanged(const QMultiMap<QString, QString> & metaData);
0215     void prefinishMarkReached(qint32 msecToEnd);
0216     void seekableChanged(bool seekable);
0217     void stateChanged(Phonon::State newState, Phonon::State oldState);
0218     void tick(qint64 time);
0219     void totalTimeChanged(qint64 newTotalTime);
0220 
0221     void moveToNext();
0222 
0223 private Q_SLOTS:
0224     /**
0225      * If the new state is different from the current state, the current state is
0226      * changed and the corresponding signal is emitted.
0227      */
0228     void changeState(Phonon::State newState);
0229 
0230     /**
0231      * Checks when the tick(), prefinishMarkReached(), aboutToFinish() signals need to
0232      * be emitted and emits them if necessary.
0233      *
0234      * \param currentTime The current play time for the media, in milliseconds.
0235      */
0236     void timeChanged(qint64 time);
0237     void emitTick(qint64 time);
0238 
0239     /**
0240      * If the next media source is valid, the current source is replaced and playback is commenced.
0241      * The next source is set to an empty source.
0242      *
0243      * \see setNextSource()
0244      */
0245     void moveToNextSource();
0246 
0247     /*** Update media duration time - see comment in CPP */
0248     void updateDuration(qint64 newDuration);
0249 
0250     /** Retrieve meta data of a file (i.e ARTIST, TITLE, ALBUM, etc...). */
0251     void updateMetaData();
0252     void updateState(MediaPlayer::State state);
0253 
0254     /** Called when the availability of video output changed */
0255     void onHasVideoChanged(bool hasVideo);
0256 
0257     void setBufferStatus(int percent);
0258 
0259     /** Refreshes all MediaController descriptors if Video is present. */
0260     void refreshDescriptors();
0261 
0262 private:
0263     /**
0264      * This method actually calls the functions needed to begin playing the media.
0265      * If another media is already playing, it is discarded. The new media filename is set
0266      * with loadMediaInternal(). A new VLC Media is created and set into the VLC Media Player.
0267      * All the connected sink nodes are connected to the new media. It connects the media object
0268      * to the events for the VLC Media, updates the meta-data, sets up the video widget id, and
0269      * starts playing.
0270      *
0271      * \see loadMediaInternal()
0272      * \see connectToMediaVLCEvents()
0273      * \see updateMetaData()
0274      * \see setVLCWidgetId()
0275      */
0276     void setupMedia();
0277 
0278     /**
0279      * Seeks to the required position. If the state is not playing, the seek position is remembered.
0280      */
0281     void seekInternal(qint64 milliseconds);
0282 
0283     bool hasNextTrack();
0284 
0285     /**
0286      * Changes the current state to buffering and sets the new current file.
0287      *
0288      * \param filename The MRL of the media source
0289      */
0290     void loadMedia(const QByteArray &mrl);
0291 
0292     /**
0293      * Overload for loadMedia, converting a QString to a QByteArray.
0294      *
0295      * \param filename The MRL of the media source
0296      *
0297      * \see loadMedia
0298      */
0299     void loadMedia(const QString &mrl);
0300 
0301     /**
0302      * Uninitializes the media
0303      */
0304     void unloadMedia();
0305 
0306     MediaSource m_nextSource;
0307 
0308     MediaSource m_mediaSource;
0309     StreamReader *m_streamReader;
0310     Phonon::State m_state;
0311 
0312     qint32 m_prefinishMark;
0313     bool m_prefinishEmitted;
0314 
0315     bool m_aboutToFinishEmitted;
0316 
0317     qint32 m_tickInterval;
0318     qint64 m_lastTick;
0319     qint32 m_transitionTime;
0320 
0321     Media *m_media;
0322 
0323     qint64 m_totalTime;
0324     QByteArray m_mrl;
0325     QMultiMap<QString, QString> m_vlcMetaData;
0326     QList<SinkNode *> m_sinks;
0327 
0328     bool m_hasVideo;
0329     bool m_isScreen;
0330 
0331     /**
0332      * Workaround for being able to seek before VLC goes to playing state.
0333      * Seeks before playing are stored in this var, and processed on state change
0334      * to Playing.
0335      */
0336     qint64 m_seekpoint;
0337 
0338     int m_timesVideoChecked;
0339 
0340     bool m_buffering;
0341     Phonon::State m_stateAfterBuffering;
0342 };
0343 
0344 } // namespace VLC
0345 } // namespace Phonon
0346 
0347 #endif // PHONON_VLC_MEDIAOBJECT_H