千家信息网

Qt mpv通用接口怎么实现

发表于:2025-02-05 作者:千家信息网编辑
千家信息网最后更新 2025年02月05日,本篇内容介绍了"Qt mpv通用接口怎么实现"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!一、前言前
千家信息网最后更新 2025年02月05日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通用接口怎么实现"的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注网站,小编将为大家输出更多高质量的实用文章!

0