1 /*
2 * vlcmediawidget.cpp
3 *
4 * Copyright (C) 2010-2012 Christoph Pfister <christophpfister@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21 #include "../log.h"
22
23 #include <QApplication>
24 #include <QCursor>
25 #include <QMouseEvent>
26 #include <QTimer>
27 #include <QMap>
28 #include <vlc/libvlc_version.h>
29
30 #include "../configuration.h"
31 #include "vlcmediawidget.h"
32
vlcEventName(int event)33 const char *vlcEventName(int event)
34 {
35 switch (event) {
36 case libvlc_MediaMetaChanged:
37 return "MediaMetaChanged";
38 case libvlc_MediaPlayerEncounteredError:
39 return "MediaPlayerEncounteredError";
40 case libvlc_MediaPlayerEndReached:
41 return "MediaPlayerEndReached";
42 case libvlc_MediaPlayerLengthChanged:
43 return "MediaPlayerLengthChanged";
44 case libvlc_MediaPlayerSeekableChanged:
45 return "MediaPlayerSeekableChanged";
46 case libvlc_MediaPlayerStopped:
47 return "MediaPlayerStopped";
48 case libvlc_MediaPlayerTimeChanged:
49 return "MediaPlayerTimeChanged";
50 case libvlc_MediaSubItemAdded:
51 return "MediaSubItemAdded";
52 case libvlc_MediaDurationChanged:
53 return "MediaDurationChanged";
54 case libvlc_MediaParsedChanged:
55 return "MediaParsedChanged";
56 case libvlc_MediaFreed:
57 return "MediaFreed";
58 case libvlc_MediaStateChanged:
59 return "MediaStateChanged";
60 case libvlc_MediaSubItemTreeAdded:
61 return "MediaSubItemTreeAdded";
62 case libvlc_MediaPlayerMediaChanged:
63 return "MediaPlayerMediaChanged";
64 case libvlc_MediaPlayerNothingSpecial:
65 return "MediaPlayerNothingSpecial";
66 case libvlc_MediaPlayerOpening:
67 return "MediaPlayerOpening";
68 case libvlc_MediaPlayerBuffering:
69 return "MediaPlayerBuffering";
70 case libvlc_MediaPlayerPlaying:
71 return "MediaPlayerPlaying";
72 case libvlc_MediaPlayerPaused:
73 return "MediaPlayerPaused";
74 case libvlc_MediaPlayerForward:
75 return "MediaPlayerForward";
76 case libvlc_MediaPlayerBackward:
77 return "MediaPlayerBackward";
78 case libvlc_MediaPlayerPositionChanged:
79 return "MediaPlayerPositionChanged";
80 case libvlc_MediaPlayerPausableChanged:
81 return "MediaPlayerPausableChanged";
82 case libvlc_MediaPlayerTitleChanged:
83 return "MediaPlayerTitleChanged";
84 case libvlc_MediaPlayerSnapshotTaken:
85 return "MediaPlayerSnapshotTaken";
86 case libvlc_MediaPlayerVout:
87 return "MediaPlayerVout";
88 case libvlc_MediaPlayerScrambledChanged:
89 return "MediaPlayerScrambledChanged";
90 case libvlc_MediaPlayerUncorked:
91 return "MediaPlayerUncorked";
92 case libvlc_MediaPlayerMuted:
93 return "MediaPlayerMuted";
94 case libvlc_MediaListItemAdded:
95 return "MediaListItemAdded";
96 case libvlc_MediaListWillAddItem:
97 return "MediaListWillAddItem";
98 case libvlc_MediaListItemDeleted:
99 return "MediaListItemDeleted";
100 case libvlc_MediaListWillDeleteItem:
101 return "MediaListWillDeleteItem";
102 case libvlc_MediaListViewItemAdded:
103 return "MediaListViewItemAdded";
104 case libvlc_MediaListViewWillAddItem:
105 return "MediaListViewWillAddItem";
106 case libvlc_MediaListViewItemDeleted:
107 return "MediaListViewItemDeleted";
108 case libvlc_MediaListViewWillDeleteItem:
109 return "MediaListViewWillDeleteItem";
110 case libvlc_MediaListPlayerPlayed:
111 return "MediaListPlayerPlayed";
112 case libvlc_MediaListPlayerNextItemSet:
113 return "MediaListPlayerNextItemSet";
114 case libvlc_MediaListPlayerStopped:
115 return "MediaListPlayerStopped";
116 case libvlc_VlmMediaAdded:
117 return "VlmMediaAdded";
118 case libvlc_VlmMediaRemoved:
119 return "VlmMediaRemoved";
120 case libvlc_VlmMediaChanged:
121 return "VlmMediaChanged";
122 case libvlc_VlmMediaInstanceStarted:
123 return "VlmMediaInstanceStarted";
124 case libvlc_VlmMediaInstanceStopped:
125 return "VlmMediaInstanceStopped";
126 case libvlc_VlmMediaInstanceStatusInit:
127 return "VlmMediaInstanceStatusInit";
128 case libvlc_VlmMediaInstanceStatusOpening:
129 return "VlmMediaInstanceStatusOpening";
130 case libvlc_VlmMediaInstanceStatusPlaying:
131 return "VlmMediaInstanceStatusPlaying";
132 case libvlc_VlmMediaInstanceStatusPause:
133 return "VlmMediaInstanceStatusPause";
134 case libvlc_VlmMediaInstanceStatusEnd:
135 return "VlmMediaInstanceStatusEnd";
136 case libvlc_VlmMediaInstanceStatusError:
137 return "VlmMediaInstanceStatusError";
138 #if LIBVLC_VERSION_MAJOR > 2
139 case libvlc_RendererDiscovererItemAdded:
140 return "RendererDiscovererItemAdded";
141 case libvlc_RendererDiscovererItemDeleted:
142 return "RendererDiscovererItemDeleted";
143 case libvlc_MediaPlayerAudioVolume:
144 return "MediaPlayerAudioVolume";
145 case libvlc_MediaPlayerAudioDevice:
146 return "MediaPlayerAudioDevice";
147 case libvlc_MediaListEndReached:
148 return "MediaListEndReached";
149 case libvlc_MediaPlayerChapterChanged:
150 return "MediaPlayerChapterChanged";
151 case libvlc_MediaPlayerESAdded:
152 return "MediaPlayerESAdded";
153 case libvlc_MediaPlayerESDeleted:
154 return "MediaPlayerESDeleted";
155 case libvlc_MediaPlayerESSelected:
156 return "MediaPlayerESSelected";
157 case libvlc_MediaPlayerCorked:
158 return "MediaPlayerCorked";
159 case libvlc_MediaPlayerUnmuted:
160 return "MediaPlayerUnmuted";
161 #endif
162
163 default:
164 return "Unknown";
165 }
166 }
167
VlcMediaWidget(QWidget * parent)168 VlcMediaWidget::VlcMediaWidget(QWidget *parent) : AbstractMediaWidget(parent),
169 timer(NULL), vlcInstance(NULL), vlcMedia(NULL), vlcMediaPlayer(NULL),
170 isPaused(false), playingDvd(false), urlIsAudioCd(false),
171 typeOfDevice(""), trackNumber(1), numTracks(1)
172 {
173 libvlc_event_e events[] = {
174 libvlc_MediaPlayerEncounteredError,
175 libvlc_MediaPlayerEndReached,
176 libvlc_MediaPlayerLengthChanged,
177 libvlc_MediaPlayerSeekableChanged,
178 libvlc_MediaPlayerStopped,
179 libvlc_MediaPlayerTimeChanged,
180 #if LIBVLC_VERSION_MAJOR > 2
181 libvlc_MediaMetaChanged,
182 libvlc_MediaPlayerESAdded,
183 libvlc_MediaPlayerESDeleted,
184 #endif
185 #if 0 // all other possible events
186 libvlc_MediaSubItemAdded,
187 libvlc_MediaDurationChanged,
188 libvlc_MediaParsedChanged,
189 libvlc_MediaFreed,
190 libvlc_MediaStateChanged,
191 libvlc_MediaSubItemTreeAdded,
192 libvlc_MediaPlayerMediaChanged,
193 libvlc_MediaPlayerNothingSpecial,
194 libvlc_MediaPlayerOpening,
195 libvlc_MediaPlayerBuffering,
196 libvlc_MediaPlayerPlaying,
197 libvlc_MediaPlayerPaused,
198 libvlc_MediaPlayerForward,
199 libvlc_MediaPlayerBackward,
200 libvlc_MediaPlayerPositionChanged,
201 libvlc_MediaPlayerPausableChanged,
202 libvlc_MediaPlayerTitleChanged,
203 libvlc_MediaPlayerSnapshotTaken,
204 libvlc_MediaPlayerVout,
205 libvlc_MediaPlayerScrambledChanged,
206 libvlc_MediaPlayerUncorked,
207 libvlc_MediaPlayerMuted,
208 libvlc_MediaListItemAdded,
209 libvlc_MediaListWillAddItem,
210 libvlc_MediaListItemDeleted,
211 libvlc_MediaListWillDeleteItem,
212 libvlc_MediaListViewItemAdded,
213 libvlc_MediaListViewWillAddItem,
214 libvlc_MediaListViewItemDeleted,
215 libvlc_MediaListViewWillDeleteItem,
216 libvlc_MediaListPlayerPlayed,
217 libvlc_MediaListPlayerNextItemSet,
218 libvlc_MediaListPlayerStopped,
219 libvlc_VlmMediaAdded,
220 libvlc_VlmMediaRemoved,
221 libvlc_VlmMediaChanged,
222 libvlc_VlmMediaInstanceStarted,
223 libvlc_VlmMediaInstanceStopped,
224 libvlc_VlmMediaInstanceStatusInit,
225 libvlc_VlmMediaInstanceStatusOpening,
226 libvlc_VlmMediaInstanceStatusPlaying,
227 libvlc_VlmMediaInstanceStatusPause,
228 libvlc_VlmMediaInstanceStatusEnd,
229 libvlc_VlmMediaInstanceStatusError,
230 #if LIBVLC_VERSION_MAJOR > 2
231 libvlc_MediaListEndReached,
232 libvlc_MediaPlayerAudioDevice,
233 libvlc_MediaPlayerAudioVolume,
234 libvlc_MediaPlayerChapterChanged,
235 libvlc_MediaPlayerESSelected,
236 libvlc_MediaPlayerCorked,
237 libvlc_MediaPlayerUnmuted,
238 libvlc_RendererDiscovererItemAdded,
239 libvlc_RendererDiscovererItemDeleted,
240 #endif /*LIBVLC_VERSION_MAJOR */
241 #endif
242 };
243
244 for (uint i = 0; i < (sizeof(events) / sizeof(events[0])); ++i)
245 eventType.append(events[i]);
246 }
247
init()248 bool VlcMediaWidget::init()
249 {
250 QString args = Configuration::instance()->getLibVlcArguments();
251 QStringList argList;
252 int argc = 0, size;
253
254 argList = args.split(' ', QString::SkipEmptyParts);
255 size = argList.size();
256
257 const char **argv = new const char *[size];
258 QVector<QByteArray> str(size);
259
260 for (int i = 0; i < size; i++) {
261 str[i] = argList.at(i).toUtf8();
262 argv[argc++] = str[i];
263 }
264
265 vlcInstance = libvlc_new(argc, argv);
266 if (!vlcInstance) {
267 qCWarning(logMediaWidget, "libVLC: failed to use extra args: %s", qPrintable(args));
268 argc = 0;
269 vlcInstance = libvlc_new(0, NULL);
270 if (vlcInstance)
271 qCInfo(logMediaWidget, "Using libVLC without arguments");
272 }
273
274 if (vlcInstance == NULL) {
275 qFatal("Cannot create vlc instance %s", qPrintable(libvlc_errmsg()));
276 delete[] argv;
277 return false;
278 }
279
280 if (argc) {
281 QString log = "Using libVLC with args:";
282 for (int i = 0; i < argc; i++)
283 log += ' ' + QLatin1String(argv[i]);
284
285 qCDebug(logVlc, "%s", qPrintable(log));
286 }
287 delete[] argv;
288
289 vlcMediaPlayer = libvlc_media_player_new(vlcInstance);
290
291 if (vlcMediaPlayer == NULL) {
292 qFatal("Cannot create vlc media player %s", qPrintable(libvlc_errmsg()));
293 return false;
294 }
295
296 eventManager = libvlc_media_player_event_manager(vlcMediaPlayer);
297
298 if (!registerEvents())
299 return false;
300
301 timer = new QTimer();
302 connect(timer, SIGNAL(timeout()), this, SLOT(hideMouse()));
303
304 libvlc_media_player_set_xwindow(vlcMediaPlayer, quint32(winId()));
305 setAttribute(Qt::WA_NativeWindow);
306
307 libvlc_audio_set_mute(vlcMediaPlayer, false);
308
309 // This is broken on qt5: the kernel/qwidget.cpp tries to repaint
310 // on a wrong place, causing this warning:
311 // QWidget::paintEngine: Should no longer be called
312 // setAttribute(Qt::WA_PaintOnScreen);
313 return true;
314 }
315
~VlcMediaWidget()316 VlcMediaWidget::~VlcMediaWidget()
317 {
318 metadata.clear();
319 audioStreams.clear();
320 subtitles.clear();
321 subtitleId.clear();
322
323 if (timer != NULL) {
324 timer->stop();
325 delete timer;
326 }
327
328 unregisterEvents();
329
330 if (vlcMedia != NULL)
331 libvlc_media_release(vlcMedia);
332
333 if (vlcInstance != NULL)
334 libvlc_release(vlcInstance);
335
336 if (vlcMediaPlayer != NULL)
337 libvlc_media_player_release(vlcMediaPlayer);
338 }
339
createVlcMediaWidget(QWidget * parent)340 VlcMediaWidget *VlcMediaWidget::createVlcMediaWidget(QWidget *parent)
341 {
342 QScopedPointer<VlcMediaWidget> vlcMediaWidget(new VlcMediaWidget(parent));
343
344 if (!vlcMediaWidget->init()) {
345 return NULL;
346 }
347
348 return vlcMediaWidget.take();
349 }
350
getAudioDevices()351 QStringList VlcMediaWidget::getAudioDevices()
352 {
353 libvlc_audio_output_device_t *vlcAudioOutput, *i;
354 QStringList audioDevices;
355
356 // Get audio device list
357 vlcAudioOutput = libvlc_audio_output_device_enum(vlcMediaPlayer);
358 if (!vlcAudioOutput)
359 return audioDevices;
360
361 for (i = vlcAudioOutput; i != NULL; i = i->p_next) {
362 QString device = QString::fromUtf8(i->psz_description);
363 audioDevices.append(device);
364 }
365 libvlc_audio_output_device_list_release(vlcAudioOutput);
366
367 return audioDevices;
368 }
369
setAudioDevice(QString device)370 void VlcMediaWidget::setAudioDevice(QString device)
371 {
372 libvlc_audio_output_device_t *vlcAudioOutput, *i;
373 vlcAudioOutput = libvlc_audio_output_device_enum(vlcMediaPlayer);
374
375 if (!vlcAudioOutput)
376 return;
377
378 for (i = vlcAudioOutput; i != NULL; i = i->p_next) {
379 if (device.compare(QString::fromUtf8(i->psz_description)))
380 continue;
381 qCDebug(logVlc, "Setting audio output to: %s", qPrintable(i->psz_device));
382
383 libvlc_audio_output_device_set(vlcMediaPlayer, NULL, i->psz_device);
384 }
385 libvlc_audio_output_device_list_release(vlcAudioOutput);
386 }
387
setMuted(bool muted)388 void VlcMediaWidget::setMuted(bool muted)
389 {
390 libvlc_audio_set_mute(vlcMediaPlayer, muted);
391 }
392
setVolume(int volume)393 void VlcMediaWidget::setVolume(int volume)
394 {
395 // 0 <= volume <= 200
396 if (libvlc_audio_set_volume(vlcMediaPlayer, volume) != 0) {
397 qCWarning(logMediaWidget, "cannot set volume %i", volume);
398 }
399 }
400
setAspectRatio(MediaWidget::AspectRatio aspectRatio)401 void VlcMediaWidget::setAspectRatio(MediaWidget::AspectRatio aspectRatio)
402 {
403 const char *vlcAspectRatio = "";
404
405 switch (aspectRatio) {
406 case MediaWidget::AspectRatioAuto:
407 break;
408 case MediaWidget::AspectRatio1_1:
409 vlcAspectRatio = "1:1";
410 break;
411 case MediaWidget::AspectRatio4_3:
412 vlcAspectRatio = "4:3";
413 break;
414 case MediaWidget::AspectRatio5_4:
415 vlcAspectRatio = "5:4";
416 break;
417 case MediaWidget::AspectRatio16_9:
418 vlcAspectRatio = "16:9";
419 break;
420 case MediaWidget::AspectRatio16_10:
421 vlcAspectRatio = "16:10";
422 break;
423 case MediaWidget::AspectRatio221_100:
424 vlcAspectRatio = "221:100";
425 break;
426 case MediaWidget::AspectRatio235_100:
427 vlcAspectRatio = "235:100";
428 break;
429 case MediaWidget::AspectRatio239_100:
430 vlcAspectRatio = "239:100";
431 break;
432 }
433
434 libvlc_video_set_aspect_ratio(vlcMediaPlayer, vlcAspectRatio);
435 }
436
resizeToVideo(float resizeFactor)437 void VlcMediaWidget::resizeToVideo(float resizeFactor)
438 {
439 qCDebug(logMediaWidget, "video resized to %.1f", resizeFactor);
440 libvlc_video_set_scale(vlcMediaPlayer, resizeFactor);
441 }
442
setDeinterlacing(MediaWidget::DeinterlaceMode deinterlacing)443 void VlcMediaWidget::setDeinterlacing(MediaWidget::DeinterlaceMode deinterlacing)
444 {
445 const char *vlcDeinterlaceMode;
446
447 switch (deinterlacing) {
448 case MediaWidget::DeinterlaceDiscard:
449 vlcDeinterlaceMode = "discard";
450 break;
451 case MediaWidget::DeinterlaceBob:
452 vlcDeinterlaceMode = "bob";
453 break;
454 case MediaWidget::DeinterlaceLinear:
455 vlcDeinterlaceMode = "linear";
456 break;
457 case MediaWidget::DeinterlaceYadif:
458 vlcDeinterlaceMode = "yadif";
459 break;
460 case MediaWidget::DeinterlaceYadif2x:
461 vlcDeinterlaceMode = "yadif2x";
462 break;
463 case MediaWidget::DeinterlacePhosphor:
464 vlcDeinterlaceMode = "phosphor";
465 break;
466 case MediaWidget::DeinterlaceX:
467 vlcDeinterlaceMode = "x";
468 break;
469 case MediaWidget::DeinterlaceMean:
470 vlcDeinterlaceMode = "mean";
471 break;
472 case MediaWidget::DeinterlaceBlend:
473 vlcDeinterlaceMode = "blend";
474 break;
475 case MediaWidget::DeinterlaceIvtc:
476 vlcDeinterlaceMode = "ivtc";
477 break;
478 case MediaWidget::DeinterlaceDisabled:
479 default:
480 vlcDeinterlaceMode = NULL;
481 }
482
483
484 libvlc_video_set_deinterlace(vlcMediaPlayer, vlcDeinterlaceMode);
485 }
486
play(const MediaSource & source)487 void VlcMediaWidget::play(const MediaSource &source)
488 {
489 addPendingUpdates(PlaybackStatus | DvdMenu);
490 QByteArray url = source.getUrl().toEncoded();
491 playingDvd = false;
492
493 trackNumber = 1;
494 urlIsAudioCd = false;
495
496 switch (source.getType()) {
497 case MediaSource::Url:
498 if (url.endsWith(".iso")) {
499 playingDvd = true;
500 }
501
502 break;
503 case MediaSource::AudioCd:
504 urlIsAudioCd = true;
505
506 if (url.size() >= 7) {
507 url.replace(0, 4, "cdda");
508 } else {
509 url = "cdda://";
510 }
511
512 break;
513 case MediaSource::VideoCd:
514 if (url.size() >= 7) {
515 url.replace(0, 4, "vcd");
516 } else {
517 url = "vcd://";
518 }
519
520 break;
521 case MediaSource::Dvd:
522 if (url.size() >= 7) {
523 url.replace(0, 4, "dvd");
524 } else {
525 url = "dvd://";
526 }
527
528 playingDvd = true;
529 break;
530 case MediaSource::Dvb:
531 break;
532 }
533
534 typeOfDevice = url.constData();
535
536 if (vlcMedia != NULL) {
537 libvlc_media_player_stop(vlcMediaPlayer);
538 libvlc_media_release(vlcMedia);
539 }
540
541 vlcMedia = libvlc_media_new_location(vlcInstance, typeOfDevice);
542 if (urlIsAudioCd)
543 libvlc_media_add_option(vlcMedia, "cdda-track=1");
544
545 if (makePlay() < 0) {
546 stop();
547 return;
548 }
549
550 setCursor(Qt::BlankCursor);
551 setCursor(Qt::ArrowCursor);
552 timer->start(1000);
553 setMouseTracking(true);
554 }
555
unregisterEvents()556 void VlcMediaWidget::unregisterEvents()
557 {
558 for (int i = 0; i < eventType.size(); ++i)
559 libvlc_event_detach(eventManager, eventType.at(i),
560 vlcEventHandler, this);
561 #if LIBVLC_VERSION_MAJOR <= 2
562 if (!vlcMedia)
563 return;
564 libvlc_event_manager_t *mediaEvent = libvlc_media_event_manager(vlcMedia);
565 libvlc_event_detach(mediaEvent, libvlc_MediaMetaChanged,
566 vlcEventHandler, this);
567 #endif
568 }
569
registerEvents()570 bool VlcMediaWidget::registerEvents()
571 {
572 for (int i = 0; i < eventType.size(); ++i) {
573 if (libvlc_event_attach(eventManager, eventType.at(i), vlcEventHandler, this) != 0) {
574 qCCritical(logMediaWidget, "Cannot attach event handler %d", eventType.at(i));
575 return false;
576 }
577 }
578 return true;
579 }
580
makePlay()581 int VlcMediaWidget::makePlay()
582 {
583 if (vlcMedia == NULL) {
584 libvlc_media_player_stop(vlcMediaPlayer);
585 return -1;
586 }
587
588 #if LIBVLC_VERSION_MAJOR <= 2
589 /*
590 * There is a difference between libVlc 2.x and 3.x:
591 * With version 2.x, the event needs to be registered at the
592 * vlcMedia object, just before calling libvlc_media_player_set_media()
593 *
594 * On version 3.x, while this still works, you can simply register the
595 * event directly at vlcMediaPlayer, together with all other events,
596 * with simplifies the code.
597 */
598 libvlc_event_manager_t *mediaEvent = libvlc_media_event_manager(vlcMedia);
599
600 if (libvlc_event_attach(mediaEvent, libvlc_MediaMetaChanged,
601 vlcEventHandler, this) != 0) {
602 qCWarning(logMediaWidget, "Cannot attach event handler %d",
603 libvlc_MediaMetaChanged);
604 }
605 #endif
606
607 libvlc_media_player_set_media(vlcMediaPlayer, vlcMedia);
608
609 /*
610 * FIXME: This is mostly a boilerplate as, at least with vlc 3,
611 * this function always return -1
612 */
613 if (urlIsAudioCd)
614 numTracks = libvlc_audio_get_track_count(vlcMediaPlayer);
615
616 return libvlc_media_player_play(vlcMediaPlayer);
617 }
618
playDirection(int direction)619 void VlcMediaWidget::playDirection(int direction)
620 {
621 QString strBuf = "cdda-track=";
622 libvlc_state_t state;
623 int oldTrackNumber = trackNumber;
624
625 if (direction == -1)
626 trackNumber--;
627 else
628 trackNumber++;
629
630 if (numTracks > 0 && trackNumber > numTracks)
631 trackNumber = numTracks;
632 if (trackNumber < 1)
633 trackNumber = 1;
634
635 strBuf += QString::number(trackNumber);
636
637 if (vlcMedia != NULL) {
638 libvlc_media_player_stop(vlcMediaPlayer);
639 libvlc_media_release(vlcMedia);
640 }
641
642 vlcMedia = libvlc_media_new_location(vlcInstance, typeOfDevice);
643 libvlc_media_add_option(vlcMedia, strBuf.toUtf8());
644
645 if (makePlay() < 0)
646 stop();
647
648 do {
649 state = libvlc_media_player_get_state (vlcMediaPlayer);
650 } while(state != libvlc_Playing &&
651 state != libvlc_Error &&
652 state != libvlc_Ended );
653
654 if (state != libvlc_Playing) {
655 stop();
656 trackNumber = oldTrackNumber;
657 }
658 }
659
stop()660 void VlcMediaWidget::stop()
661 {
662 libvlc_media_player_stop(vlcMediaPlayer);
663
664 if (vlcMedia != NULL) {
665 libvlc_media_release(vlcMedia);
666 vlcMedia = NULL;
667 }
668
669 timer->stop();
670 setCursor(Qt::BlankCursor);
671 setCursor(Qt::ArrowCursor);
672 addPendingUpdates(PlaybackStatus | Metadata |
673 Subtitles | AudioStreams);
674 }
675
setPaused(bool paused)676 void VlcMediaWidget::setPaused(bool paused)
677 {
678 isPaused = paused;
679 libvlc_media_player_set_pause(vlcMediaPlayer, paused);
680 // we don't monitor playing / buffering / paused state changes
681 addPendingUpdates(PlaybackStatus);
682 }
683
seek(int time)684 void VlcMediaWidget::seek(int time)
685 {
686 if (!seekable)
687 return;
688
689 libvlc_media_player_set_time(vlcMediaPlayer, time);
690 }
691
setCurrentAudioStream(int _currentAudioStream)692 void VlcMediaWidget::setCurrentAudioStream(int _currentAudioStream)
693 {
694 if (_currentAudioStream < 0 ||
695 _currentAudioStream > libvlc_audio_get_track(vlcMediaPlayer))
696 _currentAudioStream = 0;
697 // skip the 'deactivate' audio channel
698 libvlc_audio_set_track(vlcMediaPlayer, _currentAudioStream + 1);
699
700 currentAudioStream = _currentAudioStream;
701 }
702
setCurrentSubtitle(int currentSubtitle)703 void VlcMediaWidget::setCurrentSubtitle(int currentSubtitle)
704 {
705 libvlc_track_description_t *tr, *track;
706 int requestedSubtitle = -1;
707
708 QMap<int, int>::const_iterator i = subtitleId.constBegin();
709 while (i != subtitleId.constEnd()) {
710 qCDebug(logVlc, "Subtitle #%d, key: %d", i.value(), i.key());
711 if (i.value() == currentSubtitle) {
712 requestedSubtitle = i.key();
713 break;
714 }
715 i++;
716 }
717
718 qCDebug(logVlc, "Try to set subtitle #%d, id %d", currentSubtitle, requestedSubtitle);
719 libvlc_video_set_spu(vlcMediaPlayer, requestedSubtitle);
720
721 /* Print what it was actually selected */
722
723 tr = libvlc_video_get_spu_description(vlcMediaPlayer);
724 track = tr;
725 while (track != NULL) {
726 QString subtitle = QString::fromUtf8(track->psz_name);
727
728 if (subtitle.isEmpty()) {
729 subtitle = i18n("Subtitle %1", track->i_id);
730 }
731
732 if (track->i_id == requestedSubtitle)
733 qCDebug(logVlc, "Subtitle set to id %d: %s", track->i_id, qPrintable(subtitle));
734 track = track->p_next;
735 }
736 libvlc_track_description_list_release(tr);
737
738 }
739
setExternalSubtitle(const QUrl & url)740 void VlcMediaWidget::setExternalSubtitle(const QUrl &url)
741 {
742 QString fname = url.toLocalFile();
743
744 #if LIBVLC_VERSION_MAJOR > 2
745 if (libvlc_media_player_add_slave(vlcMediaPlayer,
746 libvlc_media_slave_type_subtitle,
747 url.toEncoded().constData(),
748 true) == 0)
749 qCWarning(logMediaWidget, "Cannot set subtitle file %s", qPrintable(fname));
750 #else
751 if (libvlc_video_set_subtitle_file(vlcMediaPlayer,
752 fname.toLocal8Bit().constData()) == 0)
753 qCWarning(logMediaWidget, "Cannot set subtitle file %s", qPrintable(fname));
754 #endif
755 }
756
setCurrentTitle(int currentTitle)757 void VlcMediaWidget::setCurrentTitle(int currentTitle)
758 {
759 libvlc_media_player_set_title(vlcMediaPlayer, currentTitle);
760 }
761
setCurrentChapter(int currentChapter)762 void VlcMediaWidget::setCurrentChapter(int currentChapter)
763 {
764 libvlc_media_player_set_chapter(vlcMediaPlayer, currentChapter);
765 }
766
setCurrentAngle(int currentAngle)767 void VlcMediaWidget::setCurrentAngle(int currentAngle)
768 {
769 Q_UNUSED(currentAngle)
770 // FIXME
771 }
772
jumpToPreviousChapter()773 bool VlcMediaWidget::jumpToPreviousChapter()
774 {
775 int currentTitle = libvlc_media_player_get_title(vlcMediaPlayer);
776 int currentChapter = libvlc_media_player_get_chapter(vlcMediaPlayer);
777 if (urlIsAudioCd)
778 playDirection(-1);
779 else
780 libvlc_media_player_previous_chapter(vlcMediaPlayer);
781
782 if ((libvlc_media_player_get_title(vlcMediaPlayer) != currentTitle) ||
783 (libvlc_media_player_get_chapter(vlcMediaPlayer) != currentChapter)) {
784 return true;
785 }
786
787 return false;
788 }
789
jumpToNextChapter()790 bool VlcMediaWidget::jumpToNextChapter()
791 {
792 int currentTitle = libvlc_media_player_get_title(vlcMediaPlayer);
793 int currentChapter = libvlc_media_player_get_chapter(vlcMediaPlayer);
794 if (urlIsAudioCd)
795 playDirection(1);
796 else
797 libvlc_media_player_next_chapter(vlcMediaPlayer);
798
799 if ((libvlc_media_player_get_title(vlcMediaPlayer) != currentTitle) ||
800 (libvlc_media_player_get_chapter(vlcMediaPlayer) != currentChapter)) {
801 return true;
802 }
803
804 return false;
805 }
806
showDvdMenu()807 void VlcMediaWidget::showDvdMenu()
808 {
809 if (playingDvd) {
810 libvlc_media_player_set_title(vlcMediaPlayer, 0);
811 }
812 }
813
updatePlaybackStatus()814 int VlcMediaWidget::updatePlaybackStatus()
815 {
816 MediaWidget::PlaybackStatus oldPlaybackStatus = playbackStatus;
817
818 switch (libvlc_media_player_get_state(vlcMediaPlayer)) {
819 case libvlc_NothingSpecial:
820 case libvlc_Stopped:
821 playbackStatus = MediaWidget::Idle;
822 break;
823 case libvlc_Opening:
824 case libvlc_Buffering:
825 playbackStatus = MediaWidget::Playing;
826 break;
827 case libvlc_Playing:
828 // The first time libVLC is set to pause, it reports status as playing
829 if (isPaused)
830 playbackStatus = MediaWidget::Paused;
831 else
832 playbackStatus = MediaWidget::Playing;
833 break;
834 case libvlc_Paused:
835 playbackStatus = MediaWidget::Paused;
836 break;
837 case libvlc_Ended:
838 playDirection(1);
839 break;
840 case libvlc_Error:
841 playbackStatus = MediaWidget::Idle;
842 // don't keep last picture shown
843 libvlc_media_player_stop(vlcMediaPlayer);
844 break;
845 }
846
847 if (playbackStatus == MediaWidget::Idle) {
848 addPendingUpdates(DvdMenu);
849 playingDvd = false;
850 }
851
852 // Report if the status has changed
853 return (oldPlaybackStatus != playbackStatus);
854 }
855
updateCurrentTotalTime()856 void VlcMediaWidget::updateCurrentTotalTime()
857 {
858 if (playbackStatus == MediaWidget::Idle)
859 return;
860
861 currentTime = int(libvlc_media_player_get_time(vlcMediaPlayer));
862 totalTime = int(libvlc_media_player_get_length(vlcMediaPlayer));
863
864 if (currentTime < 0) {
865 currentTime = 0;
866 }
867
868 if (totalTime < 0) {
869 totalTime = 0;
870 }
871
872 if (totalTime && currentTime > totalTime) {
873 currentTime = totalTime;
874 }
875 }
876
updateSeekable()877 void VlcMediaWidget::updateSeekable()
878 {
879 seekable = libvlc_media_player_is_seekable(vlcMediaPlayer);
880 }
881
updateMetadata()882 void VlcMediaWidget::updateMetadata()
883 {
884 char *meta;
885
886 metadata.clear();
887 if (vlcMedia != NULL) {
888 QString s;
889 meta = libvlc_media_get_meta(vlcMedia, libvlc_meta_Title);
890 if (meta) {
891 metadata.insert(MediaWidget::Title, QString::fromUtf8(meta));
892 free(meta);
893 }
894 meta = libvlc_media_get_meta(vlcMedia, libvlc_meta_Artist);
895 if (meta) {
896 metadata.insert(MediaWidget::Artist, QString::fromUtf8(meta));
897 free(meta);
898 }
899 meta = libvlc_media_get_meta(vlcMedia, libvlc_meta_Album);
900 if (meta) {
901 metadata.insert(MediaWidget::Album, QString::fromUtf8(meta));
902 free(meta);
903 }
904 meta = libvlc_media_get_meta(vlcMedia, libvlc_meta_TrackNumber);
905 if (meta) {
906 metadata.insert(MediaWidget::TrackNumber, QString::fromUtf8(meta));
907 free(meta);
908 }
909 }
910
911 if (urlIsAudioCd)
912 metadata.insert(MediaWidget::Title,
913 i18n("CD track ") + QString::number(trackNumber));
914 }
915
updateAudioStreams()916 void VlcMediaWidget::updateAudioStreams()
917 {
918 audioStreams.clear();
919 libvlc_track_description_t *tr, *track;
920
921 tr = libvlc_audio_get_track_description(vlcMediaPlayer);
922 track = tr;
923
924 if (track != NULL) {
925 // skip the 'deactivate' audio channel
926 track = track->p_next;
927 }
928
929 while (track != NULL) {
930 QString audioStream = QString::fromUtf8(track->psz_name);
931 int cutBegin = (audioStream.indexOf(QLatin1Char('[')) + 1);
932
933 if (cutBegin > 0) {
934 int cutEnd = audioStream.lastIndexOf(QLatin1Char(']'));
935
936 if (cutEnd >= 0) {
937 // remove unnecessary text
938 audioStream = audioStream.mid(cutBegin, cutEnd - cutBegin);
939 }
940 }
941
942 if (audioStream.isEmpty()) {
943 audioStream = QString::number(audioStreams.size() + 1);
944 }
945
946 audioStreams.append(audioStream);
947 track = track->p_next;
948 }
949 libvlc_track_description_list_release(tr);
950
951 // skip the 'deactivate' audio channel
952 currentAudioStream = (libvlc_audio_get_track(vlcMediaPlayer) - 1);
953 if (currentAudioStream < 0)
954 setCurrentAudioStream(0);
955 }
956
updateSubtitles()957 void VlcMediaWidget::updateSubtitles()
958 {
959 libvlc_track_description_t *tr, *track;
960 int i = 0;
961
962 subtitles.clear();
963 subtitleId.clear();
964
965 tr = libvlc_video_get_spu_description(vlcMediaPlayer);
966 track = tr;
967
968 if (track != NULL) {
969 // skip the 'deactivate' subtitle
970 track = track->p_next;
971 }
972
973 while (track != NULL) {
974 QString subtitle = QString::fromUtf8(track->psz_name);
975
976 if (subtitle.isEmpty()) {
977 subtitle = i18n("Subtitle %1", track->i_id);
978 }
979
980 // 0 is reserved for "disabled" at mediawidget. So, we should
981 // Start counting from 1, to match the range expected for
982 // currentSubtitle
983 subtitleId[track->i_id] = ++i;
984 subtitles.append(subtitle);
985 qCDebug(logVlc, "Got subtitle id#%d: %s", track->i_id, qPrintable(subtitle));
986 track = track->p_next;
987 }
988 libvlc_track_description_list_release(tr);
989
990 // skip the 'deactivate' subtitle
991 currentSubtitle = subtitleId.value(libvlc_video_get_spu(vlcMediaPlayer), -1);
992 }
993
updateTitles()994 void VlcMediaWidget::updateTitles()
995 {
996 titleCount = libvlc_media_player_get_title_count(vlcMediaPlayer);
997 currentTitle = libvlc_media_player_get_title(vlcMediaPlayer);
998 }
999
updateChapters()1000 void VlcMediaWidget::updateChapters()
1001 {
1002 chapterCount = libvlc_media_player_get_chapter_count(vlcMediaPlayer);
1003 currentChapter = libvlc_media_player_get_chapter(vlcMediaPlayer);
1004 }
1005
updateAngles()1006 void VlcMediaWidget::updateAngles()
1007 {
1008 // FIXME
1009 }
1010
updateDvdMenu()1011 void VlcMediaWidget::updateDvdMenu()
1012 {
1013 dvdMenu = playingDvd;
1014 }
1015
updateVideoSize()1016 void VlcMediaWidget::updateVideoSize()
1017 {
1018 // FIXME
1019 }
1020
dvdNavigate(int key)1021 void VlcMediaWidget::dvdNavigate(int key)
1022 {
1023 int event;
1024
1025 switch (key){
1026 case Qt::Key_Return:
1027 event = libvlc_navigate_activate;
1028 break;
1029 case Qt::Key_Up:
1030 event = libvlc_navigate_up;
1031 break;
1032 case Qt::Key_Down:
1033 event = libvlc_navigate_down;
1034 break;
1035 case Qt::Key_Left:
1036 event = libvlc_navigate_left;
1037 break;
1038 case Qt::Key_Right:
1039 event = libvlc_navigate_right;
1040 break;
1041 default:
1042 return;
1043 }
1044 libvlc_media_player_navigate(vlcMediaPlayer, event);
1045 }
1046
mousePressEvent(QMouseEvent * event)1047 void VlcMediaWidget::mousePressEvent(QMouseEvent *event)
1048 {
1049 AbstractMediaWidget::mousePressEvent(event);
1050 }
1051
hideMouse()1052 void VlcMediaWidget::hideMouse()
1053 {
1054 timer->stop();
1055
1056 setCursor(Qt::ArrowCursor);
1057 setCursor(Qt::BlankCursor);
1058 }
1059
mouseMoveEvent(QMouseEvent * event)1060 void VlcMediaWidget::mouseMoveEvent(QMouseEvent *event)
1061 {
1062 if (!timer->isActive()) {
1063 setCursor(Qt::BlankCursor);
1064 setCursor(Qt::ArrowCursor);
1065 }
1066 if (this->underMouse())
1067 timer->start(1000);
1068 else
1069 timer->stop();
1070
1071 AbstractMediaWidget::mouseMoveEvent(event);
1072 }
1073
vlcEvent(const libvlc_event_t * event)1074 void VlcMediaWidget::vlcEvent(const libvlc_event_t *event)
1075 {
1076 PendingUpdates pendingUpdatesToBeAdded = 0;
1077
1078 switch (event->type) {
1079 #if LIBVLC_VERSION_MAJOR > 2
1080 case libvlc_MediaPlayerESAdded:
1081 case libvlc_MediaPlayerESDeleted:
1082 #endif
1083 case libvlc_MediaMetaChanged:
1084 pendingUpdatesToBeAdded = Metadata | Subtitles | AudioStreams;
1085 break;
1086 case libvlc_MediaPlayerEncounteredError:
1087 pendingUpdatesToBeAdded = PlaybackStatus;
1088 break;
1089 case libvlc_MediaPlayerEndReached:
1090 pendingUpdatesToBeAdded = (PlaybackFinished | PlaybackStatus);
1091 break;
1092 case libvlc_MediaPlayerLengthChanged:
1093 pendingUpdatesToBeAdded = CurrentTotalTime;
1094 break;
1095 case libvlc_MediaPlayerSeekableChanged:
1096 pendingUpdatesToBeAdded = Seekable | Subtitles;
1097 break;
1098 case libvlc_MediaPlayerStopped:
1099 pendingUpdatesToBeAdded = PlaybackStatus;
1100 setMouseTracking(false);
1101 break;
1102 case libvlc_MediaPlayerTimeChanged:
1103 pendingUpdatesToBeAdded = CurrentTotalTime;
1104 break;
1105 }
1106
1107 if (pendingUpdatesToBeAdded != 0) {
1108 addPendingUpdates(pendingUpdatesToBeAdded);
1109 } else {
1110 qCWarning(logMediaWidget, "Unhandled event %s (%d)",
1111 vlcEventName(event->type), event->type);
1112 }
1113 }
1114
vlcEventHandler(const libvlc_event_t * event,void * instance)1115 void VlcMediaWidget::vlcEventHandler(const libvlc_event_t *event, void *instance)
1116 {
1117 reinterpret_cast<VlcMediaWidget *>(instance)->vlcEvent(event);
1118 }
1119