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, vlc_exception); // 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, vlc_exception);
89 // No need to keep the media now
90 // libvlc_media_release(p_vlc_media);
92 // connectToAllVLCEvents() at the end since it needs p_vlc_media_player
93 connectToAllVLCEvents();
95 b_play_request_reached = false;
97 // Get meta data (artist, title, etc...)
100 // Update available audio channels/subtitles/angles/chapters/etc...
101 // i.e everything from MediaController
102 // There is no audio channel/subtitle/angle/chapter events inside libvlc
103 // so let's send our own events...
104 // This will reset the GUI
105 clearMediaController();
107 // We need to do this, otherwise we never get any events with the real length
108 libvlc_media_get_duration(p_vlc_media, vlc_exception);
110 if (b_play_request_reached) {
111 // The media is playing, no need to load it
115 emit stateChanged(Phonon::StoppedState);
118 void VLCMediaObject::setVLCWidgetId()
120 // Get our media player to use our window
121 #if defined(Q_OS_UNIX)
122 libvlc_media_player_set_xwindow(p_vlc_media_player, i_video_widget_id, vlc_exception);
123 #elif defined(Q_OS_WIN)
124 libvlc_media_player_set_hwnd(p_vlc_media_player, i_video_widget_id, vlc_exception);
125 #elif defined(Q_OS_MAC)
126 libvlc_media_player_set_agl(p_vlc_media_player, i_video_widget_id, vlc_exception);
128 vlcExceptionRaised();
131 void VLCMediaObject::playInternal()
133 b_play_request_reached = true;
135 // Clear subtitles/chapters/etc...
136 clearMediaController();
138 vlc_current_media_player = p_vlc_media_player;
143 libvlc_media_player_play(p_vlc_media_player, vlc_exception);
144 vlcExceptionRaised();
147 void VLCMediaObject::pause()
149 libvlc_media_player_pause(p_vlc_media_player, vlc_exception);
150 vlcExceptionRaised();
153 void VLCMediaObject::stop()
155 libvlc_media_player_stop(p_vlc_media_player, vlc_exception);
156 vlcExceptionRaised();
160 void VLCMediaObject::seekInternal(qint64 milliseconds)
162 qDebug() << __FUNCTION__ << milliseconds;
163 libvlc_media_player_set_time(p_vlc_media_player, milliseconds, vlc_exception);
164 vlcExceptionRaised();
167 QString VLCMediaObject::errorString() const
169 return libvlc_errmsg();
172 bool VLCMediaObject::hasVideo() const
177 bool VLCMediaObject::isSeekable() const
182 void VLCMediaObject::connectToAllVLCEvents()
184 // Get the event manager from which the media player send event
185 p_vlc_media_player_event_manager = libvlc_media_player_event_manager(p_vlc_media_player, vlc_exception);
186 libvlc_event_type_t eventsMediaPlayer[] = {
187 libvlc_MediaPlayerPlaying,
188 libvlc_MediaPlayerPaused,
189 libvlc_MediaPlayerEndReached,
190 libvlc_MediaPlayerStopped,
191 libvlc_MediaPlayerEncounteredError,
192 libvlc_MediaPlayerTimeChanged,
193 libvlc_MediaPlayerTitleChanged,
194 libvlc_MediaPlayerPositionChanged,
195 //libvlc_MediaPlayerSeekableChanged, //FIXME: doesn't work anymore? it asserts
196 libvlc_MediaPlayerPausableChanged,
198 int i_nbEvents = sizeof(eventsMediaPlayer) / sizeof(*eventsMediaPlayer);
199 for (int i = 0; i < i_nbEvents; i++) {
200 libvlc_event_attach(p_vlc_media_player_event_manager, eventsMediaPlayer[i],
201 libvlc_callback, this, vlc_exception);
202 vlcExceptionRaised();
206 // Get event manager from media descriptor object
207 p_vlc_media_event_manager = libvlc_media_event_manager(p_vlc_media);
208 libvlc_event_type_t eventsMedia[] = {
209 libvlc_MediaMetaChanged,
210 libvlc_MediaSubItemAdded,
211 libvlc_MediaDurationChanged,
212 // FIXME libvlc does not know this event
213 // libvlc_MediaPreparsedChanged,
215 libvlc_MediaStateChanged,
217 i_nbEvents = sizeof(eventsMedia) / sizeof(*eventsMedia);
218 for (int i = 0; i < i_nbEvents; i++) {
219 libvlc_event_attach(p_vlc_media_event_manager, eventsMedia[i], libvlc_callback, this, vlc_exception);
220 vlcExceptionRaised();
223 // Get event manager from media service discoverer object
224 // FIXME why libvlc_media_discoverer_event_manager() does not take a libvlc_exception_t ?
225 // p_vlc_media_discoverer_event_manager = libvlc_media_discoverer_event_manager(p_vlc_media_discoverer);
226 // libvlc_event_type_t eventsMediaDiscoverer[] = {
227 // libvlc_MediaDiscovererStarted,
228 // libvlc_MediaDiscovererEnded
230 // nbEvents = sizeof(eventsMediaDiscoverer) / sizeof(*eventsMediaDiscoverer);
231 // for (int i = 0; i < nbEvents; i++) {
232 // libvlc_event_attach(p_vlc_media_discoverer_event_manager, eventsMediaDiscoverer[i], libvlc_callback, this, vlc_exception);
236 void VLCMediaObject::libvlc_callback(const libvlc_event_t *p_event, void *p_user_data)
238 static int i_first_time_media_player_time_changed = 0;
239 static bool b_media_player_title_changed = false;
241 VLCMediaObject *p_vlc_mediaObject = (VLCMediaObject *) p_user_data;
243 // qDebug() << (int)pp_vlc_mediaObject << "event:" << libvlc_event_type_name(event->type);
245 // Media player events
246 if (p_event->type == libvlc_MediaPlayerTimeChanged) {
248 i_first_time_media_player_time_changed++;
250 // FIXME It is ugly. It should be solved by some events in libvlc
251 if (i_first_time_media_player_time_changed == 15) {
253 p_vlc_mediaObject->updateMetaData();
255 // Is this media player seekable
256 bool b_seekable = libvlc_media_player_is_seekable(p_vlc_mediaObject->p_vlc_media_player, vlc_exception);
257 vlcExceptionRaised();
258 if (b_seekable != p_vlc_mediaObject->b_seekable) {
259 qDebug() << "libvlc_callback(): isSeekable:" << b_seekable;
260 p_vlc_mediaObject->b_seekable = b_seekable;
261 emit p_vlc_mediaObject->seekableChanged(p_vlc_mediaObject->b_seekable);
264 // Get current video width
265 int i_width = libvlc_video_get_width(p_vlc_mediaObject->p_vlc_media_player, vlc_exception);
266 vlcExceptionRaised();
268 // Get current video height
269 int i_height = libvlc_video_get_height(p_vlc_mediaObject->p_vlc_media_player, vlc_exception);
270 vlcExceptionRaised();
271 emit p_vlc_mediaObject->videoWidgetSizeChanged(i_width, i_height);
273 // Does this media player have a video output
274 bool b_has_video = libvlc_media_player_has_vout(p_vlc_mediaObject->p_vlc_media_player, vlc_exception);
275 vlcExceptionRaised();
276 if (b_has_video != p_vlc_mediaObject->b_has_video) {
277 p_vlc_mediaObject->b_has_video = b_has_video;
278 emit p_vlc_mediaObject->hasVideoChanged(p_vlc_mediaObject->b_has_video);
282 // Give info about audio tracks
283 p_vlc_mediaObject->refreshAudioChannels();
284 // Give info about subtitle tracks
285 p_vlc_mediaObject->refreshSubtitles();
287 // Get movie chapter count
288 // It is not a title/chapter media if there is no chapter
289 if (libvlc_media_player_get_chapter_count(
290 p_vlc_mediaObject->p_vlc_media_player, vlc_exception) > 0) {
291 vlcExceptionRaised();
292 // Give info about title
293 // only first time, no when title changed
294 if (!b_media_player_title_changed) {
295 libvlc_track_description_t *p_info = libvlc_video_get_title_description(
296 p_vlc_mediaObject->p_vlc_media_player, vlc_exception);
297 vlcExceptionRaised();
299 p_vlc_mediaObject->titleAdded(p_info->i_id, p_info->psz_name);
300 p_info = p_info->p_next;
302 libvlc_track_description_release(p_info);
305 // Give info about chapters for actual title 0
306 if (b_media_player_title_changed)
307 p_vlc_mediaObject->refreshChapters(libvlc_media_player_get_title(
308 p_vlc_mediaObject->p_vlc_media_player, vlc_exception));
310 p_vlc_mediaObject->refreshChapters(0);
312 if (b_media_player_title_changed)
313 b_media_player_title_changed = false;
316 // Bugfix with Qt mediaplayer example
317 // Now we are in playing state
318 emit p_vlc_mediaObject->stateChanged(Phonon::PlayingState);
321 emit p_vlc_mediaObject->tickInternal(p_vlc_mediaObject->currentTime());
324 if (p_event->type == libvlc_MediaPlayerPlaying) {
325 if (p_vlc_mediaObject->state() != Phonon::LoadingState) {
326 // Bugfix with Qt mediaplayer example
327 emit p_vlc_mediaObject->stateChanged(Phonon::PlayingState);
331 if (p_event->type == libvlc_MediaPlayerPaused) {
332 emit p_vlc_mediaObject->stateChanged(Phonon::PausedState);
335 if (p_event->type == libvlc_MediaPlayerEndReached) {
336 i_first_time_media_player_time_changed = 0;
337 p_vlc_mediaObject->clearMediaController();
338 emit p_vlc_mediaObject->stateChanged(Phonon::StoppedState);
339 emit p_vlc_mediaObject->finished();
342 if (p_event->type == libvlc_MediaPlayerStopped) {
343 i_first_time_media_player_time_changed = 0;
344 p_vlc_mediaObject->clearMediaController();
345 emit p_vlc_mediaObject->stateChanged(Phonon::StoppedState);
348 if (p_event->type == libvlc_MediaPlayerTitleChanged) {
349 i_first_time_media_player_time_changed = 0;
350 b_media_player_title_changed = true;
355 if (p_event->type == libvlc_MediaDurationChanged) {
356 // Get duration of media descriptor object item
357 libvlc_time_t totalTime = libvlc_media_get_duration(p_vlc_mediaObject->p_vlc_media, vlc_exception);
358 vlcExceptionRaised();
360 if (totalTime != p_vlc_mediaObject->i_total_time) {
361 p_vlc_mediaObject->i_total_time = totalTime;
362 emit p_vlc_mediaObject->totalTimeChanged(p_vlc_mediaObject->i_total_time);
366 if (p_event->type == libvlc_MediaMetaChanged) {
370 void VLCMediaObject::updateMetaData()
372 QMultiMap<QString, QString> metaDataMap;
374 metaDataMap.insert(QLatin1String("ARTIST"),
375 QString::fromUtf8(libvlc_media_get_meta(p_vlc_media, libvlc_meta_Artist)));
376 vlcExceptionRaised();
377 metaDataMap.insert(QLatin1String("ALBUM"),
378 QString::fromUtf8(libvlc_media_get_meta(p_vlc_media, libvlc_meta_Album)));
379 vlcExceptionRaised();
380 metaDataMap.insert(QLatin1String("TITLE"),
381 QString::fromUtf8(libvlc_media_get_meta(p_vlc_media, libvlc_meta_Title)));
382 vlcExceptionRaised();
383 metaDataMap.insert(QLatin1String("DATE"),
384 QString::fromUtf8(libvlc_media_get_meta(p_vlc_media, libvlc_meta_Date)));
385 vlcExceptionRaised();
386 metaDataMap.insert(QLatin1String("GENRE"),
387 QString::fromUtf8(libvlc_media_get_meta(p_vlc_media, libvlc_meta_Genre)));
388 vlcExceptionRaised();
389 metaDataMap.insert(QLatin1String("TRACKNUMBER"),
390 QString::fromUtf8(libvlc_media_get_meta(p_vlc_media, libvlc_meta_TrackNumber)));
391 vlcExceptionRaised();
392 metaDataMap.insert(QLatin1String("DESCRIPTION"),
393 QString::fromUtf8(libvlc_media_get_meta(p_vlc_media, libvlc_meta_Description)));
394 vlcExceptionRaised();
395 metaDataMap.insert(QLatin1String("COPYRIGHT"),
396 QString::fromUtf8(libvlc_media_get_meta(p_vlc_media, libvlc_meta_TrackNumber)));
397 vlcExceptionRaised();
398 metaDataMap.insert(QLatin1String("URL"),
399 QString::fromUtf8(libvlc_media_get_meta(p_vlc_media, libvlc_meta_URL)));
400 vlcExceptionRaised();
401 metaDataMap.insert(QLatin1String("ENCODEDBY"),
402 QString::fromUtf8(libvlc_media_get_meta(p_vlc_media, libvlc_meta_EncodedBy)));
404 qDebug() << "updateMetaData(): artist:"
405 << libvlc_media_get_meta(p_vlc_media, libvlc_meta_Artist);
406 vlcExceptionRaised();
407 qDebug() << "updateMetaData(): title:"
408 << libvlc_media_get_meta(p_vlc_media, libvlc_meta_Title);
409 vlcExceptionRaised();
411 emit metaDataChanged(metaDataMap);
414 qint64 VLCMediaObject::totalTime() const
419 qint64 VLCMediaObject::currentTimeInternal() const
421 libvlc_time_t time = libvlc_media_player_get_time(p_vlc_media_player, vlc_exception);
422 vlcExceptionRaised();
428 } // Namespace Phonon::VLC