背景:
最近公司要基于双目视觉做鹤管自动充装项目,需要对相机的流媒体进行推流,推流到流媒体服务器后,再将流转换成页面能播放的flv或m3u8格式的直播流,然后在页面进行视频直播。本项目共有四个鹤位,所以需要同时对4个相机的视频进行直播,且要保证直播的实时性。
实现:
1、安装流媒体服务器 基于nginx 安装nginx-http-flv-module模块
下载nginx依赖
apt-get install build-essential libpcre3 libpcre3-dev libssl-de
新建一个文件夹nginx_rtmp并切换到该目录下
mkdir nginx_rtmp cd nginx_rtmp/上传nginx和nginx-http-flv-module压缩包到nginx_rtmp,压缩包下载地址:链接:https://pan.baidu.com/s/1n_40umpZgZY8hEdtoJrg0Q 提取码:weda
解压nginx.zip、nginx-http-flv-module.zip
解压缩
tar -xf nginx-1.21.6.tar.gz unzip nginx-http-flv-module.zip 将解压后的nginx-http-flv-module 移动到 /usr/local/nginx-http-flv-module 目录下编译nginx, 同时设置第三方模块
cd nginx-1.21.6/ ./configure --with-http_ssl_module --add-module=/usr/local/nginx-http-flv-module make && make install如果此步报错,可能是没装zlib,可执行以下命令
sudo apt update sudo apt install zlib1g-dev检查nginx是否安装完成
/usr/local/nginx/sbin/nginx -v将nginx添加到环境变量中, 不一定用vim
vim /etc/profile.d/export_path.sh添加内容
#!/bin/bash export PATH=$PATH:/usr/local/nginx/sbin/生效:
. /etc/profile nginx -v修改nginx的配置文件 路径>>/usr/local/nginx/conf/nginx.conf*
vim /usr/local/nginx/conf/nginx.conf将准备好的nginx.conf内容覆盖进去,配置文件有两个,一个是转流为flv格式的,一个是转流为m3u8格式的,后续说一下区别
启动
/usr/local/nginx/sbin/nginx
2、使用ffmpeg进行推流
安装ffmpeg
```bash
apt install ffmpeg
```
推流命令
A、将rtsp视频推流生成flv格式:
ffmpeg -rtsp_transport tcp -i rtsp://admin:Admin12345@192.168.1.65:554/h264/ch0/main/av_stream -c:v libx264 -c:a aac -threads 5 -preset ultrafast -max_delay 100000 -f flv -an rtmp://192.168.1.171:1935/live/room
其中,运行日志中的fps为帧率,即一秒会产生多少张图片。
说明:
此种方式使用的是nginx-flv.conf中的配置内容
a、rtsp://admin:Admin12345@192.168.1.65:554/h264/ch0/main/av_stream 这个地址是我的摄像头播放地址,请查看并使用你使用的摄像头播放地址,可以是rtsp的也可以是MP4。
b、rtmp://192.168.1.171:1935/live/room 为nginx.conf配置的rtmp的地址,room是推流地址唯一标识,可以自定义。
推流成功后,使用VLC播放器进行播放,播放地址为:http://192.168.1.171:80/live?port=1935&app=live&stream=room,其中192.168.1.171换成你的服务器ip ,live是nginx.conf配置文件中配置的http标签下server下的location live的请求服务地址,port为nginx.conf配置文件中rtmp标签下server监听的端口号(注意开放服务器防火墙),app=live这个live与rtmp标签下 server下的location live所对应,stream=room这个room与你自定义推流地址所对应。
至此,rtsp转换成flv转换完成。
B、将相机最原始的视频转成m3u8,这种方式指的是将相机与服务器直接通过usb相连,然后获取相机中的视频并进行转换,不是将网络地址进行推流转换。
ffmpeg -y -an -f rawvideo -vcodec rawvideo -pix_fmt bgr24 -s 768x512 -r 20 -i - -c:v libx264 -pix_fmt yuv420p -preset ultrafast -f flv -rtmp_live live -tune zerolatency -preset ultrafast -g 14 rtmp://192.168.1.171:1935/live/171
说明:
此种方式使用的是nginx-m3u8.conf中的配置内容。
rtmp://192.168.1.171:1935/live/171 为nginx.conf配置的rtmp的地址,171是推流地址唯一标识,可以自定义。
推流成功后,使用VLC播放器进行播放,播放地址为:http://192.168.1.171:80/live/171.m3u8,其中192.168.1.171换成你的服务器ip ,live是nginx.conf配置文件中配置的http标签下server下的location live的请求服务地址,room.m3u8这个room与你自定义推流地址所对应。
其中,nginx-m3u8.conf配置文件相关配置如下:
rtmp {
server {
listen 1935;
chunk_size 4096;
application live {
live on;
hls on;
hls_path /usr/local/hls/files;
hls_fragment 200ms;
hls_playlist_length 1400ms;
hls_cleanup on;
hls_max_fragment 200ms;
# exec_push ffmpeg -i rtmp://input -an -c:v libx264 -preset veryfast -f flv rtmp://output;
}
}
}
rtmp标签下hls部分参数解释如下:
live on; # 开启直播模式
hls on; # hls 格式
hls_path /usr/local/hls/files; # 生成的视频流文件临时存储路径
hls_fragment 700ms; # 一个ts切片文件的时长,eg:500ms
hls_max_fragment 1000ms; #一个ts切片的最大时长,eg: 700ms; ts文件的时长会小于 hls_max_fragment ,大于等于 hs _fragment,建议hls_max_fragment大于等于2000ms,并且小于2 * hls_fragment
hls_playlist_length 2100ms; #与hls_fragment参数一起控制.m3u8文件中.ts列表数,eg:hls_playlist_length=1500ms,hls_fragment=500ms,则.m3u8文件中共有3个ts文件列表,建议此值为hls_fragment的三倍
hls_sync 2s; #音视频的同步时间,通俗一点就是强制的音/视频同步,可以防止音画不同步的现象,默认是2ms,
hls_continuous onloff #设置连续模式,打开HLS连续模式。 在这种模式下,HLS序列号从上次停止的地方开始。 老片段被保存。 默认为关闭。
hls_nested on|off #默认是off。切换HLS嵌套模式。在此模式下,hls_path为每个流创建一个子目录。播放列表和片段在该子目录中创建。默认为关闭。
hls_base_url #设置基准URL,对于m3u8中使用相对URL有效。设置HLS播放列表项目的基本URL。 当为空时,这些项目没有前缀,并假定与父播放列表位于相同的位置,或者在使用hls_nested时降低一个级别。 此功能适用于主(变式)和从HLS播放列表。 它可以让您下载播放列表并在本地播放,因为它包含对子播放列表或片段的完整引用。 默认为空。
hls_cleanup on|off #切换HLS清理。 默认情况下,该功能处于打开状态。 在这种模式下,nginx缓存管理器进程从HLS目录中删除旧的HLS片段和播放列表。
hls_fragment_naming system|timestamp|sequential #使用系统时间、使用流时间戳、使用递增的整数顺序(默认),
exec_push ffmpeg -i rtmp://input -an -c:v libx264 -preset veryfast -f flv rtmp://output; # 某些情况下,可以使用此参数对流进行二次处理
参考:【官方文档】Nginx模块Nginx-Rtmp-Module学习笔记(二)HLS 指令详解_51CTO博客_Nginx-rtmp-module
通过此种方式,会在hls_path配置的路径下生成.m3u8文件和.ts文件,.m3u8文件中的内容是要播放的.ts列表,然后再通过nginx http标签配置代理转发到.m3u8文件,就可以实现视频流的播放,如下图:
至此,m3u8转换完成。
ffmpeg相关参数说明:
-threads 5 -preset ultrafast -max_delay 100000 参数
-threads 5的意思是 设置编解码等工作的线程数,线程数多了速度自然比一个线程处理的快;
-preset ultrafast 用来指定视频的输出质量,它共有以下几个可以用的值:
ultrafast 超快的
superfast 超高速的
veryfast 非常快
faster 更快
fast 快
medium 中等
slow 缓慢的
slower 较慢的
veryslow 非常慢
我们这里使用的是 ultrafast 超快的;-max_delay 100000 表示指定视频的最大延迟,这里设置100ms
以上参数为调优参数,可以降低视频的延迟,也可以使用降低分辨率、视频大小来增加推送速度,降低延时
下面是一些常用参数:
-i (input): 指定输入文件或者 URL。
-f (format): 指定输出文件格式。
-vcodec (video codec): 指定视频编解码器。
-acodec (audio codec): 指定音频编解码器。
-ss (start time): 指定开始时间。
-t (duration): 指定持续时间。
-r (frame rate): 指定帧率。
-s (size): 指定视频分辨率。
-b (video bitrate): 指定视频比特率。
-ab (audio bitrate): 指定音频比特率。
-ar (audio sampling rate): 指定音频采样率。
-vn: 禁止视频流。
-an: 禁止音频流。
-c:v copy: 将视频流拷贝到输出文件,避免重新编码。
-c:a copy: 将音频流拷贝到输出文件,避免重新编码。
-filter_complex: 指定复杂的过滤器图形。
-map: 选择流进行处理和映射。
-preset: 指定编码预设。
-crf: 指定恒定质量的压缩级别。
-pix_fmt: 指定像素格式。
-af: 音频过滤器。
-vf: 视频过滤器。
-movflags: 指定 MOV 文件特定的标志。
-y: 覆盖输出文件而不询问。
-loglevel: 指定日志级别。
-g: 关键帧数,推流生成hls时使用,值为:帧率(ffmpeg -r参数值) * hls_fragment(rtmp配置中的值,转换成秒,如700ms,则为0.7)
遇到的问题及调优
1、生成的flv视频延迟严重及卡顿问题?
通过修改ffmpeg推流参数解决:-threads 5 -preset ultrafast -max_delay 100000(具体参数解释,上文中有说明)
也可以修改相机的曝光度、推流分辨率等方法实现。
2、生成的.ts文件不连续,且有时不生成,配置的hls相关参数不生效?
此处原因是因为生成ts文件时,需要一个关键帧的概念,ts文件是根据关键帧生产的,如果ffmpeg推流时不设置关键帧或者关键帧设置的不对,生产.ts文件时就会有问题,且hls_fragment、 hls_playlist_length等参数设置不生效。关键帧的设置方式是在ffmpeg推流时添加 -R参数,例如:ffmpeg -R 10。其中关键帧的计算方式为:ffmpeg推送帧率(-r 参数对应的值) * nginx.conf中hls_max..的值(按秒进行折算),比如:ffmpeg推送帧率是20,nginx.conf中配置的hls_fragment的值为700ms,则关键帧=20*0.7 = 14,此时生成的每个ts文件中会有14帧,即14张图片。
3、vue3集成video.js组件播放m3u8视频流时,视频经常卡顿,不流畅?
这个问题主要原因是nginx.conf中关于hls的相关参数设置不当造成的,hls_fragment不易设置过低,如果过低,其生成速度会过快,导致前端页面请求速度跟不上(前端请求完.m3u8获取ts列表后,相应的ts就消失了),会导致丢帧,在不考虑延时问题的情况下,hls_fragment值大一些会比较好,比如2s。由于我们对时效性有要求,所以最开始的时候设置的太低(200ms),结果导致出现问题。后来,hls_fragment改为500ms,hls_playlist_length改为1500ms,视频开始流畅,随着数值加大会更好,但是延时会增加。总之,hls_fragment、hls_max_fragment、hls_playlist_length几个参数要不断尝试,以调整出最优参数
4、vue3集成video.js组件播放m3u8视频流时,播放一段时间后,发现视频也会有稍微的卡顿,且此时http请求获取的ts文件大小都是375B(正常是200KB左右),此时如果刷新浏览器会恢复正常。(使用vlc没有这个问题)?
这个问题是由于m3u8是基于HLS协议的格式,需要浏览器对视频进行「解码」播放,如果浏览器的解码能力有限(比如当视频的 m3u8 文件加载成功并且浏览器无法获取其中一个 ts 文件时),video.js会不断进行重试,导致视频画面卡顿。而VLC支持多种媒体格式和协议,最重要的是能自适应解码(能够在解码过程中自动调整解码参数),提供了流畅的播放效果。所以video.js插件播放m3u8会卡顿,VLC就不会。此时刷新浏览器也可以恢复正常。
当出现卡顿时,http请求.ts文件的响应数据结果都是375B(正常是200KB左右)刷新浏览器加载出首帧时,说明初始化已经成功,刚开始不会卡顿,直到继续在解码过程中解码性能受阻时,才会继续卡顿。 出现卡顿时,http的请求数据为375B,可以认为是异常了,因为无法继续获取下一个有效的ts文件(正常的180KB),仅获取到了一些无用的文件(大小375B)。
综上所述,基本认为是浏览器的解码能力有限导致的。
解决此问题,
1、可以继续加大hls_fragment参数的值,通过降低ts文件的请求次数从而降低对浏览器解码性能的消耗,但是此方法会增加视频延时。
2、也可以通过提升浏览器的解码能力来改善,提升浏览器解码能力的方法为:
a、chrome浏览器–>右键–>属性–>目标: 先加一个空格,然后输入:--enable-features=PlatformHEVCDecoderSupport; 点击应用.
--enable-gpu-rasterization # 启用GPU
--force-local-ntp # 强制本地NTP
--enable-features=PlatformHEVCDecoderSupport # 使用HEVC硬件解码---Windows以外平台需要提供解码包b、设置谷歌浏览器使用独立显卡
桌面-右键-显示设置-显示卡-浏览-选择谷歌浏览器安装目录下的Chrome.exe文件,添加后,点击选项-弹窗后选择高性能
5、使用video.js组件播放直播视频时,无法刷新、无法更换视频播放地址
前端是VUE3,之前使用video.js组件,但是使用此组件,无法更换视频地址,也无法刷新视频,用了网上的N种方法都不行,后来机缘巧合之后,发现了一个叫videojs-player的组件,引入方式为在package.json文件的dependencies下添加依赖:"@videojs-player/vue": "^1.0.0",注意此组件应该是对video.js组件进行了封装,所以也需要依赖video.js。
添加依赖之后,在代码中添加一下代码即可:
<div v-for="(arm, index) in loadArmData" class="view-option" :style="[{ height: optionHeight + 'px' }]"> <video-player :ref="el => (videoRefs[index] = el)" :id="'video' + index" style="width: 100%; height: 100%" controls autoplay :muted="true" :preload="true" :src="arm.videoAddress" v-if="videoShow[index]"/> </div>
如果想对视频进行刷新,有两种非常简单的方式:
一种是通过v-if进行控制,代码如下:
videoShow.value[index] = false nextTick(() => { videoShow.value[index] = true })
一种是通过修改src的值来实现,代码如下:
loadArmData.value[index].videoAddress = loadArmVideoUrlData.value[index] + '?t=' + new Date().getTime()
参考博客地址:https://blog.csdn.net/Aarstg/article/details/122937043