本文将介绍 RTSP H264/HEVC 裸流如何于网页前端播放。波及 WebSocket 代理发送流数据, Wasm 前端解码等。

  • 代码: https://github.com/ikuokuo/rt...

相干模块:

# RTSP WebSocket ProxyRTSP/Webcam/File > FFmpeg open > Packets > WebSocket# WS Wasm PlayerWebSocket > Packets > Wasm FFmpeg decode to YUV > WebGL display                                                > Wasm OpenGL display# WS Local PlayerWebSocket > 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 ProxyRTSP/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: trueserver:  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 fpsstream_get_frequency: 25# test only: multithreading glfw not coding stable nowstream_ui_enable: false

将想要代理的 RTSP 流配置进 streams,运行服务即可。

前端解码与播放

主流程:

# WS Wasm PlayerWebSocket > 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 集体实际的教训分享,可关注公众号!