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

0001 // SPDX-FileCopyrightText: 2006-2010, 2012, 2021 Jesper K. Pedersen <blackie@kde.org>
0002 // SPDX-FileCopyrightText: 2007 Dirk Mueller <mueller@kde.org>
0003 // SPDX-FileCopyrightText: 2007 Thiago Macieira <thiago@kde.org>
0004 // SPDX-FileCopyrightText: 2007-2008 Laurent Montel <montel@kde.org>
0005 // SPDX-FileCopyrightText: 2008 Henner Zeller <h.zeller@acm.org>
0006 // SPDX-FileCopyrightText: 2009 Tuomas Suutari <tuomas@nepnep.net>
0007 // SPDX-FileCopyrightText: 2013 Dominik Broj <broj.dominik@gmail.com>
0008 // SPDX-FileCopyrightText: 2013 Miika Turkia <miika.turkia@gmail.com>
0009 // SPDX-FileCopyrightText: 2013, 2015-2016, 2019-2022 Johannes Zarl-Zierl <johannes@zarl-zierl.at>
0010 // SPDX-FileCopyrightText: 2018-2019 Tobias Leupold <tl at stonemx dot de>
0011 //
0012 // SPDX-License-Identifier: GPL-2.0-or-later
0013 
0014 #include "PhononDisplay.h"
0015 #include "Logging.h"
0016 
0017 #include <DB/ImageInfo.h>
0018 #include <DB/ImageInfoPtr.h>
0019 #include <MainWindow/FeatureDialog.h>
0020 
0021 #include "VideoToolBar.h"
0022 #include <KLocalizedString>
0023 #include <QAction>
0024 #include <QGuiApplication>
0025 #include <QResizeEvent>
0026 #include <QScreen>
0027 #include <QtMath>
0028 #include <kmessagebox.h>
0029 #include <ktoolbar.h>
0030 #include <kxmlguibuilder.h>
0031 #include <kxmlguiclient.h>
0032 #include <kxmlguifactory.h>
0033 #include <phonon/audiooutput.h>
0034 #include <phonon/mediaobject.h>
0035 #include <phonon/videowidget.h>
0036 #include <qglobal.h>
0037 #include <qlayout.h>
0038 
0039 namespace
0040 {
0041 constexpr qreal LOUDNESS_TO_VOLTAGE_EXPONENT = qreal(0.67);
0042 constexpr qreal VOLTAGE_TO_LOUDNESS_EXPONENT = qreal(1.0 / LOUDNESS_TO_VOLTAGE_EXPONENT);
0043 }
0044 
0045 Viewer::PhononDisplay::PhononDisplay(QWidget *parent)
0046     : Viewer::VideoDisplay(parent)
0047 {
0048     setBackgroundRole(QPalette::Shadow);
0049     setAutoFillBackground(true);
0050     setup();
0051 }
0052 
0053 void Viewer::PhononDisplay::setup()
0054 {
0055     m_mediaObject = new Phonon::MediaObject(this);
0056     m_audioDevice = new Phonon::AudioOutput(Phonon::VideoCategory, this);
0057     Phonon::createPath(m_mediaObject, m_audioDevice);
0058 
0059     m_videoWidget = new Phonon::VideoWidget(this);
0060     Phonon::createPath(m_mediaObject, m_videoWidget);
0061 
0062     m_videoToolBar = new VideoToolBar(this);
0063     m_videoToolBar->show();
0064     m_mediaObject->setTickInterval(100);
0065 
0066     m_videoWidget->setFocus();
0067     m_videoWidget->resize(1024, 768);
0068     m_videoWidget->move(0, 0);
0069     m_videoWidget->show();
0070 
0071     connect(m_mediaObject, &Phonon::MediaObject::finished, this, &PhononDisplay::stopped);
0072     connect(m_mediaObject, &Phonon::MediaObject::stateChanged, this, &PhononDisplay::phononStateChanged);
0073     connect(m_mediaObject, &Phonon::MediaObject::tick, m_videoToolBar, &VideoToolBar::setPosition);
0074     connect(m_videoToolBar, &VideoToolBar::positionChanged, m_mediaObject, &Phonon::MediaObject::seek);
0075     // use proxy slots to avoid a signal-loop between the VideoToolBar and the Phonon::AudioOutput
0076     connect(m_videoToolBar, &VideoToolBar::volumeChanged, this, &PhononDisplay::changeVolume);
0077     connect(m_audioDevice, &Phonon::AudioOutput::volumeChanged, this, &PhononDisplay::updateVolume);
0078     connect(m_videoToolBar, &VideoToolBar::muted, this, &PhononDisplay::setMuted);
0079     connect(m_audioDevice, &Phonon::AudioOutput::mutedChanged, this, &PhononDisplay::updateMuteState);
0080 }
0081 
0082 bool Viewer::PhononDisplay::setImageImpl(DB::ImageInfoPtr info, bool /*forward*/)
0083 {
0084     m_mediaObject->setCurrentSource(QUrl::fromLocalFile(info->fileName().absolute()));
0085     m_mediaObject->play();
0086 
0087     return true;
0088 }
0089 
0090 void Viewer::PhononDisplay::zoomIn()
0091 {
0092     resize(1.25);
0093 }
0094 
0095 void Viewer::PhononDisplay::zoomOut()
0096 {
0097     resize(0.8);
0098 }
0099 
0100 void Viewer::PhononDisplay::zoomFull()
0101 {
0102     m_zoomType = FullZoom;
0103     setVideoWidgetSize();
0104 }
0105 
0106 void Viewer::PhononDisplay::zoomPixelForPixel()
0107 {
0108     m_zoomType = PixelForPixelZoom;
0109     m_zoomFactor = 1;
0110     setVideoWidgetSize();
0111 }
0112 
0113 void Viewer::PhononDisplay::resize(double factor)
0114 {
0115     m_zoomType = FixedZoom;
0116     m_zoomFactor *= factor;
0117     setVideoWidgetSize();
0118 }
0119 
0120 void Viewer::PhononDisplay::resizeEvent(QResizeEvent *event)
0121 {
0122     AbstractDisplay::resizeEvent(event);
0123     setVideoWidgetSize();
0124 }
0125 
0126 Viewer::PhononDisplay::~PhononDisplay()
0127 {
0128     if (m_mediaObject)
0129         m_mediaObject->stop();
0130 }
0131 
0132 void Viewer::PhononDisplay::stop()
0133 {
0134     if (m_mediaObject)
0135         m_mediaObject->stop();
0136 }
0137 
0138 void Viewer::PhononDisplay::playPause()
0139 {
0140     if (!m_mediaObject)
0141         return;
0142 
0143     if (m_mediaObject->state() != Phonon::PlayingState)
0144         m_mediaObject->play();
0145     else
0146         m_mediaObject->pause();
0147 }
0148 
0149 QImage Viewer::PhononDisplay::screenShoot()
0150 {
0151     return QGuiApplication::primaryScreen()->grabWindow(m_videoWidget->winId()).toImage();
0152 }
0153 
0154 void Viewer::PhononDisplay::restart()
0155 {
0156     if (!m_mediaObject)
0157         return;
0158 
0159     m_mediaObject->seek(0);
0160     m_mediaObject->play();
0161 }
0162 
0163 bool Viewer::PhononDisplay::isPaused() const
0164 {
0165     if (!m_mediaObject)
0166         return false;
0167 
0168     return m_mediaObject->state() == Phonon::PausedState;
0169 }
0170 
0171 bool Viewer::PhononDisplay::isPlaying() const
0172 {
0173     if (!m_mediaObject)
0174         return false;
0175 
0176     return m_mediaObject->state() == Phonon::PlayingState;
0177 }
0178 
0179 void Viewer::PhononDisplay::phononStateChanged(Phonon::State newState, Phonon::State /*oldState*/)
0180 {
0181     setVideoWidgetSize();
0182     if (newState == Phonon::ErrorState) {
0183         KMessageBox::error(nullptr, m_mediaObject->errorString(), i18n("Error playing media"));
0184     }
0185 }
0186 
0187 void Viewer::PhononDisplay::updateVolume(qreal newVolumeVolt)
0188 {
0189     const QSignalBlocker blocker { m_videoToolBar };
0190     const auto volume = qPow(newVolumeVolt, VOLTAGE_TO_LOUDNESS_EXPONENT) * 100.0;
0191     m_videoToolBar->setVolume(volume);
0192     qCDebug(ViewerLog) << "Phonon volume is now at" << volume;
0193 }
0194 
0195 void Viewer::PhononDisplay::updateMuteState(bool mute)
0196 {
0197     const QSignalBlocker blocker { m_videoToolBar };
0198     m_videoToolBar->setMuted(mute);
0199     qCDebug(ViewerLog) << "Phonon mute state is now" << mute;
0200 }
0201 
0202 void Viewer::PhononDisplay::setVideoWidgetSize()
0203 {
0204     if (!m_mediaObject)
0205         return;
0206 
0207     QSize videoSize;
0208     if (m_zoomType == FullZoom) {
0209         videoSize = QSize(size().width(), size().height() - m_videoToolBar->height());
0210         if (m_videoWidget->sizeHint().width() > 0) {
0211             m_zoomFactor = videoSize.width() / m_videoWidget->sizeHint().width();
0212         }
0213     } else {
0214         videoSize = m_videoWidget->sizeHint();
0215         if (m_zoomType == FixedZoom)
0216             videoSize *= m_zoomFactor;
0217     }
0218 
0219     m_videoWidget->resize(videoSize);
0220 
0221     QPoint pos = QPoint(width() / 2, (height() - m_videoToolBar->sizeHint().height()) / 2) - QPoint(videoSize.width() / 2, videoSize.height() / 2);
0222     m_videoWidget->move(pos);
0223 
0224     m_videoToolBar->move(0, height() - m_videoToolBar->sizeHint().height());
0225     m_videoToolBar->resize(width(), m_videoToolBar->sizeHint().height());
0226     m_videoToolBar->setRange(0, m_mediaObject->totalTime());
0227 }
0228 
0229 void Viewer::PhononDisplay::rotate(const DB::ImageInfoPtr & /*info*/)
0230 {
0231     // Not supported.
0232 }
0233 
0234 void Viewer::PhononDisplay::changeVolume(int newVolumePercent)
0235 {
0236     QSignalBlocker blocker { m_audioDevice };
0237     m_audioDevice->setVolume(qPow(newVolumePercent / 100.0, LOUDNESS_TO_VOLTAGE_EXPONENT));
0238 }
0239 
0240 void Viewer::PhononDisplay::setMuted(bool mute)
0241 {
0242     QSignalBlocker blocker { m_audioDevice };
0243     // Phonon::AudioDevice::setMuted() does not seem to be able to reliably unmute things
0244     // luckily, we know the correct value for the volume slider
0245     m_audioDevice->setMuted(mute);
0246     if (!mute) {
0247         const auto volumeDb = qPow(m_videoToolBar->volume() / 100.0, LOUDNESS_TO_VOLTAGE_EXPONENT);
0248         m_audioDevice->setVolume(volumeDb);
0249     }
0250 }
0251 
0252 void Viewer::PhononDisplay::relativeSeek(int msec)
0253 {
0254     m_mediaObject->seek(m_mediaObject->currentTime() + msec);
0255 }
0256 
0257 // vi:expandtab:tabstop=4 shiftwidth=4:
0258 
0259 #include "moc_PhononDisplay.cpp"