RTSP H264/HEVC 流 Wasm 播放

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

相关模块:

1# RTSP WebSocket Proxy 2RTSP/Webcam/File > FFmpeg open > Packets > WebSocket 3# WS Wasm Player 4WebSocket > Packets > Wasm FFmpeg decode to YUV > WebGL display 5 > Wasm OpenGL display 6# WS Local Player 7WebSocket > 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 显示。

前端效果:

后端流代理服务

主流程:

1# RTSP WebSocket Proxy 2RTSP/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)。

最终,可配置项有:

1log: 2 # true: stderr, false: logfiles 3 logtostderr: true 4 alsologtostderr: false 5 colorlogtostderr: true 6 # LOG(), 0: INFO, 1: WARNING, 2: ERROR, 3: FATAL 7 minloglevel: 0 8 # VLOG(N) 9 v: 0 10 log_prefix: true 11 log_dir: "." 12 max_log_size: 8 13 stop_logging_if_full_disk: true 14 15server: 16 addr: "0.0.0.0" 17 port: 8080 18 threads: 3 19 20 http: 21 enable: true 22 doc_root: "../ws-wasm-player/" 23 24 cors: 25 enabled: true 26 allowed_origins: "*" 27 allowed_methods: [ GET ] 28 allowed_headers: 29 - Content-Type 30 allowed_credentials: false 31 exposed_headers: 32 - Content-Type 33 debug: false 34 35 stream: 36 http_target: "/streams" 37 ws_target_prefix: "/stream/" 38 39streams: 40 - 41 id: "a" 42 method: "file" 43 input_url: "../data/test.mp4" 44 - 45 id: "b" 46 method: "network" 47 input_url: "rtsp://127.0.0.1:8554/test" 48 49 max_delay: 1000000 50 rtsp_transport: "tcp" 51 stimeout: 5000000 52 - 53 id: "c" 54 method: "webcam" 55 input_url: "/dev/video0" 56 57 input_format: "v4l2" 58 width: 640 59 height: 480 60 framerate: 20 61 pixel_format: "yuyv422" 62 63# 25 = 1000 / 40 fps 64stream_get_frequency: 25 65 66# test only: multithreading glfw not coding stable now 67stream_ui_enable: false

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

前端解码与播放

主流程:

1# WS Wasm Player 2WebSocket > Packets > Wasm FFmpeg decode to YUV > WebGL display 3 > 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 个人实践的经验分享,可关注公众号!

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )