Qt音视频开发1-vlc解码播放
一、前言
最开始接触视频监控这块的时候,用的就是vlc作为解码的内核,主要是因为vlc使用简单方便,直接传入一个句柄即可,简单几行代码就可以实现一个视频流播放,很适合初学者使用,也推荐初学者用qt+vlc来做播放器,提供的接口还是非常友好的,而且门类特别多,想要获取媒体文件的各种信息比如宽高,设置宽高比等,直接调用接口函数传入参数就能设置。
所有用vlc做视频监控解码的人都会遇到一个问题,那就是鼠标事件被接管拦截了,不能识别鼠标事件,比如双击最大化等,这就很憋屈了,明明很好用的一个东西,怎么突然之间鼠标事件也识别不到了呢,网上一搜一大把,主要有三个解决办法。
- 修改vlc源码,重新编译,替换动态库文件。
- 全局鼠标钩子拦截鼠标消息进行处理。
- 设置句柄以后直接将控件/接受视频渲染的控件禁用掉。
最终采用方法3,实现起来简单快速,修改vlc源码的编译工作量太大了,毕竟vlc依赖一大堆的插件,用vlc的人一般都是初学者半吊子,哪里有能力去编译一遍vlc哦。
二、功能特点
- 多线程实时播放视频流和本地视频。
- 支持windows+linux+mac,支持vlc2和vlc3。
- 多线程显示图像,不卡主界面。
- 自动重连网络摄像头。
- 可设置边框大小即偏移量和边框颜色。
- 可设置是否绘制OSD标签即标签文本或图片和标签位置。
- 可设置两种OSD位置和风格。
- 可设置是否保存到文件以及文件名。
- 可直接拖曳文件到vlcwidget控件播放。
- 支持h265视频流+rtmp等常见视频流。
- 可暂停播放和继续播放。
- 支持回调模式和句柄两种模式。
- 支持线程读取进度等信息和事件回调两种处理模式。
- 自动将当前播放位置和音量大小是否静音以信号发出去。
- 提供接口设置播放位置和音量及设置静音。
- 支持存储单个视频文件和定时存储视频文件。
- 自定义顶部悬浮条,发送单击信号通知,可设置是否启用。
三、效果图

四、相关站点
- 国内站点:https://gitee.com/feiyangqingyun/QWidgetDemo
- 国际站点:https://github.com/feiyangqingyun/QWidgetDemo
- 个人主页:https://blog.csdn.net/feiyangqingyun
- 知乎主页:https://www.zhihu.com/people/feiyangqingyun/
- 体验地址: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;
}
Qt音视频开发1-vlc解码播放的更多相关文章
- Android 音视频深入 三 MP4解码播放视频 (附源码下载)
本篇项目地址,名字是媒体解码MediaCodec,MediaExtractor,求starhttps://github.com/979451341/Audio-and-video-learning-m ...
- Android 音视频开发(一):PCM 格式音频的播放与采集
什么是 PCM 格式 声音从模拟信号转化为数字信号的技术,经过采样.量化.编码三个过程将模拟信号数字化. 采样 顾名思义,对模拟信号采集样本,该过程是从时间上对信号进行数字化,例如每秒采集 44100 ...
- Android IOS WebRTC 音视频开发总结(八十五)-- 使用WebRTC广播网络摄像头视频(下)
本文主要介绍WebRTC (我们翻译和整理的,译者:weizhenwei,校验:blacker),最早发表在[编风网] 支持原创,转载必须注明出处,欢迎关注我的微信公众号blacker(微信ID:bl ...
- Android音视频开发(1):H264 基本原理
前言 H264 视频压缩算法现在无疑是所有视频压缩技术中使用最广泛,最流行的.随着 x264/openh264 以及 ffmpeg 等开源库的推出,大多数使用者无需再对H264的细节做过多的研究,这大 ...
- Android IOS WebRTC 音视频开发总结(八十三)-- 使用WebRTC广播网络摄像头视频(上)
本文主要介绍WebRTC (我们翻译和整理的,译者:weizhenwei,校验:blacker),最早发表在[编风网] 支持原创,转载必须注明出处,欢迎关注我的微信公众号blacker(微信ID:bl ...
- Android IOS WebRTC 音视频开发总结(十九)-- kurento
折腾了一个多星期终于将kurento的环境搭建好(开发阶段的产品,有些BUG要自己解决),所以单独写篇文件来介绍. 下面开始介绍kurento,文章来自博客园RTC.Blacker,转载请说明出处. ...
- Android WebRTC 音视频开发总结
www.cnblogs.com/lingyunhu/p/3621057.html 前面介绍了WebRTCDemo的基本结构,本节主要介绍WebRTC音视频服务端的处理,,转载请说明出处(博客园RTC. ...
- WebRTC 音视频开发
WebRTC 音视频开发 webrtc Android IOS WebRTC 音视频开发总结(七八)-- 为什么WebRTC端到端监控很关键? 摘要: 本文主要介绍WebRTC端到端监控(我们翻译 ...
- Android 音视频开发学习思路
Android 音视频开发这块目前的确没有比较系统的教程或者书籍,网上的博客文章也都是比较零散的.只能通过一点点的学习和积累把这块的知识串联积累起来. 初级入门篇: Android 音视频开发(一) ...
- 转:Android IOS WebRTC 音视频开发总结 (系列文章集合)
随笔分类 - webrtc Android IOS WebRTC 音视频开发总结(七八)-- 为什么WebRTC端到端监控很关键? 摘要: 本文主要介绍WebRTC端到端监控(我们翻译和整理的,译 ...
随机推荐
- rancher发布nacos server docker 失败
使用rancher发布nacos server 时报错 进入镜像查看日志发现报错No DataSource set 检查了好几遍环境变量已经全都配了,最后发现在nohup.out文件中指出没有找到na ...
- Monaco Editor 实现一个日志查看器
我们是袋鼠云数栈 UED 团队,致力于打造优秀的一站式数据中台产品.我们始终保持工匠精神,探索前端道路,为社区积累并传播经验价值. 本文作者:文长 前言 在 Web IDE 中,控制台中展示日志是至关 ...
- Ubuntu自动连接到虚拟专用网络
在我们继续之前,我们所做的一个重要假设是,您已经拥有了虚拟专用网络客户端配置文件. 您可以通过以下链接在我们的上一指南中看到一个示例 Open虚拟专用网络 客户端配置文件: 在 CentOS 8/乌本 ...
- Shell简单入门程序参考
目录 0 前言 0.1 shell初试 1 程序功能 1.1 显示当前主机名和IP地址. 1.1.1 if 语句 详解 1.2 创建目录或者文件 1.3 修改文件属性 1.3.1 chmod 修改文件 ...
- docker新建自定义网桥,实现不同主机容器互联
不同主机间的容器网络互联,网络上的所有教程都是通过open vswitch等虚拟网桥方式实现的,但是最近本人发现可以直接通过配置网桥实现网络的互联,而不用安装配置open vswitch.在这里分享一 ...
- 题解:CF1015D Walking Between Houses
题解:CF1015D Walking Between Houses 算法 模拟,分类讨论 分析 首先,设每步走的距离为 \(t_i\),我们发现 \(t_i\) 应是满足 \(1\le t_i\le ...
- 鸿蒙NEXT开发案例:年龄计算
[引言] 本案例的目标是开发一款年龄计算器应用,该应用能够根据用户输入的出生日期,计算出用户的实际年龄.虚岁.星座.生肖等信息.同时,应用还将提供距离下次公历和农历生日的天数及星期等信息.为了实现 ...
- 《Django 5 By Example》阅读笔记:p679-p765
<Django 5 By Example>学习第10天,p679-p765总结,总计87页. 一.技术总结 1.channel 书里通过聊天软件功能演示Django中channel以及异步 ...
- 数据抽取平台pydatax使用案例---11个库项目使用
数据抽取平台pydatax,前期项目做过介绍: 1,数据抽取平台pydatax介绍--实现和项目使用 项目2: 客户有9个分公司,用的ERP有9套,有9个库,不同版本,抽取的同一个表字段长度有不一样, ...
- 使用<a-select>时,placeholder不起作用
当绑定v-model的值之后,placeholder设置的值不起作用,此时需要把v-model绑定的值设置为undefined就可以了