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

时间:2016-04-05 09:24:33

标签: opencv nginx ffmpeg rtmp hls

输出视频: 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'我可以在日志中看到速度接近1x。 但是HLS并没有在那里播放~2分钟的延迟,它停止了。克里斯的建议部分奏效。我不确定问题究竟在哪里,我开始相信它与nginx-rtmp模块有关。

这是最终输出,左边是闪光灯,右边是它。我在最后展示了ffmpeg选项。 https://youtu.be/jsm6XNFOUE4

3 个答案:

答案 0 :(得分:1)

在流式播放原始视频(如您)或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使用静态帧率

答案 1 :(得分:0)

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

答案 2 :(得分:0)

我遇到了同样的问题,发现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