一、前言

最开始接触视频监控这块的时候,用的就是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
  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

五、核心代码

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解码播放的更多相关文章

  1. Android 音视频深入 三 MP4解码播放视频 (附源码下载)

    本篇项目地址,名字是媒体解码MediaCodec,MediaExtractor,求starhttps://github.com/979451341/Audio-and-video-learning-m ...

  2. Android 音视频开发(一):PCM 格式音频的播放与采集

    什么是 PCM 格式 声音从模拟信号转化为数字信号的技术,经过采样.量化.编码三个过程将模拟信号数字化. 采样 顾名思义,对模拟信号采集样本,该过程是从时间上对信号进行数字化,例如每秒采集 44100 ...

  3. Android IOS WebRTC 音视频开发总结(八十五)-- 使用WebRTC广播网络摄像头视频(下)

    本文主要介绍WebRTC (我们翻译和整理的,译者:weizhenwei,校验:blacker),最早发表在[编风网] 支持原创,转载必须注明出处,欢迎关注我的微信公众号blacker(微信ID:bl ...

  4. Android音视频开发(1):H264 基本原理

    前言 H264 视频压缩算法现在无疑是所有视频压缩技术中使用最广泛,最流行的.随着 x264/openh264 以及 ffmpeg 等开源库的推出,大多数使用者无需再对H264的细节做过多的研究,这大 ...

  5. Android IOS WebRTC 音视频开发总结(八十三)-- 使用WebRTC广播网络摄像头视频(上)

    本文主要介绍WebRTC (我们翻译和整理的,译者:weizhenwei,校验:blacker),最早发表在[编风网] 支持原创,转载必须注明出处,欢迎关注我的微信公众号blacker(微信ID:bl ...

  6. Android IOS WebRTC 音视频开发总结(十九)-- kurento

    折腾了一个多星期终于将kurento的环境搭建好(开发阶段的产品,有些BUG要自己解决),所以单独写篇文件来介绍. 下面开始介绍kurento,文章来自博客园RTC.Blacker,转载请说明出处. ...

  7. Android WebRTC 音视频开发总结

    www.cnblogs.com/lingyunhu/p/3621057.html 前面介绍了WebRTCDemo的基本结构,本节主要介绍WebRTC音视频服务端的处理,,转载请说明出处(博客园RTC. ...

  8. WebRTC 音视频开发

    WebRTC 音视频开发 webrtc   Android IOS WebRTC 音视频开发总结(七八)-- 为什么WebRTC端到端监控很关键? 摘要: 本文主要介绍WebRTC端到端监控(我们翻译 ...

  9. Android 音视频开发学习思路

    Android 音视频开发这块目前的确没有比较系统的教程或者书籍,网上的博客文章也都是比较零散的.只能通过一点点的学习和积累把这块的知识串联积累起来. 初级入门篇: Android 音视频开发(一) ...

  10. 转:Android IOS WebRTC 音视频开发总结 (系列文章集合)

    随笔分类 - webrtc   Android IOS WebRTC 音视频开发总结(七八)-- 为什么WebRTC端到端监控很关键? 摘要: 本文主要介绍WebRTC端到端监控(我们翻译和整理的,译 ...

随机推荐

  1. rancher发布nacos server docker 失败

    使用rancher发布nacos server 时报错 进入镜像查看日志发现报错No DataSource set 检查了好几遍环境变量已经全都配了,最后发现在nohup.out文件中指出没有找到na ...

  2. Monaco Editor 实现一个日志查看器

    我们是袋鼠云数栈 UED 团队,致力于打造优秀的一站式数据中台产品.我们始终保持工匠精神,探索前端道路,为社区积累并传播经验价值. 本文作者:文长 前言 在 Web IDE 中,控制台中展示日志是至关 ...

  3. Ubuntu自动连接到虚拟专用网络

    在我们继续之前,我们所做的一个重要假设是,您已经拥有了虚拟专用网络客户端配置文件. 您可以通过以下链接在我们的上一指南中看到一个示例 Open虚拟专用网络 客户端配置文件: 在 CentOS 8/乌本 ...

  4. Shell简单入门程序参考

    目录 0 前言 0.1 shell初试 1 程序功能 1.1 显示当前主机名和IP地址. 1.1.1 if 语句 详解 1.2 创建目录或者文件 1.3 修改文件属性 1.3.1 chmod 修改文件 ...

  5. docker新建自定义网桥,实现不同主机容器互联

    不同主机间的容器网络互联,网络上的所有教程都是通过open vswitch等虚拟网桥方式实现的,但是最近本人发现可以直接通过配置网桥实现网络的互联,而不用安装配置open vswitch.在这里分享一 ...

  6. 题解:CF1015D Walking Between Houses

    题解:CF1015D Walking Between Houses 算法 模拟,分类讨论 分析 首先,设每步走的距离为 \(t_i\),我们发现 \(t_i\) 应是满足 \(1\le t_i\le ...

  7. 鸿蒙NEXT开发案例:年龄计算

    ​ [引言] 本案例的目标是开发一款年龄计算器应用,该应用能够根据用户输入的出生日期,计算出用户的实际年龄.虚岁.星座.生肖等信息.同时,应用还将提供距离下次公历和农历生日的天数及星期等信息.为了实现 ...

  8. 《Django 5 By Example》阅读笔记:p679-p765

    <Django 5 By Example>学习第10天,p679-p765总结,总计87页. 一.技术总结 1.channel 书里通过聊天软件功能演示Django中channel以及异步 ...

  9. 数据抽取平台pydatax使用案例---11个库项目使用

    数据抽取平台pydatax,前期项目做过介绍: 1,数据抽取平台pydatax介绍--实现和项目使用 项目2: 客户有9个分公司,用的ERP有9套,有9个库,不同版本,抽取的同一个表字段长度有不一样, ...

  10. 使用<a-select>时,placeholder不起作用

    当绑定v-model的值之后,placeholder设置的值不起作用,此时需要把v-model绑定的值设置为undefined就可以了