繁体   English   中英

在Opencv中处理相机流,并使用FFMPEG将其推送到RTMP(NGINX RTMP模块)上

[英]Processing Camera stream in Opencv, pushing it over RTMP (NGINX RTMP Module) using FFMPEG

输出视频: https : //youtu.be/VxfoBQjoY6E

说明:

我要:在Opencv中处理摄像机流,并将其推送到RTMP服务器。 我已经设置了NGINX(RTMP模块),并且已经使用RTMP(Flash Player)和HLS测试了流视频。

我正在循环读取帧,并在python中使用“子进程”执行ffmpeg命令。 这是我正在使用的命令:

command = [ffmpeg,
    '-y',
    '-f', 'rawvideo',
    '-vcodec','rawvideo',
    '-pix_fmt', 'bgr24',
    '-s', dimension,
    '-i', '-',
    '-c:v', 'libx264',
    '-pix_fmt', 'yuv420p',
    '-preset', 'ultrafast',
    '-f', 'flv',
    'rtmp://10.10.10.80/live/mystream']


import subprocess as sp
...
proc = sp.Popen(command, stdin=sp.PIPE,shell=False)
...
proc.stdin.write(frame.tostring()) #frame is read using opencv

问题:

我可以看到流正常,但是它会冻结并经常恢复。 这是FFMPEG终端日志的输出:

Stream mapping:
  Stream #0:0 -> #0:0 (rawvideo (native) -> h264 (libx264))
frame=  117 fps= 16 q=22.0 size=     344kB time=00:00:04.04 bitrate= 697.8kbits/s speed=0.543x   

最后提到速度。 我相信应该接近1倍。 我不确定如何实现这一目标。

而且我与服务器位于同一网络上,如果需要,我可以发布python代码。 需要一些ffmpeg专家给我一些建议。

编辑

我输入的fps实际上是〜3。 使用'-use_wallclock_as_timestamps', '1'我可以在日志中看到速度接近1倍。 但是HLS的直播时间大约有2分钟的延迟,因此暂停并停止。 克里斯的建议部分起作用。 我不确定问题出在哪里,我开始相信这与nginx-rtmp模块有关。

这是最终的输出,左边是flash,右边是hls。 我在最后显示了ffmpeg选项。 https://youtu.be/jsm6XNFOUE4

在流传输原始视频(如您)或从MJPEG来源传输视频时,我遇到过类似的问题。 ffmpeg有两个输入选项可以尝试使其保持1倍的速度:

选项1

ffmpeg -re -i <rest of input options>

-re告诉ffmpeg以本机输入速率读取

选项2

ffmpeg -use_wallclock_as_timestamps 1 -i <rest of input options>

-use_wallclock_as_timestamps告诉ffmepg在进入每个帧时仅获取它们,获取系统时间,并为其添加时间戳。 我发现当速度降低时,此选项最有效。

不管

确保以恒定帧速率编码。 当帧率变化时,ffmpeg可能会有点挑剔,因此在输出选项上,使用-r 25 (将25替换为所需的输出帧率)来强制ffmpeg使用静态帧率

我认为最简单的方法是使用MoviePy模块(我发现很棒)。 看一下MoviePy Video Writer 它应该写入本地文件,但是您也可以将其与rtmp流一起使用,方法是在命令末尾添加-f flv以指定输出格式。 要将帧写入流,只需使用write_frame(your_frame)方法。 对我来说效果很好

我遇到了同样的问题,发现ffmpeg无法自动填补空白,因此当您以3 fps的速率喂ffmpeg时,客户端仍将以25 fps的速度播放,因此客户端需要先缓存很多帧,然后再播放以高速移动,然后停止再次缓存帧

所以很容易在使用以下代码填充ffmpeg时填补空白

timeStart = get_time_seconds()
count = 0
some loop:
  frame = getimage()
  targetCount = (get_time_seconds()-timeStart)*25
  repeatCount = targetCount - count
  loop for repeatCount times:
     proc.stdin.write(frame.tostring()) 
  count = targetCount 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM