File indexing completed on 2024-04-28 04:21:28

0001 // SPDX-FileCopyrightText: 2021 Henner Zeller <h.zeller@acm.org>
0002 // SPDX-FileCopyrightText: 2021 Jesper K. Pedersen <blackie@kde.org>
0003 // SPDX-FileCopyrightText: 2021-2023 Johannes Zarl-Zierl <johannes@zarl-zierl.at>
0004 //
0005 // SPDX-License-Identifier: GPL-2.0-or-later
0006 
0007 #include "VLCDisplay.h"
0008 #include "Logging.h"
0009 #include "VideoToolBar.h"
0010 
0011 #include <DB/ImageInfo.h>
0012 
0013 #include <QDebug>
0014 #include <QGuiApplication>
0015 #include <QLabel>
0016 #include <QScreen>
0017 #include <QSlider>
0018 #include <QTimer>
0019 #include <QVBoxLayout>
0020 
0021 #include <vlc/libvlc_media_player.h>
0022 #include <vlc/libvlc_version.h>
0023 
0024 Viewer::VLCDisplay::VLCDisplay(QWidget *parent)
0025     : Viewer::VideoDisplay(parent)
0026 {
0027     QVBoxLayout *layout = new QVBoxLayout(this);
0028     m_videoWidget = new QWidget(this);
0029     layout->addWidget(m_videoWidget, 1);
0030 
0031     m_videoToolBar = new VideoToolBar;
0032     layout->addWidget(m_videoToolBar);
0033 
0034     m_poller = new QTimer(this);
0035 
0036     setupVLC();
0037 
0038     connect(m_poller, &QTimer::timeout, this, &Viewer::VLCDisplay::updateInterface);
0039     connect(m_videoToolBar, &VideoToolBar::positionChanged, this, &VLCDisplay::setPosition);
0040     connect(m_videoToolBar, &VideoToolBar::volumeChanged, this, &VLCDisplay::changeVolume);
0041     connect(m_videoToolBar, &VideoToolBar::muted, this, [this](bool b) {
0042         libvlc_audio_set_mute(m_player, b);
0043     });
0044 }
0045 
0046 Viewer::VLCDisplay::~VLCDisplay()
0047 {
0048     if (VLCDisplay::isPlaying()) {
0049         qCWarning(ViewerLog) << "VLCDisplay is deleted while video is still playing! Please file a bug with KPhotoAlbum!";
0050     }
0051     releaseVLC();
0052 }
0053 
0054 void Viewer::VLCDisplay::changeVolume(int newVolume)
0055 {
0056     libvlc_audio_set_volume(m_player, newVolume);
0057 }
0058 
0059 void Viewer::VLCDisplay::setPosition(int newPosition)
0060 {
0061     // It's possible that the vlc doesn't play anything
0062     // so check before
0063     libvlc_media_t *curMedia = libvlc_media_player_get_media(m_player);
0064     if (curMedia == nullptr)
0065         return;
0066 
0067     float pos = (float)(newPosition) / (float)m_videoToolBar->maximum();
0068 #if LIBVLC_VERSION_INT >= 0x04000000
0069     libvlc_media_player_set_position(m_player, pos, /*fastseek=*/true);
0070 #else
0071     libvlc_media_player_set_position(m_player, pos);
0072 #endif
0073 }
0074 
0075 void Viewer::VLCDisplay::playPause()
0076 {
0077     libvlc_media_player_set_pause(m_player, isPaused() ? 0 : 1);
0078 }
0079 
0080 void Viewer::VLCDisplay::updateInterface()
0081 {
0082     libvlc_media_t *curMedia = libvlc_media_player_get_media(m_player);
0083     if (!curMedia || libvlc_media_get_state(m_media) == libvlc_Ended) {
0084         m_poller->stop();
0085         Q_EMIT stopped();
0086         return;
0087     }
0088 
0089     const int currentPos
0090         = libvlc_media_player_get_position(m_player) * m_videoToolBar->maximum();
0091     const auto length = libvlc_media_player_get_length(m_player);
0092     m_videoToolBar->setRange(0, length);
0093     m_videoToolBar->setPosition(currentPos);
0094     m_videoToolBar->setVolume(libvlc_audio_get_volume(m_player));
0095     m_videoToolBar->setMuted(libvlc_audio_get_mute(m_player));
0096 }
0097 
0098 bool Viewer::VLCDisplay::setImageImpl(DB::ImageInfoPtr info, bool /*forward*/)
0099 {
0100     if (m_media) {
0101         libvlc_media_release(m_media);
0102     }
0103     m_media = libvlc_media_new_path(m_vlcInstance, info->fileName().absolute().toUtf8().data());
0104 
0105     libvlc_media_player_set_media(m_player, m_media);
0106 
0107     int windid = m_videoWidget->winId();
0108     libvlc_media_player_set_xwindow(m_player, windid);
0109 
0110     libvlc_media_player_play(m_player);
0111     m_poller->start(100);
0112 
0113     return true;
0114 }
0115 
0116 bool Viewer::VLCDisplay::isPaused() const
0117 {
0118     return libvlc_media_get_state(m_media) == libvlc_Paused;
0119 }
0120 
0121 void Viewer::VLCDisplay::stop()
0122 {
0123 #if LIBVLC_VERSION_INT >= 0x04000000
0124     libvlc_media_player_stop_async(m_player);
0125 #else
0126     libvlc_media_player_stop(m_player);
0127 #endif
0128     m_poller->stop();
0129 }
0130 
0131 void Viewer::VLCDisplay::rotate(const DB::ImageInfoPtr &info)
0132 {
0133     m_info = info;
0134     libvlc_time_t offset = 0;
0135     if (m_vlcInstance)
0136         offset = libvlc_media_player_get_time(m_player);
0137 
0138     releaseVLC();
0139     setupVLC();
0140 
0141     if (m_info)
0142         setImage(m_info, true);
0143 
0144     setPosition(offset);
0145 }
0146 
0147 void Viewer::VLCDisplay::releaseVLC()
0148 {
0149     if (!m_vlcInstance)
0150         return;
0151 
0152     stop();
0153     if (m_media) {
0154         libvlc_media_release(m_media);
0155         m_media = nullptr;
0156     }
0157     libvlc_media_player_release(m_player);
0158     libvlc_release(m_vlcInstance);
0159 }
0160 
0161 void Viewer::VLCDisplay::setupVLC()
0162 {
0163     if (m_info && !m_info->isNull() && m_info->angle() != 0) {
0164         constexpr int BUF_SIZE = 64;
0165         char buf[BUF_SIZE];
0166         snprintf(buf, BUF_SIZE, "--video-filter=transform{type=%d}", m_info->angle());
0167 
0168         const char *vlc_args[] = { "--verbose=2", // be much more verbose then normal for debugging purpose
0169                                    buf };
0170         m_vlcInstance = libvlc_new(sizeof(vlc_args) / sizeof(vlc_args[0]), vlc_args);
0171     } else
0172         m_vlcInstance = libvlc_new(0, {});
0173 
0174     m_player = libvlc_media_player_new(m_vlcInstance);
0175 }
0176 
0177 bool Viewer::VLCDisplay::isPlaying() const
0178 {
0179     return m_media && libvlc_media_get_state(m_media) == libvlc_Playing;
0180 }
0181 
0182 QImage Viewer::VLCDisplay::screenShoot()
0183 {
0184     return QGuiApplication::primaryScreen()->grabWindow(m_videoWidget->winId()).toImage();
0185 }
0186 
0187 void Viewer::VLCDisplay::relativeSeek(int msec)
0188 {
0189     setPosition(libvlc_media_player_get_time(m_player) + msec);
0190 }
0191 
0192 void Viewer::VLCDisplay::restart()
0193 {
0194     setImageImpl(m_info, true);
0195 }
0196 
0197 #include "moc_VLCDisplay.cpp"