4、H265在WebRTC中的挑战:浏览器原生不支持H265、专利授权问题、SDP协商与Payload Type映射

说实话,H265(HEVC)在WebRTC里落地,是我这几年踩坑最多的领域之一。你想想看,H265压缩效率比H264高出一大截,同等画质下码率能省30%-50%,这对流媒体来说简直是天大的诱惑。但为什么到现在,大部分WebRTC应用还在用H264?

原因就四个字:水土不服。WebRTC这套体系,从设计之初就没给H265留位置。今天我就把这块硬骨头掰开揉碎,跟你聊聊浏览器为什么不支持、专利问题有多坑、以及SDP协商里那些让人抓狂的细节。

4.1 浏览器原生不支持H265:一个历史遗留问题

先问个问题:Chrome、Firefox、Safari,哪个浏览器原生支持H265?

答案是——只有Safari。而且Safari的支持还是从macOS High Sierra和iOS 11才开始,靠的是系统级硬件解码器。Chrome和Firefox呢?至今没有原生H265解码能力。

为什么会这样?我个人的理解是,这背后有两层原因。

第一,专利地雷阵。H265的专利池比H264复杂得多。MPEG LA、HEVC Advance、Velos Media……好几家都在收专利费。浏览器厂商一旦内置H265解码器,就得面对这些专利持有者的诉讼风险。Google当年推VP9,很大程度上就是为了绕开这个坑。

第二,WebRTC标准委员会的态度。WebRTC的编解码器强制要求是H264和VP8。H265从来就没进过标准列表。我记得2017年我在一次技术会议上跟Chrome团队的工程师聊过,对方明确说:“我们不会在Chromium里内置H265解码器,除非专利问题彻底解决。”嗯,到现在也没解决。

那实际项目中怎么办?我常用的方案是:

  • 纯软件解码:用WASM(WebAssembly)把FFmpeg的H265解码器编译到浏览器里跑。缺点是性能开销大,移动端发热严重。
  • WebCodec API:Chrome 94+支持WebCodec,可以调用系统解码器。但前提是操作系统本身有H265解码能力(Windows 10+、macOS、Android 5.0+)。
  • MediaSource Extensions(MSE):把H265流封装成fMP4,通过MSE喂给<video>标签。这个方案在Safari上很稳,Chrome需要做能力检测。

核心结论:浏览器原生不支持H265,不是技术问题,是商业和标准博弈的结果。作为开发者,我们只能做能力检测,然后降级或走替代方案。

4.2 专利授权问题:悬在头顶的达摩克利斯之剑

聊到H265,专利问题永远绕不开。我2019年做过一个商业直播项目,客户指定要用H265。结果法务部门一查,直接叫停了——因为专利授权费可能比服务器带宽还贵。

H265的专利授权有多复杂?我整理了一张表:

专利池 管理方 授权模式 费用(参考)
MPEG LA HEVC MPEG LA 按设备/按内容 设备$0.20/台,内容上限$2500万/年
HEVC Advance HEVC Advance 按设备/按内容 设备$0.40/台,内容上限$4000万/年
Velos Media Velos Media 按设备 约$0.20/台
独立专利持有者 各公司/个人 单独谈判 不确定

你看,光是主流专利池就有三个。而且它们之间还有重叠专利。也就是说,你即使向MPEG LA交了费,HEVC Advance照样可能来告你。我有个朋友的公司就被HEVC Advance发过律师函,最后赔了一笔和解金了事。

那开源项目呢?FFmpeg里H265编码器是开源的,但专利风险依然存在。FFmpeg项目本身在官网明确写了:“某些功能可能受专利保护,使用者需自行承担法律风险。”

避坑指南:如果你做的是商业产品,尤其是面向欧美市场,H265的专利问题必须提前找法务评估。我曾经见过一个创业团队,产品都上线了,突然收到专利池的追缴通知,差点把公司搞垮。

有没有替代方案?有。AV1是开放免专利费的,但编码复杂度太高,实时编码基本不现实。VP9也是免专利费的,Google在大力推,但硬件支持不如H265。说白了,H265的专利问题短期内无解,只能靠商业谈判或技术规避。

4.3 SDP协商与Payload Type映射:协议层面的硬仗

好,假设你搞定了浏览器解码和专利授权,接下来要面对的是SDP协商。这是WebRTC里最磨人的环节,没有之一。

WebRTC的SDP(Session Description Protocol)负责在两端之间协商媒体参数。H264在SDP里有标准定义:H264(96-127动态PT)、level-asymmetry-allowed、packetization-mode等等。但H265呢?标准里没有。

所以我们需要自己定义Payload Type(PT)映射。我一般用动态PT范围(96-127),比如:

m=video 9 UDP/TLS/RTP/SAVPF 101
a=rtpmap:101 H265/90000
a=fmtp:101 profile-id=1; level-id=93; sprop-vps=QAEMAf//AWAAAAMAAAMAAAMAAAMAAAM=; sprop-sps=QgEBAWAAAAMAAAMAAAMAAAMAAAM=; sprop-pps=RAHA8vA8kAA=

这里有几个关键点:

  • PT=101:动态分配,只要两端一致就行。我习惯用101,好记。
  • H265/90000:时钟频率90000Hz,这是视频RTP的标准值。
  • profile-id/level-id:对应H265的Profile和Level。Main Profile是1,Main 10 Profile是2。
  • sprop-vps/sps/pps:H265的VPS、SPS、PPS参数集,Base64编码。这些必须传对,否则解码器不认识流。

我在项目中遇到过最坑的问题是什么?是两端对H265的SDP属性理解不一致。比如,Chrome的WebCodec要求sprop-vps必须包含,但有些Android设备自带的WebRTC栈却忽略这个字段。结果就是Chrome端能解码,Android端黑屏。

解决办法?我写了一个SDP兼容层,在发送端强制填充所有参数集,接收端做容错处理。核心逻辑大概这样:

// 发送端:强制填充H265参数集
function fillH265Params(sdp) {
  // 解析原始SDP,找到H265媒体行
  // 如果缺少sprop-vps/sps/pps,从编码器获取并注入
  // 注意:参数集必须与当前编码配置一致
  return sdp.replace(
    /a=fmtp:(\d+) profile-id=([^;]+)/,
    (match, pt, profile) => {
      const vps = getBase64VPS();
      const sps = getBase64SPS();
      const pps = getBase64PPS();
      return `a=fmtp:${pt} profile-id=${profile}; sprop-vps=${vps}; sprop-sps=${sps}; sprop-pps=${pps}`;
    }
  );
}

另外,PT值冲突也是常见问题。如果SDP里同时有H264和H265,它们的PT不能重复。我习惯用H264占96-100,H265占101-105,VP8/VP9占106-110。这样不容易打架。

小技巧:调试SDP协商时,用chrome://webrtc-internals抓取原始SDP文本,直接对比两端的内容。我80%的H265互通问题都是靠这个定位的。

4.4 一张图看懂H265在WebRTC中的挑战

说了这么多,我画了一张结构图,把H265在WebRTC里遇到的三大挑战串起来。你看完应该能有个全局印象。

H265在WebRTC中的三大挑战 H265 + WebRTC 浏览器原生不支持H265 仅Safari原生支持 Chrome/Firefox需WASM或WebCodec 性能开销大,移动端发热 能力检测 + 降级方案 专利授权问题 三大专利池:MPEG LA、HEVC Advance、Velos 费用按设备/内容收取 开源项目也有风险 商业产品需法务评估 SDP协商与PT映射 动态PT分配(96-127) 参数集sprop-vps/sps/pps profile-id/level-id匹配 PT冲突与兼容层 解决方案:能力检测 + 兼容层 + 商业谈判 三大挑战相互关联:浏览器不支持导致依赖WASM,专利问题限制商业使用,SDP协商决定能否互通 实际项目中需要同时解决这三个层面,缺一不可

4.5 实战中的避坑清单

最后,我把自己这几年踩过的坑整理成一份清单。你如果要在项目里上H265,建议逐条核对:

  1. 浏览器兼容性检测:不要假设所有浏览器都支持。用MediaCapabilities.decodingInfo()做运行时检测。
  2. 专利授权确认:如果是商业产品,先找法务确认授权范围。个人项目或开源项目,建议加免责声明。
  3. SDP参数完整性:发送端必须填充VPS/SPS/PPS,接收端做好容错。我曾经因为少传一个sprop-vps,排查了整整两天。
  4. PT值冲突检测:如果SDP里有多路视频流,确保每路的PT不重复。建议用固定范围分配。
  5. 降级方案:H265协商失败时,自动回退到H264或VP9。用户体验不能断。
  6. 性能监控:WASM解码时,监控CPU和内存占用。移动端超过80% CPU就要考虑降码率或切编码器。