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"