Qt mpv通用接口怎么实现
本篇内容介绍了“Qt mpv通用接口怎么实现”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
一、前言
前面几篇文章,依次讲了解码播放、录像存储、读取和控制、事件订阅等,其实这些功能的实现都离不开封装的通用的接口,最开始本人去调用一些设置的时候,发现多参数的不好实现,原来需要用mpv_node处理,而Qt中如何转成mpv_node需要特殊的处理才行,后来在开源主页看到了官方提供的demo例子,直接用qt封装好了多个接口(https://github.com/mpv-player/mpv-examples/tree/master/libmpv),看里面的注释是英文的,估计应该是官方提供的,传入的参数都是支持QVariant的,这样兼容性就超级强大了,多种不同类型的数据参数都可以传入进去,再次感谢官方的demo,官方的demo除了有QWidget的外还有qml的版本,同时还提供了opengl版本,各位有兴趣都可以down下来看看,不过demo比较简单就是,并没有演示所有的功能,只演示了最基础的功能比如播放视频进度控制等,离一个完整的视频播放器差十万八千里不止。
主要接口如下:
通用获取属性接口函数 get_property_variant
通用设置属性接口函数 set_property_variant
通用设置参数接口函数 set_option_variant
通用执行命令接口函数 command_variant
二、功能特点
多线程实时播放视频流+本地视频等。
支持windows+linux+mac。
多线程显示图像,不卡主界面。
自动重连网络摄像头。
可设置是否保存到文件以及文件名。
可直接拖曳文件到mpvwidget控件播放。
支持h365视频流+rtmp等常见视频流。
可暂停播放和继续播放。
支持存储单个视频文件和定时存储视频文件。
自定义顶部悬浮条,发送单击信号通知,可设置是否启用。
可设置画面拉伸填充或者等比例填充。
可对视频进行截图(原始图片)和截屏。
录像文件存储MP4文件。
支持qsv、dxva2、d3d11va等硬解码。
三、效果图
四、核心代码
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) 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; } list->num = qlist.size(); 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; } list->num = qmap.size(); 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; } }; struct node_autofree { mpv_node *ptr; node_autofree(mpv_node *a_ptr) : ptr(a_ptr) {} ~node_autofree() { mpv_free_node_contents(ptr); } }; 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); } 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()); } static inline int set_option_variant(mpv_handle *ctx, const QString &name, const QVariant &v) { node_builder node(v); return mpv_set_option(ctx, name.toUtf8().data(), MPV_FORMAT_NODE, node.node()); } 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); } static inline QVariant get_property(mpv_handle *ctx, const QString &name) { mpv_node node; int err = mpv_get_property(ctx, name.toUtf8().data(), MPV_FORMAT_NODE, &node); if (err < 0) { return QVariant::fromValue(ErrorReturn(err)); } node_autofree f(&node); return node_to_variant(&node); } static inline int set_property(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()); }
“Qt mpv通用接口怎么实现”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注网站,小编将为大家输出更多高质量的实用文章!