千家信息网

Qt mpv通用接口怎么实现

发表于:2026-11-03 作者:千家信息网编辑
千家信息网最后更新 2026年11月03日,本篇内容介绍了"Qt mpv通用接口怎么实现"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!一、前言前
千家信息网最后更新 2026年11月03日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比较简单就是,并没有演示所有的功能,只演示了最基础的功能比如播放视频进度控制等,离一个完整的视频播放器差十万八千里不止。

主要接口如下:

  1. 通用获取属性接口函数 get_property_variant

  2. 通用设置属性接口函数 set_property_variant

  3. 通用设置参数接口函数 set_option_variant

  4. 通用执行命令接口函数 command_variant

二、功能特点

  1. 多线程实时播放视频流+本地视频等。

  2. 支持windows+linux+mac。

  3. 多线程显示图像,不卡主界面。

  4. 自动重连网络摄像头。

  5. 可设置是否保存到文件以及文件名。

  6. 可直接拖曳文件到mpvwidget控件播放。

  7. 支持h365视频流+rtmp等常见视频流。

  8. 可暂停播放和继续播放。

  9. 支持存储单个视频文件和定时存储视频文件。

  10. 自定义顶部悬浮条,发送单击信号通知,可设置是否启用。

  11. 可设置画面拉伸填充或者等比例填充。

  12. 可对视频进行截图(原始图片)和截屏。

  13. 录像文件存储MP4文件。

  14. 支持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(v.type()) == static_cast(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 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 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通用接口怎么实现"的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注网站,小编将为大家输出更多高质量的实用文章!

接口 视频 文件 支持 函数 功能 参数 官方 存储 视频流 可设 内容 属性 录像 更多 版本 知识 线程 处理 封装 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 深圳九邦互联网科技有限公司 疫情对互联网科技公司影响 互联网中国科技 互联网 科技公司 深圳互联网科技公司 广州宏创互联网科技 中国互联网金融科技基金 新华互联网科技校企合作 中国的互联网科技企业的崛起 互联网系的金融科技公司 常德市电业局互联网科技部 和信科技工业互联网 洛阳昕诺飞互联网科技有限公司 深圳市罗太互联网科技有限公司 四川互联网展示科技馆设计 浙南科技城互联网大厦招聘 互联网科技平台产品运营 恒生科技指数 中概互联网 重庆科技产业互联网有哪些 山东亿川互联网科技有限责任公司 什么是科技互联网 广州大一互联网络科技有限公司 今日互联网科技 中资互联网科技 互联网科技生活的内容 济南华为互联网科技产业总部基地 广州新华互联网科技学校电竞方面 兰石爱特工业互联网科技分公司 众联互联网络科技 安徽九吞吴互联网科技有限公司
0