V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
yangheng4922
V2EX  ›  Node.js

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

  •  1
     
  •   yangheng4922 · 229 天前 · 2077 次点击
    这是一个创建于 229 天前的主题,其中的信息可能已经有所发展或是发生改变。

    最近在用 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 条回复    2020-07-30 10:47:44 +08:00
    yangheng4922
        1
    yangheng4922   229 天前
    不要沉啊
    yangheng4922
        2
    yangheng4922   229 天前
    有大佬遇到过这种问题么
    circleee
        3
    circleee   228 天前
    能转成 rtmp 吗?
    jiobanma
        4
    jiobanma   228 天前
    c 的话不知道怎么做,不过我开源了一套 java 的 rtsp-rtmp 的服务,使用开源的 javacv 框架(调用底层 ffmpeg ) 使用了转封装的技术,直接将音视频解复用,然后转封装为 flv 格式的包推出去,因为不涉及编解码 所以 cpu 内存占用率很低。延迟的话大概 1-3s ggitee 地址: https://gitee.com/banmajio/RTSPtoRTMP github: https://github.com/banmajio/RTSPtoRTMP 如果有帮助,劳烦点个 star
    leega0
        5
    leega0   228 天前
    @circleee rtmp 最多用到年底
    lower
        6
    lower   228 天前
    有没有可能直接集成个 vlc 直接取 rtsp 流?
    tangchi695
        7
    tangchi695   227 天前
    想问下海康的视频流怎么获取的呢?同样在弄一个有监控的项目,以前没做过视频,不知道怎么在 nvr 上做二次开发。
    SongGG3
        8
    SongGG3   227 天前
    试试 input output 添加 -fflags nobuffer -tune zerolatency

    然后 flv.js 添加 enableStashBuffer: true
    yangheng4922
        9
    yangheng4922   227 天前
    @SongGG3 #8
    在 ffmpeg 的配置里面添加么
    yangheng4922
        10
    yangheng4922   227 天前
    @tangchi695 #7 海康可以通过 rtsp 协议获取视频流
    yangheng4922
        11
    yangheng4922   227 天前
    @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   227 天前
    @SongGG3 #8 是这样子么
    yangheng4922
        13
    yangheng4922   224 天前
    @SongGG3 #8
    我修改了一下参数 但是还是没有明显的改善
    SongGG3
        14
    SongGG3   223 天前
    @yangheng4922 output 的参数也加上去 -fflags nobuffer.
    flv.js enableStashBuffer: false 才对,忘记改了
    yangheng4922
        15
    yangheng4922   223 天前
    @SongGG3 #14 改了一下 差不多延时控制在 一秒左右
    yangheng4922
        16
    yangheng4922   221 天前
    @SongGG3 #14 我查了文档说是可以通过设置 video.currentTime = this.player.buffered.end(0) 来清除延迟
    是可以 但是 视频会一卡一卡的
    lifefriend
        17
    lifefriend   220 天前
    @yangheng4922 怎么做到 1s 延迟的。我按照 lz 给出的代码,延迟在 5s 。
    关于   ·   帮助文档   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   1343 人在线   最高记录 5497   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 32ms · UTC 18:18 · PVG 02:18 · LAX 10:18 · JFK 13:18
    ♥ Do have faith in what you're doing.