1 /*****************************************************************************
2 * VLC backend for the Phonon library *
3 * Copyright (C) 2007-2008 Tanguy Krotoff <tkrotoff@gmail.com> *
4 * Copyright (C) 2008 Lukas Durfina <lukas.durfina@gmail.com> *
5 * Copyright (C) 2009 Fathi Boudra <fabo@kde.org> *
7 * This program is free software; you can redistribute it and/or *
8 * modify it under the terms of the GNU Lesser General Public *
9 * License as published by the Free Software Foundation; either *
10 * version 3 of the License, or (at your option) any later version. *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
15 * Lesser General Public License for more details. *
17 * You should have received a copy of the GNU Lesser General Public *
18 * License along with this package; if not, write to the Free Software *
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA *
20 *****************************************************************************/
22 #include "vlcmediaobject.h"
24 #include "videowidget.h"
26 #include "vlcloader.h"
28 #include <QtCore/QTimer>
29 #include <QtCore/QtDebug>
35 VLCMediaObject::VLCMediaObject(QObject * parent)
36 : MediaObject(parent), VLCMediaController()
38 // Create an empty Media Player object
39 p_vlc_media_player = libvlc_media_player_new(vlc_instance, vlc_exception);
41 p_vlc_media_player_event_manager = 0;
45 p_vlc_media_event_manager = 0;
48 p_vlc_media_discoverer = 0;
49 p_vlc_media_discoverer_event_manager = 0;
56 VLCMediaObject::~VLCMediaObject()
60 libvlc_media_player_stop(p_vlc_media_player); // ensure that we are stopped
61 libvlc_media_player_release(p_vlc_media_player);
64 void VLCMediaObject::unloadMedia()
66 // if( p_vlc_media_player ) {
67 // libvlc_media_player_release(p_vlc_media_player);
68 // p_vlc_media_player = 0;
72 libvlc_media_release(p_vlc_media);
77 void VLCMediaObject::loadMediaInternal(const QString & filename)
79 qDebug() << __FUNCTION__ << filename;
81 // Create a media with the given MRL
82 p_vlc_media = libvlc_media_new(vlc_instance, filename.toAscii(), vlc_exception);
85 // Set the media that will be used by the media player
86 libvlc_media_player_set_media(p_vlc_media_player, p_vlc_media);
88 // No need to keep the media now
89 // libvlc_media_release(p_vlc_media);
91 // connectToAllVLCEvents() at the end since it needs p_vlc_media_player
92 connectToAllVLCEvents();
94 b_play_request_reached = false;
96 // Get meta data (artist, title, etc...)
99 // Update available audio channels/subtitles/angles/chapters/etc...
100 // i.e everything from MediaController
101 // There is no audio channel/subtitle/angle/chapter events inside libvlc
102 // so let's send our own events...
103 // This will reset the GUI
104 clearMediaController();
106 // We need to do this, otherwise we never get any events with the real length
107 libvlc_media_get_duration(p_vlc_media, vlc_exception);
109 if (b_play_request_reached) {
110 // The media is playing, no need to load it
114 emit stateChanged(Phonon::StoppedState);
117 void VLCMediaObject::setVLCWidgetId()
119 // Get our media player to use our window
120 #if defined(Q_OS_UNIX)
121 libvlc_media_player_set_xwindow(p_vlc_media_player, i_video_widget_id);
122 #elif defined(Q_OS_WIN)
123 libvlc_media_player_set_hwnd(p_vlc_media_player, i_video_widget_id);
124 #elif defined(Q_OS_MAC)
125 libvlc_media_player_set_agl(p_vlc_media_player, i_video_widget_id);
129 void VLCMediaObject::playInternal()
131 b_play_request_reached = true;
133 // Clear subtitles/chapters/etc...
134 clearMediaController();
136 vlc_current_media_player = p_vlc_media_player;
141 libvlc_media_player_play(p_vlc_media_player, vlc_exception);
142 vlcExceptionRaised();
145 void VLCMediaObject::pause()
147 libvlc_media_player_pause(p_vlc_media_player, vlc_exception);
148 vlcExceptionRaised();
151 void VLCMediaObject::stop()
153 libvlc_media_player_stop(p_vlc_media_player);
157 void VLCMediaObject::seekInternal(qint64 milliseconds)
159 qDebug() << __FUNCTION__ << milliseconds;
160 libvlc_media_player_set_time(p_vlc_media_player, milliseconds, vlc_exception);
161 vlcExceptionRaised();
164 QString VLCMediaObject::errorString() const
166 return libvlc_errmsg();
169 bool VLCMediaObject::hasVideo() const
174 bool VLCMediaObject::isSeekable() const
179 void VLCMediaObject::connectToAllVLCEvents()
181 // Get the event manager from which the media player send event
182 p_vlc_media_player_event_manager = libvlc_media_player_event_manager(p_vlc_media_player);
183 libvlc_event_type_t eventsMediaPlayer[] = {
184 libvlc_MediaPlayerPlaying,
185 libvlc_MediaPlayerPaused,
186 libvlc_MediaPlayerEndReached,
187 libvlc_MediaPlayerStopped,
188 libvlc_MediaPlayerEncounteredError,
189 libvlc_MediaPlayerTimeChanged,
190 libvlc_MediaPlayerTitleChanged,
191 libvlc_MediaPlayerPositionChanged,
192 //libvlc_MediaPlayerSeekableChanged, //FIXME: doesn't work anymore? it asserts
193 libvlc_MediaPlayerPausableChanged,
195 int i_nbEvents = sizeof(eventsMediaPlayer) / sizeof(*eventsMediaPlayer);
196 for (int i = 0; i < i_nbEvents; i++) {
197 libvlc_event_attach(p_vlc_media_player_event_manager, eventsMediaPlayer[i],
198 libvlc_callback, this);
202 // Get event manager from media descriptor object
203 p_vlc_media_event_manager = libvlc_media_event_manager(p_vlc_media);
204 libvlc_event_type_t eventsMedia[] = {
205 libvlc_MediaMetaChanged,
206 libvlc_MediaSubItemAdded,
207 libvlc_MediaDurationChanged,
208 // FIXME libvlc does not know this event
209 // libvlc_MediaPreparsedChanged,
211 libvlc_MediaStateChanged,
213 i_nbEvents = sizeof(eventsMedia) / sizeof(*eventsMedia);
214 for (int i = 0; i < i_nbEvents; i++) {
215 libvlc_event_attach(p_vlc_media_event_manager, eventsMedia[i], libvlc_callback, this);
218 // Get event manager from media service discoverer object
219 // FIXME why libvlc_media_discoverer_event_manager() does not take a libvlc_exception_t ?
220 // p_vlc_media_discoverer_event_manager = libvlc_media_discoverer_event_manager(p_vlc_media_discoverer);
221 // libvlc_event_type_t eventsMediaDiscoverer[] = {
222 // libvlc_MediaDiscovererStarted,
223 // libvlc_MediaDiscovererEnded
225 // nbEvents = sizeof(eventsMediaDiscoverer) / sizeof(*eventsMediaDiscoverer);
226 // for (int i = 0; i < nbEvents; i++) {
227 // libvlc_event_attach(p_vlc_media_discoverer_event_manager, eventsMediaDiscoverer[i], libvlc_callback, this, vlc_exception);
231 void VLCMediaObject::libvlc_callback(const libvlc_event_t *p_event, void *p_user_data)
233 static int i_first_time_media_player_time_changed = 0;
234 static bool b_media_player_title_changed = false;
236 VLCMediaObject *p_vlc_mediaObject = (VLCMediaObject *) p_user_data;
238 // qDebug() << (int)pp_vlc_mediaObject << "event:" << libvlc_event_type_name(event->type);
240 // Media player events
241 if (p_event->type == libvlc_MediaPlayerTimeChanged) {
243 i_first_time_media_player_time_changed++;
245 // FIXME It is ugly. It should be solved by some events in libvlc
246 if (i_first_time_media_player_time_changed == 15) {
248 p_vlc_mediaObject->updateMetaData();
250 // Is this media player seekable
251 bool b_seekable = libvlc_media_player_is_seekable(p_vlc_mediaObject->p_vlc_media_player, vlc_exception);
252 vlcExceptionRaised();
253 if (b_seekable != p_vlc_mediaObject->b_seekable) {
254 qDebug() << "libvlc_callback(): isSeekable:" << b_seekable;
255 p_vlc_mediaObject->b_seekable = b_seekable;
256 emit p_vlc_mediaObject->seekableChanged(p_vlc_mediaObject->b_seekable);
259 // Get current video width
260 int i_width = libvlc_video_get_width(p_vlc_mediaObject->p_vlc_media_player, vlc_exception);
261 vlcExceptionRaised();
263 // Get current video height
264 int i_height = libvlc_video_get_height(p_vlc_mediaObject->p_vlc_media_player, vlc_exception);
265 vlcExceptionRaised();
266 emit p_vlc_mediaObject->videoWidgetSizeChanged(i_width, i_height);
268 // Does this media player have a video output
269 bool b_has_video = libvlc_media_player_has_vout(p_vlc_mediaObject->p_vlc_media_player, vlc_exception);
270 vlcExceptionRaised();
271 if (b_has_video != p_vlc_mediaObject->b_has_video) {
272 p_vlc_mediaObject->b_has_video = b_has_video;
273 emit p_vlc_mediaObject->hasVideoChanged(p_vlc_mediaObject->b_has_video);
277 // Give info about audio tracks
278 p_vlc_mediaObject->refreshAudioChannels();
279 // Give info about subtitle tracks
280 p_vlc_mediaObject->refreshSubtitles();
282 // Get movie chapter count
283 // It is not a title/chapter media if there is no chapter
284 if (libvlc_media_player_get_chapter_count(
285 p_vlc_mediaObject->p_vlc_media_player, vlc_exception) > 0) {
286 vlcExceptionRaised();
287 // Give info about title
288 // only first time, no when title changed
289 if (!b_media_player_title_changed) {
290 libvlc_track_description_t *p_info = libvlc_video_get_title_description(
291 p_vlc_mediaObject->p_vlc_media_player, vlc_exception);
292 vlcExceptionRaised();
294 p_vlc_mediaObject->titleAdded(p_info->i_id, p_info->psz_name);
295 p_info = p_info->p_next;
297 libvlc_track_description_release(p_info);
300 // Give info about chapters for actual title 0
301 if (b_media_player_title_changed)
302 p_vlc_mediaObject->refreshChapters(libvlc_media_player_get_title(
303 p_vlc_mediaObject->p_vlc_media_player, vlc_exception));
305 p_vlc_mediaObject->refreshChapters(0);
307 if (b_media_player_title_changed)
308 b_media_player_title_changed = false;
311 // Bugfix with Qt mediaplayer example
312 // Now we are in playing state
313 emit p_vlc_mediaObject->stateChanged(Phonon::PlayingState);
316 emit p_vlc_mediaObject->tickInternal(p_vlc_mediaObject->currentTime());
319 if (p_event->type == libvlc_MediaPlayerPlaying) {
320 if (p_vlc_mediaObject->state() != Phonon::LoadingState) {
321 // Bugfix with Qt mediaplayer example
322 emit p_vlc_mediaObject->stateChanged(Phonon::PlayingState);
326 if (p_event->type == libvlc_MediaPlayerPaused) {
327 emit p_vlc_mediaObject->stateChanged(Phonon::PausedState);
330 if (p_event->type == libvlc_MediaPlayerEndReached) {
331 i_first_time_media_player_time_changed = 0;
332 p_vlc_mediaObject->clearMediaController();
333 emit p_vlc_mediaObject->stateChanged(Phonon::StoppedState);
334 emit p_vlc_mediaObject->finished();
337 if (p_event->type == libvlc_MediaPlayerStopped) {
338 i_first_time_media_player_time_changed = 0;
339 p_vlc_mediaObject->clearMediaController();
340 emit p_vlc_mediaObject->stateChanged(Phonon::StoppedState);
343 if (p_event->type == libvlc_MediaPlayerTitleChanged) {
344 i_first_time_media_player_time_changed = 0;
345 b_media_player_title_changed = true;
350 if (p_event->type == libvlc_MediaDurationChanged) {
351 // Get duration of media descriptor object item
352 libvlc_time_t totalTime = libvlc_media_get_duration(p_vlc_mediaObject->p_vlc_media, vlc_exception);
353 vlcExceptionRaised();
355 if (totalTime != p_vlc_mediaObject->i_total_time) {
356 p_vlc_mediaObject->i_total_time = totalTime;
357 emit p_vlc_mediaObject->totalTimeChanged(p_vlc_mediaObject->i_total_time);
361 if (p_event->type == libvlc_MediaMetaChanged) {
365 void VLCMediaObject::updateMetaData()
367 QMultiMap<QString, QString> metaDataMap;
369 metaDataMap.insert(QLatin1String("ARTIST"),
370 QString::fromUtf8(libvlc_media_get_meta(p_vlc_media, libvlc_meta_Artist)));
371 vlcExceptionRaised();
372 metaDataMap.insert(QLatin1String("ALBUM"),
373 QString::fromUtf8(libvlc_media_get_meta(p_vlc_media, libvlc_meta_Album)));
374 vlcExceptionRaised();
375 metaDataMap.insert(QLatin1String("TITLE"),
376 QString::fromUtf8(libvlc_media_get_meta(p_vlc_media, libvlc_meta_Title)));
377 vlcExceptionRaised();
378 metaDataMap.insert(QLatin1String("DATE"),
379 QString::fromUtf8(libvlc_media_get_meta(p_vlc_media, libvlc_meta_Date)));
380 vlcExceptionRaised();
381 metaDataMap.insert(QLatin1String("GENRE"),
382 QString::fromUtf8(libvlc_media_get_meta(p_vlc_media, libvlc_meta_Genre)));
383 vlcExceptionRaised();
384 metaDataMap.insert(QLatin1String("TRACKNUMBER"),
385 QString::fromUtf8(libvlc_media_get_meta(p_vlc_media, libvlc_meta_TrackNumber)));
386 vlcExceptionRaised();
387 metaDataMap.insert(QLatin1String("DESCRIPTION"),
388 QString::fromUtf8(libvlc_media_get_meta(p_vlc_media, libvlc_meta_Description)));
389 vlcExceptionRaised();
390 metaDataMap.insert(QLatin1String("COPYRIGHT"),
391 QString::fromUtf8(libvlc_media_get_meta(p_vlc_media, libvlc_meta_TrackNumber)));
392 vlcExceptionRaised();
393 metaDataMap.insert(QLatin1String("URL"),
394 QString::fromUtf8(libvlc_media_get_meta(p_vlc_media, libvlc_meta_URL)));
395 vlcExceptionRaised();
396 metaDataMap.insert(QLatin1String("ENCODEDBY"),
397 QString::fromUtf8(libvlc_media_get_meta(p_vlc_media, libvlc_meta_EncodedBy)));
399 qDebug() << "updateMetaData(): artist:"
400 << libvlc_media_get_meta(p_vlc_media, libvlc_meta_Artist);
401 vlcExceptionRaised();
402 qDebug() << "updateMetaData(): title:"
403 << libvlc_media_get_meta(p_vlc_media, libvlc_meta_Title);
404 vlcExceptionRaised();
406 emit metaDataChanged(metaDataMap);
409 qint64 VLCMediaObject::totalTime() const
414 qint64 VLCMediaObject::currentTimeInternal() const
416 libvlc_time_t time = libvlc_media_player_get_time(p_vlc_media_player, vlc_exception);
417 vlcExceptionRaised();
423 } // Namespace Phonon::VLC