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

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * http://www.digikam.org
0005  *
0006  * Date        : 2006-20-12
0007  * Description : a view to embed QtMultimedia media player.
0008  *
0009  * SPDX-FileCopyrightText: 2006-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0010  *
0011  * SPDX-License-Identifier: GPL-2.0-or-later
0012  *
0013  * ============================================================ */
0014 
0015 #include "mediaplayerview.h"
0016 
0017 // Qt includes
0018 
0019 #include <QApplication>
0020 #include <QVBoxLayout>
0021 #include <QMouseEvent>
0022 #include <QProxyStyle>
0023 #include <QPushButton>
0024 #include <QFileInfo>
0025 #include <QToolBar>
0026 #include <QAction>
0027 #include <QSlider>
0028 #include <QLabel>
0029 #include <QFrame>
0030 #include <QStyle>
0031 #include <QTransform>
0032 #include <QGraphicsView>
0033 #include <QGraphicsScene>
0034 #include <QGraphicsVideoItem>
0035 #include <QVideoSink>
0036 #include <QVideoFrame>
0037 #include <QAudioOutput>
0038 #include <QMediaMetaData>
0039 #include <QStandardPaths>
0040 
0041 // KDE includes
0042 
0043 #include <klocalizedstring.h>
0044 #include <ksharedconfig.h>
0045 #include <kconfiggroup.h>
0046 
0047 // Local includes
0048 
0049 #include "digikam_debug.h"
0050 #include "digikam_globals.h"
0051 #include "thememanager.h"
0052 #include "stackedview.h"
0053 #include "dlayoutbox.h"
0054 #include "metaengine.h"
0055 #include "dmetadata.h"
0056 
0057 namespace Digikam
0058 {
0059 
0060 class Q_DECL_HIDDEN MediaPlayerMouseClickFilter : public QObject
0061 {
0062     Q_OBJECT
0063 
0064 public:
0065 
0066     explicit MediaPlayerMouseClickFilter(QObject* const parent)
0067         : QObject (parent),
0068           m_parent(parent)
0069     {
0070     }
0071 
0072 protected:
0073 
0074     bool eventFilter(QObject* obj, QEvent* event) override
0075     {
0076         if ((event->type() == QEvent::MouseButtonPress) || (event->type() == QEvent::MouseButtonDblClick))
0077         {
0078             bool singleClick              = qApp->style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick);
0079             QMouseEvent* const mouseEvent = dynamic_cast<QMouseEvent*>(event);
0080 
0081             if (m_parent && mouseEvent)
0082             {
0083                 MediaPlayerView* const mplayer = dynamic_cast<MediaPlayerView*>(m_parent);
0084 
0085                 if (mplayer)
0086                 {
0087                     if      ((mouseEvent->button() == Qt::LeftButton) &&
0088                              ((singleClick && (event->type() == QEvent::MouseButtonPress)) ||
0089                              (!singleClick && (event->type() == QEvent::MouseButtonDblClick))))
0090                     {
0091                         mplayer->slotEscapePressed();
0092                     }
0093                     else if ((mouseEvent->button() == Qt::RightButton) &&
0094                              (event->type() == QEvent::MouseButtonPress))
0095                     {
0096                         mplayer->slotRotateVideo();
0097                     }
0098 
0099                     return true;
0100                 }
0101             }
0102         }
0103 
0104         return QObject::eventFilter(obj, event);
0105     }
0106 
0107 private:
0108 
0109     QObject* m_parent = nullptr;
0110 };
0111 
0112 // --------------------------------------------------------
0113 
0114 class Q_DECL_HIDDEN PlayerVideoStyle : public QProxyStyle
0115 {
0116     Q_OBJECT
0117 
0118 public:
0119 
0120     using QProxyStyle::QProxyStyle;
0121 
0122     int styleHint(QStyle::StyleHint hint,
0123                   const QStyleOption* option = nullptr,
0124                   const QWidget* widget = nullptr,
0125                   QStyleHintReturn* returnData = nullptr) const override
0126     {
0127         if (hint == QStyle::SH_Slider_AbsoluteSetButtons)
0128         {
0129             return (Qt::LeftButton | Qt::MiddleButton | Qt::RightButton);
0130         }
0131 
0132         return QProxyStyle::styleHint(hint, option, widget, returnData);
0133     }
0134 };
0135 
0136 // --------------------------------------------------------
0137 
0138 class MediaPlayerView::Private
0139 {
0140 
0141 public:
0142 
0143     enum MediaPlayerViewMode
0144     {
0145         ErrorView = 0,
0146         PlayerView
0147     };
0148 
0149 public:
0150 
0151     Private() = default;
0152 
0153     QFrame*              errorView          = nullptr;
0154     QFrame*              playerView         = nullptr;
0155 
0156     QAction*             prevAction         = nullptr;
0157     QAction*             nextAction         = nullptr;
0158     QAction*             playAction         = nullptr;
0159     QAction*             grabAction         = nullptr;
0160 
0161     QPushButton*         loopPlay           = nullptr;
0162 
0163     QToolBar*            toolBar            = nullptr;
0164 
0165     DInfoInterface*      iface              = nullptr;
0166 
0167     QGraphicsScene*      videoScene         = nullptr;
0168     QGraphicsView*       videoView          = nullptr;
0169     QGraphicsVideoItem*  videoItem          = nullptr;
0170     QMediaPlayer*        player             = nullptr;
0171     QAudioOutput*        audio              = nullptr;
0172 
0173     QSlider*             slider             = nullptr;
0174     QSlider*             volume             = nullptr;
0175     QLabel*              tlabel             = nullptr;
0176     QUrl                 currentItem;
0177 
0178     int                  videoOrientation   = 0;
0179     qint64               sliderTime         = 0;
0180 
0181 public:
0182 
0183     void adjustVideoSize()
0184     {
0185         videoItem->resetTransform();
0186 
0187         QSizeF nativeSize    = videoItem->nativeSize();
0188         int mediaOrientation = videoMediaOrientation();
0189 
0190         if ((nativeSize.width()  < 1.0) ||
0191             (nativeSize.height() < 1.0))
0192         {
0193             return;
0194         }
0195 
0196         if ((mediaOrientation == 90) ||
0197             (mediaOrientation == 270))
0198         {
0199             nativeSize.transpose();
0200         }
0201 
0202         double ratio = (nativeSize.width() /
0203                         nativeSize.height());
0204 
0205         if (videoView->width() > videoView->height())
0206         {
0207             QSizeF vsize(videoView->height() * ratio,
0208                          videoView->height());
0209             videoItem->setSize(vsize);
0210         }
0211         else
0212         {
0213             QSizeF vsize(videoView->width(),
0214                          videoView->width() / ratio);
0215             videoItem->setSize(vsize);
0216         }
0217 
0218         videoView->setSceneRect(0, 0, videoItem->size().width(),
0219                                       videoItem->size().height());
0220 
0221         QPointF center = videoItem->boundingRect().center();
0222         videoItem->setTransformOriginPoint(center);
0223         videoItem->setRotation(videoOrientation);
0224 
0225         videoView->fitInView(videoItem, Qt::KeepAspectRatio);
0226         videoView->centerOn(videoItem);
0227         videoView->raise();
0228     };
0229 
0230     int videoMediaOrientation() const
0231     {
0232         int orientation = 0;
0233         QVariant val    = player->metaData().value(QMediaMetaData::Orientation);
0234 
0235         if (!val.isNull())
0236         {
0237             orientation = val.toInt();
0238         }
0239 
0240         return orientation;
0241     };
0242 
0243     void setVideoItemOrientation(int orientation)
0244     {
0245         videoOrientation = orientation;
0246         adjustVideoSize();
0247     };
0248 };
0249 
0250 MediaPlayerView::MediaPlayerView(QWidget* const parent)
0251     : QStackedWidget(parent),
0252       d             (new Private)
0253 {
0254     setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
0255 
0256     const int spacing      = qMin(QApplication::style()->pixelMetric(QStyle::PM_LayoutHorizontalSpacing),
0257                                   QApplication::style()->pixelMetric(QStyle::PM_LayoutVerticalSpacing));
0258 
0259     d->prevAction          = new QAction(QIcon::fromTheme(QLatin1String("go-previous")),
0260                                          i18nc("go to previous image", "Back"),   this);
0261     d->nextAction          = new QAction(QIcon::fromTheme(QLatin1String("go-next")),
0262                                          i18nc("go to next image", "Forward"),    this);
0263     d->playAction          = new QAction(QIcon::fromTheme(QLatin1String("media-playback-start")),
0264                                          i18nc("pause/play video", "Pause/Play"), this);
0265     d->grabAction          = new QAction(QIcon::fromTheme(QLatin1String("view-preview")),
0266                                          i18nc("capture video frame", "Capture"), this);
0267 
0268     d->errorView           = new QFrame(this);
0269     QLabel* const errorMsg = new QLabel(i18n("An error has occurred with the media player..."), this);
0270 
0271     errorMsg->setAlignment(Qt::AlignCenter);
0272     d->errorView->setFrameStyle(QFrame::StyledPanel | QFrame::Plain);
0273     d->errorView->setLineWidth(1);
0274 
0275     QVBoxLayout* const vbox1 = new QVBoxLayout(d->errorView);
0276     vbox1->addWidget(errorMsg, 10);
0277     vbox1->setContentsMargins(QMargins());
0278     vbox1->setSpacing(spacing);
0279 
0280     insertWidget(Private::ErrorView, d->errorView);
0281 
0282     // --------------------------------------------------------------------------
0283 
0284     d->playerView = new QFrame(this);
0285     d->videoScene = new QGraphicsScene(this);
0286     d->videoView  = new QGraphicsView(d->videoScene);
0287     d->videoView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
0288     d->videoView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
0289     d->videoView->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents);
0290     d->videoItem  = new QGraphicsVideoItem();
0291     d->player     = new QMediaPlayer(this);
0292     d->audio      = new QAudioOutput;
0293     d->player->setAudioOutput(d->audio);
0294     d->player->setVideoOutput(d->videoItem);
0295     d->videoScene->addItem(d->videoItem);
0296 
0297     d->playerView->setFrameStyle(QFrame::StyledPanel | QFrame::Plain);
0298     d->playerView->setLineWidth(1);
0299 
0300     d->videoItem->setAspectRatioMode(Qt::IgnoreAspectRatio);
0301     d->videoView->setMouseTracking(true);
0302 
0303     DHBox* const hbox = new DHBox(this);
0304     d->slider         = new QSlider(Qt::Horizontal, hbox);
0305     d->slider->setStyle(new PlayerVideoStyle());
0306     d->slider->setRange(0, 0);
0307     d->tlabel         = new QLabel(hbox);
0308     d->tlabel->setText(QLatin1String("00:00:00 / 00:00:00"));
0309     d->loopPlay       = new QPushButton(hbox);
0310     d->loopPlay->setIcon(QIcon::fromTheme(QLatin1String("media-playlist-normal")));
0311     d->loopPlay->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
0312     d->loopPlay->setToolTip(i18n("Toggle playing in a loop"));
0313     d->loopPlay->setFocusPolicy(Qt::NoFocus);
0314     d->loopPlay->setMinimumSize(22, 22);
0315     d->loopPlay->setCheckable(true);
0316     QLabel* const spk = new QLabel(hbox);
0317     spk->setPixmap(QIcon::fromTheme(QLatin1String("audio-volume-high")).pixmap(22, 22));
0318     d->volume         = new QSlider(Qt::Horizontal, hbox);
0319     d->volume->setRange(0, 100);
0320     d->volume->setValue(50);
0321 
0322     hbox->setStretchFactor(d->slider, 10);
0323     hbox->setContentsMargins(0, 0, 0, spacing);
0324     hbox->setSpacing(spacing);
0325 
0326     QVBoxLayout* const vbox2 = new QVBoxLayout(d->playerView);
0327     vbox2->addWidget(d->videoView, 10);
0328     vbox2->addWidget(hbox,          0);
0329     vbox2->setContentsMargins(QMargins());
0330     vbox2->setSpacing(spacing);
0331 
0332     insertWidget(Private::PlayerView, d->playerView);
0333 
0334     d->toolBar               = new QToolBar(this);
0335     d->toolBar->addAction(d->prevAction);
0336     d->toolBar->addAction(d->nextAction);
0337     d->toolBar->addAction(d->playAction);
0338     d->toolBar->addAction(d->grabAction);
0339     d->toolBar->setStyleSheet(toolButtonStyleSheet());
0340 
0341     setPreviewMode(Private::PlayerView);
0342 
0343     d->errorView->installEventFilter(new MediaPlayerMouseClickFilter(this));
0344     d->videoView->installEventFilter(new MediaPlayerMouseClickFilter(this));
0345     d->playerView->installEventFilter(this);
0346 
0347     KSharedConfig::Ptr config = KSharedConfig::openConfig();
0348     KConfigGroup group        = config->group(QLatin1String("Media Player Settings"));
0349     int volume                = group.readEntry("Volume", 50);
0350 
0351     d->volume->setValue(volume);
0352     d->audio->setVolume(volume / 100.0F);
0353 
0354     // --------------------------------------------------------------------------
0355 
0356     connect(ThemeManager::instance(), SIGNAL(signalThemeChanged()),
0357             this, SLOT(slotThemeChanged()));
0358 
0359     connect(d->prevAction, SIGNAL(triggered()),
0360             this, SIGNAL(signalPrevItem()));
0361 
0362     connect(d->nextAction, SIGNAL(triggered()),
0363             this, SIGNAL(signalNextItem()));
0364 
0365     connect(d->playAction, SIGNAL(triggered()),
0366             this, SLOT(slotPausePlay()));
0367 
0368     connect(d->grabAction, SIGNAL(triggered()),
0369             this, SLOT(slotCapture()));
0370 
0371     connect(d->slider, SIGNAL(sliderMoved(int)),
0372             this, SLOT(slotPosition(int)));
0373 
0374     connect(d->slider, SIGNAL(valueChanged(int)),
0375             this, SLOT(slotPosition(int)));
0376 
0377     connect(d->volume, SIGNAL(valueChanged(int)),
0378             this, SLOT(slotVolumeChanged(int)));
0379 
0380     connect(d->loopPlay, SIGNAL(toggled(bool)),
0381             this, SLOT(slotLoopToggled(bool)));
0382 
0383     connect(d->player, SIGNAL(playbackStateChanged(QMediaPlayer::PlaybackState)),
0384             this, SLOT(slotPlayerStateChanged(QMediaPlayer::PlaybackState)));
0385 
0386     connect(d->player, SIGNAL(positionChanged(qint64)),
0387             this, SLOT(slotPositionChanged(qint64)));
0388 
0389     connect(d->player, SIGNAL(durationChanged(qint64)),
0390             this, SLOT(slotDurationChanged(qint64)));
0391 
0392     connect(d->player, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)),
0393             this, SLOT(slotMediaStatusChanged(QMediaPlayer::MediaStatus)));
0394 
0395     connect(d->player, SIGNAL(errorOccurred(QMediaPlayer::Error,QString)),
0396             this, SLOT(slotHandlePlayerError(QMediaPlayer::Error,QString)));
0397 
0398     connect(d->videoItem, SIGNAL(nativeSizeChanged(QSizeF)),
0399             this, SLOT(slotNativeSizeChanged()));
0400 }
0401 
0402 MediaPlayerView::~MediaPlayerView()
0403 {
0404     escapePreview();
0405 
0406     delete d;
0407 }
0408 
0409 void MediaPlayerView::setInfoInterface(DInfoInterface* const iface)
0410 {
0411     d->iface = iface;
0412 }
0413 
0414 void MediaPlayerView::reload()
0415 {
0416     d->player->stop();
0417     d->player->setSource(d->currentItem);
0418     d->player->play();
0419 }
0420 
0421 void MediaPlayerView::slotPlayerStateChanged(QMediaPlayer::PlaybackState newState)
0422 {
0423     if (newState == QMediaPlayer::PlayingState)
0424     {
0425         int rotate = d->videoMediaOrientation();
0426 
0427         qCDebug(DIGIKAM_GENERAL_LOG) << "Found video orientation with QtMultimedia:"
0428                                      << rotate;
0429 
0430         rotate     = (-rotate) + d->videoOrientation;
0431 
0432         if ((rotate > 270) || (rotate < 0))
0433         {
0434             rotate = d->videoOrientation;
0435         }
0436 
0437         d->setVideoItemOrientation(rotate);
0438 
0439         d->playAction->setIcon(QIcon::fromTheme(QLatin1String("media-playback-pause")));
0440     }
0441     else
0442     {
0443         d->playAction->setIcon(QIcon::fromTheme(QLatin1String("media-playback-start")));
0444 
0445         if (
0446             (newState           == QMediaPlayer::StoppedState)  &&
0447             (d->player->error() != QMediaPlayer::NoError)
0448            )
0449         {
0450             setPreviewMode(Private::ErrorView);
0451         }
0452 
0453         if (
0454             (newState                 == QMediaPlayer::StoppedState) &&
0455             (d->player->mediaStatus() == QMediaPlayer::EndOfMedia)
0456            )
0457         {
0458             qCDebug(DIGIKAM_GENERAL_LOG) << "Play video with QtMultimedia completed:" << d->player->source();
0459 
0460             if (d->player->error() != QMediaPlayer::NoError)
0461             {
0462                 setPreviewMode(Private::ErrorView);
0463             }
0464         }
0465     }
0466 }
0467 
0468 void MediaPlayerView::slotMediaStatusChanged(QMediaPlayer::MediaStatus newStatus)
0469 {
0470     if (newStatus == QMediaPlayer::InvalidMedia)
0471     {
0472         setPreviewMode(Private::ErrorView);
0473     }
0474 }
0475 
0476 void MediaPlayerView::escapePreview()
0477 {
0478     d->player->stop();
0479     QString dummy = QStandardPaths::locate(QStandardPaths::GenericDataLocation,
0480                                            QLatin1String("digikam/data/video-digikam.mp4"));
0481     d->player->setSource(QUrl::fromLocalFile(dummy));
0482 }
0483 
0484 void MediaPlayerView::slotThemeChanged()
0485 {
0486     QPalette palette;
0487     palette.setColor(d->errorView->backgroundRole(), qApp->palette().color(QPalette::Base));
0488     d->errorView->setPalette(palette);
0489 
0490     QPalette palette2;
0491     palette2.setColor(d->playerView->backgroundRole(), qApp->palette().color(QPalette::Base));
0492     d->playerView->setPalette(palette2);
0493 }
0494 
0495 void MediaPlayerView::slotEscapePressed()
0496 {
0497     Q_EMIT signalEscapePreview();
0498 }
0499 
0500 void MediaPlayerView::slotRotateVideo()
0501 {
0502     if (d->player->isPlaying())
0503     {
0504         int orientation = 0;
0505 
0506         switch (d->videoOrientation)
0507         {
0508             case 0:
0509             {
0510                 orientation = 90;
0511                 break;
0512             }
0513 
0514             case 90:
0515             {
0516                 orientation = 180;
0517                 break;
0518             }
0519 
0520             case 180:
0521             {
0522                 orientation = 270;
0523                 break;
0524             }
0525 
0526             default:
0527             {
0528                 orientation = 0;
0529                 break;
0530             }
0531         }
0532 
0533         d->setVideoItemOrientation(orientation);
0534     }
0535 }
0536 
0537 void MediaPlayerView::slotPausePlay()
0538 {
0539     if (!d->player->isPlaying())
0540     {
0541         d->player->play();
0542         return;
0543     }
0544 
0545     d->player->pause();
0546 }
0547 
0548 void MediaPlayerView::slotCapture()
0549 {
0550     if (d->player->playbackState() != QMediaPlayer::StoppedState)
0551     {
0552         int capturePosition    = d->player->position();
0553         QVideoSink* const sink = d->player->videoSink();
0554         QVideoFrame frame      = sink->videoFrame();
0555         QImage image           = frame.toImage();
0556 
0557         if (!image.isNull() && d->currentItem.isValid())
0558         {
0559             QFileInfo info(d->currentItem.toLocalFile());
0560             QString tempPath = QString::fromUtf8("%1/%2-%3.digikamtempfile.jpg")
0561                               .arg(info.path())
0562                               .arg(info.baseName())
0563                               .arg(capturePosition);
0564 
0565             if (image.save(tempPath, "JPG", 100))
0566             {
0567                 QScopedPointer<DMetadata> meta(new DMetadata);
0568 
0569                 if (meta->load(tempPath))
0570                 {
0571                     QDateTime dateTime;
0572                     MetaEngine::ImageOrientation orientation = MetaEngine::ORIENTATION_NORMAL;
0573 
0574                     if (d->iface)
0575                     {
0576                         DItemInfo dinfo(d->iface->itemInfo(d->currentItem));
0577 
0578                         dateTime    = dinfo.dateTime();
0579                         orientation = (MetaEngine::ImageOrientation)dinfo.orientation();
0580                     }
0581                     else
0582                     {
0583                         QScopedPointer<DMetadata> meta2(new DMetadata);
0584 
0585                         if (meta2->load(d->currentItem.toLocalFile()))
0586                         {
0587                             dateTime    = meta2->getItemDateTime();
0588                             orientation = meta2->getItemOrientation();
0589                         }
0590                     }
0591 
0592                     if (dateTime.isValid())
0593                     {
0594                         dateTime = dateTime.addMSecs(capturePosition);
0595                     }
0596                     else
0597                     {
0598                         dateTime = QDateTime::currentDateTime();
0599                     }
0600 
0601                     if (orientation == MetaEngine::ORIENTATION_UNSPECIFIED)
0602                     {
0603                         orientation = MetaEngine::ORIENTATION_NORMAL;
0604                     }
0605 
0606                     meta->setImageDateTime(dateTime, true);
0607                     meta->setItemDimensions(image.size());
0608                     meta->setItemOrientation(orientation);
0609                     meta->save(tempPath, true);
0610                 }
0611 
0612                 QString finalPath = QString::fromUtf8("%1/%2-%3.jpg")
0613                                    .arg(info.path())
0614                                    .arg(info.baseName())
0615                                    .arg(capturePosition);
0616 
0617                 if (QFile::rename(tempPath, finalPath))
0618                 {
0619                     if (d->iface)
0620                     {
0621                         d->iface->slotMetadataChangedForUrl(QUrl::fromLocalFile(finalPath));
0622                     }
0623                 }
0624                 else
0625                 {
0626                     QFile::remove(tempPath);
0627                 }
0628             }
0629         }
0630     }
0631 }
0632 
0633 int MediaPlayerView::previewMode()
0634 {
0635     return indexOf(currentWidget());
0636 }
0637 
0638 void MediaPlayerView::setPreviewMode(int mode)
0639 {
0640     if ((mode != Private::ErrorView) && (mode != Private::PlayerView))
0641     {
0642         return;
0643     }
0644 
0645     setCurrentIndex(mode);
0646 
0647     d->toolBar->adjustSize();
0648     d->toolBar->raise();
0649 }
0650 
0651 void MediaPlayerView::setCurrentItem(const QUrl& url, bool hasPrevious, bool hasNext)
0652 {
0653     d->prevAction->setEnabled(hasPrevious);
0654     d->nextAction->setEnabled(hasNext);
0655     d->adjustVideoSize();
0656 
0657     if (url.isEmpty())
0658     {
0659         d->player->stop();
0660         d->currentItem = url;
0661 
0662         return;
0663     }
0664 
0665     if (
0666         (d->currentItem == url) &&
0667         (
0668          (d->player->playbackState() == QMediaPlayer::PlayingState) ||
0669          (d->player->playbackState() == QMediaPlayer::PausedState)
0670         )
0671        )
0672     {
0673         return;
0674     }
0675 
0676     d->player->stop();
0677     int orientation = 0;
0678     d->currentItem  = url;
0679 
0680     if (d->iface)
0681     {
0682         DItemInfo info(d->iface->itemInfo(url));
0683 
0684         orientation = info.orientation();
0685     }
0686 
0687     switch (orientation)
0688     {
0689         case MetaEngine::ORIENTATION_ROT_90:
0690         case MetaEngine::ORIENTATION_ROT_90_HFLIP:
0691         case MetaEngine::ORIENTATION_ROT_90_VFLIP:
0692         {
0693             d->videoOrientation = 90;
0694             break;
0695         }
0696 
0697         case MetaEngine::ORIENTATION_ROT_180:
0698         {
0699             d->videoOrientation = 180;
0700             break;
0701         }
0702 
0703         case MetaEngine::ORIENTATION_ROT_270:
0704         {
0705             d->videoOrientation = 270;
0706             break;
0707         }
0708 
0709         default:
0710         {
0711             d->videoOrientation = 0;
0712             break;
0713         }
0714     }
0715 
0716     d->player->setSource(d->currentItem);
0717     setPreviewMode(Private::PlayerView);
0718     d->player->play();
0719 
0720     qCDebug(DIGIKAM_GENERAL_LOG) << "Play video with QtMultimedia started:" << d->player->source();
0721 }
0722 
0723 void MediaPlayerView::slotPositionChanged(qint64 position)
0724 {
0725     if ((d->sliderTime < position)       &&
0726         ((d->sliderTime + 100) > position))
0727     {
0728         return;
0729     }
0730 
0731     d->sliderTime = position;
0732 
0733     if (!d->slider->isSliderDown())
0734     {
0735         d->slider->blockSignals(true);
0736         d->slider->setValue(position);
0737         d->slider->blockSignals(false);
0738     }
0739 
0740     d->tlabel->setText(QString::fromLatin1("%1 / %2")
0741                        .arg(QTime(0, 0, 0).addMSecs(position).toString(QLatin1String("HH:mm:ss")))
0742                        .arg(QTime(0, 0, 0).addMSecs(d->slider->maximum()).toString(QLatin1String("HH:mm:ss"))));
0743 }
0744 
0745 void MediaPlayerView::slotVolumeChanged(int volume)
0746 {
0747     d->audio->setVolume(volume / 100.0F);
0748 
0749     if (objectName() != QLatin1String("main_media_player"))
0750     {
0751         return;
0752     }
0753 
0754     KSharedConfig::Ptr config = KSharedConfig::openConfig();
0755     KConfigGroup group        = config->group(QLatin1String("Media Player Settings"));
0756     group.writeEntry("Volume", volume);
0757 }
0758 
0759 void MediaPlayerView::slotLoopToggled(bool loop)
0760 {
0761     if (loop)
0762     {
0763         d->loopPlay->setIcon(QIcon::fromTheme(QLatin1String("media-playlist-repeat")));
0764         d->player->setLoops(QMediaPlayer::Infinite);
0765     }
0766     else
0767     {
0768         d->loopPlay->setIcon(QIcon::fromTheme(QLatin1String("media-playlist-normal")));
0769         d->player->setLoops(QMediaPlayer::Once);
0770     }
0771 }
0772 
0773 void MediaPlayerView::slotDurationChanged(qint64 duration)
0774 {
0775     qint64 max = qMax((qint64)1, duration);
0776     d->slider->setRange(0, max);
0777 }
0778 
0779 void MediaPlayerView::slotPosition(int position)
0780 {
0781     if (d->player->isSeekable())
0782     {
0783         d->player->setPosition((qint64)position);
0784     }
0785 }
0786 
0787 void MediaPlayerView::slotHandlePlayerError(QMediaPlayer::Error /*error*/, const QString& errStr)
0788 {
0789     setPreviewMode(Private::ErrorView);
0790 
0791     qCDebug(DIGIKAM_GENERAL_LOG) << "QtMultimedia Error: " << errStr;
0792 }
0793 
0794 void MediaPlayerView::slotNativeSizeChanged()
0795 {
0796     d->adjustVideoSize();
0797 }
0798 
0799 bool MediaPlayerView::eventFilter(QObject* watched, QEvent* event)
0800 {
0801     if ((watched == d->playerView) && (event->type() == QEvent::Resize))
0802     {
0803         d->adjustVideoSize();
0804     }
0805 
0806     return QStackedWidget::eventFilter(watched, event);
0807 }
0808 
0809 }  // namespace Digikam
0810 
0811 #include "mediaplayerview.moc"
0812 
0813 #include "moc_mediaplayerview.cpp"