Qt音视频开发43-采集屏幕桌面并推流(支持分辨率/矩形区域/帧率等设置/实时性极高)
一、前言
采集电脑屏幕桌面并推流一般是用来做共享桌面、远程协助、投屏之类的应用,最简单入门的做法可能会采用开个定时器或者线程抓图,将整个屏幕截图下来,然后将图片传出去,这种方式很简单但是性能要低不少,一般采用ffmpeg来做桌面推流的居多,毕竟如果不采用代码直接ffmpeg一行命令即可(ffmpeg -f gdigrab -r 30 -i desktop -vcodec libx264 -preset:v ultrafast -tune:v zerolatency -f rtsp -g 5 -an rtsp://192.168.0.110:6907/stream), 最起码这个还没开始写代码直接就可以体验起来这个感觉很好。很多开源项目,就因为无法保证直接编译就能跑起来,导致熄火,都跑不起来何来的看下去的兴趣,尤其是初学者而言更是如此。
采集大致步骤:
- 查找格式 av_find_input_format,参数 gdigrab/x11grab/avfoundation
- 打开桌面 avformat_open_input,参数 desktop
- 查找视频流 av_find_best_stream
- 查找解码器 avcodec_find_decoder
- 打开解码器 avcodec_open2
- 循环读取 av_read_frame
- 解码视频 avcodec_send_packet/avcodec_receive_frame
- 关闭释放 avcodec_free_context/avformat_close_input
推流大致步骤:
- 创建输出 avformat_alloc_output_context2
- 创建视频流 avformat_new_stream
- 打开输出 avio_open,参数填推流完整地址
- 写入开始符 avformat_write_header
- 写入帧数据 av_interleaved_write_frame
- 关闭释放 avio_close/avformat_free_context
二、效果图
三、体验地址
- 国内站点:https://gitee.com/feiyangqingyun
- 国际站点:https://github.com/feiyangqingyun
- 个人作品:https://blog.csdn.net/feiyangqingyun/article/details/97565652
- 体验地址:https://pan.baidu.com/s/1d7TH_GEYl5nOecuNlWJJ7g 提取码:01jf 文件名:bin_video_push。
四、相关代码
void FFmpegThread::initInputFormat()
{
//本地摄像头/桌面录屏
if (videoType == VideoType_Camera) {
#if defined(Q_OS_WIN)
//ifmt = av_find_input_format("vfwcap");
ifmt = av_find_input_format("dshow");
#elif defined(Q_OS_LINUX)
//可以打开cheese程序查看本地摄像头(如果是在虚拟机中需要设置usb选项3.1)
//ifmt = av_find_input_format("v4l2");
ifmt = av_find_input_format("video4linux2");
#elif defined(Q_OS_MAC)
ifmt = av_find_input_format("avfoundation");
#endif
} else if (videoType == VideoType_Desktop) {
#if defined(Q_OS_WIN)
ifmt = av_find_input_format("gdigrab");
#elif defined(Q_OS_LINUX)
ifmt = av_find_input_format("x11grab");
#elif defined(Q_OS_MAC)
ifmt = av_find_input_format("avfoundation");
#endif
}
}
bool FFmpegThread::initInput()
{
//实例化格式处理上下文
formatCtx = avformat_alloc_context();
//设置超时回调(有些不存在的地址或者网络不好的情况下要卡很久)
formatCtx->interrupt_callback.callback = FFmpegHelper::avinterruptCallBackFun;
formatCtx->interrupt_callback.opaque = this;
//打开输入(通过标志位控制回调那边做超时判断)
//其他地方调用 formatCtx->url formatCtx->filename 可以拿到设置的地址(两个变量值一样)
tryOpen = true;
QByteArray urlData = VideoHelper::getRightUrl(videoType, videoUrl).toUtf8();
int result = avformat_open_input(&formatCtx, urlData.data(), ifmt, &options);
tryOpen = false;
if (result < 0) {
debug("打开出错", "错误: " + FFmpegHelper::getError(result));
return false;
}
//根据自己项目需要开启下面部分代码加快视频流打开速度
//开启后由于值太小可能会出现部分视频流获取不到分辨率
if (decodeType == DecodeType_Fastest && videoType == VideoType_Rtsp) {
//接口内部读取的最大数据量(从源文件中读取的最大字节数)
//默认值5000000导致这里卡很久最耗时(可以调小来加快打开速度)
formatCtx->probesize = 50000;
//从文件中读取的最大时长(单位为 AV_TIME_BASE units)
formatCtx->max_analyze_duration = 5 * AV_TIME_BASE;
//内部读取的数据包不放入缓冲区
//formatCtx->flags |= AVFMT_FLAG_NOBUFFER;
//设置解码错误验证过滤花屏
//formatCtx->error_recognition |= AV_EF_EXPLODE;
}
//获取流信息
result = avformat_find_stream_info(formatCtx, NULL);
if (result < 0) {
debug("找流失败", "错误: " + FFmpegHelper::getError(result));
return false;
}
//解码格式
formatName = formatCtx->iformat->name;
//某些格式比如视频流不做音视频同步(响应速度快)
if (formatName == "rtsp" || videoUrl.endsWith(".sdp")) {
useSync = false;
}
//设置了最快速度则不启用音视频同步
if (decodeType == DecodeType_Fastest) {
useSync = false;
}
//有些格式不支持硬解码
if (formatName.contains("rm") || formatName.contains("avi") || formatName.contains("webm")) {
hardware = "none";
}
//本地摄像头设备解码出来的直接就是yuv显示不需要硬解码
if (videoType == VideoType_Camera || videoType == VideoType_Desktop) {
useSync = false;
hardware = "none";
}
//过低版本不支持硬解码
#if (FFMPEG_VERSION_MAJOR < 3)
hardware = "none";
#endif
//获取文件时长(这里获取到的是秒)
double length = (double)formatCtx->duration / AV_TIME_BASE;
duration = length * 1000;
this->checkVideoType();
//有时候网络地址也可能是纯音频
if (videoType == VideoType_FileHttp) {
onlyAudio = VideoHelper::getOnlyAudio(videoUrl, formatName);
}
if (getIsFile()) {
//文件必须要音视频同步
useSync = true;
//发送文件时长信号
emit receiveDuration(duration > 0 ? duration : 0);
}
QString msg = QString("格式: %1 时长: %2 秒 加速: %3").arg(formatName).arg(duration / 1000).arg(hardware);
debug("媒体信息", msg);
return true;
}
五、功能特点
5.1 文件推流
- 指定网卡和监听端口,接收网络请求推送音视频等各种文件。
- 实时统计显示每个文件对应的访问数量、总访问数量、不同IP地址访问数量。
- 可指定多种模式,0-直接播放、1-下载播放。
- 实时打印显示各种收发请求和应答数据。
- 每个文件对应MD5加密的唯一标识符,用于请求地址后缀区分访问哪个文件。
- 支持各种浏览器(谷歌chromium/微软edge/火狐firefox等)、各种播放器(vlc/mpv/ffplay/potplayer/mpchc等)打开请求。
- 播放过程中可以任意切换播放进度,支持倍速播放。
- 需要推流的文件名称历史记录自动存储和打开加载应用。
- 切换文件获取访问地址,自动拷贝地址到剪切板方便直接粘贴测试使用。
- 极低CPU占用,128路1080P同时推流不到1%CPU占用,异步发送数据机制。
- 纯QTcpSocket通信,不依赖流媒体服务程序,核心源码不到500行,注释详细,功能完整。
- 支持Qt4/Qt5/Qt6任意版本,支持任意系统(windows/linux/macos/android/嵌入式linux等)。
5.2 网络推流
- 支持各种本地视频文件和网络视频文件。
- 支持各种网络视频流,网络摄像头,协议包括rtsp、rtmp、http。
- 支持将本地摄像头设备推流,可指定分辨率和帧率等。
- 支持将本地桌面推流,可指定屏幕区域和帧率等。
- 自动启动流媒体服务程序,默认mediamtx(原rtsp-simple-server),可选用srs、EasyDarwin、LiveQing、ZLMediaKit等。
- 可实时切换预览视频文件。
- 推流的清晰度和质量可调。
- 可动态添加文件、目录、地址。
- 视频文件自动循环推流,如果视频源是视频流,在掉线后会自动重连。
- 网络视频流自动重连,重连成功自动继续推流。
- 网络视频流实时性极高,延迟极低,延迟时间大概在100ms左右。
- 推流后除了用rtmp地址访问以外,还支持直接hls/webrtc访问,可以直接浏览器打开看实时画面。
- 支持Qt4/Qt5/Qt6任意版本,支持任意系统(windows/linux/macos/android/嵌入式linux等)。
Qt音视频开发43-采集屏幕桌面并推流(支持分辨率/矩形区域/帧率等设置/实时性极高)的更多相关文章
- Android 音视频开发(一):PCM 格式音频的播放与采集
什么是 PCM 格式 声音从模拟信号转化为数字信号的技术,经过采样.量化.编码三个过程将模拟信号数字化. 采样 顾名思义,对模拟信号采集样本,该过程是从时间上对信号进行数字化,例如每秒采集 44100 ...
- Android WebRTC 音视频开发总结
www.cnblogs.com/lingyunhu/p/3621057.html 前面介绍了WebRTCDemo的基本结构,本节主要介绍WebRTC音视频服务端的处理,,转载请说明出处(博客园RTC. ...
- WebRTC 音视频开发
WebRTC 音视频开发 webrtc Android IOS WebRTC 音视频开发总结(七八)-- 为什么WebRTC端到端监控很关键? 摘要: 本文主要介绍WebRTC端到端监控(我们翻译 ...
- 转:Android IOS WebRTC 音视频开发总结 (系列文章集合)
随笔分类 - webrtc Android IOS WebRTC 音视频开发总结(七八)-- 为什么WebRTC端到端监控很关键? 摘要: 本文主要介绍WebRTC端到端监控(我们翻译和整理的,译 ...
- Android开发 音视频开发需要了解的专业术语知识
前言 在摸索一段时间的音视频开发后,越来越发现这个坑的深度真是特别的深. 除了了解Android自带的音视频处理API以外,还得了解一些视频与音频方面的知识.这篇博客就是主要讲解这方面的专业术语.内容 ...
- Android IOS WebRTC 音视频开发总结(八十五)-- 使用WebRTC广播网络摄像头视频(下)
本文主要介绍WebRTC (我们翻译和整理的,译者:weizhenwei,校验:blacker),最早发表在[编风网] 支持原创,转载必须注明出处,欢迎关注我的微信公众号blacker(微信ID:bl ...
- Android IOS WebRTC 音视频开发总结(五七)-- 网络传输上的一种QoS方案
本文主要介绍一种QoS的解决方案,文章来自博客园RTC.Blacker,欢迎关注微信公众号blacker,更多详见www.rtc.help QoS出现的背景: 而当网络发生拥塞的时候,所有的数据流都有 ...
- Android IOS WebRTC 音视频开发总结(十九)-- kurento
折腾了一个多星期终于将kurento的环境搭建好(开发阶段的产品,有些BUG要自己解决),所以单独写篇文件来介绍. 下面开始介绍kurento,文章来自博客园RTC.Blacker,转载请说明出处. ...
- Android 音视频开发学习思路
Android 音视频开发这块目前的确没有比较系统的教程或者书籍,网上的博客文章也都是比较零散的.只能通过一点点的学习和积累把这块的知识串联积累起来. 初级入门篇: Android 音视频开发(一) ...
- Android 音视频开发(一) : 通过三种方式绘制图片
版权声明:转载请说明出处:http://www.cnblogs.com/renhui/p/7456956.html 在 Android 音视频开发学习思路 里面,我们写到了,想要逐步入门音视频开发,就 ...
随机推荐
- 带你一起看看nginx如何部署安装
nginx部署安装 Linux安装 源码构建Nginx 管理器安装 windows安装 首先需要下载Nginx软件包 nginx软件官方下载地址: nginx官方下载连接 建议选择稳定的软件版本,如果 ...
- 无需等待Vue Release发布,就能在项目中体验最新版
前言 两个月前尤大在Vue 仓库中引入了 pkg.pr.new,有了这个后Vue仓库中的每个commit或者PR都会自动触发一个新的发布,我们就可以在项目中体验最新版本的Vue啦. 关注公众号:[前端 ...
- esp8266+MQTT+DHT11(温湿度计) platformio
esp8266 + MQTT + DHT11(温湿度计) 连线 #include <Arduino.h> #include <ESP8266WiFi.h> #include & ...
- Java常见面试真题之中级进阶
前言 本来想着给自己放松一下,刷刷博客,突然被几道面试题难倒!java反射的作用于原理?说说List,Set,Map三者的区别?Object 有哪些常用方法?大致说一下每个方法的含义?Java 创建对 ...
- 二元一次不定方程(Exgcd)(更方便的解法)
扩展欧几里得算法(Exgcd) 裴蜀定理 对于任意一组整数 \(a,b\),存在一组整数 \(x,y\),满足 \(ax+by=\gcd(a,b)\). Proof: 考虑数学归纳法. 当 \(b=0 ...
- .NET操作Excel高效低内存的开源框架 - MiniExcel
.Net平台上对Excel进行操作主要有两种方式.第一种,把Excel文件看成一个数据库,通过OleDb的方式进行读取与操作:第二种,调用Excel的COM组件.两种方式各有特点. 今天给大家介绍第三 ...
- 【Linux Ops】如何无痛升级 glibc
[环境]kos5.8sp2, kernel5.10 最近工作中需要搭建一个软件环境,其依赖的 glibc 版本较高,因此在安装时给出了以下错误: xxx: /lib64/libc.so.6: vers ...
- 敏捷开发:Scrum 中的 Product Backlog 介绍
Product Backlog 产品待办列表 在计划开发产品功能时,都希望产品功能上线后,用户能够喜欢并经常使用. 因此在开发产品新功能时,就要衡量哪些产品需求是对用户最有价值,这是最应该思考的问题. ...
- sql注入--学习笔记_1
实验室 sql sql可以对数据库进行访问和处理:取回数据,删除数据.web页面会使用这些. SQL 能做什么? SQL 面向数据库执行查询 SQL 可从数据库取回数据 SQL 可在数据库中插入新的记 ...
- Java深度历险(三)——Java线程:基本概念、可见性与同步
开发高性能并发应用不是一件容易的事情.这类应用的例子包括高性能Web服务器.游戏服务器和搜索引擎爬虫等.这样的应用可能需要同时处理成千上万个请求.对于这样的应用,一般采用多线程或事件驱动的架构.对于J ...