百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

Qt音视频开发1-vlc解码播放(qt视频文件怎么打开)

zhezhongyun 2025-04-02 00:26 53 浏览

## 一、前言

最开始接触视频监控这块的时候,用的就是vlc作为解码的内核,主要是因为vlc使用简单方便,直接传入一个句柄即可,简单几行代码就可以实现一个视频流播放,很适合初学者使用,也推荐初学者用qt+vlc来做播放器,提供的接口还是非常友好的,而且门类特别多,想要获取媒体文件的各种信息比如宽高,设置宽高比等,直接调用接口函数传入参数就能设置。

所有用vlc做视频监控解码的人都会遇到一个问题,那就是鼠标事件被接管拦截了,不能识别鼠标事件,比如双击最大化等,这就很憋屈了,明明很好用的一个东西,怎么突然之间鼠标事件也识别不到了呢,网上一搜一大把,主要有三个解决办法。

1. 修改vlc源码,重新编译,替换动态库文件。

2. 全局鼠标钩子拦截鼠标消息进行处理。

3. 设置句柄以后直接将控件/接受视频渲染的控件禁用掉。

最终采用方法3,实现起来简单快速,修改vlc源码的编译工作量太大了,毕竟vlc依赖一大堆的插件,用vlc的人一般都是初学者半吊子,哪里有能力去编译一遍vlc哦。

## 二、功能特点

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

2. 支持windows+linux+mac,支持vlc2和vlc3。

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

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

5. 可设置边框大小即偏移量和边框颜色。

6. 可设置是否绘制OSD标签即标签文本或图片和标签位置。

7. 可设置两种OSD位置和风格。

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

9. 可直接拖曳文件到vlcwidget控件播放。

10. 支持h265视频流+rtmp等常见视频流。

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

12. 支持回调模式和句柄两种模式。

13. 支持线程读取进度等信息和事件回调两种处理模式。

14. 自动将当前播放位置和音量大小是否静音以信号发出去。

15. 提供接口设置播放位置和音量及设置静音。

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

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

## 三、效果图



## 四、相关站点

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)

## 五、核心代码

bool VlcThread::init()
{
    //判断该摄像机是否能联通
    if (checkConn && isRtsp) {
        if (!checkUrl(url, checkTime)) {
            return false;
        }
    }

    QFileInfo info(url);
    suffix = info.suffix();

    //设置拓展名
    if (url.startsWith("dshow://")) {
        suffix = "dshow";
    } else if (url.startsWith("rtsp")) {
        suffix = "rtsp";
    } else if (url.startsWith("rtmp")) {
        suffix = "rtmp";
    } else if (url.startsWith("http")) {
        suffix = "http";
    }

    const char *tempArg = "";
    if (suffix == "h264") {
        tempArg = "--demux=h264";
    } else if (suffix == "h265") {
        tempArg = "--demux=h265";
    }

    const char *vlc_args[9] = {"-I", "dummy", "--no-osd", "--no-stats", "--ignore-config", "--no-video-on-top", "--no-video-title-show", "--no-snapshot-preview", tempArg};
    vlcInst = libvlc_new(sizeof(vlc_args) / sizeof(vlc_args[0]), vlc_args);
    if (vlcInst == NULL) {
        return false;
    }

    if (isRtsp || suffix == "dshow") {
        vlcMedia = libvlc_media_new_location(vlcInst, url.toUtf8().constData());
    } else {
        //windows上需要替换文件路径
        QString url = this->url;
        url = QDir::toNativeSeparators(url);
        vlcMedia = libvlc_media_new_path(vlcInst, url.toUtf8().constData());
    }

    if (vlcMedia == NULL) {
        return false;
    }

    //媒体播放对象
    vlcPlayer = libvlc_media_player_new_from_media(vlcMedia);
    if (vlcPlayer == NULL) {
        return false;
    }

    //创建事件管理器
    if (callbackevent) {
        vlcEvent = libvlc_media_player_event_manager(vlcPlayer);
        libvlc_event_new(vlcEvent, this);
    }

    //回调方式和句柄方式两种分别处理
    if (callback) {
        callbackData = new CallbackData;
        callbackData->thread = this;
        callbackData->pixels = new uchar[bufferWidth * bufferHeight * 4];
        memset(callbackData->pixels, 0, bufferWidth * bufferHeight * 4);

        int width = callbackData->thread->getBufferWidth();
        int height = callbackData->thread->getBufferHeight();

        //设置回调拿到每帧数据
        libvlc_video_set_callbacks(vlcPlayer, lock, unlock, display, callbackData);
        //设置每帧格式 RV32-Format_RGB32  RGBA-Format_RGBA8888 YUYV I420
        libvlc_video_set_format(vlcPlayer, "RV32", width, height, width * 4);
    } else {
        //设置播放句柄
        if (playWidget == NULL) {
            return false;
        }

#if defined(Q_OS_WIN)
        libvlc_media_player_set_hwnd(vlcPlayer, (void *)playWidget->winId());
#elif defined(Q_OS_LINUX)
        libvlc_media_player_set_xwindow(vlcPlayer, playWidget->winId());
#elif defined(Q_OS_MAC)
        libvlc_media_player_set_nsobject(vlcPlayer, (void *)playWidget->winId());
#endif

        //禁用句柄鼠标消息
        QTimer::singleShot(1000, this, SLOT(disableHwnd()));
    }

    //设置硬件加速 none auto any d3d11va dxva2
    setOption(QString(":avcodec-hw=%1").arg(hardware));
    //设置通信协议 tcp udp
    setOption(QString(":rtsp-%1").arg(transport));
    //设置缓存时间 默认500毫秒
    setOption(QString(":network-caching=%1").arg(caching));
    //:rtsp-frame-buffer-size=1000000

    //设置宽度高度,本地USB摄像头需要单独设置
    if (suffix == "dshow") {
        setOption(QString(":dshow-size=%1*%2").arg(videoWidth).arg(videoHeight));
    } else {
        setSize(videoWidth, videoHeight);
    }

    //设置保存文件
    this->initSave();
    //打开播放
    libvlc_media_player_play(vlcPlayer);

    //qDebug() << TIMEMS << "init vlc finsh";
    return true;
}

相关推荐

Python入门学习记录之一:变量_python怎么用变量

写这个,主要是对自己学习python知识的一个总结,也是加深自己的印象。变量(英文:variable),也叫标识符。在python中,变量的命名规则有以下三点:>变量名只能包含字母、数字和下划线...

python变量命名规则——来自小白的总结

python是一个动态编译类编程语言,所以程序在运行前不需要如C语言的先行编译动作,因此也只有在程序运行过程中才能发现程序的问题。基于此,python的变量就有一定的命名规范。python作为当前热门...

Python入门学习教程:第 2 章 变量与数据类型

2.1什么是变量?在编程中,变量就像一个存放数据的容器,它可以存储各种信息,并且这些信息可以被读取和修改。想象一下,变量就如同我们生活中的盒子,你可以把东西放进去,也可以随时拿出来看看,甚至可以换成...

绘制学术论文中的“三线表”具体指导

在科研过程中,大家用到最多的可能就是“三线表”。“三线表”,一般主要由三条横线构成,当然在变量名栏里也可以拆分单元格,出现更多的线。更重要的是,“三线表”也是一种数据记录规范,以“三线表”形式记录的数...

Python基础语法知识--变量和数据类型

学习Python中的变量和数据类型至关重要,因为它们构成了Python编程的基石。以下是帮助您了解Python中的变量和数据类型的分步指南:1.变量:变量在Python中用于存储数据值。它们充...

一文搞懂 Python 中的所有标点符号

反引号`无任何作用。传说Python3中它被移除是因为和单引号字符'太相似。波浪号~(按位取反符号)~被称为取反或补码运算符。它放在我们想要取反的对象前面。如果放在一个整数n...

Python变量类型和运算符_python中变量的含义

别再被小名词坑哭了:Python新手常犯的那些隐蔽错误,我用同事的真实bug拆给你看我记得有一次和同事张姐一起追查一个看似随机崩溃的脚本,最后发现罪魁祸首竟然是她把变量命名成了list。说实话...

从零开始:深入剖析 Spring Boot3 中配置文件的加载顺序

在当今的互联网软件开发领域,SpringBoot无疑是最为热门和广泛应用的框架之一。它以其强大的功能、便捷的开发体验,极大地提升了开发效率,成为众多开发者构建Web应用程序的首选。而在Spr...

Python中下划线 ‘_’ 的用法,你知道几种

Python中下划线()是一个有特殊含义和用途的符号,它可以用来表示以下几种情况:1在解释器中,下划线(_)表示上一个表达式的值,可以用来进行快速计算或测试。例如:>>>2+...

解锁Shell编程:变量_shell $变量

引言:开启Shell编程大门Shell作为用户与Linux内核之间的桥梁,为我们提供了强大的命令行交互方式。它不仅能执行简单的文件操作、进程管理,还能通过编写脚本实现复杂的自动化任务。无论是...

一文学会Python的变量命名规则!_python的变量命名有哪些要求

目录1.变量的命名原则3.内置函数尽量不要做变量4.删除变量和垃圾回收机制5.结语1.变量的命名原则①由英文字母、_(下划线)、或中文开头②变量名称只能由英文字母、数字、下画线或中文字所组成。③英文字...

更可靠的Rust-语法篇-区分语句/表达式,略览if/loop/while/for

src/main.rs://函数定义fnadd(a:i32,b:i32)->i32{a+b//末尾表达式}fnmain(){leta:i3...

C++第五课:变量的命名规则_c++中变量的命名规则

变量的命名不是想怎么起就怎么起的,而是有一套固定的规则的。具体规则:1.名字要合法:变量名必须是由字母、数字或下划线组成。例如:a,a1,a_1。2.开头不能是数字。例如:可以a1,但不能起1a。3....

Rust编程-核心篇-不安全编程_rust安全性

Unsafe的必要性Rust的所有权系统和类型系统为我们提供了强大的安全保障,但在某些情况下,我们需要突破这些限制来:与C代码交互实现底层系统编程优化性能关键代码实现某些编译器无法验证的安全操作Rus...

探秘 Python 内存管理:背后的神奇机制

在编程的世界里,内存管理就如同幕后的精密操控者,确保程序的高效运行。Python作为一种广泛使用的编程语言,其内存管理机制既巧妙又复杂,为开发者们提供了便利的同时,也展现了强大的底层控制能力。一、P...