From d09a3cbc60da86f57d06477dea1a57962a11ffb2 Mon Sep 17 00:00:00 2001
From: Mladen Milinkovic <maxrd2@smoothware.net>
Date: Mon, 8 Jul 2019 20:19:03 +0200
Subject: [PATCH] MPV player config options aren't hardcoded anymore.

---
 src/videoplayerplugins/mpv/mpvbackend.cpp     |  37 ++++++-
 src/videoplayerplugins/mpv/mpvbackend.h       |   8 +-
 .../mpv/mpvconfigwidget.cpp                   | 102 ++++++++++++++++--
 src/videoplayerplugins/mpv/mpvconfigwidget.h  |   8 ++
 4 files changed, 139 insertions(+), 16 deletions(-)

diff --git a/src/videoplayerplugins/mpv/mpvbackend.cpp b/src/videoplayerplugins/mpv/mpvbackend.cpp
index d85a56c..9fdcd95 100644
--- a/src/videoplayerplugins/mpv/mpvbackend.cpp
+++ b/src/videoplayerplugins/mpv/mpvbackend.cpp
@@ -33,8 +33,6 @@
 #include <KMessageBox>
 
 using namespace SubtitleComposer;
-using namespace mpv;
-using namespace mpv::qt;
 
 MPVBackend::MPVBackend()
 	: PlayerBackend(),
@@ -218,6 +216,37 @@ MPVBackend::mpvEventHandle(mpv_event *event)
 	}
 }
 
+static QVariant
+node_to_variant(const mpv_node *node)
+{
+	switch(node->format) {
+	case MPV_FORMAT_STRING:
+		return QVariant(QString::fromUtf8(node->u.string));
+	case MPV_FORMAT_FLAG:
+		return QVariant(static_cast<bool>(node->u.flag));
+	case MPV_FORMAT_INT64:
+		return QVariant(static_cast<qlonglong>(node->u.int64));
+	case MPV_FORMAT_DOUBLE:
+		return QVariant(node->u.double_);
+	case MPV_FORMAT_NODE_ARRAY: {
+		mpv_node_list *list = node->u.list;
+		QVariantList qlist;
+		for(int n = 0; n < list->num; n++)
+			qlist.append(node_to_variant(&list->values[n]));
+		return QVariant(qlist);
+	}
+	case MPV_FORMAT_NODE_MAP: {
+		mpv_node_list *list = node->u.list;
+		QVariantMap qmap;
+		for(int n = 0; n < list->num; n++)
+			qmap.insert(QString::fromUtf8(list->keys[n]), node_to_variant(&list->values[n]));
+		return QVariant(qmap);
+	}
+	default: // MPV_FORMAT_NONE, unknown values (e.g. future extensions)
+		return QVariant();
+	}
+}
+
 void
 MPVBackend::updateTextData(const mpv_event_property *prop)
 {
@@ -230,7 +259,7 @@ MPVBackend::updateTextData(const mpv_event_property *prop)
 				if(val.format != MPV_FORMAT_NODE_MAP)
 					continue;
 
-				const QMap<QString, QVariant> &map = mpv::qt::node_to_variant(&val).toMap();
+				const QMap<QString, QVariant> &map = node_to_variant(&val).toMap();
 
 				if(map[QStringLiteral("type")].toString() != QStringLiteral("sub")
 				|| map[QStringLiteral("external")].toBool() == true)
@@ -269,7 +298,7 @@ MPVBackend::updateAudioData(const mpv_event_property *prop)
 				if(val.format != MPV_FORMAT_NODE_MAP)
 					continue;
 
-				const QMap<QString, QVariant> &map = mpv::qt::node_to_variant(&val).toMap();
+				const QMap<QString, QVariant> &map = node_to_variant(&val).toMap();
 
 				if(map[QStringLiteral("type")].toString() != QStringLiteral("audio"))
 					continue;
diff --git a/src/videoplayerplugins/mpv/mpvbackend.h b/src/videoplayerplugins/mpv/mpvbackend.h
index d0edf2e..5e19fa1 100644
--- a/src/videoplayerplugins/mpv/mpvbackend.h
+++ b/src/videoplayerplugins/mpv/mpvbackend.h
@@ -23,7 +23,7 @@
 
 #include "videoplayer/playerbackend.h"
 
-#include <mpv/qthelper.hpp>
+#include <mpv/client.h>
 
 #include <QWidget>
 #include <QString>
@@ -76,14 +76,10 @@ signals:
 protected slots:
 	void onMPVEvents();
 
-protected:
-	void setupProcessArgs(const QString &filePath);
-
+private:
 	void mpvEventHandle(mpv_event *event);
-
 	static void wakeup(void *ctx);
 
-private:
 	void updateTextData(const mpv_event_property *prop);
 	void updateAudioData(const mpv_event_property *prop);
 	void updateVideoData();
diff --git a/src/videoplayerplugins/mpv/mpvconfigwidget.cpp b/src/videoplayerplugins/mpv/mpvconfigwidget.cpp
index 78458f8..6958141 100644
--- a/src/videoplayerplugins/mpv/mpvconfigwidget.cpp
+++ b/src/videoplayerplugins/mpv/mpvconfigwidget.cpp
@@ -20,6 +20,11 @@
 
 #include "mpvconfigwidget.h"
 
+#include <locale>
+#include <mpv/client.h>
+
+#include "scconfig.h"
+
 using namespace SubtitleComposer;
 
 MPVConfigWidget::MPVConfigWidget(QWidget *parent)
@@ -27,14 +32,99 @@ MPVConfigWidget::MPVConfigWidget(QWidget *parent)
 {
 	setupUi(this);
 
-	kcfg_mpvVideoOutput->addItems(QString("vdpau vaapi opengl opengl-hq sdl xv wayland x11 null").split(' '));
-	kcfg_mpvVideoOutput->setProperty("kcfg_property", QByteArray("currentText"));
+	// FIXME: libmpv requires LC_NUMERIC category to be set to "C".. is there some nicer way to do this?
+	std::setlocale(LC_NUMERIC, "C");
+	m_mpv = mpv_create();
+	mpv_request_log_messages(m_mpv, "info");
+	if(mpv_initialize(m_mpv) >= 0) {
+		getHelpResponse(); // make sure there are no log messages
+		static QStringList bad = {
+			QStringLiteral("libmpv"),
+			QStringLiteral("null"),
+			QStringLiteral("image"),
+			QStringLiteral("tct"),
+			QStringLiteral("caca"),
+			QStringLiteral("pcm"),
+		};
+
+		mpv_set_property_string(m_mpv, "vo", "help");
+		for(QString row : getHelpResponse()) {
+			int pos = row.indexOf(QChar(' '));
+			if(pos == -1)
+				continue;
+			const QString name = row.left(pos);
+			if(bad.contains(name))
+				continue;
+			row.insert(pos, "\t-");
+			if(SCConfig::mpvVideoOutput() == name)
+				kcfg_mpvVideoOutput->setCurrentIndex(kcfg_mpvHwDecode->count());
+			kcfg_mpvVideoOutput->addItem(row, name);
+		}
+		kcfg_mpvVideoOutput->setProperty("kcfg_property", QByteArray("currentData"));
+
+		mpv_set_property_string(m_mpv, "hwdec", "help");
+		kcfg_mpvHwDecode->addItem(QStringLiteral("auto\t- Choose best HW decoder"), QStringLiteral("auto"));
+		for(QString row : getHelpResponse()) {
+			int pos = row.indexOf(QChar(' '));
+			if(pos == -1)
+				continue;
+			const QString name = row.left(pos);
+			const QString lastName = kcfg_mpvHwDecode->itemData(kcfg_mpvHwDecode->count() - 1).toString();
+			if(lastName == name || bad.contains(name))
+				continue;
+			if(SCConfig::mpvHwDecode() == name)
+				kcfg_mpvHwDecode->setCurrentIndex(kcfg_mpvHwDecode->count());
+			kcfg_mpvHwDecode->addItem(name, name);
+		}
+		kcfg_mpvHwDecode->setProperty("kcfg_property", QByteArray("currentData"));
+
+		mpv_set_property_string(m_mpv, "ao", "help");
+		for(QString row : getHelpResponse()) {
+			int pos = row.indexOf(QChar(' '));
+			if(pos == -1)
+				continue;
+			const QString name = row.left(pos);
+			if(bad.contains(name))
+				continue;
+			row.insert(pos, "\t-");
+			if(SCConfig::mpvAudioOutput() == name)
+				kcfg_mpvAudioOutput->setCurrentIndex(kcfg_mpvHwDecode->count());
+			kcfg_mpvAudioOutput->addItem(row, name);
+		}
+		kcfg_mpvAudioOutput->setProperty("kcfg_property", QByteArray("currentData"));
 
-	kcfg_mpvHwDecode->addItems(QString("auto vdpau vaapi vaapi-copy").split(' '));
-	kcfg_mpvHwDecode->setProperty("kcfg_property", QByteArray("currentText"));
+		mpv_detach_destroy(m_mpv);
+	} else {
+		kcfg_mpvVideoOutput->addItems(QString("vdpau vaapi opengl opengl-hq sdl xv wayland x11 null").split(' '));
+		kcfg_mpvVideoOutput->setProperty("kcfg_property", QByteArray("currentText"));
 
-	kcfg_mpvAudioOutput->addItems(QString("pulse alsa oss portaudio jack null").split(' '));
-	kcfg_mpvAudioOutput->setProperty("kcfg_property", QByteArray("currentText"));
+		kcfg_mpvHwDecode->addItems(QString("auto vdpau vaapi vaapi-copy").split(' '));
+		kcfg_mpvHwDecode->setProperty("kcfg_property", QByteArray("currentText"));
+
+		kcfg_mpvAudioOutput->addItems(QString("pulse alsa oss portaudio jack null").split(' '));
+		kcfg_mpvAudioOutput->setProperty("kcfg_property", QByteArray("currentText"));
+	}
+}
+
+const QStringList
+MPVConfigWidget::getHelpResponse()
+{
+	QStringList res;
+	while(m_mpv) {
+		mpv_event *event = mpv_wait_event(m_mpv, .1);
+		if(event->event_id == MPV_EVENT_LOG_MESSAGE) {
+			mpv_event_log_message *msg = reinterpret_cast<mpv_event_log_message *>(event->data);
+			if(msg->log_level == MPV_LOG_LEVEL_INFO && strcmp(msg->prefix, "cplayer") == 0) {
+				QString row = QString::fromUtf8(msg->text).simplified();
+				if(row.endsWith(QChar(':')))
+					continue;
+				res << row;
+			}
+		} else if(event->event_id == MPV_EVENT_NONE) {
+			break;
+		}
+	}
+	return res;
 }
 
 MPVConfigWidget::~MPVConfigWidget()
diff --git a/src/videoplayerplugins/mpv/mpvconfigwidget.h b/src/videoplayerplugins/mpv/mpvconfigwidget.h
index f4105d7..775b507 100644
--- a/src/videoplayerplugins/mpv/mpvconfigwidget.h
+++ b/src/videoplayerplugins/mpv/mpvconfigwidget.h
@@ -23,6 +23,8 @@
 
 #include "ui_mpvconfigwidget.h"
 
+#include <mpv/client.h>
+
 namespace SubtitleComposer {
 class MPVConfigWidget : public QWidget, private Ui::MPVConfigWidget
 {
@@ -31,6 +33,12 @@ class MPVConfigWidget : public QWidget, private Ui::MPVConfigWidget
 public:
 	explicit MPVConfigWidget(QWidget *parent = 0);
 	virtual ~MPVConfigWidget();
+
+private:
+	const QStringList getHelpResponse();
+
+private:
+	mpv_handle *m_mpv;
 };
 }
 
-- 
2.29.2
