美文网首页
Qt音视频开发15-mpv事件订阅

Qt音视频开发15-mpv事件订阅

作者: feiyangqingyun | 来源:发表于2020-08-21 17:42 被阅读0次

一、前言

在使用libmpv的过程中,通过对mpv事件订阅,可以更准确和准时的得知一些事件,比如文件打开成功,播放状态的改变等,而不需要定时器去读取状态,尤其是打开成功这个事件,如果不采用事件订阅,有时候视频流会卡主一阵子,比如不存在的视频流或者网络不好的情况下,有两种办法可以规避这个情况,在vlc和ffmpeg解码中也是如此,一种方法是将这个打开直接放到线程中执行,本来解码处理就是一个完整的线程类,所以直接通过标志位的更改来在线程中执行初始化,毫无压力不卡主,还有一个办法就是采用事件回调,得到打开成功以后,再去执行其他的处理比如读取视频的宽度高度等信息,这些信息一般都是需要打开文件成功以后才能读取到的。

毫无疑问mpv也支持事件订阅,通过mpv_observe_property函数将需要订阅的属性事件更改加入事件订阅队列,这个函数有四个参数,第一个参数指mpv对象(通过mpv_create产生的),第二个参数指用户数据,如果不需要的话直接填0,一般都不需要,第三个参数指属性名称,至于属性名称是啥叫啥,可以官网查阅手册(http://mpv.io/manual/master/#properties),第四个参数指属性的格式类型。一般来说都会对这几个属性事件的更改订阅:duration(文件长度)、time-pos(当前播放进度)。事件订阅好以后执行mpv_set_wakeup_callback函数设置事件回调函数处理即可。

二、功能特点

  1. 多线程实时播放视频流+本地视频等。
  2. 支持windows+linux+mac。
  3. 多线程显示图像,不卡主界面。
  4. 自动重连网络摄像头。
  5. 可设置是否保存到文件以及文件名。
  6. 可直接拖曳文件到mpvwidget控件播放。
  7. 支持h265视频流+rtmp等常见视频流。
  8. 可暂停播放和继续播放。
  9. 支持存储单个视频文件和定时存储视频文件。
  10. 自定义顶部悬浮条,发送单击信号通知,可设置是否启用。
  11. 可设置画面拉伸填充或者等比例填充。
  12. 可对视频进行截图(原始图片)和截屏。
  13. 录像文件存储MP4文件。
  14. 支持qsv、dxva2、d3d11va等硬解码。

三、效果图

在这里插入图片描述

四、相关站点

  1. 国内站点:https://gitee.com/feiyangqingyun/QWidgetDemo
  2. 国际站点:https://github.com/feiyangqingyun/QWidgetDemo
  3. 个人主页:https://blog.csdn.net/feiyangqingyun
  4. 知乎主页:https://www.zhihu.com/people/feiyangqingyun/
  5. 体验地址:https://blog.csdn.net/feiyangqingyun/article/details/97565652

五、核心代码

//事件处理
static void handleEvents(mpv_handle *mpvPlayer, mpv_event *event, MpvThread *thread)
{
    switch (event->event_id) {
        case MPV_EVENT_PROPERTY_CHANGE: {
            mpv_event_property *property = (mpv_event_property *)event->data;
            QString propertyName = property->name;
            mpv_format propertyFormat = property->format;
            if (propertyName == "duration") {
                //文件总长度
                if (propertyFormat == MPV_FORMAT_DOUBLE) {
                    double time = *(double *)property->data;
                    uint length = time * 1000;
                    thread->doEvent(1, QVariantList() << length);
                    qDebug() << TIMEMS << "文件总长: " << length;
                }
            } else if (propertyName == "time-pos") {
                //当前播放进度
                if (propertyFormat == MPV_FORMAT_DOUBLE) {
                    double time = *(double *)property->data;
                    uint position = time * 1000;
                    thread->doEvent(2, QVariantList() << position);
                    //qDebug() << TIMEMS << "当前时间: " << position;
                }
            } else {
                qDebug() << TIMEMS << propertyName;
                if (propertyFormat == MPV_FORMAT_NODE) {
#if 0
                    QVariant data = qtmpv::node_to_variant((mpv_node *)property->data);
                    QJsonDocument json = QJsonDocument::fromVariant(data);
                    qDebug() << TIMEMS << json.toJson().data();
#endif
                }
            }

            break;
        }

        //获取宽高
        case MPV_EVENT_VIDEO_RECONFIG: {
            //这里会执行两次,不知道为什么
            int dwidth, dheight;
            mpv_get_property(mpvPlayer, "dwidth", MPV_FORMAT_INT64, &dwidth);
            mpv_get_property(mpvPlayer, "dheight", MPV_FORMAT_INT64, &dheight);
            qDebug() << TIMEMS << "dwidth:" << dwidth << "dheight:" << dheight;
            break;
        }

        //打印日志
        case MPV_EVENT_LOG_MESSAGE: {
            struct mpv_event_log_message *msg = (struct mpv_event_log_message *)event->data;
            QString data = QString("[%1] %2: %3").arg(msg->prefix).arg(msg->level).arg(msg->text);
            data.replace("\r", "");
            data.replace("\n", "");
            //qDebug() << TIMEMS << data;
            break;
        }

        //文件播放结束
        case MPV_EVENT_END_FILE: {
            thread->doEvent(0, QVariantList());
            break;
        }

        default:
            break;
    }
}

//订阅事件
static void attachEvents(mpv_handle *mpvPlayer)
{
    mpv_observe_property(mpvPlayer, 0, "duration", MPV_FORMAT_DOUBLE);
    mpv_observe_property(mpvPlayer, 0, "time-pos", MPV_FORMAT_DOUBLE);
    mpv_observe_property(mpvPlayer, 0, "track-list", MPV_FORMAT_NODE);
    mpv_observe_property(mpvPlayer, 0, "chapter-list", MPV_FORMAT_NODE);
}

相关文章

  • Qt音视频开发15-mpv事件订阅

    一、前言 在使用libmpv的过程中,通过对mpv事件订阅,可以更准确和准时的得知一些事件,比如文件打开成功,播放...

  • Qt音视频开发30-Onvif事件订阅

    一、前言 能够接收摄像机的报警事件,比如几乎所有的摄像机后面会增加报警输入输出接口,如果用户外接了报警输入,则当触...

  • Qt音视频开发5-vlc事件订阅

    一、前言 事件订阅可以拿到文件长度、播放进度、播放状态改变等信息,vlc的事件订阅机制封装的比较友好,只需要先创建...

  • Mac BigSur OS 下 Qt安装以及集成ffmpeg 笔

    前言 最近在学习音视频开发技术,开发环境为Qt搭配ffmpeg进行音视频开发学习。虽然网上QT环境搭建教程有许多,...

  • 简易播放器设计文档

    EntryTask: 使用FFMpeg编写一个简单音视频播放器 开发环境 开发语言:C++ IDE:QT Crea...

  • QML Book 第三章 开发工具

    3. Qt Creator 集成开发环境 Qt Creator 是 Qt 的默认集成开发环境。它是由 Qt 开发人...

  • 一个 Qt 事件对象的旅行

    Qt 的事件来自操作系统,Qt自己产生。当Qt应用程序运行时,qt有一个未处理的事件队列,每个事件处理周期内,将处...

  • 《Qt5开发及实例》

    《Qt5开发及实例》Qt是诺基亚公司的C++可视化开发平台,目前最新版本为Qt 5。《Qt5开发及实例》以Qt 5...

  • Qt中事件的理解(1)

    1、Qt中的事件 Qt中,事件作为一个对象,继承自QEvent类,常见的有键盘事件QKeyEvent、鼠标事件QM...

  • Qt及Qt Quick开发实战精解

    Qt及Qt Quick开发实战精解主要讲解了5个Qt综合应用程序的开发过程和Qt Quick的相关内容。《Qt及Q...

网友评论

      本文标题:Qt音视频开发15-mpv事件订阅

      本文链接:https://www.haomeiwen.com/subject/hhhpjktx.html