RTSP H264/HEVC 流 Wasm 播放

GoCodingInMyWay發表於2021-09-08

本文將介紹 RTSP H264/HEVC 裸流如何於網頁前端播放。涉及 WebSocket 代理髮送流資料, Wasm 前端解碼等。

相關模組:

# RTSP WebSocket Proxy
RTSP/Webcam/File > FFmpeg open > Packets > WebSocket
# WS Wasm Player
WebSocket > Packets > Wasm FFmpeg decode to YUV > WebGL display
                                                > Wasm OpenGL display
# WS Local Player
WebSocket > Packets > FFmpeg decode to YUV > OpenGL display
  • RTSP WebSocket Proxy: 流代理伺服器(C++)。HTTP 請求流資訊(支援了跨域),WebSocket 傳輸流資料。
  • WS Wasm Player: 前端播放實現(ES6)。WebSocket, Wasm, WebGL 等封裝,提供了 WsClient 介面。
  • WS Local Player: 本地播放實現(C++)。與前端流程一樣,向流代理伺服器請求資料,解碼後 OpenGL 顯示。

前端效果:

後端流代理服務

主流程:

# RTSP WebSocket Proxy
RTSP/Webcam/File > FFmpeg open > Packets > WebSocket
  • FFmpeg 開啟 RTSP/Webcam/File ,獲取 packets (common/media/stream.cc)
  • FFmpeg bsf (bitstream filter) 獲取 h264/hevc 裸流 packets (rtsp-ws-proxy/stream_handler.cc)
  • Boost.Beast 實現 WebSocket 服務,傳送裸流 packets 給訂閱的客戶端 (rtsp-ws-proxy/ws_*)

前端 FFMpeg Wasm 解碼,需要的兩個結構體為:

  • AVCodecParameters: 編碼引數。序列化為 JSON, HTTP Get 請求獲取 (common/net/json.h)
  • AVPacket: 流資料包。序列化為 binary , WebSocket 進行傳輸 (common/net/packet.h)

服務支援了 HTTP 靜態伺服器,可直接部署 WS Wasm Player 頁面。但前後端分離部署時,就要求服務允許跨域了 (common/net/cors.h)。

最終,可配置項有:

log:
  # true: stderr, false: logfiles
  logtostderr: true
  alsologtostderr: false
  colorlogtostderr: true
  # LOG(), 0: INFO, 1: WARNING, 2: ERROR, 3: FATAL
  minloglevel: 0
  # VLOG(N)
  v: 0
  log_prefix: true
  log_dir: "."
  max_log_size: 8
  stop_logging_if_full_disk: true

server:
  addr: "0.0.0.0"
  port: 8080
  threads: 3

  http:
    enable: true
    doc_root: "../ws-wasm-player/"

  cors:
    enabled: true
    allowed_origins: "*"
    allowed_methods: [ GET ]
    allowed_headers:
      - Content-Type
    allowed_credentials: false
    exposed_headers:
      - Content-Type
    debug: false

  stream:
    http_target: "/streams"
    ws_target_prefix: "/stream/"

streams:
  -
    id: "a"
    method: "file"
    input_url: "../data/test.mp4"
  -
    id: "b"
    method: "network"
    input_url: "rtsp://127.0.0.1:8554/test"

    max_delay: 1000000
    rtsp_transport: "tcp"
    stimeout: 5000000
  -
    id: "c"
    method: "webcam"
    input_url: "/dev/video0"

    input_format: "v4l2"
    width: 640
    height: 480
    framerate: 20
    pixel_format: "yuyv422"

# 25 = 1000 / 40 fps
stream_get_frequency: 25

# test only: multithreading glfw not coding stable now
stream_ui_enable: false

將想要代理的 RTSP 流配置進 streams,執行服務即可。

前端解碼與播放

主流程:

# WS Wasm Player
WebSocket > Packets > Wasm FFmpeg decode to YUV > WebGL display
                                                > Wasm OpenGL display
  • 前端頁面填寫服務地址,重新整理並選擇某流,再開啟 (ws-wasm-player/index.html)
  • WebSocket 獲取流資料,給到 Wasm FFmpeg 解碼,再轉碼為 YUV420p (ws-wasm-player/src/decoder.h)
  • WebGL 顯示 YUV420p ,或給到 Wasm OpenGL 進行顯示 (ws-wasm-player/src/player.h)

簡單實測:

  • H264 1920x1080 25fps, 前端解碼轉碼耗時 80~120 ms,來不及處理,引起卡頓
  • H264 1280x720 25fps, 前端解碼轉碼耗時 10~30 ms,能夠及時處理及顯示

所以於高解析度的場景,考慮 MediaSource, WebCodecs 等硬解更好。

此外 RTSP 建議用 TCP 。UDP 時,後端服務報丟包警告,前端解碼則報 P 幀警告,容易花屏、OOM。

結語

除了 RTSP 流,也支援了 WebCam/File ,所以可以直播 WebCam 攝像頭或輪播某 MP4 檔案。

目前想實際體驗的話,需要依照程式碼 README 自己編譯。以後可能會打包釋出,能夠快速體驗。

GoCoding 個人實踐的經驗分享,可關注公眾號!

相關文章