File indexing completed on 2025-01-05 03:57:27

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2014-09-22
0007  * Description : Slideshow video viewer based on QtAVPlayer
0008  *
0009  * SPDX-FileCopyrightText: 2014-2024 Gilles Caulier <caulier dot gilles at gmail dot com>
0010  *
0011  * SPDX-License-Identifier: GPL-2.0-or-later
0012  *
0013  * ============================================================ */
0014 
0015 #include "slidevideo.h"
0016 
0017 // Qt includes
0018 
0019 #include <QApplication>
0020 #include <QProxyStyle>
0021 #include <QGridLayout>
0022 #include <QString>
0023 #include <QSlider>
0024 #include <QStyle>
0025 #include <QLabel>
0026 
0027 // KDE includes
0028 
0029 #include <klocalizedstring.h>
0030 #include <ksharedconfig.h>
0031 #include <kconfiggroup.h>
0032 
0033 // Local includes
0034 
0035 #include "digikam_debug.h"
0036 #include "dlayoutbox.h"
0037 #include "metaengine.h"
0038 
0039 namespace Digikam
0040 {
0041 
0042 class Q_DECL_HIDDEN SlideVideoStyle : public QProxyStyle
0043 {
0044     Q_OBJECT
0045 
0046 public:
0047 
0048     using QProxyStyle::QProxyStyle;
0049 
0050     int styleHint(QStyle::StyleHint hint,
0051                   const QStyleOption* option = nullptr,
0052                   const QWidget* widget = nullptr,
0053                   QStyleHintReturn* returnData = nullptr) const override
0054     {
0055         if (hint == QStyle::SH_Slider_AbsoluteSetButtons)
0056         {
0057             return (Qt::LeftButton | Qt::MiddleButton | Qt::RightButton);
0058         }
0059 
0060         return QProxyStyle::styleHint(hint, option, widget, returnData);
0061     }
0062 };
0063 
0064 class Q_DECL_HIDDEN SlideVideo::Private
0065 {
0066 public:
0067 
0068     Private() = default;
0069 
0070     DInfoInterface*      iface            = nullptr;
0071 
0072     DVideoWidget*        videoWidget      = nullptr;
0073 
0074     QSlider*             slider           = nullptr;
0075     QSlider*             volume           = nullptr;
0076     QLabel*              tlabel           = nullptr;
0077 
0078     DHBox*               indicator        = nullptr;
0079 };
0080 
0081 SlideVideo::SlideVideo(QWidget* const parent)
0082     : QWidget(parent),
0083       d      (new Private)
0084 {
0085     setMouseTracking(true);
0086 
0087     d->videoWidget    = new DVideoWidget(this);
0088 
0089     d->indicator      = new DHBox(this);
0090     d->slider         = new QSlider(Qt::Horizontal, d->indicator);
0091     d->slider->setStyle(new SlideVideoStyle());
0092     d->slider->setRange(0, 0);
0093     d->slider->setAutoFillBackground(true);
0094     d->tlabel         = new QLabel(d->indicator);
0095     d->tlabel->setText(QLatin1String("00:00:00 / 00:00:00"));
0096     d->tlabel->setAutoFillBackground(true);
0097     QLabel* const spk = new QLabel(d->indicator);
0098     spk->setPixmap(QIcon::fromTheme(QLatin1String("audio-volume-high")).pixmap(22, 22));
0099     d->volume         = new QSlider(Qt::Horizontal, d->indicator);
0100     d->volume->setRange(0, 100);
0101     d->volume->setValue(50);
0102     d->indicator->setStretchFactor(d->slider, 10);
0103     d->indicator->setAutoFillBackground(true);
0104     d->indicator->setSpacing(4);
0105 
0106     QGridLayout* const grid = new QGridLayout(this);
0107     grid->addWidget(d->videoWidget, 0, 0, 2, 1);
0108     grid->addWidget(d->indicator,   0, 0, 1, 1); // Widget will be over player to not change layout when visibility is changed.
0109     grid->setRowStretch(0, 1);
0110     grid->setRowStretch(1, 100);
0111     grid->setContentsMargins(QMargins());
0112 
0113     KSharedConfig::Ptr config = KSharedConfig::openConfig();
0114     KConfigGroup group        = config->group(QLatin1String("Media Player Settings"));
0115     int volume                = group.readEntry("Volume", 50);
0116 
0117     d->videoWidget->audioOutput()->setVolume(volume);
0118     d->volume->setValue(volume);
0119 
0120     // --------------------------------------------------------------------------
0121 
0122     connect(d->slider, SIGNAL(sliderMoved(int)),
0123             this, SLOT(slotPosition(int)));
0124 
0125     connect(d->slider, SIGNAL(valueChanged(int)),
0126             this, SLOT(slotPosition(int)));
0127 
0128     connect(d->volume, SIGNAL(valueChanged(int)),
0129             this, SLOT(slotVolumeChanged(int)));
0130 
0131     connect(d->videoWidget->player(), SIGNAL(stateChanged(QAVPlayer::State)),
0132             this, SLOT(slotPlayerStateChanged(QAVPlayer::State)));
0133 
0134     connect(d->videoWidget->player(), SIGNAL(seeked(qint64)),
0135             this, SLOT(slotPositionChanged(qint64)),
0136             Qt::QueuedConnection);
0137 
0138     connect(d->videoWidget->player(), SIGNAL(durationChanged(qint64)),
0139             this, SLOT(slotDurationChanged(qint64)));
0140 
0141     connect(d->videoWidget->player(), SIGNAL(errorOccurred(QAVPlayer::Error,QString)),
0142             this, SLOT(slotHandlePlayerError(QAVPlayer::Error,QString)));
0143 
0144     connect(d->videoWidget->player(), SIGNAL(mediaStatusChanged(QAVPlayer::MediaStatus)),
0145             this, SLOT(slotMediaStatusChanged(QAVPlayer::MediaStatus)));
0146 
0147     // --------------------------------------------------------------------------
0148 
0149     layout()->activate();
0150     resize(sizeHint());
0151     show();
0152 }
0153 
0154 SlideVideo::~SlideVideo()
0155 {
0156     stop();
0157     delete d;
0158 }
0159 
0160 void SlideVideo::setInfoInterface(DInfoInterface* const iface)
0161 {
0162     d->iface = iface;
0163 }
0164 
0165 void SlideVideo::setCurrentUrl(const QUrl& url)
0166 {
0167     d->videoWidget->player()->stop();
0168 
0169     int orientation = 0;
0170 
0171     if (d->iface)
0172     {
0173         DItemInfo info(d->iface->itemInfo(url));
0174 
0175         orientation = info.orientation();
0176     }
0177 
0178     switch (orientation)
0179     {
0180         case MetaEngine::ORIENTATION_ROT_90:
0181         case MetaEngine::ORIENTATION_ROT_90_HFLIP:
0182         case MetaEngine::ORIENTATION_ROT_90_VFLIP:
0183         {
0184             d->videoWidget->setVideoItemOrientation(90);
0185             break;
0186         }
0187 
0188         case MetaEngine::ORIENTATION_ROT_180:
0189         {
0190             d->videoWidget->setVideoItemOrientation(180);
0191             break;
0192         }
0193 
0194         case MetaEngine::ORIENTATION_ROT_270:
0195         {
0196             d->videoWidget->setVideoItemOrientation(270);
0197             break;
0198         }
0199 
0200         default:
0201         {
0202             d->videoWidget->setVideoItemOrientation(0);
0203             break;
0204         }
0205     }
0206 
0207     d->videoWidget->player()->setSource(url.toLocalFile());
0208     d->videoWidget->player()->play();
0209 
0210     showIndicator(false);
0211 }
0212 
0213 void SlideVideo::showIndicator(bool b)
0214 {
0215     d->indicator->setVisible(b);
0216 }
0217 
0218 void SlideVideo::slotPlayerStateChanged(QAVPlayer::State newState)
0219 {
0220     if (newState == QAVPlayer::PlayingState)
0221     {
0222         // Nothing to do.
0223     }
0224 }
0225 
0226 void SlideVideo::slotMediaStatusChanged(QAVPlayer::MediaStatus newStatus)
0227 {
0228     switch (newStatus)
0229     {
0230         case QAVPlayer::EndOfMedia:
0231         {
0232             Q_EMIT signalVideoFinished();
0233 
0234             break;
0235         }
0236 
0237         case QAVPlayer::LoadedMedia:
0238         {
0239             int rotate = d->videoWidget->videoMediaOrientation();
0240 
0241             qCDebug(DIGIKAM_GENERAL_LOG) << "Video orientation from QtAVPlayer:"
0242                                          << rotate;
0243 
0244             rotate     = (-rotate) + d->videoWidget->videoItemOrientation();
0245 
0246             if ((rotate > 270) || (rotate < 0))
0247             {
0248                 rotate = d->videoWidget->videoItemOrientation();
0249             }
0250 
0251             d->videoWidget->setVideoItemOrientation(rotate);
0252 
0253             Q_EMIT signalVideoLoaded(true);
0254 
0255             break;
0256         }
0257 
0258         case QAVPlayer::InvalidMedia:
0259         {
0260             Q_EMIT signalVideoLoaded(false);
0261 
0262             break;
0263         }
0264 
0265         default:
0266         {
0267             break;
0268         }
0269     }
0270 }
0271 
0272 void SlideVideo::pause(bool b)
0273 {
0274     if (!b && (d->videoWidget->player()->state() != QAVPlayer::PlayingState))
0275     {
0276         d->videoWidget->player()->play();
0277         return;
0278     }
0279 
0280     if (b && (d->videoWidget->player()->state() != QAVPlayer::PausedState))
0281     {
0282        d->videoWidget->player()->pause();
0283     }
0284 }
0285 
0286 void SlideVideo::stop()
0287 {
0288     d->videoWidget->player()->stop();
0289     d->videoWidget->player()->setSource(QString());
0290 }
0291 
0292 void SlideVideo::slotPositionChanged(qint64 position)
0293 {
0294     if (!d->slider->isSliderDown())
0295     {
0296         d->slider->blockSignals(true);
0297         d->slider->setValue(position);
0298         d->slider->blockSignals(false);
0299     }
0300 
0301     d->tlabel->setText(QString::fromLatin1("%1 / %2")
0302                        .arg(QTime(0, 0, 0).addMSecs(position).toString(QLatin1String("HH:mm:ss")))
0303                        .arg(QTime(0, 0, 0).addMSecs(d->slider->maximum()).toString(QLatin1String("HH:mm:ss"))));
0304 
0305     Q_EMIT signalVideoPosition(position);
0306 }
0307 
0308 void SlideVideo::slotVolumeChanged(int volume)
0309 {
0310     d->videoWidget->audioOutput()->setVolume((qreal)volume / 100.0);
0311 }
0312 
0313 void SlideVideo::slotDurationChanged(qint64 duration)
0314 {
0315     qint64 max = qMax((qint64)1, duration);
0316     d->slider->setRange(0, max);
0317 
0318     Q_EMIT signalVideoDuration(duration);
0319 }
0320 
0321 void SlideVideo::slotPosition(int position)
0322 {
0323     if (d->videoWidget->player()->isSeekable())
0324     {
0325         d->videoWidget->player()->seek((qint64)position);
0326     }
0327 }
0328 
0329 void SlideVideo::slotHandlePlayerError(QAVPlayer::Error /*err*/, const QString& message)
0330 {
0331     qCDebug(DIGIKAM_GENERAL_LOG) << "QtAVPlayer Error: " << message;
0332 }
0333 
0334 } // namespace Digikam
0335 
0336 #include "slidevideo.moc"
0337 
0338 #include "moc_slidevideo.cpp"