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

0001 // SPDX-FileCopyrightText: 2021 Ömer Fadıl USTA <omerusta@gmail.com>
0002 // SPDX-FileCopyrightText: 2021-2022 Jesper K. Pedersen <jesper.pedersen@kdab.com>
0003 // SPDX-FileCopyrightText: 2021-2023 Johannes Zarl-Zierl <johannes@zarl-zierl.at>
0004 //
0005 // SPDX-License-Identifier: GPL-2.0-or-later
0006 
0007 // QtAVWidgets/WidgetRenderer 1.13 is incompatible witch QT_DISABLE_DEPRECATED_BEFORE 5.15:
0008 #undef QT_DISABLE_DEPRECATED_BEFORE
0009 
0010 #include "QtAVDisplay.h"
0011 #include "QtAVVideoToolBar.h"
0012 
0013 #include <DB/ImageInfo.h>
0014 
0015 #include <KLocalizedString>
0016 #include <QGuiApplication>
0017 #include <QMessageBox>
0018 #include <QPainterPath>
0019 #include <QScreen>
0020 #include <QVBoxLayout>
0021 #include <QtAV/AVPlayer.h>
0022 #include <QtAV/LibAVFilter.h>
0023 #include <QtAV/VideoRenderer.h>
0024 #include <QtAVWidgets/WidgetRenderer.h>
0025 #include <QtAVWidgets/global.h>
0026 
0027 Viewer::QtAVDisplay::QtAVDisplay(QWidget *parent)
0028     : Viewer::VideoDisplay(parent)
0029 {
0030     m_renderer = new QtAV::WidgetRenderer(this, Qt::Widget);
0031     if (!m_renderer) {
0032         QMessageBox::critical(this, i18n("Failed to set up video playback"), i18n("Failed to set up video playback (renderer wasn't created)"));
0033         return;
0034     }
0035 
0036     m_player = new QtAV::AVPlayer(this);
0037 
0038     // I need this for the use case where we click on the slider after end of video playback.
0039     // If I don't disable asynchronous loading the seek will have no effect.
0040     // See VideoDisplay::seekToPosition
0041     m_player->setAsyncLoad(false);
0042 
0043     m_videoWidget = m_renderer->widget();
0044     if (!m_videoWidget) {
0045         QMessageBox::critical(this, i18n("Failed to set up video playback"), i18n("Failed to set up video playback (widget wasn't created)"));
0046         return;
0047     }
0048     QVBoxLayout *layout = new QVBoxLayout(this);
0049     layout->addWidget(m_videoWidget, 1);
0050 
0051     m_player->setRenderer(m_renderer);
0052 
0053     connect(m_player, &QtAV::AVPlayer::stopped, this, &QtAVDisplay::stopped);
0054 
0055     m_toolBar = new QtAVVideoToolBar(m_player, this);
0056     layout->addWidget(m_toolBar);
0057 
0058     connect(m_toolBar, &VideoToolBar::positionChanged, this, &QtAVDisplay::seekToPosition);
0059     connect(m_player, &QtAV::AVPlayer::positionChanged, this, &QtAVDisplay::displayPosition);
0060     connect(m_toolBar, &VideoToolBar::muted, m_player, [this](bool b) { m_player->audio()->setMute(b); });
0061 
0062     connect(m_toolBar, &VideoToolBar::volumeChanged, m_player, [this](int value) { m_player->audio()->setVolume(value / 100.0); });
0063     m_toolBar->setVolume(100 * m_player->audio()->volume());
0064 
0065     m_rotateFilter = new QtAV::LibAVFilterVideo(m_player);
0066 }
0067 
0068 bool Viewer::QtAVDisplay::setImageImpl(DB::ImageInfoPtr info, bool /*forward*/)
0069 {
0070     if (!m_videoWidget)
0071         return false;
0072 
0073     rotate(m_info);
0074 
0075     m_player->play(info->fileName().absolute());
0076     m_toolBar->closePreview();
0077 
0078     return true;
0079 }
0080 
0081 Viewer::QtAVDisplay::~QtAVDisplay()
0082 {
0083     stop();
0084 }
0085 
0086 void Viewer::QtAVDisplay::stop()
0087 {
0088     if (m_player)
0089         m_player->stop();
0090 }
0091 
0092 void Viewer::QtAVDisplay::playPause()
0093 {
0094     if (!m_player)
0095         return;
0096     m_player->togglePause();
0097 }
0098 
0099 QImage Viewer::QtAVDisplay::screenShoot()
0100 {
0101     return QGuiApplication::primaryScreen()->grabWindow(m_videoWidget->winId()).toImage();
0102 }
0103 
0104 void Viewer::QtAVDisplay::restart()
0105 {
0106     if (!m_player)
0107         return;
0108 
0109     m_player->seek(m_player->startPosition());
0110     m_player->play();
0111 }
0112 
0113 void Viewer::QtAVDisplay::relativeSeek(int msec)
0114 {
0115     seekToPosition(msec + m_player->position());
0116 }
0117 
0118 void Viewer::QtAVDisplay::seekToPosition(qint64 pos)
0119 {
0120     if (!m_player->isPlaying())
0121         m_player->play();
0122     m_player->setSeekType(QtAV::AccurateSeek);
0123     m_player->seek(pos);
0124 }
0125 
0126 void Viewer::QtAVDisplay::rotate(const DB::ImageInfoPtr &info)
0127 {
0128     m_info = info;
0129     m_rotateFilter->uninstall();
0130     if (info->angle() != 0) {
0131         m_rotateFilter->installTo(m_player);
0132         // See https://ffmpeg.org/ffmpeg-filters.html
0133         m_rotateFilter->setOptions(QString::fromUtf8("rotate=PI*%1/180").arg(info->angle()));
0134     }
0135 }
0136 
0137 bool Viewer::QtAVDisplay::isPaused() const
0138 {
0139     if (!m_player)
0140         return false;
0141 
0142     return m_player->isPaused();
0143 }
0144 
0145 bool Viewer::QtAVDisplay::isPlaying() const
0146 {
0147     if (!m_player)
0148         return false;
0149 
0150     return m_player->isPlaying();
0151 }
0152 
0153 void Viewer::QtAVDisplay::displayPosition(qint64 pos)
0154 {
0155     if (m_player->isSeekable())
0156         m_toolBar->setPosition(pos);
0157 }
0158 
0159 // vi:expandtab:tabstop=4 shiftwidth=4:
0160 
0161 #include "moc_QtAVDisplay.cpp"