summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--DOCS/client-api-changes.rst1
-rw-r--r--libmpv/client.h2
-rw-r--r--libmpv/qthelper.hpp234
-rw-r--r--wscript_build.py2
4 files changed, 237 insertions, 2 deletions
diff --git a/DOCS/client-api-changes.rst b/DOCS/client-api-changes.rst
index b1274cad7b..a72bf9e398 100644
--- a/DOCS/client-api-changes.rst
+++ b/DOCS/client-api-changes.rst
@@ -25,6 +25,7 @@ API changes
::
+ 1.8 - add qthelper.hpp
1.7 - add mpv_command_node(), mpv_command_node_async()
1.6 - modify "core-idle" property behavior
- MPV_EVENT_LOG_MESSAGE now always sends complete lines
diff --git a/libmpv/client.h b/libmpv/client.h
index 084f6e6e6c..7f545866aa 100644
--- a/libmpv/client.h
+++ b/libmpv/client.h
@@ -162,7 +162,7 @@ extern "C" {
* relational operators (<, >, <=, >=).
*/
#define MPV_MAKE_VERSION(major, minor) (((major) << 16) | (minor) | 0UL)
-#define MPV_CLIENT_API_VERSION MPV_MAKE_VERSION(1, 7)
+#define MPV_CLIENT_API_VERSION MPV_MAKE_VERSION(1, 8)
/**
* Return the MPV_CLIENT_API_VERSION the mpv source has been compiled with.
diff --git a/libmpv/qthelper.hpp b/libmpv/qthelper.hpp
new file mode 100644
index 0000000000..07bf194a1d
--- /dev/null
+++ b/libmpv/qthelper.hpp
@@ -0,0 +1,234 @@
+/* Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * Note: these helpers are provided for convenience for C++/Qt applications.
+ * This is based on the public API in client.h, and it does not encode any
+ * knowledge that is not known or guaranteed outside of the C client API. You
+ * can even copy and modify this code as you like, or implement similar things
+ * for other languages.
+ */
+
+#include <cstring>
+
+#include <QVariant>
+#include <QString>
+#include <QList>
+#include <QHash>
+
+#include <mpv/client.h>
+
+namespace mpv {
+namespace qt {
+
+static inline 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();
+ }
+}
+
+struct node_builder {
+ node_builder(const QVariant& v) {
+ set(&node_, v);
+ }
+ ~node_builder() {
+ free_node(&node_);
+ }
+ mpv_node *node() { return &node_; }
+private:
+ Q_DISABLE_COPY(node_builder)
+ //node_builder(node_builder const&); // disallow
+ //node_builder& operator=(node_builder const&); // disallow
+ mpv_node node_;
+ mpv_node_list *create_list(mpv_node *dst, bool is_map, int num) {
+ dst->format = is_map ? MPV_FORMAT_NODE_MAP : MPV_FORMAT_NODE_ARRAY;
+ mpv_node_list *list = new mpv_node_list();
+ dst->u.list = list;
+ if (!list)
+ goto err;
+ list->values = new mpv_node[num]();
+ if (!list->values)
+ goto err;
+ if (is_map) {
+ list->keys = new char*[num]();
+ if (!list->keys)
+ goto err;
+ }
+ return list;
+ err:
+ free_node(dst);
+ return NULL;
+ }
+ char *dup_qstring(const QString &s) {
+ QByteArray b = s.toUtf8();
+ char *r = new char[b.size() + 1];
+ if (r)
+ std::memcpy(r, b.data(), b.size() + 1);
+ return r;
+ }
+ bool test_type(const QVariant &v, QMetaType::Type t) {
+ // The Qt docs say: "Although this function is declared as returning
+ // "QVariant::Type(obsolete), the return value should be interpreted
+ // as QMetaType::Type."
+ // So a cast really seems to be needed to avoid warnings (urgh).
+ return static_cast<int>(v.type()) == static_cast<int>(t);
+ }
+ void set(mpv_node *dst, const QVariant &src) {
+ if (test_type(src, QMetaType::QString)) {
+ dst->format = MPV_FORMAT_STRING;
+ dst->u.string = dup_qstring(src.toString());
+ if (!dst->u.string)
+ goto fail;
+ } else if (test_type(src, QMetaType::Bool)) {
+ dst->format = MPV_FORMAT_FLAG;
+ dst->u.flag = src.toBool() ? 1 : 0;
+ } else if (test_type(src, QMetaType::Int) ||
+ test_type(src, QMetaType::LongLong) ||
+ test_type(src, QMetaType::UInt) ||
+ test_type(src, QMetaType::ULongLong))
+ {
+ dst->format = MPV_FORMAT_INT64;
+ dst->u.int64 = src.toLongLong();
+ } else if (test_type(src, QMetaType::Double)) {
+ dst->format = MPV_FORMAT_DOUBLE;
+ dst->u.double_ = src.toDouble();
+ } else if (src.canConvert<QVariantList>()) {
+ QVariantList qlist = src.toList();
+ mpv_node_list *list = create_list(dst, false, qlist.size());
+ if (!list)
+ goto fail;
+ for (int n = 0; n < qlist.size(); n++)
+ set(&list->values[n], qlist[n]);
+ } else if (src.canConvert<QVariantMap>()) {
+ QVariantMap qmap = src.toMap();
+ mpv_node_list *list = create_list(dst, true, qmap.size());
+ if (!list)
+ goto fail;
+ for (int n = 0; n < qmap.size(); n++) {
+ list->keys[n] = dup_qstring(qmap.keys()[n]);
+ if (!list->keys[n]) {
+ free_node(dst);
+ goto fail;
+ }
+ set(&list->values[n], qmap.values()[n]);
+ }
+ } else {
+ goto fail;
+ }
+ return;
+ fail:
+ dst->format = MPV_FORMAT_NONE;
+ }
+ void free_node(mpv_node *dst) {
+ switch (dst->format) {
+ case MPV_FORMAT_STRING:
+ delete[] dst->u.string;
+ break;
+ case MPV_FORMAT_NODE_ARRAY:
+ case MPV_FORMAT_NODE_MAP: {
+ mpv_node_list *list = dst->u.list;
+ if (list) {
+ for (int n = 0; n < list->num; n++) {
+ if (list->keys)
+ delete list->keys[n];
+ if (list->values)
+ free_node(&list->values[n]);
+ }
+ }
+ delete[] list->keys;
+ delete[] list->values;
+ delete list;
+ break;
+ }
+ default: ;
+ }
+ dst->format = MPV_FORMAT_NONE;
+ }
+};
+
+/**
+ * RAII wrapper that calls mpv_free_node_contents() on the pointer.
+ */
+struct node_autofree {
+ mpv_node *ptr;
+ node_autofree(mpv_node *a_ptr) : ptr(a_ptr) {}
+ ~node_autofree() { mpv_free_node_contents(ptr); }
+};
+
+/**
+ * Return the given property as mpv_node converted to QVariant, or QVariant()
+ * on error.
+ *
+ * @param name the property name
+ */
+static inline QVariant get_property_variant(mpv_handle *ctx, const QString &name)
+{
+ mpv_node node;
+ if (mpv_get_property(ctx, name.toUtf8().data(), MPV_FORMAT_NODE, &node) < 0)
+ return QVariant();
+ node_autofree f(&node);
+ return node_to_variant(&node);
+}
+
+/**
+ * Set the given property as mpv_node converted from the QVariant argument.
+ */
+static inline int set_property_variant(mpv_handle *ctx, const QString &name,
+ const QVariant &v)
+{
+ node_builder node(v);
+ return mpv_set_property(ctx, name.toUtf8().data(), MPV_FORMAT_NODE, node.node());
+}
+
+/**
+ * mpv_command_node() equivalent. Returns QVariant() on error (and
+ * unfortunately, the same on success).
+ */
+static inline QVariant command_variant(mpv_handle *ctx, const QVariant &args)
+{
+ node_builder node(args);
+ mpv_node res;
+ if (mpv_command_node(ctx, node.node(), &res) < 0)
+ return QVariant();
+ node_autofree f(&res);
+ return node_to_variant(&res);
+}
+
+}
+}
diff --git a/wscript_build.py b/wscript_build.py
index f7df1c5aad..3f2cc68ffc 100644
--- a/wscript_build.py
+++ b/wscript_build.py
@@ -505,7 +505,7 @@ def build(ctx):
PRIV_LIBS = get_deps(),
)
- headers = ["client.h"]
+ headers = ["client.h", "qthelper.hpp"]
for f in headers:
ctx.install_as(ctx.env.INCDIR + '/mpv/' + f, 'libmpv/' + f)