V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
ZoomQuiet
V2EX  ›  程序员

[FFmpeg] 如何通过实时摄像头帧图片生成 rtmp 直播流?

  •  
  •   ZoomQuiet ·
    ZoomQuiet · 2018-03-08 20:23:29 +08:00 · 18044 次点击
    这是一个创建于 2444 天前的主题,其中的信息可能已经有所发展或是发生改变。

    背景

    • 已经完成用 Python 对摄像头硬件实时提取帧图像并进行一系列机械视觉处理
    • 客户突然提出, 一定要通过 rtml:// 进行远程工作状态的监控

    分析

    • 因为硬件驱动的原因
    • 系统中一个 usb camera, 同一时刻, 只能有一个加载进程来读取实时帧图像
    • 如果如客户自己实验通过的:
      • FFmpeg -f dshow -i video="... -f mpegts -f flv "rtmp://20878.... 形式
      • 从硬件直接拿视频并实时编译为 flv 编码的 rtmp 直播流
      • 那么, 原先软件将无法获得合法的帧图像进行业务分析

    尝试

    • 知道 FFmpeg 有能力从图片中编译出 avi/mp4/... 视频
    • 那么一定也可以编译为 rtmp 直播流

    问题

    动态固定图片

    尝试将实时帧图像,另外输出到硬盘固定图片文件, 内容动态变化,

    命令改变为: ffmpeg -f image2 -loop 1 -i "path/2/frame.png" ...

    但是, 无论怎么调整参数,都只能工作十多帧就崩溃了, 报错都是类似:

    ...
    Error while decoding stream #0:0: Invalid data found when processing input
        Last message repeated 1 times
    Past duration 0.799995 too large
    [flv @ 0x7fabfa001800] Failed to update header with correct duration.34.3kbits/s dup=0 drop=1120 speed=7.25x
    [flv @ 0x7fabfa001800] Failed to update header with correct filesize.
    frame= 1730 fps=109 q=5.5 Lsize=    3300kB time=00:01:55.40 bitrate= 234.3kbits/s dup=0 drop=1120 speed=7.24x
    video:3273kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.832250%
    

    系列静态图片

    而将帧图像持续输出为一系列有命名规模的静态图片后, 参考:

    无论怎么折腾参数, 都无法工作, 报错为:

    ...
    
      Metadata:
        encoder         : Lavf57.71.100
        Stream #0:0: Video: flv1 (flv) ([2][0][0][0] / 0x0002), yuv420p, 480x270, q=2-31, 200 kb/s, 25 fps, 1k tbn, 25 tbc
        Metadata:
          encoder         : Lavc57.89.100 flv
        Side data:
          cpb: bitrate max/min/avg: 0/0/200000 buffer size: 0 vbv_delay: -1
    [flv @ 0x7ff53d008600] Failed to update header with correct duration.
    [flv @ 0x7ff53d008600] Failed to update header with correct filesize.
    frame=   20 fps=0.0 q=9.7 Lsize=     173kB time=00:00:00.76 bitrate=1867.3kbits/s speed=10.1x
    video:173kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.300397%
    

    所以, 综合以上, 想知道如何能通过动态图片 /实时增长的系列图片 实时编译为 rmtp 直播流?

    或是说, 思路上还有什么选择?

    第 1 条附言  ·  2018-03-14 00:01:07 +08:00

    解决+回顾

    问题其实应该是:

    如何通过[FFmpeg]将 webcam 实时帧数据合法推送给第3方 rtmp 直播频道?

    @Panic 一语中的:

    应该就是使用 pipe,先将 png 转成 rgb 格式或 YUV 格式的 rawvideo, 再送到 ffmpeg 的 pipe 进行编码,输出 rtmp 到...

    回顾之前收集到的有关文章:

    重新构建了测试脚本实现了实时推送, 延时也在容忍范畴之内 ;-)

    注意:

    命令参数一定要有:

    , '-f', 'rawvideo'
    , '-vcodec','rawvideo'
    

    对应的, 要将 cv2 处理的图片格式, 从 numpy.ndarray->cv2.cv.cvmat

    才能使用 .tostring() 通过 stdin 丢给 FFmpeg 完成格式化并推送

    回顾:

    大家的各种质疑, 主要还是系统架构的决策问题:

    • 为毛不用 FFmpeg 直接从硬件获得图像并推流?
    • 简单的说, 这是业务决定的...
    • 之前尝试过, 但是, 透过 FFmpeg 的自动化视频流处理后
      • 应用系统再难获得合理/时间线同步的帧数据了
      • 因为系统包含了一组多个摄像头
      • 而业务是严重依赖所有视觉数据的帧时间戳信息
    • 进一步的, 尝试先将硬件实时图像先吐到本地 UDP 通道中
      • 然后无论机械视觉业务
      • 视频记录功能
      • rmtp 之类远程监察要求
      • ...
      • 都可以另外用单独进程从 UDP 并行提取
      • 但是, 依然失败了...
    • 所以, 才恢复了用 Python 直读硬件信息并处理
      • 实时输出硬盘帧图片
      • 后期再用 FFmpeg 生成各种期待的格式视频
    • 只是年后, 突然有了 rmtp 通道...这才想在原有架构上追加个输出渠道
    • 万幸的是 win10 系统也有 stdin 的机制,否则, 当前这方案也得瞎...

    PS:

    同时在尝试其它渠道来提问, 但是 V2Ex 的响应最快, 最多...

    实在是...

    C'est la vie (´-ι_-`)
    
    34 条回复    2019-03-26 11:31:12 +08:00
    contmonad
        1
    contmonad  
       2018-03-08 21:47:33 +08:00
    经过磁盘文件中转后实时性不好吧,直接用 pipe。这里有个 OpenCV 到 FFmpeg 的例子: https://stackoverflow.com/q/36422211/3107204

    我猜用 FFmpeg 的 Python binding 也可以( libavdevice 操作摄像头,libavformat 转封装),而且自由度更高。
    contmonad
        2
    contmonad  
       2018-03-08 21:51:17 +08:00
    你帖子中的描述概念错误好多啊。。建议找 H.264 和 RTMP 的规范看一下
    wdlth
        3
    wdlth  
       2018-03-08 22:11:37 +08:00 via Android
    为何不直接传输视频流?
    likuku
        4
    likuku  
       2018-03-08 22:55:11 +08:00
    rtmp 传输的也就是包装成 flv 的 h264 流 (video: h264, audio: aac)
    likuku
        5
    likuku  
       2018-03-08 22:56:38 +08:00
    ffmpeg 本身就具有直接读取摄像头抓取信息的能力,只要你机器编码足够快(GPU 之类加速就 OK),实时推流不是问题
    fgodt
        6
    fgodt  
       2018-03-08 22:59:21 +08:00 via Android
    不是很懂你的构架,正常的如果有图片源用 ffmpeg 编成 264 封装成 flv 输出到 rtmp 地址就行了
    picone
        7
    picone  
       2018-03-09 01:13:28 +08:00
    动态图片不可行,刚好我毕设在做相关的项目,可以一起讨论。
    因为是本科生的毕设,所以就用动态图片实现了,websocket+protobuf,传输图片,前端 img 加载。
    后端用 APS 定时抓帧,用 jpeg 编码再推送出去。
    我的 mac 跑,9fps,单核 cpu 跑满。。。再高的 fps 就有延迟了。。。
    https://github.com/picone/RealTimeTrackingCamera
    你可以用 jsmpeg 实现以下,把视频用 mpeg 压缩,效果会好很多
    ETiV
        8
    ETiV  
       2018-03-09 02:26:39 +08:00
    // 可能需要重写 Python 的部分

    摄像头 -> FFmpeg -> nginx-rtmp -> 通过指令 push 把直播流推出去 -> 直播站点
                 \-> Python (或 FFmpeg )读 rtmp:// 直播流,拆出来图片 -> Python 分析
    ZoomQuiet
        9
    ZoomQuiet  
    OP
       2018-03-09 07:15:09 +08:00 via iPhone
    @likuku 是也乎 ╮(╯▽╰)╭

    多谢提醒…可以无声的…推流~
    ZoomQuiet
        10
    ZoomQuiet  
    OP
       2018-03-09 07:18:02 +08:00 via iPhone
    @ETiV 试过…不可用…
    机械视觉部分实时要求高…

    且需要用原帧~
    从第三方直播服装绕时间轴全乱套了…

    是也乎 ╮(╯▽╰)╭
    ZoomQuiet
        11
    ZoomQuiet  
    OP
       2018-03-09 07:19:04 +08:00 via iPhone
    @fgodt 是也乎 ╮(╯▽╰)╭

    正常的是图片已准备好…
    俺这是实时动态生成的…
    ZoomQuiet
        12
    ZoomQuiet  
    OP
       2018-03-09 07:20:37 +08:00 via iPhone
    @contmonad
    是也乎 ╮(╯▽╰)╭

    多谢提醒…概念术语的确不准…
    直播方面是二把刀…
    临时突然要追加的…
    ZoomQuiet
        13
    ZoomQuiet  
    OP
       2018-03-09 07:21:26 +08:00 via iPhone
    @contmonad 多谢~
    有方向好探查…

    是也乎 ╮(╯▽╰)╭
    ZoomQuiet
        14
    ZoomQuiet  
    OP
       2018-03-09 07:23:25 +08:00 via iPhone
    @picone 多谢提醒…
    也尝试过 jsmpeg …官网效果看着好~
    竟然安装不上…
    俺这就再刷一下…
    ZoomQuiet
        15
    ZoomQuiet  
    OP
       2018-03-09 07:57:25 +08:00
    @contmonad 再次感谢
    pipe 是个靠谱的方向, 之前实现过, 都忘记了...

    > ... libavdevice 操作摄像头,libavformat 转封装...

    涉及 FFmpeg 底层 C 库了,这种调试起来就嗯哼了...
    gggxxxx
        16
    gggxxxx  
       2018-03-09 09:01:18 +08:00
    几年前我自己用 librtmp 做过类似的,摄像头画面直接推到 rtmp 服务器。
    不用 ffmpeg 也能实现。
    fgodt
        17
    fgodt  
       2018-03-09 09:34:05 +08:00
    你想不写代码用几个命令来处理还是有点难度,正确的流程应该是
    1 视频流->ffmpeg->pkt
    2 pkt->ffmpeg->图片->py 处理
    3 pkt->ffmpeg->rtmp
    第二步第三步可以互不影响
    Panic
        18
    Panic  
       2018-03-09 10:07:19 +08:00
    应该就是使用 pipe,先将 png 转成 rgb 格式或 YUV 格式的 rawvideo, 再送到 ffmpeg 的 pipe 进行编码,输出 rtmp 到添加了 rtmp 模块的 nginx 服务器。客户端连接通过 rtmp 链接访问 nginx 就可以了。
    retamia
        19
    retamia  
       2018-03-09 10:44:19 +08:00
    你是要将摄像头采集到的图片帧处理后,进行直播推流吗?
    ZoomQuiet
        20
    ZoomQuiet  
    OP
       2018-03-09 18:49:56 +08:00 via iPhone
    @retamia 是也乎 ╮(╯▽╰)╭

    对的…整体数据流必须这样…

    通过硬盘文件来隔离不同业务…

    否则有硬件争用现象…
    ZoomQuiet
        21
    ZoomQuiet  
    OP
       2018-03-09 18:50:51 +08:00 via iPhone
    @fgodt 是也乎 ╮(╯▽╰)╭

    pkt 是指数值封装嘛?
    ZoomQuiet
        22
    ZoomQuiet  
    OP
       2018-03-09 18:53:41 +08:00 via iPhone
    @gggxxxx 是也乎 ╮(╯▽╰)╭

    已在看此模块

    官方样例是从 rmtp 流拿帧的…
    但文档中说能写…

    但只接受 flv 封装的图片…
    然有…找不到可用的… flv 封装模块

    所以…你之前是乍写入上游直播流的?
    nanhuo
        23
    nanhuo  
       2018-03-17 16:12:49 +08:00
    @ZoomQuiet 方便透露一下使用这个方案延时最终能控制在什么范围吗?
    ZoomQuiet
        24
    ZoomQuiet  
    OP
       2018-03-17 17:35:48 +08:00 via iPhone
    @nanhuo 是也乎 ╮(╯▽╰)╭

    国内 3 秒内

    海外 30 秒内

    关键是上游 直播服务平台的资源分布了…
    fqxyhdsy
        25
    fqxyhdsy  
       2018-03-19 14:47:50 +08:00
    @ZoomQuiet 您好,楼主!请问你这问题解决了吗!现在因为业务需求也要弄个类似的!这边现在的情况是,直播流通过 ffmpeg 切帧,将切完的帧存放在了服务器某个文件夹下,然后不停的覆盖该文件。应该就是您上面说的动态固定图片那种情况。请问具体如何结合 pipe,将这个动态固定图片推成一个视频流!刚接触 python 没多久,请详细讲解一哈!谢谢!
    fqxyhdsy
        26
    fqxyhdsy  
       2018-03-20 15:05:04 +08:00
    @picone 您好!请问,动态图片+websocket+protobuf,这种方案怎么用 protobuf 来传输图片呀? 这边之前的解决方案是 socket 传输 base64 数据,前端用 websocket 接受数据然后绑定图片到视图层。但是太吃内存了,服务器承受不了!求解惑!万分感谢!
    picone
        27
    picone  
       2018-03-20 15:49:04 +08:00
    @fqxyhdsy #26 不要转 base64 了,直接把图片 jpeg 编码,然后直接使用 protobuf 序列化就 OK 了,protobuf 接受二进制。如果是连续动态的图片,建议用 mpeg 编码
    fqxyhdsy
        28
    fqxyhdsy  
       2018-03-20 16:04:07 +08:00
    @picone 首先万分感谢回复! 如果将 jpeg(mpeg)编码后的图片用 protobuf 序列化传过去,应该是没问题。但是现在前端是用 js 的 websocket 来链接的!那怎么来反序列化 protobuf 传过来的数据呢! js 这边是否能够支持 protobuf 和 jpeg(mpeg)解码!刚接触没多久,万分包涵!
    picone
        29
    picone  
       2018-03-20 16:09:16 +08:00
    @fqxyhdsy #28 js 也提供了 protobuf,也可以做到。jsmpeg 网上也有项目
    ZoomQuiet
        30
    ZoomQuiet  
    OP
       2018-03-29 19:29:04 +08:00 via iPhone
    @fqxyhdsy 是也乎 ╮(╯▽╰)╭

    不好意思才看到…

    已有流的话…

    FFmpeg 本身就支持:
    - 拖流为视频文件
    - 或直接转播推流到其它协议流

    进一步的…图片序列少 TPS 信息…体积也大…
    不如存为 .mkv 需要时 --> 推为流
    liu826250634
        31
    liu826250634  
       2018-08-21 19:27:14 +08:00
    题主您好。
    我也是遇到这样的问题,需要从海康摄像头抓取之后进行人脸识别,对视频进行处理之后进行 rtmp 进行推流。
    我的代码:
    size = (int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)), int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)))
    sizeStr = str(size[0]) + 'x' + str(size[1])
    fps = cap.get(cv2.CAP_PROP_FPS) # 30p/self
    fps = int(fps)
    rtmpUrl = 'rtmp://192.168.1.71:1935/live/app'
    command = ['ffmpeg',
    '-y',
    '-f', 'rawvideo',
    '-vcodec','rawvideo',
    '-pix_fmt', 'bgr24',
    '-s', sizeStr,
    '-r', str(fps),
    '-i', '-',
    '-c:v', 'libx264',
    '-pix_fmt', 'yuv420p',
    '-preset', 'ultrafast',
    '-f', 'flv',
    rtmpUrl]

    while True:
    ret, frame = cap.read()
    proc = sp.Popen(command, stdin=sp.PIPE, shell=False)
    proc.stdin.write(frame.tostring())
    if cv2.waitKey(1) & 0xFF == ord('q'):
    break

    运行是成功了(也不能说成功,有时候会崩溃),但是用 VLC 却是不能拉流观看。
    然后再想是否是你说的这个问题,从 numpy.ndarray->cv2.cv.cvmat。
    但是在网上查资料说 mat_array = cv2.cv.fromarray(frame),这个 opencv-python 2.4 之后就没了。
    希望题主看到之后能解答一下!
    ZoomQuiet
        32
    ZoomQuiet  
    OP
       2018-12-01 17:46:42 +08:00
    [FFmpeg] Python 2.7 怎样合理的包裹外部指令安定调用第三方工具并安全结束? - V2EX
    https://www.v2ex.com/t/513363#reply0

    新问题....
    ZoomQuiet
        33
    ZoomQuiet  
    OP
       2018-12-01 17:49:41 +08:00
    @liu826250634 是也乎,( ̄▽ ̄)
    这也是为什么, 我们一直没升级到 Py3+cv3 的原因,
    py2.7.X+OpenCV2.4.X 的组合足够安定就没理由升级到可能更好的体系...

    另外, VLC 版本也有不同的问题.
    建议参考 FFmpeg 官方文档, 先用 ffplayer 来检验 rmtp 是否真正推流成功...

    以及, 俺的经验, 这个 rmtp 最好还是先走 腾讯云的视频流服务,
    完成一个安定的数据流....
    否则, 本地局网的情况太复杂....不好判定
    hellotiny
        34
    hellotiny  
       2019-03-26 11:31:12 +08:00
    博主你好啊,我也遇到这个问题,不太理解基于 pipe 进行数据共享推流的这个原理,想问逻辑问题。
    通过管道的方式实现的哪一种形式呢?
    一是将处理过的图片缓存进 buff 中形成了有顺序的帧形成的视频流,使用 ffmpeg 推出的就是 buff 中缓存的视频流吗?
    那么推流时抓图和处理图片的进程会不会暂停?
    二是处理一帧放入管道,然后就通过 ffmpeg 推送一帧到 rtmp 服务器吗?
    我没办法判断我通过 pipe 推流有没有成功,我在 RTMP 播放器中输入推流的 RTMP 地址是没有直播在播放的。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2850 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 03:55 · PVG 11:55 · LAX 19:55 · JFK 22:55
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.