2020年2月份,还记得火神山与雷神山医院在短短72小时之内建成并迅速投入到使用吗?这让全世界的人民都见识了什么叫做中国速度。而当时火神山与雷神山医院的建设过程也实时的在互联网平台直播在引来大量观看的观众的同时也开创了一种新型的直播方式–慢直播。
那有没有一种简单的方式可以实现这种慢直播。我想挑战一下自我。然后试试?试试就逝世。为了实现我的想法于是我在云端租借一台云服务器尝试着搭建这套系统。
云服务器没有GUI那么OBS,VMIX这些强大的工具都不能使用,这不是巧妇难为无米之炊吗?而且云服务器的性能还不是很高,对于一般的http请求,分发问题不大,可是视频编解码?这个没法玩吧。好吧,技术人不能说自己不行。
先来一波需求性分析:
1、对接各种品牌的摄像头,说明各种协议不同,srt,rtmp,webrtc,rtsp,http,ftp,甚至本地视频文件
2、rtmp转发
3、背景音乐叠加
4、logo叠加
5、游走字幕叠加
6、24小时循环播放,无人值守
好吧,看到这个需求我只能说能用现成技术和设备就能解决的事情何必再尝试新的解决方案。我只能祭出免费开源的视频神器ffmpeg了。先对整个系统的流程做个草图:
好吧,这个草图有够潦草,原谅我对于丐版文化的鄙视,但是图草理不糙。在经过对网上很多资料的搜寻,还真没有对于同类型的设计项目和应用。所以我只能一点点尝试了。首先才能尝试对一个摄像头的拉流与推流操作:
ffmpeg -i 'rtsp地址' -vcodec copy -acodec copy -f flv 'rtmp地址'
通过以上命令可以很轻松的实现拉取rtsp然后推流到rtmp,先说明为什么是rtsp,原因很简单,现在大部分的摄像头都是rtsp协议,海康威视摄像头也是这种协议,不过不重要,很简单的操作嘛,小骄傲!然而打脸的事情接踵而至。拉流查看效果,发现花屏,马赛克,卡顿。啊?刚开始就遇到问题咋搞?技术人怎么会被这种事情难倒,经过我的冷静分析,是因为rtsp协议传输的不稳定引起的。遇事不对查文档,经过一番英文洗礼。好吧,我们可以把rstp改成tcp连接方式,tcp采用三次握手而且是长链接,可以和摄像头建立稳定的连接方式,保证我拉取到的流不中断。
ffmpeg-rtsp_transport tcp -i 'rtsp地址' -vcodec copy -acodec copy -f flv 'rtmp地址'
经过测试,再也不会出现花屏现象。完美!
第二步,多个摄像头循环拉流推流!
单个摄像头都实现了我还在乎多个摄像头吗?ffmpeg不是支持画中画吗?那肯定是支持多输入的嘛,查文档!啪啪打脸,ffmpeg是支持列表播放,但是当前只支持本地视频文件列表播放,不支持网络文件列表播放。难得我又接受了一波英文洗礼。这是问题吗?上才艺!
#!/bin/bash
vedio_path="/mnt/app/list.txt"
while true
do
cat ${vedio_path} | while read line
do
</dev/null ffmpeg -rtsp_transport tcp -t 30 -i $line -an -vcodec copy -f flv rtmp地址
done
done
我一个脚本下去,这不就实现了多个摄像头循环播放了吗?可是好像有点啥问题?我也不知道,算了,试试。再次逝世!
从B站的结果上看,每一个摄像头播放30秒,然后切换到下一个摄像头然后黑场,转圈圈,传输画面中断。这个怎么办?疯狂燃烧吧我的脑细胞!我决定祭出linux大杀器–管道!我把拉流与推流当成两个部分,然后数据通过管道连接,这样的话就能保证数据的连续性,保证视频切换不会出现黑场,转圈圈等问题。重新制作草图:
先解释一波原理,linux管道又分匿名管道和命名管道,我一开始尝试使用匿名管道发现无法解决问题,匿名管道具有一定的局限性:首先,这个管道只能是具有血缘关系的进程之间通信;第二,它只能实现一个进程写另一个进程读,而如果需要两者同时进行时,就得重新打开一个管道。于是我尝试使用命名管道,关于命名管道:
1、区别:命名提供了一个路径名与之关联,以FIFO文件的形式存储于文件系统中,能够实现任何两个进程之间通信。而匿名管道对于文件系统是不可见的,它仅限于在父子进程之间的通信。
2、FIFO是一个设备文件,在文件系统中以文件名的形式存在,因此即使进程与创建FIFO的进程不存在血缘关系也依然可以通信,前提是可以访问该路径。
3、FIFO(first input first output)总是遵循先进先出的原则,即第一个进来的数据会第一个被读走。
好嘛,说这么多这不就是个队列嘛,任何人都往里面放,拿的人顺序拿,解释完毕!于是我再次更改我的脚本。
#!/bin/bash
vedio_path="/mnt/app/list.txt"
while true
do
cat ${vedio_path} | while read line
do
</dev/null ffmpeg -rtsp_transport tcp -t 30 -i $line -an -vcodec copy -f flv pipe:1.flv | cat - >> push
done
done
然后推流端:
ffmpeg -re -i push -c:v copy -c:a aac -f flvrtmp
地址果然还是不行?到底哪里出了问题?按道理我的思路是没有问题的呀。查看ffmpeg报错:
Unable to seek to the next packet
push: Invalid data found when processing input
无效的数据?这是因为输入端媒体流的封装格式问题吗?这时想到了可以试试改用TS格式封装(TS的全称则是Transport Stream,即传输流,DVD节目中的MPEG2格式,是MPEG2-PS,MPEG2-TS格式的特点就是要求从视频流的任一片段开始都是可以独立解码的。现主流视频网站都采用这种模式。重新修改脚本:
#!/bin/bash
vedio_path="/mnt/app/list.txt"
while true
do
cat ${vedio_path} | while read line
do
</dev/null ffmpeg -rtsp_transport tcp -t 30 -i $line -an -f mpegts -vcodec copy -vbsf h264_mp4toannexb pipe:1.ts | cat - >> push
done
done
ok完美解决,再也不花屏了,可是这又产生了新的问题!
当网络波动导致推流卡死或者手动关闭推流进程,导致管道读端关闭,使整个管道关闭,输入进程会由于写入失败而关闭,再次运行则重新按文件列表顺序推流(重新开始后又要从第一集开始播放);又例如,手动关闭输入进程,推流进程会读取完管道里的数据后关闭。如果我想要输入进程或者推流进程其中一个关闭后,另一个不关闭,而是进入等待状态的话,那就需要维持管道的开启。
我还怎么实现24小时无人值守?
经过查找大神的资料我发现只要维持管道不被关闭,那么推流那一端如果在拉流那一端断开时会等待而不会自动退出,这样就能保证连上时能继续恢复推流。完美!于是我想了个办法,利用管道的阻塞特点,通过新建两个新的管道文件keep1、keep2,一个指向push的写端,另一个指向push的读端,使push读端和写端的引用计数都不为0,具体如下:
mkfifo keep1
mkfifopush
mkfifo keep2
cat keep1 > push
cat keep2 < push
ok,已经完美实现了24小时循环推流了,正当我测试打算买瓶可乐奖励自己的时候发现切换的时候有时候会转圈圈,有时候会卡,有时候会黑。这引起我的注意,现在还不是庆祝的时候。难道是切换的时候让管道里面写入了空白帧?我查看ffmepg日志发现如下警告:
这是啥玩意?DTS?不过timestamps我还是认识的,时间戳嘛。难道是同步问题,就像传统媒体一样的同步切换问题?咋搞?编程?这也不是预计内的事情呀。肯定还有办法。经过多方文档和案例查询,这是由于pts时间计算引起的问题,摄像头在切换的时候两个pts不一致,导致两帧的数据播放器不能识别两帧之间的间隔。继续查文档,在经过一个星期的文档洗礼之后我发现如下几种方式可以对时间戳操作:
-video_track_timescale
-reset_timestamps 1重置时间戳
-correct_ts_overflow 0 重新计算时间戳
-use_wallclock_as_timestamps 1根据接收到的帧重写时间戳
我才用最后一种方法终于解决了时间戳问题,自此终于可以实现无缝切换了。
重写推流命令:
ffmpeg -use_wallclock_as_timestamps 1 -i push -stream_loop -1 -i音频文件 -c:v copy -c:a aac -reset_timestamps 1 -f flv rtmp地址
至此已经完成部分需求,至于叠加图片都是很简单的操作了在这里不再赘述,该方案在B站能实现完美的推流,在其他平台如有格式需求进行相应转码即可。
经过测试整个项目内存消耗600M左右,cpu(两核)消耗6%左右,算是极低的消耗了。
随着时代的发展,人们对于远程视频观看的需求越来越旺盛,慢直播以后会越发的火热,像建房,城市建设,景区宣传,各地风貌介绍等等直播场景会越来越多。可是低成本,高可用,低消耗的技术在这一方面还没有开始普及。我们媒体技术人员在这一方面可以开发出更多的可用的技术储备以备不时之需。
作者:王健 播控部 | 来源:公众号——技术制播中心党总支
版权声明:本文内容转自互联网,本文观点仅代表作者本人。本站仅提供信息存储空间服务,所有权归原作者所有。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至1393616908@qq.com 举报,一经查实,本站将立刻删除。