c++ qt qlistwidget清空_Qt音视频开发16-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. 支持h265视频流+rtmp等常见视频流。

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

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

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

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

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

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

14. 支持qsv、dxva2、d3d11va等硬解码。

## 三、效果图

c1d853f59b71af5f518ad152b8a9bc3a.png

## 四、相关站点

1. 国内站点:[https://gitee.com/feiyangqingyun/QWidgetDemo](https://gitee.com/feiyangqingyun/QWidgetDemo)

2. 国际站点:[https://github.com/feiyangqingyun/QWidgetDemo](https://github.com/feiyangqingyun/QWidgetDemo)

3. 个人主页:[https://blog.csdn.net/feiyangqingyun](https://blog.csdn.net/feiyangqingyun)

4. 知乎主页:[https://www.zhihu.com/people/feiyangqingyun/](https://www.zhihu.com/people/feiyangqingyun/)

5. 体验地址:[https://blog.csdn.net/feiyangqingyun/article/details/97565652](https://blog.csdn.net/feiyangqingyun/article/details/97565652)

## 五、核心代码

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());}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值