File indexing completed on 2024-05-12 05:04:25

0001 // SPDX-FileCopyrightText: 2019 Linus Jahn <lnj@kaidan.im>
0002 // SPDX-FileCopyrightText: 2022 Devin Lin <devin@kde.org>
0003 // SPDX-FileCopyrightText: 2023 Joshua Goins <josh@redstrate.com>
0004 //
0005 // SPDX-License-Identifier: GPL-3.0-or-later
0006 
0007 #include "mpvplayer.h"
0008 
0009 #include <MpvController>
0010 
0011 MpvPlayer::MpvPlayer(QQuickItem *parent)
0012     : MpvAbstractItem(parent)
0013 {
0014     // enable console output
0015     setProperty(QStringLiteral("terminal"), QStringLiteral("yes"));
0016 
0017     // don't load user scripts or configs
0018     setProperty(QStringLiteral("config"), QStringLiteral("no"));
0019     setProperty(QStringLiteral("load-scripts"), QStringLiteral("no"));
0020 
0021     // force vo to libmpv (which it should be set to anyway)
0022     setProperty(QStringLiteral("vo"), QStringLiteral("libmpv"));
0023 
0024     // use safe hardware acceleration
0025     setProperty(QStringLiteral("hwdec"), QStringLiteral("auto-safe"));
0026 
0027     // disable OSD and fonts
0028     setProperty(QStringLiteral("osd-level"), QStringLiteral("0"));
0029     setProperty(QStringLiteral("embeddedfonts"), QStringLiteral("no"));
0030 
0031     // disable input
0032     setProperty(QStringLiteral("input-builtin-bindings"), QStringLiteral("no"));
0033     setProperty(QStringLiteral("input-default-bindings"), QStringLiteral("no"));
0034     setProperty(QStringLiteral("input-vo-keyboard"), QStringLiteral("no"));
0035 
0036     observeProperty(QStringLiteral("duration"), MPV_FORMAT_DOUBLE);
0037     observeProperty(QStringLiteral("time-pos"), MPV_FORMAT_DOUBLE);
0038     observeProperty(QStringLiteral("pause"), MPV_FORMAT_FLAG);
0039 
0040     connect(mpvController(), &MpvController::propertyChanged, this, &MpvPlayer::onPropertyChanged, Qt::QueuedConnection);
0041     connect(
0042         mpvController(),
0043         &MpvController::fileLoaded,
0044         this,
0045         [this] {
0046             m_loading = false;
0047             Q_EMIT loadingChanged();
0048         },
0049         Qt::QueuedConnection);
0050     connect(
0051         mpvController(),
0052         &MpvController::videoReconfig,
0053         this,
0054         [this] {
0055             const int64_t w = getProperty(QStringLiteral("dwidth")).toInt();
0056             const int64_t h = getProperty(QStringLiteral("dheight")).toInt();
0057             if (w > 0 && h > 0) {
0058                 const QSize newSize(w, h);
0059                 if (newSize != m_sourceSize) {
0060                     m_sourceSize = newSize;
0061                     Q_EMIT sourceSizeChanged();
0062                 }
0063             }
0064         },
0065         Qt::QueuedConnection);
0066 }
0067 
0068 qreal MpvPlayer::position() const
0069 {
0070     return m_position;
0071 }
0072 
0073 qreal MpvPlayer::duration() const
0074 {
0075     return m_duration;
0076 }
0077 
0078 bool MpvPlayer::paused() const
0079 {
0080     return m_paused;
0081 }
0082 
0083 QSize MpvPlayer::sourceSize() const
0084 {
0085     return m_sourceSize;
0086 }
0087 
0088 QString MpvPlayer::source() const
0089 {
0090     return m_source;
0091 }
0092 
0093 bool MpvPlayer::loading() const
0094 {
0095     return m_loading;
0096 }
0097 
0098 bool MpvPlayer::looping() const
0099 {
0100     return m_looping;
0101 }
0102 
0103 bool MpvPlayer::autoPlay() const
0104 {
0105     return m_autoPlay;
0106 }
0107 
0108 bool MpvPlayer::stopped() const
0109 {
0110     return m_currentSource.isEmpty();
0111 }
0112 
0113 void MpvPlayer::setSource(const QString &source)
0114 {
0115     if (m_source == source) {
0116         return;
0117     }
0118 
0119     m_source = source;
0120 
0121     if (m_autoPlay) {
0122         play();
0123     }
0124 
0125     Q_EMIT sourceChanged();
0126 }
0127 
0128 void MpvPlayer::setLooping(bool loop)
0129 {
0130     if (m_looping == loop) {
0131         return;
0132     }
0133 
0134     m_looping = loop;
0135     setProperty(QStringLiteral("loop-file"), loop ? QStringLiteral("inf") : QStringLiteral("no"));
0136 
0137     Q_EMIT loopingChanged();
0138 }
0139 
0140 void MpvPlayer::setAutoPlay(bool autoPlay)
0141 {
0142     if (m_autoPlay == autoPlay) {
0143         return;
0144     }
0145 
0146     m_autoPlay = autoPlay;
0147 
0148     Q_EMIT autoPlayChanged();
0149 }
0150 
0151 void MpvPlayer::play()
0152 {
0153     if (!paused() || m_source.isEmpty()) {
0154         return;
0155     }
0156 
0157     // setSource doesn't actually load the file into MPV, because the player is always created
0158     // regardless of autoPlay. This incurs a very visible overhead in the UI, so we want to delay
0159     // the loadfile command until the last possible moment (when the user requests to play it).
0160     if (m_currentSource != m_source) {
0161         m_loading = true;
0162         Q_EMIT loadingChanged();
0163 
0164         command(QStringList{QStringLiteral("loadfile"), m_source});
0165 
0166         m_currentSource = m_source;
0167         m_paused = false;
0168 
0169         Q_EMIT stoppedChanged();
0170         Q_EMIT pausedChanged();
0171     }
0172 
0173     setProperty(QStringLiteral("pause"), false);
0174 }
0175 
0176 void MpvPlayer::pause()
0177 {
0178     if (paused()) {
0179         return;
0180     }
0181     setProperty(QStringLiteral("pause"), true);
0182 }
0183 
0184 void MpvPlayer::stop()
0185 {
0186     setPosition(0);
0187     setProperty(QStringLiteral("pause"), true);
0188 }
0189 
0190 void MpvPlayer::setPosition(double value)
0191 {
0192     if (value == position()) {
0193         return;
0194     }
0195     setProperty(QStringLiteral("time-pos"), value);
0196 }
0197 
0198 void MpvPlayer::seek(qreal offset)
0199 {
0200     command(QStringList() << QStringLiteral("add") << QStringLiteral("time-pos") << QString::number(offset));
0201 }
0202 
0203 void MpvPlayer::onPropertyChanged(const QString &property, const QVariant &value)
0204 {
0205     if (property == QStringLiteral("time-pos")) {
0206         m_position = value.toDouble();
0207         Q_EMIT positionChanged();
0208     } else if (property == QStringLiteral("duration")) {
0209         m_duration = value.toDouble();
0210         Q_EMIT durationChanged();
0211     } else if (property == QStringLiteral("pause")) {
0212         // pause is expected to be false if there's no currently loaded media, so skip it
0213         if (!m_currentSource.isEmpty()) {
0214             m_paused = value.toBool();
0215             Q_EMIT pausedChanged();
0216         }
0217     }
0218 }
0219 
0220 #include "moc_mpvplayer.cpp"