File indexing completed on 2024-05-19 04:53:10
0001 /* 0002 * vlcmediawidget.cpp 0003 * 0004 * Copyright (C) 2010-2012 Christoph Pfister <christophpfister@gmail.com> 0005 * 0006 * This program is free software; you can redistribute it and/or modify 0007 * it under the terms of the GNU General Public License as published by 0008 * the Free Software Foundation; either version 2 of the License, or 0009 * (at your option) any later version. 0010 * 0011 * This program is distributed in the hope that it will be useful, 0012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0014 * GNU General Public License for more details. 0015 * 0016 * You should have received a copy of the GNU General Public License along 0017 * with this program; if not, write to the Free Software Foundation, Inc., 0018 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 0019 */ 0020 0021 #include "../log.h" 0022 0023 #include <QApplication> 0024 #include <QCursor> 0025 #include <QMouseEvent> 0026 #include <QTimer> 0027 #include <QMap> 0028 #include <vlc/libvlc_version.h> 0029 0030 #include "../configuration.h" 0031 #include "vlcmediawidget.h" 0032 0033 const char *vlcEventName(int event) 0034 { 0035 switch (event) { 0036 case libvlc_MediaMetaChanged: 0037 return "MediaMetaChanged"; 0038 case libvlc_MediaPlayerEncounteredError: 0039 return "MediaPlayerEncounteredError"; 0040 case libvlc_MediaPlayerEndReached: 0041 return "MediaPlayerEndReached"; 0042 case libvlc_MediaPlayerLengthChanged: 0043 return "MediaPlayerLengthChanged"; 0044 case libvlc_MediaPlayerSeekableChanged: 0045 return "MediaPlayerSeekableChanged"; 0046 case libvlc_MediaPlayerStopped: 0047 return "MediaPlayerStopped"; 0048 case libvlc_MediaPlayerTimeChanged: 0049 return "MediaPlayerTimeChanged"; 0050 case libvlc_MediaSubItemAdded: 0051 return "MediaSubItemAdded"; 0052 case libvlc_MediaDurationChanged: 0053 return "MediaDurationChanged"; 0054 case libvlc_MediaParsedChanged: 0055 return "MediaParsedChanged"; 0056 case libvlc_MediaFreed: 0057 return "MediaFreed"; 0058 case libvlc_MediaStateChanged: 0059 return "MediaStateChanged"; 0060 case libvlc_MediaSubItemTreeAdded: 0061 return "MediaSubItemTreeAdded"; 0062 case libvlc_MediaPlayerMediaChanged: 0063 return "MediaPlayerMediaChanged"; 0064 case libvlc_MediaPlayerNothingSpecial: 0065 return "MediaPlayerNothingSpecial"; 0066 case libvlc_MediaPlayerOpening: 0067 return "MediaPlayerOpening"; 0068 case libvlc_MediaPlayerBuffering: 0069 return "MediaPlayerBuffering"; 0070 case libvlc_MediaPlayerPlaying: 0071 return "MediaPlayerPlaying"; 0072 case libvlc_MediaPlayerPaused: 0073 return "MediaPlayerPaused"; 0074 case libvlc_MediaPlayerForward: 0075 return "MediaPlayerForward"; 0076 case libvlc_MediaPlayerBackward: 0077 return "MediaPlayerBackward"; 0078 case libvlc_MediaPlayerPositionChanged: 0079 return "MediaPlayerPositionChanged"; 0080 case libvlc_MediaPlayerPausableChanged: 0081 return "MediaPlayerPausableChanged"; 0082 case libvlc_MediaPlayerTitleChanged: 0083 return "MediaPlayerTitleChanged"; 0084 case libvlc_MediaPlayerSnapshotTaken: 0085 return "MediaPlayerSnapshotTaken"; 0086 case libvlc_MediaPlayerVout: 0087 return "MediaPlayerVout"; 0088 case libvlc_MediaPlayerScrambledChanged: 0089 return "MediaPlayerScrambledChanged"; 0090 case libvlc_MediaPlayerUncorked: 0091 return "MediaPlayerUncorked"; 0092 case libvlc_MediaPlayerMuted: 0093 return "MediaPlayerMuted"; 0094 case libvlc_MediaListItemAdded: 0095 return "MediaListItemAdded"; 0096 case libvlc_MediaListWillAddItem: 0097 return "MediaListWillAddItem"; 0098 case libvlc_MediaListItemDeleted: 0099 return "MediaListItemDeleted"; 0100 case libvlc_MediaListWillDeleteItem: 0101 return "MediaListWillDeleteItem"; 0102 case libvlc_MediaListViewItemAdded: 0103 return "MediaListViewItemAdded"; 0104 case libvlc_MediaListViewWillAddItem: 0105 return "MediaListViewWillAddItem"; 0106 case libvlc_MediaListViewItemDeleted: 0107 return "MediaListViewItemDeleted"; 0108 case libvlc_MediaListViewWillDeleteItem: 0109 return "MediaListViewWillDeleteItem"; 0110 case libvlc_MediaListPlayerPlayed: 0111 return "MediaListPlayerPlayed"; 0112 case libvlc_MediaListPlayerNextItemSet: 0113 return "MediaListPlayerNextItemSet"; 0114 case libvlc_MediaListPlayerStopped: 0115 return "MediaListPlayerStopped"; 0116 case libvlc_VlmMediaAdded: 0117 return "VlmMediaAdded"; 0118 case libvlc_VlmMediaRemoved: 0119 return "VlmMediaRemoved"; 0120 case libvlc_VlmMediaChanged: 0121 return "VlmMediaChanged"; 0122 case libvlc_VlmMediaInstanceStarted: 0123 return "VlmMediaInstanceStarted"; 0124 case libvlc_VlmMediaInstanceStopped: 0125 return "VlmMediaInstanceStopped"; 0126 case libvlc_VlmMediaInstanceStatusInit: 0127 return "VlmMediaInstanceStatusInit"; 0128 case libvlc_VlmMediaInstanceStatusOpening: 0129 return "VlmMediaInstanceStatusOpening"; 0130 case libvlc_VlmMediaInstanceStatusPlaying: 0131 return "VlmMediaInstanceStatusPlaying"; 0132 case libvlc_VlmMediaInstanceStatusPause: 0133 return "VlmMediaInstanceStatusPause"; 0134 case libvlc_VlmMediaInstanceStatusEnd: 0135 return "VlmMediaInstanceStatusEnd"; 0136 case libvlc_VlmMediaInstanceStatusError: 0137 return "VlmMediaInstanceStatusError"; 0138 #if LIBVLC_VERSION_MAJOR > 2 0139 case libvlc_RendererDiscovererItemAdded: 0140 return "RendererDiscovererItemAdded"; 0141 case libvlc_RendererDiscovererItemDeleted: 0142 return "RendererDiscovererItemDeleted"; 0143 case libvlc_MediaPlayerAudioVolume: 0144 return "MediaPlayerAudioVolume"; 0145 case libvlc_MediaPlayerAudioDevice: 0146 return "MediaPlayerAudioDevice"; 0147 case libvlc_MediaListEndReached: 0148 return "MediaListEndReached"; 0149 case libvlc_MediaPlayerChapterChanged: 0150 return "MediaPlayerChapterChanged"; 0151 case libvlc_MediaPlayerESAdded: 0152 return "MediaPlayerESAdded"; 0153 case libvlc_MediaPlayerESDeleted: 0154 return "MediaPlayerESDeleted"; 0155 case libvlc_MediaPlayerESSelected: 0156 return "MediaPlayerESSelected"; 0157 case libvlc_MediaPlayerCorked: 0158 return "MediaPlayerCorked"; 0159 case libvlc_MediaPlayerUnmuted: 0160 return "MediaPlayerUnmuted"; 0161 #endif 0162 0163 default: 0164 return "Unknown"; 0165 } 0166 } 0167 0168 VlcMediaWidget::VlcMediaWidget(QWidget *parent) : AbstractMediaWidget(parent), 0169 timer(NULL), vlcInstance(NULL), vlcMedia(NULL), vlcMediaPlayer(NULL), 0170 isPaused(false), playingDvd(false), urlIsAudioCd(false), 0171 typeOfDevice(""), trackNumber(1), numTracks(1) 0172 { 0173 libvlc_event_e events[] = { 0174 libvlc_MediaPlayerEncounteredError, 0175 libvlc_MediaPlayerEndReached, 0176 libvlc_MediaPlayerLengthChanged, 0177 libvlc_MediaPlayerSeekableChanged, 0178 libvlc_MediaPlayerStopped, 0179 libvlc_MediaPlayerTimeChanged, 0180 #if LIBVLC_VERSION_MAJOR > 2 0181 libvlc_MediaMetaChanged, 0182 libvlc_MediaPlayerESAdded, 0183 libvlc_MediaPlayerESDeleted, 0184 #endif 0185 #if 0 // all other possible events 0186 libvlc_MediaSubItemAdded, 0187 libvlc_MediaDurationChanged, 0188 libvlc_MediaParsedChanged, 0189 libvlc_MediaFreed, 0190 libvlc_MediaStateChanged, 0191 libvlc_MediaSubItemTreeAdded, 0192 libvlc_MediaPlayerMediaChanged, 0193 libvlc_MediaPlayerNothingSpecial, 0194 libvlc_MediaPlayerOpening, 0195 libvlc_MediaPlayerBuffering, 0196 libvlc_MediaPlayerPlaying, 0197 libvlc_MediaPlayerPaused, 0198 libvlc_MediaPlayerForward, 0199 libvlc_MediaPlayerBackward, 0200 libvlc_MediaPlayerPositionChanged, 0201 libvlc_MediaPlayerPausableChanged, 0202 libvlc_MediaPlayerTitleChanged, 0203 libvlc_MediaPlayerSnapshotTaken, 0204 libvlc_MediaPlayerVout, 0205 libvlc_MediaPlayerScrambledChanged, 0206 libvlc_MediaPlayerUncorked, 0207 libvlc_MediaPlayerMuted, 0208 libvlc_MediaListItemAdded, 0209 libvlc_MediaListWillAddItem, 0210 libvlc_MediaListItemDeleted, 0211 libvlc_MediaListWillDeleteItem, 0212 libvlc_MediaListViewItemAdded, 0213 libvlc_MediaListViewWillAddItem, 0214 libvlc_MediaListViewItemDeleted, 0215 libvlc_MediaListViewWillDeleteItem, 0216 libvlc_MediaListPlayerPlayed, 0217 libvlc_MediaListPlayerNextItemSet, 0218 libvlc_MediaListPlayerStopped, 0219 libvlc_VlmMediaAdded, 0220 libvlc_VlmMediaRemoved, 0221 libvlc_VlmMediaChanged, 0222 libvlc_VlmMediaInstanceStarted, 0223 libvlc_VlmMediaInstanceStopped, 0224 libvlc_VlmMediaInstanceStatusInit, 0225 libvlc_VlmMediaInstanceStatusOpening, 0226 libvlc_VlmMediaInstanceStatusPlaying, 0227 libvlc_VlmMediaInstanceStatusPause, 0228 libvlc_VlmMediaInstanceStatusEnd, 0229 libvlc_VlmMediaInstanceStatusError, 0230 #if LIBVLC_VERSION_MAJOR > 2 0231 libvlc_MediaListEndReached, 0232 libvlc_MediaPlayerAudioDevice, 0233 libvlc_MediaPlayerAudioVolume, 0234 libvlc_MediaPlayerChapterChanged, 0235 libvlc_MediaPlayerESSelected, 0236 libvlc_MediaPlayerCorked, 0237 libvlc_MediaPlayerUnmuted, 0238 libvlc_RendererDiscovererItemAdded, 0239 libvlc_RendererDiscovererItemDeleted, 0240 #endif /*LIBVLC_VERSION_MAJOR */ 0241 #endif 0242 }; 0243 0244 for (uint i = 0; i < (sizeof(events) / sizeof(events[0])); ++i) 0245 eventType.append(events[i]); 0246 } 0247 0248 bool VlcMediaWidget::init() 0249 { 0250 QString args = Configuration::instance()->getLibVlcArguments(); 0251 QStringList argList; 0252 int argc = 0, size; 0253 0254 #if QT_VERSION < 0x050e00 0255 argList = args.split(' ', QString::SkipEmptyParts); 0256 #else 0257 argList = args.split(' ', Qt::SkipEmptyParts); 0258 #endif 0259 size = argList.size(); 0260 0261 const char **argv = new const char *[size]; 0262 QVector<QByteArray> str(size); 0263 0264 for (int i = 0; i < size; i++) { 0265 str[i] = argList.at(i).toUtf8(); 0266 argv[argc++] = str[i]; 0267 } 0268 0269 vlcInstance = libvlc_new(argc, argv); 0270 if (!vlcInstance) { 0271 qCWarning(logMediaWidget, "libVLC: failed to use extra args: %s", qPrintable(args)); 0272 argc = 0; 0273 vlcInstance = libvlc_new(0, NULL); 0274 if (vlcInstance) 0275 qCInfo(logMediaWidget, "Using libVLC without arguments"); 0276 } 0277 0278 if (vlcInstance == NULL) { 0279 qFatal("Cannot create vlc instance %s", qPrintable(libvlc_errmsg())); 0280 delete[] argv; 0281 return false; 0282 } 0283 0284 if (argc) { 0285 QString log = "Using libVLC with args:"; 0286 for (int i = 0; i < argc; i++) 0287 log += ' ' + QLatin1String(argv[i]); 0288 0289 qCDebug(logVlc, "%s", qPrintable(log)); 0290 } 0291 delete[] argv; 0292 0293 vlcMediaPlayer = libvlc_media_player_new(vlcInstance); 0294 0295 if (vlcMediaPlayer == NULL) { 0296 qFatal("Cannot create vlc media player %s", qPrintable(libvlc_errmsg())); 0297 return false; 0298 } 0299 0300 eventManager = libvlc_media_player_event_manager(vlcMediaPlayer); 0301 0302 if (!registerEvents()) 0303 return false; 0304 0305 timer = new QTimer(); 0306 connect(timer, SIGNAL(timeout()), this, SLOT(hideMouse())); 0307 0308 libvlc_media_player_set_xwindow(vlcMediaPlayer, quint32(winId())); 0309 setAttribute(Qt::WA_NativeWindow); 0310 0311 libvlc_audio_set_mute(vlcMediaPlayer, false); 0312 0313 // This is broken on qt5: the kernel/qwidget.cpp tries to repaint 0314 // on a wrong place, causing this warning: 0315 // QWidget::paintEngine: Should no longer be called 0316 // setAttribute(Qt::WA_PaintOnScreen); 0317 return true; 0318 } 0319 0320 VlcMediaWidget::~VlcMediaWidget() 0321 { 0322 metadata.clear(); 0323 audioStreams.clear(); 0324 subtitles.clear(); 0325 subtitleId.clear(); 0326 0327 if (timer != NULL) { 0328 timer->stop(); 0329 delete timer; 0330 } 0331 0332 unregisterEvents(); 0333 0334 if (vlcMedia != NULL) 0335 libvlc_media_release(vlcMedia); 0336 0337 if (vlcInstance != NULL) 0338 libvlc_release(vlcInstance); 0339 0340 if (vlcMediaPlayer != NULL) 0341 libvlc_media_player_release(vlcMediaPlayer); 0342 } 0343 0344 VlcMediaWidget *VlcMediaWidget::createVlcMediaWidget(QWidget *parent) 0345 { 0346 QScopedPointer<VlcMediaWidget> vlcMediaWidget(new VlcMediaWidget(parent)); 0347 0348 if (!vlcMediaWidget->init()) { 0349 return NULL; 0350 } 0351 0352 return vlcMediaWidget.take(); 0353 } 0354 0355 QStringList VlcMediaWidget::getAudioDevices() 0356 { 0357 libvlc_audio_output_device_t *vlcAudioOutput, *i; 0358 QStringList audioDevices; 0359 0360 // Get audio device list 0361 vlcAudioOutput = libvlc_audio_output_device_enum(vlcMediaPlayer); 0362 if (!vlcAudioOutput) 0363 return audioDevices; 0364 0365 for (i = vlcAudioOutput; i != NULL; i = i->p_next) { 0366 QString device = QString::fromUtf8(i->psz_description); 0367 audioDevices.append(device); 0368 } 0369 libvlc_audio_output_device_list_release(vlcAudioOutput); 0370 0371 return audioDevices; 0372 } 0373 0374 void VlcMediaWidget::setAudioDevice(QString device) 0375 { 0376 libvlc_audio_output_device_t *vlcAudioOutput, *i; 0377 vlcAudioOutput = libvlc_audio_output_device_enum(vlcMediaPlayer); 0378 0379 if (!vlcAudioOutput) 0380 return; 0381 0382 for (i = vlcAudioOutput; i != NULL; i = i->p_next) { 0383 if (device.compare(QString::fromUtf8(i->psz_description))) 0384 continue; 0385 qCDebug(logVlc, "Setting audio output to: %s", qPrintable(i->psz_device)); 0386 0387 libvlc_audio_output_device_set(vlcMediaPlayer, NULL, i->psz_device); 0388 } 0389 libvlc_audio_output_device_list_release(vlcAudioOutput); 0390 } 0391 0392 void VlcMediaWidget::setMuted(bool muted) 0393 { 0394 libvlc_audio_set_mute(vlcMediaPlayer, muted); 0395 } 0396 0397 void VlcMediaWidget::setVolume(int volume) 0398 { 0399 // 0 <= volume <= 200 0400 if (libvlc_audio_set_volume(vlcMediaPlayer, volume) != 0) { 0401 qCWarning(logMediaWidget, "cannot set volume %i", volume); 0402 } 0403 } 0404 0405 void VlcMediaWidget::setAspectRatio(MediaWidget::AspectRatio aspectRatio) 0406 { 0407 const char *vlcAspectRatio = ""; 0408 0409 switch (aspectRatio) { 0410 case MediaWidget::AspectRatioAuto: 0411 break; 0412 case MediaWidget::AspectRatio1_1: 0413 vlcAspectRatio = "1:1"; 0414 break; 0415 case MediaWidget::AspectRatio4_3: 0416 vlcAspectRatio = "4:3"; 0417 break; 0418 case MediaWidget::AspectRatio5_4: 0419 vlcAspectRatio = "5:4"; 0420 break; 0421 case MediaWidget::AspectRatio16_9: 0422 vlcAspectRatio = "16:9"; 0423 break; 0424 case MediaWidget::AspectRatio16_10: 0425 vlcAspectRatio = "16:10"; 0426 break; 0427 case MediaWidget::AspectRatio221_100: 0428 vlcAspectRatio = "221:100"; 0429 break; 0430 case MediaWidget::AspectRatio235_100: 0431 vlcAspectRatio = "235:100"; 0432 break; 0433 case MediaWidget::AspectRatio239_100: 0434 vlcAspectRatio = "239:100"; 0435 break; 0436 } 0437 0438 libvlc_video_set_aspect_ratio(vlcMediaPlayer, vlcAspectRatio); 0439 } 0440 0441 void VlcMediaWidget::resizeToVideo(float resizeFactor) 0442 { 0443 qCDebug(logMediaWidget, "video resized to %.1f", resizeFactor); 0444 libvlc_video_set_scale(vlcMediaPlayer, resizeFactor); 0445 } 0446 0447 void VlcMediaWidget::setDeinterlacing(MediaWidget::DeinterlaceMode deinterlacing) 0448 { 0449 const char *vlcDeinterlaceMode; 0450 0451 switch (deinterlacing) { 0452 case MediaWidget::DeinterlaceDiscard: 0453 vlcDeinterlaceMode = "discard"; 0454 break; 0455 case MediaWidget::DeinterlaceBob: 0456 vlcDeinterlaceMode = "bob"; 0457 break; 0458 case MediaWidget::DeinterlaceLinear: 0459 vlcDeinterlaceMode = "linear"; 0460 break; 0461 case MediaWidget::DeinterlaceYadif: 0462 vlcDeinterlaceMode = "yadif"; 0463 break; 0464 case MediaWidget::DeinterlaceYadif2x: 0465 vlcDeinterlaceMode = "yadif2x"; 0466 break; 0467 case MediaWidget::DeinterlacePhosphor: 0468 vlcDeinterlaceMode = "phosphor"; 0469 break; 0470 case MediaWidget::DeinterlaceX: 0471 vlcDeinterlaceMode = "x"; 0472 break; 0473 case MediaWidget::DeinterlaceMean: 0474 vlcDeinterlaceMode = "mean"; 0475 break; 0476 case MediaWidget::DeinterlaceBlend: 0477 vlcDeinterlaceMode = "blend"; 0478 break; 0479 case MediaWidget::DeinterlaceIvtc: 0480 vlcDeinterlaceMode = "ivtc"; 0481 break; 0482 case MediaWidget::DeinterlaceDisabled: 0483 default: 0484 vlcDeinterlaceMode = NULL; 0485 } 0486 0487 0488 libvlc_video_set_deinterlace(vlcMediaPlayer, vlcDeinterlaceMode); 0489 } 0490 0491 void VlcMediaWidget::play(const MediaSource &source) 0492 { 0493 addPendingUpdates(PlaybackStatus | DvdMenu); 0494 QByteArray url = source.getUrl().toEncoded(); 0495 playingDvd = false; 0496 0497 trackNumber = 1; 0498 urlIsAudioCd = false; 0499 0500 switch (source.getType()) { 0501 case MediaSource::Url: 0502 if (url.endsWith(".iso")) { 0503 playingDvd = true; 0504 } 0505 0506 break; 0507 case MediaSource::AudioCd: 0508 urlIsAudioCd = true; 0509 0510 if (url.size() >= 7) { 0511 url.replace(0, 4, "cdda"); 0512 } else { 0513 url = "cdda://"; 0514 } 0515 0516 break; 0517 case MediaSource::VideoCd: 0518 if (url.size() >= 7) { 0519 url.replace(0, 4, "vcd"); 0520 } else { 0521 url = "vcd://"; 0522 } 0523 0524 break; 0525 case MediaSource::Dvd: 0526 if (url.size() >= 7) { 0527 url.replace(0, 4, "dvd"); 0528 } else { 0529 url = "dvd://"; 0530 } 0531 0532 playingDvd = true; 0533 break; 0534 case MediaSource::Dvb: 0535 break; 0536 } 0537 0538 typeOfDevice = url.constData(); 0539 0540 if (vlcMedia != NULL) { 0541 libvlc_media_player_stop(vlcMediaPlayer); 0542 libvlc_media_release(vlcMedia); 0543 } 0544 0545 vlcMedia = libvlc_media_new_location(vlcInstance, typeOfDevice); 0546 if (urlIsAudioCd) 0547 libvlc_media_add_option(vlcMedia, "cdda-track=1"); 0548 0549 if (makePlay() < 0) { 0550 stop(); 0551 return; 0552 } 0553 0554 setCursor(Qt::BlankCursor); 0555 setCursor(Qt::ArrowCursor); 0556 timer->start(1000); 0557 setMouseTracking(true); 0558 } 0559 0560 void VlcMediaWidget::unregisterEvents() 0561 { 0562 for (int i = 0; i < eventType.size(); ++i) 0563 libvlc_event_detach(eventManager, eventType.at(i), 0564 vlcEventHandler, this); 0565 #if LIBVLC_VERSION_MAJOR <= 2 0566 if (!vlcMedia) 0567 return; 0568 libvlc_event_manager_t *mediaEvent = libvlc_media_event_manager(vlcMedia); 0569 libvlc_event_detach(mediaEvent, libvlc_MediaMetaChanged, 0570 vlcEventHandler, this); 0571 #endif 0572 } 0573 0574 bool VlcMediaWidget::registerEvents() 0575 { 0576 for (int i = 0; i < eventType.size(); ++i) { 0577 if (libvlc_event_attach(eventManager, eventType.at(i), vlcEventHandler, this) != 0) { 0578 qCCritical(logMediaWidget, "Cannot attach event handler %d", eventType.at(i)); 0579 return false; 0580 } 0581 } 0582 return true; 0583 } 0584 0585 int VlcMediaWidget::makePlay() 0586 { 0587 if (vlcMedia == NULL) { 0588 libvlc_media_player_stop(vlcMediaPlayer); 0589 return -1; 0590 } 0591 0592 #if LIBVLC_VERSION_MAJOR <= 2 0593 /* 0594 * There is a difference between libVlc 2.x and 3.x: 0595 * With version 2.x, the event needs to be registered at the 0596 * vlcMedia object, just before calling libvlc_media_player_set_media() 0597 * 0598 * On version 3.x, while this still works, you can simply register the 0599 * event directly at vlcMediaPlayer, together with all other events, 0600 * with simplifies the code. 0601 */ 0602 libvlc_event_manager_t *mediaEvent = libvlc_media_event_manager(vlcMedia); 0603 0604 if (libvlc_event_attach(mediaEvent, libvlc_MediaMetaChanged, 0605 vlcEventHandler, this) != 0) { 0606 qCWarning(logMediaWidget, "Cannot attach event handler %d", 0607 libvlc_MediaMetaChanged); 0608 } 0609 #endif 0610 0611 libvlc_media_player_set_media(vlcMediaPlayer, vlcMedia); 0612 0613 /* 0614 * FIXME: This is mostly a boilerplate as, at least with vlc 3, 0615 * this function always return -1 0616 */ 0617 if (urlIsAudioCd) 0618 numTracks = libvlc_audio_get_track_count(vlcMediaPlayer); 0619 0620 return libvlc_media_player_play(vlcMediaPlayer); 0621 } 0622 0623 void VlcMediaWidget::playDirection(int direction) 0624 { 0625 QString strBuf = "cdda-track="; 0626 libvlc_state_t state; 0627 int oldTrackNumber = trackNumber; 0628 0629 if (direction == -1) 0630 trackNumber--; 0631 else 0632 trackNumber++; 0633 0634 if (numTracks > 0 && trackNumber > numTracks) 0635 trackNumber = numTracks; 0636 if (trackNumber < 1) 0637 trackNumber = 1; 0638 0639 strBuf += QString::number(trackNumber); 0640 0641 if (vlcMedia != NULL) { 0642 libvlc_media_player_stop(vlcMediaPlayer); 0643 libvlc_media_release(vlcMedia); 0644 } 0645 0646 vlcMedia = libvlc_media_new_location(vlcInstance, typeOfDevice); 0647 libvlc_media_add_option(vlcMedia, strBuf.toUtf8()); 0648 0649 if (makePlay() < 0) 0650 stop(); 0651 0652 do { 0653 state = libvlc_media_player_get_state (vlcMediaPlayer); 0654 } while(state != libvlc_Playing && 0655 state != libvlc_Error && 0656 state != libvlc_Ended ); 0657 0658 if (state != libvlc_Playing) { 0659 stop(); 0660 trackNumber = oldTrackNumber; 0661 } 0662 } 0663 0664 void VlcMediaWidget::stop() 0665 { 0666 libvlc_media_player_stop(vlcMediaPlayer); 0667 0668 if (vlcMedia != NULL) { 0669 libvlc_media_release(vlcMedia); 0670 vlcMedia = NULL; 0671 } 0672 0673 timer->stop(); 0674 setCursor(Qt::BlankCursor); 0675 setCursor(Qt::ArrowCursor); 0676 addPendingUpdates(PlaybackStatus | Metadata | 0677 Subtitles | AudioStreams); 0678 } 0679 0680 void VlcMediaWidget::setPaused(bool paused) 0681 { 0682 isPaused = paused; 0683 libvlc_media_player_set_pause(vlcMediaPlayer, paused); 0684 // we don't monitor playing / buffering / paused state changes 0685 addPendingUpdates(PlaybackStatus); 0686 } 0687 0688 void VlcMediaWidget::seek(int time) 0689 { 0690 if (!seekable) 0691 return; 0692 0693 libvlc_media_player_set_time(vlcMediaPlayer, time); 0694 } 0695 0696 void VlcMediaWidget::setCurrentAudioStream(int _currentAudioStream) 0697 { 0698 if (_currentAudioStream < 0 || 0699 _currentAudioStream > libvlc_audio_get_track(vlcMediaPlayer)) 0700 _currentAudioStream = 0; 0701 // skip the 'deactivate' audio channel 0702 libvlc_audio_set_track(vlcMediaPlayer, _currentAudioStream + 1); 0703 0704 currentAudioStream = _currentAudioStream; 0705 } 0706 0707 void VlcMediaWidget::setCurrentSubtitle(int currentSubtitle) 0708 { 0709 libvlc_track_description_t *tr, *track; 0710 int requestedSubtitle = -1; 0711 0712 QMap<int, int>::const_iterator i = subtitleId.constBegin(); 0713 while (i != subtitleId.constEnd()) { 0714 qCDebug(logVlc, "Subtitle #%d, key: %d", i.value(), i.key()); 0715 if (i.value() == currentSubtitle) { 0716 requestedSubtitle = i.key(); 0717 break; 0718 } 0719 i++; 0720 } 0721 0722 qCDebug(logVlc, "Try to set subtitle #%d, id %d", currentSubtitle, requestedSubtitle); 0723 libvlc_video_set_spu(vlcMediaPlayer, requestedSubtitle); 0724 0725 /* Print what it was actually selected */ 0726 0727 tr = libvlc_video_get_spu_description(vlcMediaPlayer); 0728 track = tr; 0729 while (track != NULL) { 0730 QString subtitle = QString::fromUtf8(track->psz_name); 0731 0732 if (subtitle.isEmpty()) { 0733 subtitle = i18n("Subtitle %1", track->i_id); 0734 } 0735 0736 if (track->i_id == requestedSubtitle) 0737 qCDebug(logVlc, "Subtitle set to id %d: %s", track->i_id, qPrintable(subtitle)); 0738 track = track->p_next; 0739 } 0740 libvlc_track_description_list_release(tr); 0741 0742 } 0743 0744 void VlcMediaWidget::setExternalSubtitle(const QUrl &url) 0745 { 0746 QString fname = url.toLocalFile(); 0747 0748 #if LIBVLC_VERSION_MAJOR > 2 0749 if (libvlc_media_player_add_slave(vlcMediaPlayer, 0750 libvlc_media_slave_type_subtitle, 0751 url.toEncoded().constData(), 0752 true) == 0) 0753 qCWarning(logMediaWidget, "Cannot set subtitle file %s", qPrintable(fname)); 0754 #else 0755 if (libvlc_video_set_subtitle_file(vlcMediaPlayer, 0756 fname.toLocal8Bit().constData()) == 0) 0757 qCWarning(logMediaWidget, "Cannot set subtitle file %s", qPrintable(fname)); 0758 #endif 0759 } 0760 0761 void VlcMediaWidget::setCurrentTitle(int currentTitle) 0762 { 0763 libvlc_media_player_set_title(vlcMediaPlayer, currentTitle); 0764 } 0765 0766 void VlcMediaWidget::setCurrentChapter(int currentChapter) 0767 { 0768 libvlc_media_player_set_chapter(vlcMediaPlayer, currentChapter); 0769 } 0770 0771 void VlcMediaWidget::setCurrentAngle(int currentAngle) 0772 { 0773 Q_UNUSED(currentAngle) 0774 // FIXME 0775 } 0776 0777 bool VlcMediaWidget::jumpToPreviousChapter() 0778 { 0779 int currentTitle = libvlc_media_player_get_title(vlcMediaPlayer); 0780 int currentChapter = libvlc_media_player_get_chapter(vlcMediaPlayer); 0781 if (urlIsAudioCd) 0782 playDirection(-1); 0783 else 0784 libvlc_media_player_previous_chapter(vlcMediaPlayer); 0785 0786 if ((libvlc_media_player_get_title(vlcMediaPlayer) != currentTitle) || 0787 (libvlc_media_player_get_chapter(vlcMediaPlayer) != currentChapter)) { 0788 return true; 0789 } 0790 0791 return false; 0792 } 0793 0794 bool VlcMediaWidget::jumpToNextChapter() 0795 { 0796 int currentTitle = libvlc_media_player_get_title(vlcMediaPlayer); 0797 int currentChapter = libvlc_media_player_get_chapter(vlcMediaPlayer); 0798 if (urlIsAudioCd) 0799 playDirection(1); 0800 else 0801 libvlc_media_player_next_chapter(vlcMediaPlayer); 0802 0803 if ((libvlc_media_player_get_title(vlcMediaPlayer) != currentTitle) || 0804 (libvlc_media_player_get_chapter(vlcMediaPlayer) != currentChapter)) { 0805 return true; 0806 } 0807 0808 return false; 0809 } 0810 0811 void VlcMediaWidget::showDvdMenu() 0812 { 0813 if (playingDvd) { 0814 libvlc_media_player_set_title(vlcMediaPlayer, 0); 0815 } 0816 } 0817 0818 int VlcMediaWidget::updatePlaybackStatus() 0819 { 0820 MediaWidget::PlaybackStatus oldPlaybackStatus = playbackStatus; 0821 0822 switch (libvlc_media_player_get_state(vlcMediaPlayer)) { 0823 case libvlc_NothingSpecial: 0824 case libvlc_Stopped: 0825 playbackStatus = MediaWidget::Idle; 0826 break; 0827 case libvlc_Opening: 0828 case libvlc_Buffering: 0829 playbackStatus = MediaWidget::Playing; 0830 break; 0831 case libvlc_Playing: 0832 // The first time libVLC is set to pause, it reports status as playing 0833 if (isPaused) 0834 playbackStatus = MediaWidget::Paused; 0835 else 0836 playbackStatus = MediaWidget::Playing; 0837 break; 0838 case libvlc_Paused: 0839 playbackStatus = MediaWidget::Paused; 0840 break; 0841 case libvlc_Ended: 0842 playDirection(1); 0843 break; 0844 case libvlc_Error: 0845 playbackStatus = MediaWidget::Idle; 0846 // don't keep last picture shown 0847 libvlc_media_player_stop(vlcMediaPlayer); 0848 break; 0849 } 0850 0851 if (playbackStatus == MediaWidget::Idle) { 0852 addPendingUpdates(DvdMenu); 0853 playingDvd = false; 0854 } 0855 0856 // Report if the status has changed 0857 return (oldPlaybackStatus != playbackStatus); 0858 } 0859 0860 void VlcMediaWidget::updateCurrentTotalTime() 0861 { 0862 if (playbackStatus == MediaWidget::Idle) 0863 return; 0864 0865 currentTime = int(libvlc_media_player_get_time(vlcMediaPlayer)); 0866 totalTime = int(libvlc_media_player_get_length(vlcMediaPlayer)); 0867 0868 if (currentTime < 0) { 0869 currentTime = 0; 0870 } 0871 0872 if (totalTime < 0) { 0873 totalTime = 0; 0874 } 0875 0876 if (totalTime && currentTime > totalTime) { 0877 currentTime = totalTime; 0878 } 0879 } 0880 0881 void VlcMediaWidget::updateSeekable() 0882 { 0883 seekable = libvlc_media_player_is_seekable(vlcMediaPlayer); 0884 } 0885 0886 void VlcMediaWidget::updateMetadata() 0887 { 0888 char *meta; 0889 0890 metadata.clear(); 0891 if (vlcMedia != NULL) { 0892 QString s; 0893 meta = libvlc_media_get_meta(vlcMedia, libvlc_meta_Title); 0894 if (meta) { 0895 metadata.insert(MediaWidget::Title, QString::fromUtf8(meta)); 0896 free(meta); 0897 } 0898 meta = libvlc_media_get_meta(vlcMedia, libvlc_meta_Artist); 0899 if (meta) { 0900 metadata.insert(MediaWidget::Artist, QString::fromUtf8(meta)); 0901 free(meta); 0902 } 0903 meta = libvlc_media_get_meta(vlcMedia, libvlc_meta_Album); 0904 if (meta) { 0905 metadata.insert(MediaWidget::Album, QString::fromUtf8(meta)); 0906 free(meta); 0907 } 0908 meta = libvlc_media_get_meta(vlcMedia, libvlc_meta_TrackNumber); 0909 if (meta) { 0910 metadata.insert(MediaWidget::TrackNumber, QString::fromUtf8(meta)); 0911 free(meta); 0912 } 0913 } 0914 0915 if (urlIsAudioCd) 0916 metadata.insert(MediaWidget::Title, 0917 i18n("CD track %1", QString::number(trackNumber))); 0918 } 0919 0920 void VlcMediaWidget::updateAudioStreams() 0921 { 0922 audioStreams.clear(); 0923 libvlc_track_description_t *tr, *track; 0924 0925 tr = libvlc_audio_get_track_description(vlcMediaPlayer); 0926 track = tr; 0927 0928 if (track != NULL) { 0929 // skip the 'deactivate' audio channel 0930 track = track->p_next; 0931 } 0932 0933 while (track != NULL) { 0934 QString audioStream = QString::fromUtf8(track->psz_name); 0935 int cutBegin = (audioStream.indexOf(QLatin1Char('[')) + 1); 0936 0937 if (cutBegin > 0) { 0938 int cutEnd = audioStream.lastIndexOf(QLatin1Char(']')); 0939 0940 if (cutEnd >= 0) { 0941 // remove unnecessary text 0942 audioStream = audioStream.mid(cutBegin, cutEnd - cutBegin); 0943 } 0944 } 0945 0946 if (audioStream.isEmpty()) { 0947 audioStream = QString::number(audioStreams.size() + 1); 0948 } 0949 0950 audioStreams.append(audioStream); 0951 track = track->p_next; 0952 } 0953 libvlc_track_description_list_release(tr); 0954 0955 // skip the 'deactivate' audio channel 0956 currentAudioStream = (libvlc_audio_get_track(vlcMediaPlayer) - 1); 0957 if (currentAudioStream < 0) 0958 setCurrentAudioStream(0); 0959 } 0960 0961 void VlcMediaWidget::updateSubtitles() 0962 { 0963 libvlc_track_description_t *tr, *track; 0964 int i = 0; 0965 0966 subtitles.clear(); 0967 subtitleId.clear(); 0968 0969 tr = libvlc_video_get_spu_description(vlcMediaPlayer); 0970 track = tr; 0971 0972 if (track != NULL) { 0973 // skip the 'deactivate' subtitle 0974 track = track->p_next; 0975 } 0976 0977 while (track != NULL) { 0978 QString subtitle = QString::fromUtf8(track->psz_name); 0979 0980 if (subtitle.isEmpty()) { 0981 subtitle = i18n("Subtitle %1", track->i_id); 0982 } 0983 0984 // 0 is reserved for "disabled" at mediawidget. So, we should 0985 // Start counting from 1, to match the range expected for 0986 // currentSubtitle 0987 subtitleId[track->i_id] = ++i; 0988 subtitles.append(subtitle); 0989 qCDebug(logVlc, "Got subtitle id#%d: %s", track->i_id, qPrintable(subtitle)); 0990 track = track->p_next; 0991 } 0992 libvlc_track_description_list_release(tr); 0993 0994 // skip the 'deactivate' subtitle 0995 currentSubtitle = subtitleId.value(libvlc_video_get_spu(vlcMediaPlayer), -1); 0996 } 0997 0998 void VlcMediaWidget::updateTitles() 0999 { 1000 titleCount = libvlc_media_player_get_title_count(vlcMediaPlayer); 1001 currentTitle = libvlc_media_player_get_title(vlcMediaPlayer); 1002 } 1003 1004 void VlcMediaWidget::updateChapters() 1005 { 1006 chapterCount = libvlc_media_player_get_chapter_count(vlcMediaPlayer); 1007 currentChapter = libvlc_media_player_get_chapter(vlcMediaPlayer); 1008 } 1009 1010 void VlcMediaWidget::updateAngles() 1011 { 1012 // FIXME 1013 } 1014 1015 void VlcMediaWidget::updateDvdMenu() 1016 { 1017 dvdMenu = playingDvd; 1018 } 1019 1020 void VlcMediaWidget::updateVideoSize() 1021 { 1022 // FIXME 1023 } 1024 1025 void VlcMediaWidget::dvdNavigate(int key) 1026 { 1027 int event; 1028 1029 switch (key){ 1030 case Qt::Key_Return: 1031 event = libvlc_navigate_activate; 1032 break; 1033 case Qt::Key_Up: 1034 event = libvlc_navigate_up; 1035 break; 1036 case Qt::Key_Down: 1037 event = libvlc_navigate_down; 1038 break; 1039 case Qt::Key_Left: 1040 event = libvlc_navigate_left; 1041 break; 1042 case Qt::Key_Right: 1043 event = libvlc_navigate_right; 1044 break; 1045 default: 1046 return; 1047 } 1048 libvlc_media_player_navigate(vlcMediaPlayer, event); 1049 } 1050 1051 void VlcMediaWidget::mousePressEvent(QMouseEvent *event) 1052 { 1053 AbstractMediaWidget::mousePressEvent(event); 1054 } 1055 1056 void VlcMediaWidget::hideMouse() 1057 { 1058 timer->stop(); 1059 1060 setCursor(Qt::ArrowCursor); 1061 setCursor(Qt::BlankCursor); 1062 } 1063 1064 void VlcMediaWidget::mouseMoveEvent(QMouseEvent *event) 1065 { 1066 if (!timer->isActive()) { 1067 setCursor(Qt::BlankCursor); 1068 setCursor(Qt::ArrowCursor); 1069 } 1070 if (this->underMouse()) 1071 timer->start(1000); 1072 else 1073 timer->stop(); 1074 1075 AbstractMediaWidget::mouseMoveEvent(event); 1076 } 1077 1078 void VlcMediaWidget::vlcEvent(const libvlc_event_t *event) 1079 { 1080 PendingUpdates pendingUpdatesToBeAdded = Nothing; 1081 1082 switch (event->type) { 1083 #if LIBVLC_VERSION_MAJOR > 2 1084 case libvlc_MediaPlayerESAdded: 1085 case libvlc_MediaPlayerESDeleted: 1086 #endif 1087 case libvlc_MediaMetaChanged: 1088 pendingUpdatesToBeAdded = Metadata | Subtitles | AudioStreams; 1089 break; 1090 case libvlc_MediaPlayerEncounteredError: 1091 pendingUpdatesToBeAdded = PlaybackStatus; 1092 break; 1093 case libvlc_MediaPlayerEndReached: 1094 pendingUpdatesToBeAdded = (PlaybackFinished | PlaybackStatus); 1095 break; 1096 case libvlc_MediaPlayerLengthChanged: 1097 pendingUpdatesToBeAdded = CurrentTotalTime; 1098 break; 1099 case libvlc_MediaPlayerSeekableChanged: 1100 pendingUpdatesToBeAdded = Seekable | Subtitles; 1101 break; 1102 case libvlc_MediaPlayerStopped: 1103 pendingUpdatesToBeAdded = PlaybackStatus; 1104 setMouseTracking(false); 1105 break; 1106 case libvlc_MediaPlayerTimeChanged: 1107 pendingUpdatesToBeAdded = CurrentTotalTime; 1108 break; 1109 } 1110 1111 if (pendingUpdatesToBeAdded != 0) { 1112 addPendingUpdates(pendingUpdatesToBeAdded); 1113 } else { 1114 qCWarning(logMediaWidget, "Unhandled event %s (%d)", 1115 vlcEventName(event->type), event->type); 1116 } 1117 } 1118 1119 void VlcMediaWidget::vlcEventHandler(const libvlc_event_t *event, void *instance) 1120 { 1121 reinterpret_cast<VlcMediaWidget *>(instance)->vlcEvent(event); 1122 } 1123 1124 #include "moc_vlcmediawidget.cpp"