Qt音视频开发44-本地摄像头推流(支持分辨率/帧率等设置/实时性极高)
一、前言
本地摄像头推流和本地桌面推流类似,无非就是采集的设备源头换成了本地摄像头设备而不是桌面,其他代码完全一样。采集本地摄像头实时视频要注意的是如果设置分辨率和帧率,一定要是设备本身就支持的,如果不支持那就歇菜,比如设备本身最大分辨率到1280x720,你主动设置要采集1080x720分辨率的图像,那是采集不到的,会失败的,如果默认不设置,一般会采用640x480分辨率以及25帧率去采集。采集本地摄像头设备命令行是 ffmpeg -f dshow -i video="USB Video Device":audio="麦克风 (USB Audio Device)" -vcodec libx264 -preset:v ultrafast -tune:v zerolatency -f rtsp rtsp://192.168.0.110:6907/stream ,可以指定带上麦克风,这样音视频都有。
采集大致步骤:
- 查找格式 av_find_input_format,参数 dshow/v4l2/avfoundation
 - 打开桌面 avformat_open_input,参数 video=USB Video Device
 - 查找视频流 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音视频开发44-本地摄像头推流(支持分辨率/帧率等设置/实时性极高)的更多相关文章
- Android IOS WebRTC 音视频开发总结(六二)-- 大数据解密国外实时通讯行业开发现状
		
本文主要介绍国外实时通讯行业现状,文章最早发表在我们的微信公众号上,详见这里,欢迎关注微信公众号blackerteam,更多详见www.blackerteam.com 上篇文章我们采用百度搜索指数来分 ...
 - WebRTC 音视频开发
		
WebRTC 音视频开发 webrtc Android IOS WebRTC 音视频开发总结(七八)-- 为什么WebRTC端到端监控很关键? 摘要: 本文主要介绍WebRTC端到端监控(我们翻译 ...
 - 转:Android IOS WebRTC 音视频开发总结 (系列文章集合)
		
随笔分类 - webrtc Android IOS WebRTC 音视频开发总结(七八)-- 为什么WebRTC端到端监控很关键? 摘要: 本文主要介绍WebRTC端到端监控(我们翻译和整理的,译 ...
 - Android IOS WebRTC 音视频开发总结(八十五)-- 使用WebRTC广播网络摄像头视频(下)
		
本文主要介绍WebRTC (我们翻译和整理的,译者:weizhenwei,校验:blacker),最早发表在[编风网] 支持原创,转载必须注明出处,欢迎关注我的微信公众号blacker(微信ID:bl ...
 - Android IOS WebRTC 音视频开发总结(八十三)-- 使用WebRTC广播网络摄像头视频(上)
		
本文主要介绍WebRTC (我们翻译和整理的,译者:weizhenwei,校验:blacker),最早发表在[编风网] 支持原创,转载必须注明出处,欢迎关注我的微信公众号blacker(微信ID:bl ...
 - Android开发 音视频开发需要了解的专业术语知识
		
前言 在摸索一段时间的音视频开发后,越来越发现这个坑的深度真是特别的深. 除了了解Android自带的音视频处理API以外,还得了解一些视频与音频方面的知识.这篇博客就是主要讲解这方面的专业术语.内容 ...
 - Android 音视频开发(一):PCM 格式音频的播放与采集
		
什么是 PCM 格式 声音从模拟信号转化为数字信号的技术,经过采样.量化.编码三个过程将模拟信号数字化. 采样 顾名思义,对模拟信号采集样本,该过程是从时间上对信号进行数字化,例如每秒采集 44100 ...
 - Android音视频开发(1):H264 基本原理
		
前言 H264 视频压缩算法现在无疑是所有视频压缩技术中使用最广泛,最流行的.随着 x264/openh264 以及 ffmpeg 等开源库的推出,大多数使用者无需再对H264的细节做过多的研究,这大 ...
 - Android 音视频开发学习思路
		
Android 音视频开发这块目前的确没有比较系统的教程或者书籍,网上的博客文章也都是比较零散的.只能通过一点点的学习和积累把这块的知识串联积累起来. 初级入门篇: Android 音视频开发(一) ...
 - Python音视频开发:消除抖音短视频Logo的图形化工具实现
		
☞ ░ 前往老猿Python博文目录 ░ 一.引言 在<Python音视频开发:消除抖音短视频Logo和去电视台标的实现详解>节介绍了怎么通过Python+Moviepy+OpenCV实现 ...
 
随机推荐
- kotlin类与对象——>可见性修饰符
			
1.在 Kotlin 中有这四个可⻅性修饰符:private .protected .internal 和public .如果没有显式指定修饰符的话,默认可⻅性是 public . 2.包,函数.属性 ...
 - day14-Scanner
			
Scanner对象 之前我们学的基本语法中我们并没有实现程序和人的交互,但是Java给我们提供了这样一个工具类,我们可以获取用户的输入.Java.util.Scanner是Java5的新特征,我们可以 ...
 - 云原生周刊:Istio 加入 Phippy 家族 | 2024.3.18
			
开源项目推荐 ko "ko" 是一个用于构建和部署 Go 应用程序的简单.快速的容器镜像构建工具.它适用于那些镜像中只包含单个 Go 应用程序且没有或很少依赖于操作系统基础镜像的情 ...
 - Vue 中 v-html 无法被 style scoped 渲染的问题
			
假设有这么一个 vue 组件: <template> <div v-html="docPreview"/> </template> <st ...
 - RabbitMQ3.8.16安装延迟队列插件
			
安装过程 1:RabbitMQ 延迟插件GitHub 2:各版本地址 如我的MQ版本是3.8.16,那么根据提示下载的版本是: ①:移动插件到RabbitMQ的插件目录下,如我的位置是:/usr/li ...
 - 4.8 Linux解压.bz2格式的文件(bunzip2命令)
			
要解压".bz2"格式的压缩包文件,除了使用"bzip2 -d 压缩包名"命令外,还可以使用 bunzip2 命令. bunzip2 命令的使用和 gunzip ...
 - 题解:CF1015D Walking Between Houses
			
题解:CF1015D Walking Between Houses 算法 模拟,分类讨论 分析 首先,设每步走的距离为 \(t_i\),我们发现 \(t_i\) 应是满足 \(1\le t_i\le ...
 - php orm的C扩展 ycdatabase
			
背景:昨天看了ice框架后,感觉运行效率非常高,与其差不多的就是yaf了,然后因为yaf没有orm有点遗憾,不过我就这样去找了找orm,产生了这样的感想 今天又看了一下yaf框架,确实和ice差不多, ...
 - typeScript 基础类型 (三)
			
typeScript 的基础类型包含 Boolean.Number.String.null.undefined 以及 ES6 的 Symbol 和 ES10 的 BigInt. 下面介绍每种类型的使 ...
 - 曲线救国--访问dockerhub仓库
			
前言 由于dockerhub也被墙了,导致基础镜像没法拉取.后面解封了,又被墙了... 在这次被墙之前,访问国外的速度也是堪忧,甚至访问不了k8s的镜像,基于此,分享一下笔者经验 使用Daocloud ...