feat: add subtitle track selection, secondary subtitle and delay
This commit is contained in:
1 parent
1eb67b829c
commit
48cac86d60
5 files changed
+320
-4
No files matched your search
+122
-2
@@ -2,19 +2,38 @@
|
||||
|
||||
#include <MpvController>
|
||||
|
||||
#include <cmath>
|
||||
#include <utility>
|
||||
|
||||
namespace
|
||||
{
|
||||
QString localPathOrUrl(const QUrl &url)
|
||||
{
|
||||
return url.isLocalFile() ? url.toLocalFile() : url.toString();
|
||||
}
|
||||
|
||||
// mpv takes "no" to deselect a track.
|
||||
QVariant trackIdValue(int id)
|
||||
{
|
||||
return id > 0 ? QVariant(id) : QVariant(QStringLiteral("no"));
|
||||
}
|
||||
}
|
||||
|
||||
MpvItem::MpvItem(QQuickItem *parent)
|
||||
: MpvAbstractItem(parent)
|
||||
{
|
||||
// Leave the player on the last frame at end of file instead of unloading it.
|
||||
setPropertyAsync(QStringLiteral("keep-open"), QStringLiteral("yes"));
|
||||
setPropertyAsync(QStringLiteral("hwdec"), QStringLiteral("auto-safe"));
|
||||
// Also pick up "movie.en.srt" style files next to "movie.mkv".
|
||||
setPropertyAsync(QStringLiteral("sub-auto"), QStringLiteral("fuzzy"));
|
||||
|
||||
observeProperty(QStringLiteral("media-title"), MPV_FORMAT_STRING);
|
||||
observeProperty(QStringLiteral("time-pos"), MPV_FORMAT_DOUBLE);
|
||||
observeProperty(QStringLiteral("duration"), MPV_FORMAT_DOUBLE);
|
||||
observeProperty(QStringLiteral("pause"), MPV_FORMAT_FLAG);
|
||||
observeProperty(QStringLiteral("track-list"), MPV_FORMAT_NODE);
|
||||
observeProperty(QStringLiteral("sub-delay"), MPV_FORMAT_DOUBLE);
|
||||
|
||||
// MpvController lives on a worker thread; queue its signals back to the GUI thread.
|
||||
connect(mpvController(), &MpvController::propertyChanged, this, &MpvItem::onPropertyChanged, Qt::QueuedConnection);
|
||||
@@ -98,9 +117,10 @@ void MpvItem::loadFile(const QUrl &url)
|
||||
return;
|
||||
}
|
||||
|
||||
const QString target = url.isLocalFile() ? url.toLocalFile() : url.toString();
|
||||
commandAsync(QStringList{QStringLiteral("loadfile"), target});
|
||||
commandAsync(QStringList{QStringLiteral("loadfile"), localPathOrUrl(url)});
|
||||
setPropertyAsync(QStringLiteral("pause"), false);
|
||||
// sub-delay is global in mpv; start every file in sync.
|
||||
setSubtitleDelay(0.0);
|
||||
}
|
||||
|
||||
void MpvItem::togglePause()
|
||||
@@ -113,6 +133,63 @@ void MpvItem::seek(double seconds)
|
||||
commandAsync(QStringList{QStringLiteral("seek"), QString::number(seconds), QStringLiteral("absolute")});
|
||||
}
|
||||
|
||||
QVariantList MpvItem::subtitleTracks() const
|
||||
{
|
||||
return m_subtitleTracks;
|
||||
}
|
||||
|
||||
int MpvItem::subtitleId() const
|
||||
{
|
||||
return m_subtitleId;
|
||||
}
|
||||
|
||||
void MpvItem::setSubtitleId(int id)
|
||||
{
|
||||
setPropertyAsync(QStringLiteral("sid"), trackIdValue(id));
|
||||
}
|
||||
|
||||
int MpvItem::secondarySubtitleId() const
|
||||
{
|
||||
return m_secondarySubtitleId;
|
||||
}
|
||||
|
||||
void MpvItem::setSecondarySubtitleId(int id)
|
||||
{
|
||||
setPropertyAsync(QStringLiteral("secondary-sid"), trackIdValue(id));
|
||||
}
|
||||
|
||||
double MpvItem::subtitleDelay() const
|
||||
{
|
||||
return m_subtitleDelay;
|
||||
}
|
||||
|
||||
void MpvItem::setSubtitleDelay(double seconds)
|
||||
{
|
||||
// Keep whole milliseconds so repeated +/-0.1 steps don't drift.
|
||||
const double rounded = std::round(seconds * 1000.0) / 1000.0;
|
||||
// Update right away so quick repeated steps build on each other instead of on the
|
||||
// last value mpv reported; mpv confirms it through the observed property.
|
||||
if (rounded != m_subtitleDelay) {
|
||||
m_subtitleDelay = rounded;
|
||||
Q_EMIT subtitleDelayChanged();
|
||||
}
|
||||
setPropertyAsync(QStringLiteral("sub-delay"), rounded);
|
||||
setPropertyAsync(QStringLiteral("secondary-sub-delay"), rounded);
|
||||
}
|
||||
|
||||
void MpvItem::addSubtitleFile(const QUrl &url)
|
||||
{
|
||||
if (!url.isValid()) {
|
||||
return;
|
||||
}
|
||||
commandAsync(QStringList{QStringLiteral("sub-add"), localPathOrUrl(url), QStringLiteral("select")});
|
||||
}
|
||||
|
||||
void MpvItem::showText(const QString &text)
|
||||
{
|
||||
commandAsync(QStringList{QStringLiteral("show-text"), text});
|
||||
}
|
||||
|
||||
void MpvItem::onPropertyChanged(const QString &property, const QVariant &value)
|
||||
{
|
||||
if (property == u"media-title") {
|
||||
@@ -127,9 +204,52 @@ void MpvItem::onPropertyChanged(const QString &property, const QVariant &value)
|
||||
} else if (property == u"pause") {
|
||||
m_paused = value.toBool();
|
||||
Q_EMIT pausedChanged();
|
||||
} else if (property == u"track-list") {
|
||||
updateTracks(value.toList());
|
||||
} else if (property == u"sub-delay") {
|
||||
m_subtitleDelay = value.toDouble();
|
||||
Q_EMIT subtitleDelayChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void MpvItem::updateTracks(const QVariantList &trackList)
|
||||
{
|
||||
QVariantList subtitles;
|
||||
int primary = 0;
|
||||
int secondary = 0;
|
||||
|
||||
for (const QVariant &entry : trackList) {
|
||||
const QVariantMap track = entry.toMap();
|
||||
if (track.value(QStringLiteral("type")).toString() != u"sub") {
|
||||
continue;
|
||||
}
|
||||
|
||||
const int id = track.value(QStringLiteral("id")).toInt();
|
||||
if (track.value(QStringLiteral("selected")).toBool()) {
|
||||
// main-selection is 0 for the primary subtitle and 1 for the secondary one.
|
||||
if (track.value(QStringLiteral("main-selection")).toInt() == 0) {
|
||||
primary = id;
|
||||
} else {
|
||||
secondary = id;
|
||||
}
|
||||
}
|
||||
|
||||
subtitles.append(QVariantMap{
|
||||
{QStringLiteral("id"), id},
|
||||
{QStringLiteral("title"), track.value(QStringLiteral("title")).toString()},
|
||||
{QStringLiteral("lang"), track.value(QStringLiteral("lang")).toString()},
|
||||
{QStringLiteral("codec"), track.value(QStringLiteral("codec")).toString()},
|
||||
{QStringLiteral("external"), track.value(QStringLiteral("external")).toBool()},
|
||||
{QStringLiteral("externalFilename"), track.value(QStringLiteral("external-filename")).toString()},
|
||||
});
|
||||
}
|
||||
|
||||
m_subtitleTracks = subtitles;
|
||||
m_subtitleId = primary;
|
||||
m_secondarySubtitleId = secondary;
|
||||
Q_EMIT subtitleTracksChanged();
|
||||
}
|
||||
|
||||
void MpvItem::setFileLoaded(bool loaded)
|
||||
{
|
||||
if (loaded == m_fileLoaded) {
|
||||
|
||||
Reference in new issue
Block a user