yangheng4922
V2EX  ›  Node.js

关于 RTSP 用 FFMPEG 转 flv 播放延迟问题

  •  1
     
  •   yangheng4922 · Jul 21, 2020 · 5565 views
    This topic created in 2143 days ago, the information mentioned may be changed or developed.

    最近在用 Electron 开发一个客户端 需要集成监控摄像头

    摄像头是海康的网络摄像头 通过 RTSP 协议获取到推流视频

    通过在 node 主进程创建一个服务 通过 websocket 接受 rtsp 连接

    在通过 ffmpeg 转码通过 stream 推到渲染进程

    渲染进程通过 flv.js 播放视频

    通过转码可以实现 web 页面播放 rtsp 的视频流

    但是会有 5~6 秒的延迟 体验很不好

    而且 客户端集成 ffmpeg 体积太大了

    想了解下 关于 rtsp 转码的方法还有那些 在 node 端可以实现的

    主进程创建的 web 服务

    import * as express from 'express'
    import * as expressWebSocket from 'express-ws'
    import ffmpeg from 'fluent-ffmpeg'
    import webSocketStream from 'websocket-stream/stream'
    const path = require('path')
    
    let ffmpegPath
    if (process.env.NODE_ENV === 'development') {
      ffmpegPath = path.join(__static, 'ffmpeg', 'bin', 'ffmpeg.exe')
    } else {
      ffmpegPath = path.join(process.cwd(), 'ffmpeg', 'bin', 'ffmpeg.exe')
    }
    ffmpeg.setFfmpegPath(ffmpegPath)
    
    // 启动视频转码服务服务
    function videoServer () {
      let app = express()
      app.use(express.static(__dirname))
      expressWebSocket(app, null, {
        perMessageDeflate: true
      })
      app.ws('/rtsp/', rtspRequestHandle)
      app.listen(8888)
      console.log('express listened')
    }
    
    // RTSP 转码方法
    function rtspRequestHandle (ws, req) {
      console.log('rtsp request handle')
      const stream = webSocketStream(ws, {
        binary: true,
        browserBufferTimeout: 1000000
      },
      {
        browserBufferTimeout: 1000000
      })
      let url = req.query.url
      console.log('rtsp url:', url)
      try {
        ffmpeg(url)
          .addInputOption('-rtsp_transport', 'tcp', '-buffer_size', '102400') // 这里可以添加一些 RTSP 优化的参数
          .on('start', function () {
            console.log(url, 'Stream started.')
          })
          .on('codecData', function () {
            console.log(url, 'Stream codecData.')
          })
          .on('error', function (err) {
            console.log(url, 'An error occured: ', err.message)
          })
          .on('end', function () {
            console.log(url, 'Stream end!')
          })
          .outputFormat('flv').videoCodec('copy').noAudio().pipe(stream)
      } catch (error) {
        console.log(error)
      }
    }
    
    export default videoServer
    

    渲染进程通过播放视频

    <template>
      <div class="video">
        <video class="video-box" ref="player"></video>
      </div>
    </template>
    
    <script>
      import flvjs from 'flv.js'
      export default {
        name: 'videopage',
        props: {
          rtsp: String
        },
        data () {
          return {
            player: null
          }
        },
        mounted () {
          if (flvjs.isSupported()) {
            let video = this.$refs.player
            if (video) {
              this.player = flvjs.createPlayer({
                type: 'flv',
                isLive: true,
                url: 'ws://localhost:8888/rtsp/?url=' + this.rtsp
              })
              this.player.attachMediaElement(video)
              try {
                this.player.load()
                this.player.play()
              } catch (error) {
                console.log(error)
              }
            }
          }
        },
        methods: {
          getCurrentFrame () {
            let video = this.$refs.player
            let scale = 1
            let canvas = document.createElement('canvas')
            canvas.width = video.videoWidth * scale
            canvas.height = video.videoHeight * scale
            canvas.getContext('2d').drawImage(video, 0, 0, canvas.width, canvas.height)
            return canvas.toDataURL('image/png')
          }
        },
        beforeDestroy () {
          this.player.destory()
        }
      }
    </script>
    
    <style lang="scss">
    .video {
      width: 100%;
      height: 100%;
      font-size: 0;
      video {
        width: 100%;
        height: 100%;
      }
    }
    </style>
    
    17 replies    2020-07-30 10:47:44 +08:00
    yangheng4922
        1
    yangheng4922  
    OP
       Jul 21, 2020
    不要沉啊
    yangheng4922
        2
    yangheng4922  
    OP
       Jul 22, 2020
    有大佬遇到过这种问题么
    circleee
        3
    circleee  
       Jul 22, 2020
    能转成 rtmp 吗?
    jiobanma
        4
    jiobanma  
       Jul 22, 2020
    c 的话不知道怎么做,不过我开源了一套 java 的 rtsp-rtmp 的服务,使用开源的 javacv 框架(调用底层 ffmpeg ) 使用了转封装的技术,直接将音视频解复用,然后转封装为 flv 格式的包推出去,因为不涉及编解码 所以 cpu 内存占用率很低。延迟的话大概 1-3s ggitee 地址: https://gitee.com/banmajio/RTSPtoRTMP github: https://github.com/banmajio/RTSPtoRTMP 如果有帮助,劳烦点个 star
    seven2f
        5
    seven2f  
       Jul 22, 2020
    @circleee rtmp 最多用到年底
    lower
        6
    lower  
       Jul 22, 2020
    有没有可能直接集成个 vlc 直接取 rtsp 流?
    tangchi695
        7
    tangchi695  
       Jul 23, 2020
    想问下海康的视频流怎么获取的呢?同样在弄一个有监控的项目,以前没做过视频,不知道怎么在 nvr 上做二次开发。
    SongGG3
        8
    SongGG3  
       Jul 23, 2020
    试试 input output 添加 -fflags nobuffer -tune zerolatency

    然后 flv.js 添加 enableStashBuffer: true
    yangheng4922
        9
    yangheng4922  
    OP
       Jul 23, 2020
    @SongGG3 #8
    在 ffmpeg 的配置里面添加么
    yangheng4922
        10
    yangheng4922  
    OP
       Jul 23, 2020
    @tangchi695 #7 海康可以通过 rtsp 协议获取视频流
    yangheng4922
        11
    yangheng4922  
    OP
       Jul 24, 2020
    @SongGG3 #8
    ```javascript
    ffmpeg(url)
    .addInputOption('-rtsp_transport', 'tcp', '-buffer_size', '102400', '-fflags', 'nobuffer', '-tune', 'zerolatency')
    ```

    ```javascript
    flvjs.createPlayer({
    type: 'flv',
    isLive: true,
    url: 'ws://localhost:8888/rtsp/?url=' + this.rtsp,
    enableStashBuffer: true // 添加行
    })
    ```
    yangheng4922
        12
    yangheng4922  
    OP
       Jul 24, 2020
    @SongGG3 #8 是这样子么
    yangheng4922
        13
    yangheng4922  
    OP
       Jul 26, 2020
    @SongGG3 #8
    我修改了一下参数 但是还是没有明显的改善
    SongGG3
        14
    SongGG3  
       Jul 27, 2020
    @yangheng4922 output 的参数也加上去 -fflags nobuffer.
    flv.js enableStashBuffer: false 才对,忘记改了
    yangheng4922
        15
    yangheng4922  
    OP
       Jul 27, 2020
    @SongGG3 #14 改了一下 差不多延时控制在 一秒左右
    yangheng4922
        16
    yangheng4922  
    OP
       Jul 29, 2020
    @SongGG3 #14 我查了文档说是可以通过设置 video.currentTime = this.player.buffered.end(0) 来清除延迟
    是可以 但是 视频会一卡一卡的
    lifefriend
        17
    lifefriend  
       Jul 30, 2020
    @yangheng4922 怎么做到 1s 延迟的。我按照 lz 给出的代码,延迟在 5s 。
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   3497 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 53ms · UTC 10:42 · PVG 18:42 · LAX 03:42 · JFK 06:42
    ♥ Do have faith in what you're doing.