通过这个帖子把我对通过webrtc方式播放H265视频的技术探索过程记录下来。虽然最终不一定能够形成产品进行实现,但觉得也是一个有意义的过程。很多事情不就是这样吗?也希望将来能够有同道中人看到这个帖子,一起分享交流~
-----------------------------
一。背景
1)由于Webrtc具有低延时、高稳定、浏览器原生支持等特点,目前使用webrtc进行视频播放已经是一个主流的方案;2)受限于专利许可、硬件支持、生态系统支持等限制,目前主流的浏览器并不将H265作为Webrtc的默认视频编解码器选项之一。3)由于H265编码相对于H264具有更高的视频压缩比和视频质量,当前现场的摄像机设备大多默认支持的是H265视频编码。
在尽量不修改现场摄像机配置的前提下,进行H265视频的播放可以通过如下几种解决方案:1)后端转码:服务器后台进行H265到H264的视频转码,将转码后的视频传输到前端使用webrtc进行播放。缺点:视频转码会使服务器后台消耗大量计算资源,难以承担多用户多视频流的同时播放。2)FLV播放器:使用能够播放H265视频的FLV前端播放器。缺点:a)FLV播放会有1~3秒延迟;b)浏览器端解码会消耗客户端资源,对客户电脑硬件有要求;3)改造webrtc支持H265视频播放。预研基于webrtc的datachannel数据通道传输H265视频到前端播放器,定制前端播放器解码H265视频进行播放。
方案1)具有可行性,但最好是通过给服务器搭配专用的GPU硬件转码芯片,否则纯CPU扛不住多路转码。
方案2)如果对视频播放的时延要求不高,可以使用,传统的也都是这样的。
方案3)是一个新的技术方向,市面上也有一些公司已经在使用了。
基于方案3)可以预见的缺点:a)技术难度较大,需要对webrtc协议的深度理解,需要改造zlm后端,需要改造webrtc播放器。b)通过前端播放器进行解码仍会存对客户电脑硬件有要求的缺点,不过现在客户的电脑配置已经越来越高了。
基于方案3)可以预见的优点:a)借助于webrtc协议底层udp、sctp、qos等优化技术,能够高效稳定的传输的H265视频流,视频播放整体延迟会比FLV要低。b)通过预研前端播放器视频解码方式,可以逐步适配wasm、webcodec等软硬件解码方案,能够最大程度发挥客户电脑的资源能力。通过前后端解码策略控制,寻找服务器端与客户端资源占用的最优解。
二。理论原理:
1.Datachannel介绍:
webrtc涉及到协议栈如下图所示,主要分为两类。左侧基于TCP部分webrtc前期建立的SDP交互信令传输。其它核心协议是基于右侧的UDP搭建起来的,其中ICE、STUN、TURN用于网络建立,DTLS是用于对传输内容进行加密,SRTP是对音频和视频数据进行RTP封装之后再进行加密传输,SCTP是用于UDP数据的加密可靠传输,RTCPeerConnection用来建立和维护端到端的音视频传输连接,DataChannel用来支持端到端的任意文本或二进制数据传输。
DataChannel的底层是基于UDP、DTLS、SCTP等技术实现。允许服务器与浏览器直接进行双向的、实时的数据传输。与音视频流不同,DataChannel主要用于传输任意类型的数据,如文本、文件、二进制数据等。可以用于文本聊天等即时通信,文件传输,游戏数据传输,实时协作控制、物联网数据传输等。由于DataChannel是基于UDP的并且可以传输任意类型的二进制数据,因此理论上也可以用于传输H265编码的视频数据,并且能够降低数据传输的延迟。并且SCTP协议封装了一些丢包重传、差错控制、数据加密等特性,可以保证视频数据稳定可靠的传输到浏览器端。因此在技术上是可以通过改造ZLM实现基于DataChannel数据通道传输H265视频的。
如果要实现基于webrtc的datachannel播放H265视频,至少有如下几个方面需要去改造实现:
1)webrtc使用的是SDP媒体协商机制,由于当前浏览器端并不支持H265编码,因此需要在浏览器端或ZLM端在媒体协商的地方进行一些修改,能够协商出H265编码,否则后续流程无法进行。
2)webrtc传输视频流底层是使用RTP进行封装的,即使使用DataChannel传输H265视频流,底层其实还是使用的RTP对视频流进行封装。在服务端应该能够判断出视频编码类型,并通过DataChannel通道传输RTP视频流。在浏览器端应该能够通过DataChannel通道获取到RTP视频流,对RTP包解封装获取到原始的H265视频帧。因此需要对RTP的封装和解封装进行掌握和了解。
3)前端播放器解析出原始的H265视频帧之后,需要进行解码和渲染。经过调研,前端浏览器视频解码的技术有wasm、webcodec、mse等,视频画面渲染的技术有canvas、webgl等,因此需要对前端视频解码渲染进行掌握和了解。
2.RTP协议学习:
前期已经有过相关技术储备,只不过把视频编码改为H265即可,套路差不多:
https://www.cnblogs.com/feixiang-energy/p/18350369
https://www.cnblogs.com/feixiang-energy/p/18525281
3.WASM学习:
什么是WebAssembly?1)一种新型的代码,可以运行在 Web 浏览器,提供一些新特性并主要专注于高性能;2)主要不是用于写,而是 C/C++、C#、Rust 等语言编译的目标,所以你即使不知道如何编写 WebAssembly 代码也能利用它的优势;3)其他语言编写的代码也能以近似于原生速度运行,客户端 App 也能在 Web 上运行;4)在浏览器或 Node.js 中可以导入 WebAssembly 模块,JS 框架能够使用 WebAssembly 来获得巨大的性能优势和新的特性的同时在功能上易于使用。
WebAssembly与JS的关系?1)WebAssembly 是一种与 JavaScript 不同的语言,被设计为与 JS 互为补充并能协作,使得 Web 开发者能够重复利用两种语言的优点;2)JS 是高层次的语言,灵活且极具表现力,动态类型、不需要编译步骤,并且有强大的生态,非常易于编写 Web 应用;3)WebAssembly 是一种低层次、类汇编的语言,使用一种紧凑的二级制格式,能够以近乎原生的性能运行,并提供了低层次的内存模型,是 C++、Rust 等语言的编译目标,使得这类语言编写的代码能够在 Web 上运行(需要注意的是,WebAssembly 将在未来提供垃圾回收的内存模型等高层次的目标)。
如何移植C++应用?1)EMScripten 将 C/C++ 代码喂给 Clang 编译器(一个基于 LLVM 编译架构的 C/C++ 编译器),编译成 LLVM IR;2)EMScripten 将 LLVM IR 转换成 .wasm 的二进制字节码;3)WebAssembly 无法直接获取到 DOM,只能调用 JS,传入整形或浮点型的等原始数据类型,因此 WebAssembly 需要调用 JS 来获取 Web API 和调用,EMScripten 则通过创建了 HTML 文件和 JS 胶水代码来达到上述效果。
三。后端改造ZLM实现DataChannel推送H265视频流
1.ZLM开启DataChannel支持:
1)修改CMakeLists.txt文件,ENABLE_SCTP字段设置为ON。
2)安装libusrsctp库:
git clone https://github.com/sctplab/usrsctp.git cd usrsctp ./bootstrap make && sudo make install
3)重新编译ZLM,提示WebRTC datachannel功能已打开。
4)扩展ZLM,封装接口支持发送简单文本信息。a)ZLM的webRtcTransport.cpp类中封装了sendDataChannel函数。支持两种ppid。51:文本string;53:二进制。b)ZLM的webRtcTransportManager是一个webrtc连接的全局管理器,在其中增加根据app和stream查找连接的函数。c)ZLM的WebApi.cpp封装了HTTP接口调用,在其中增加发送datachannel的接口函数。
5)简单测试验证:前端播放器已经能够回调输出通过datachannel传输的文本数据。(其实这个功能也有很大的应用意义)
6)改造ZLM的SDP协商细节。核心逻辑在WebRtcTransport::getAnswerSdp和RtcConfigure::matchMedia中实现,主要是根据浏览器提供的offerSDP内容匹配当前MediaSource的音视频编码,协商出真正建立连接的媒体编码格式。由于浏览器offerSDP中不包含H265,因此当视频流为H265编码时,会匹配失败。
7)经过SDP交互媒体信息、ICE协商网络连接、DTLS秘钥握手等一系列操作之后。在WebRtcPlayer::onStartWebRTC函数中开始发送数据,在ZLM的代码架构中,webrtc播放和其他协议的播放差不多,都认为是一个Player,通过在MediaSource的视频环形缓存队列上注册Reader回调函数实现,当RTSP拉流端接收到新的RTP视频帧时,通过回调的方式进入到webrtc的发送方法。
8)修改WebRtcTransportImp::canSendRtp函数,先粗暴的不判断answerSDP中是否协商出发送通道,直接返回True。
9)修改webrtc发送视频帧的代码。判断当视频编码为H265时,不再使用SRTP的videoChannel媒体通道发送,而是使用DataChannel发送原始RTP帧。
10)ZLM通过datachannel发送H265测试验证。通过RTSP方式拉取一个H265的视频,通过Webrtc的方式进行播放。可以通过前端的consol日志查看,接收到了原始的H265视频帧。
四。WASM播放H265技术验证:
1)emsdk环境搭建,略。
2)编写简单Demo测试JS加载C++函数。略
3)找到一个开源项目:https://github.com/sonysuqin/WasmVideoPlayer
4)编译ffmpeg-wasm的过程:使用的是ffmpeg-4.4.4.tar.gz
编译选项配置: emconfigure ./configure --cc="emcc" --cxx="em++" --ar="emar" --ranlib="emranlib" --objcc=emcc --dep-cc=emcc --prefix=../WasmVideoPlayer/dist --enable-cross-compile --target-os=none --arch=x86_32 --cpu=generic --enable-gpl --enable-version3 --disable-avdevice --disable-swresample --disable-postproc --disable-avfilter --disable-programs --disable-logging --disable-everything --enable-avformat --enable-decoder=hevc --enable-decoder=h264 --enable-decoder=aac --disable-ffplay --disable-ffprobe --disable-asm --disable-doc --disable-devices --disable-network --disable-hwaccels --disable-parsers --disable-bsfs --disable-debug --enable-protocol=file --enable-demuxer=mov --enable-demuxer=flv --disable-indevs --disable-outdevs ------------------------ 编译: emcc make -j4 && make install ------------------------ 生成libffmpeg.wasm和libffmpeg.js export TOTAL_MEMORY=67108864 export EXPORTED_FUNCTIONS="[ \ '_initDecoder', \ '_uninitDecoder', \ '_openDecoder', \ '_closeDecoder', \ '_sendData', \ '_decodeOnePacket', \ '_seekTo', \ '_main', '_malloc', '_free' ]" echo "Running Emscripten..." emcc decoder.c dist/lib/libavformat.a dist/lib/libavcodec.a dist/lib/libavutil.a dist/lib/libswscale.a dist/lib/libswresample.a \ -O3 \ -I "dist/include" \ -s WASM=1 \ -s TOTAL_MEMORY=${TOTAL_MEMORY} \ -s EXPORTED_FUNCTIONS="${EXPORTED_FUNCTIONS}" \ -s EXTRA_EXPORTED_RUNTIME_METHODS="['addFunction']" \ -s RESERVED_FUNCTION_POINTERS=14 \ -s FORCE_FILESYSTEM=1 \ -o libffmpeg.js echo "Finished Build"
5)跑通WasmVideoPlayer演示Demo,实现在web页面上播放H265格式的MP4文件
五。最终目标:通过webrtc+datachannel+wasm实现H265的视频播放。
六。未完成项:
- 1.继续完善SDP协商机制。通过修改前端代码增加H265选项或修改ZLM后台逻辑,使得能够匹配出H265的媒体通道协商。
- 2.继续预研前端浏览器通过WASM方式进行H265视频解码的实现方案。
- 3.继续进一步研究H265的RTP封装逻辑。能够实现在浏览器端通过WASM的方式将RTP包重新解析为原始的H265视频帧。
- 4.预研基于ZLMRTCClien.js进行修改,将Datachannel接收H265视频帧与WASM技术相结合,实现视频画面渲染播放。
- 5.由于WASM技术只能使用CPU进行视频解码,已经有点落伍。未来可以研究比较新的前端webcodec、mse等硬件解码方式。提升播放器解码性能。
标签:视频,--,H265,datachannel,disable,wasm,播放,webrtc From: https://www.cnblogs.com/feixiang-energy/p/18536950