1. 现状:WebRTC H.265的兼容性到底有多“分裂”?

如果你最近在捣鼓实时音视频应用,特别是对带宽和画质有极致要求的场景,比如高清远程协作、云游戏或者低码率直播,那你大概率会和我一样,把目光投向H.265(也叫HEVC)。这玩意儿压缩效率比老前辈H.264高出一大截,理论上能省下近一半的带宽,听起来简直是“降本增效”的神器。但当你兴冲冲地想把它塞进WebRTC的流程里,准备在浏览器里大展拳脚时,现实会给你泼一盆冷水:兼容性现状,用一个词形容,就是“分裂”。

这种分裂不是简单的“有的支持,有的不支持”,而是像一张复杂的地图,横轴是操作系统,纵轴是浏览器内核,每个格子里的情况都不一样。我实测下来,感觉就像在玩一个兼容性扫雷游戏。最稳的组合目前看来是 macOS上的Safari 和 Windows/macOS上的Chrome(特定版本以上)。Safari对H.265的支持算是“原生亲儿子”,毕竟苹果在硬件和系统层面早就深度整合了HEVC。而Chrome在138版本之后,终于在非Linux的桌面平台上默认开启了WebRTC H.265的支持,这算是一个里程碑。

但除此之外,几乎全是“雷区”。所有我测试过的Edge浏览器,无论Windows还是macOS,全部不支持。这很有意思,因为Edge和Chrome同样基于Chromium内核,但微软似乎有意关闭了这扇门。Firefox更是态度明确,从桌面版到Linux版,全线不支持。至于国内的各种“套壳”浏览器,比如360系列、QQ浏览器等,目前也都没有跟上。最让人头疼的是Linux桌面环境,无论是Ubuntu、Deepin还是统信UOS,其上的Chrome、Firefox以及系统自带浏览器,目前全军覆没,无一支持WebRTC H.265。

这种分裂带来的直接后果就是,你几乎不可能开发一个纯依赖WebRTC H.265的、能在所有用户浏览器上跑通的通用应用。你不得不为那些不支持的浏览器准备一个“降级方案”,通常是切回兼容性无敌的H.264。这就引出了两个问题:第一,为什么技术更先进的H.265支持起来这么难?第二,我们开发者现在到底该怎么应对?

2. 深挖:技术瓶颈与标准化的“拦路虎”

为什么一个能明显提升效率的技术,推广起来却步履维艰?我踩过几次坑之后,发现这背后远不止“技术实现”那么简单,更像是一场由技术、商业和法律共同构成的“三国杀”。

2.1 专利池的“达摩克利斯之剑”

首先要说的就是H.265头上那柄著名的“专利之剑”。H.265的专利授权体系非常复杂,由MPEG LA、HEVC Advance等多个专利池管理,费用高昂且条款曾一度模糊。这对于开源项目来说简直是噩梦。像Chromium、Firefox(Gecko引擎)这类开源浏览器内核,其开发哲学强调自由与开放,引入一个可能让下游分发者(比如Linux发行版、其他浏览器厂商)面临潜在专利诉讼风险的编解码器,是社区非常谨慎甚至抵触的。

Firefox的开发者们就多次在公开讨论中明确表示,除非有明确、免费且无法律风险的授权路径,否则不会轻易将H.265纳入WebRTC的默认支持列表。Chromium社区虽然最终在桌面端迈出了这一步,但也经历了漫长的争论和评估,并且至今将Linux排除在外,很大程度上也是出于对开源生态中专利风险的顾虑。相比之下,苹果的Safari(WebKit内核)和微软的Edge(虽基于Chromium但由微软控制)作为商业产品,在专利谈判和风险承担上有更大的自主权和不同的考量。

2.2 浏览器内核的“路线图分歧”

其次,三大浏览器内核(Chromium/Blink、Gecko、WebKit)在多媒体技术路线上的策略差异,直接导致了支持进度的不同。

Chromium/Blink:现在是“积极但谨慎”的探索者。它通过RTCRtpSender.setParameters()等API暴露了编解码器协商能力,并逐步在桌面端启用H.265。但它对硬件加速的依赖很强,需要底层操作系统(如Windows的Media Foundation,macOS的VideoToolbox)提供稳定的H.265编解码支持。这也是为什么Linux支持滞后的另一个原因——碎片化的图形驱动和硬件编解码接口(如VA-API)整合起来挑战巨大。

Gecko (Firefox):可以说是“原则性的保守派”。Mozilla基金会将用户隐私、开放网络和避免专利陷阱放在极高优先级。在H.265的专利阴云没有彻底散去,或者没有出现一个真正开放免专利费的强大替代品(比如AV1)之前,Firefox主动拥抱H.265的动力不足。他们更倾向于推动下一代开放编解码器AV1在WebRTC中的普及。

WebKit (Safari):则是“软硬一体的先行者”。苹果从macOS High Sierra和iOS 11时代就开始在全系统层面力推HEVC,iPhone等设备的摄像头早已支持HEVC录制。因此,Safari对H.265的支持是水到渠成,深度集成在系统的Media框架中,性能和能效表现都很好。

2.3 开发者端的“适配成本”

对于我们这些写代码的来说,这种分裂意味着更高的适配成本。你不能简单地在SDP Offer/Answer里塞一个H265/90000就完事了。你需要写额外的JavaScript代码来检测浏览器支持情况。

// 一个简单的检测示例
async function checkH265Support() {
  const capabilities = RTCRtpSender.getCapabilities('video');
  if (!capabilities) return false;
  
  // 查找支持的编解码器里有没有H.265
  const h265Codec = capabilities.codecs.find(codec => 
    codec.mimeType.toLowerCase() === 'video/h265' ||
    codec.mimeType.toLowerCase() === 'video/hevc'
  );
  
  return !!h265Codec;
}

// 根据检测结果,动态选择编解码器
const useH265 = await checkH265Support();
const offerOptions = {
  offerToReceiveAudio: true,
  offerToReceiveVideo: true
};

const pc = new RTCPeerConnection(configuration);
// ... 添加本地流 ...

const offer = await pc.createOffer(offerOptions);
// 这里可能需要根据useH265修改SDP,优先或排除H.265
await pc.setLocalDescription(offer);

这还只是最基础的检测。更复杂的是,你还需要在后端的媒体服务器(比如Janus、Mediasoup、LiveKit)上做对应的配置,确保它能正确转发和处理H.265码流。如果客户端混合了H.265和H.264,服务器可能还需要做转码,这又会引入延迟和性能开销。

3. 实战:现阶段如何安全地应用WebRTC H.265?

知道了现状和原因,我们总不能干等着。在实际项目中,我摸索出了一套相对稳妥的策略,核心思想是:把H.265作为“增强体验”,而非“基础功能”。

3.1 建立分级支持策略

我的建议是建立一个清晰的分级策略,而不是简单的“是或否”。

  • 第一梯队(全功能支持):针对 macOS Safari 和 高版本桌面Chrome(138+)用户。在这些平台上,你可以大胆地在SDP中优先提供H.265选项,让它们建立高质量的H.265视频通道,享受低带宽、高画质的红利。
  • 第二梯队(尝试性支持):针对新版Edge、以及未来可能更新的其他Chromium系浏览器。你可以通过代码检测,如果支持则启用,但不作为主要卖点。同时要做好完备的降级测试。
  • 第三梯队(降级保障):针对 Firefox、Linux用户、国产浏览器以及所有检测不支持H.265的环境。必须无缝降级到H.264(VP8/VP9也可作为备选)。这里的关键是“无缝”,用户不应该感受到任何错误或中断,只是画质/带宽比可能略有不同。

一个简单的实现流程图可以帮你理清思路:

  1. 页面加载后,异步检测浏览器对 video/H265 或 video/HEVC 的支持。
  2. 创建RTCPeerConnection时,根据检测结果,在transceiver.setCodecPreferences()中设置编解码器优先级顺序。支持H265的,就把H265放前面;不支持的,就只放H264/VP8。
  3. 在信令交互(交换SDP)时,浏览器会根据你设置的优先级生成对应的媒体行。
  4. 媒体服务器需要能够理解并处理客户端发来的多种编解码器提议,选择双方都支持的最高优先级进行通信。

3.2 关键配置与代码示例

假设我们使用一个简单的Node.js信令服务器和前端。前端的关键配置部分如下:

// 配置ICE服务器和编解码器偏好
const pcConfig = {
  iceServers: [{ urls: 'stun:stun.l.google.com:19302' }],
  // 注意:sdpSemantics 已废弃,现代浏览器默认使用'unified-plan'
};

const pc = new RTCPeerConnection(pcConfig);

// 假设我们已经有了一个视频流 localStream
const videoTrack = localStream.getVideoTracks()[0];
const sender = pc.addTrack(videoTrack, localStream);

// **核心:动态设置编解码器偏好**
if (supportsH265) {
  // 如果支持H.265,我们优先选择它,其次是H.264和VP8
  const h265Codec = { mimeType: 'video/H265' }; // 或 'video/HEVC'
  const h264Codec = { mimeType: 'video/H264', clockRate: 90000, parameters: { 'packetization-mode': 1 } };
  const vp8Codec = { mimeType: 'video/VP8', clockRate: 90000 };
  
  // 获取发送器并设置偏好
  const transceiver = pc.getTransceivers().find(t => t.sender === sender);
  if (transceiver) {
    transceiver.setCodecPreferences([h265Codec, h264Codec, vp8Codec]);
  }
} else {
  // 不支持H.265,则优先H.264
  const h264Codec = { mimeType: 'video/H264', clockRate: 90000, parameters: { 'packetization-mode': 1 } };
  const vp8Codec = { mimeType: 'video/VP8', clockRate: 90000 };
  const transceiver = pc.getTransceivers().find(t => t.sender === sender);
  if (transceiver) {
    transceiver.setCodecPreferences([h264Codec, vp8Codec]);
  }
}

在后端的媒体服务器(以Mediasoup为例)配置中,你需要在routerOptions里明确声明支持的编解码器:

const mediaCodecs = [
  {
    kind: 'video',
    mimeType: 'video/H265',
    clockRate: 90000,
    parameters: {
      'packetization-mode': 1,
      'profile-level-id': '640032' // 示例参数,具体根据需求调整
    }
  },
  {
    kind: 'video',
    mimeType: 'video/H264',
    clockRate: 90000,
    parameters: {
      'packetization-mode': 1,
      'profile-level-id': '42e01f' // 常用约束基线配置
    }
  },
  {
    kind: 'video',
    mimeType: 'video/VP8',
    clockRate: 90000
  }
];

这样,当支持H.265的客户端连接时,媒体服务器就能与之协商建立H.265通道;不支持的客户端,则会自动协商到H.264或VP8。

3.3 必须绕开的“坑”

在实际部署中,我遇到过几个典型的坑:

  • SDP解析差异:不同浏览器生成的H.265相关的SDP行(a=rtpmap, a=fmtp)格式可能略有不同,你的信令服务器或SDP处理逻辑需要有足够的容错性,不要做过于严格的字符串匹配。
  • 硬件加速不一致:即使在支持的平台上,H.265编码和解码也严重依赖硬件加速。务必要在目标设备上进行充分的性能和功耗测试。有时软件编解码的H.265可能还不如硬件加速的H.264。
  • 移动端仍是禁区:目前,iOS和Android上的所有浏览器(包括Chrome和Safari),在WebRTC中均不支持H.265。这是因为移动端的WebRTC实现通常有更严格的编解码器限制。所以如果你的应用有移动端需求,现阶段完全不用考虑H.265。

4. 展望:未来1-2年,我们会看到什么变化?

预测未来总是有风险的,但结合开源社区的动态和一些行业风向,我们可以对接下来一两年做个有理有据的猜想。

4.1 浏览器支持路线图预测

  • Chrome/Chromium:我认为它会继续巩固在Windows和macOS上的支持,并逐步解决Linux桌面的支持难题。突破口可能在两个方面:一是Linux硬件编解码生态的进一步成熟(比如Wayland和PipeWire的普及),二是Chromium社区可能推动基于VA-API或V4L2的通用硬件加速接口更加完善。预计在未来1-2个主要版本内,我们可能会看到Linux版Chrome在具备条件的系统上实验性支持H.265。
  • Firefox:短期内态度发生根本转变的可能性不大。Mozilla的重心明显在推动AV1上。只有当H.265的专利问题出现重大转机(例如出现一个对所有网络应用免费的授权方案),或者AV1在实时通信领域的普及遇到难以逾越的障碍时,Firefox才会重新评估。我个人认为,未来两年内Firefox默认启用WebRTC H.265的概率低于30%。
  • Edge:这是一个变数。Edge完全有能力跟随Chromium上游的改动快速启用H.265。微软的迟疑可能源于其自身的战略考量,比如推广其自家的媒体技术,或者评估专利风险。一旦微软认为时机成熟,Edge可能通过一个标志(flag)或直接默认的方式快速跟上。值得密切关注其开发者博客和Chromium提交记录。
  • Safari:它会继续保持领先和支持,并可能进一步优化与Apple Silicon芯片的协同,提供能效比更高的H.265实时编解码体验。

4.2 来自AV1的“降维打击”

讨论H.265的未来,绝对绕不开AV1这个“房间里的大象”。AV1由开放媒体联盟(AOM)开发,免版权费,压缩效率对标甚至在某些场景超越H.265。它才是开源浏览器社区的“心头好”。

目前,Chrome、Firefox、Edge的最新版都已支持在<video>标签中播放AV1视频。但在WebRTC中,AV1的支持仍处于非常早期的阶段。Chrome和Firefox都在进行实验性的实现。可以预见,未来1-2年,浏览器厂商,尤其是Firefox和Chromium,会将大量资源投入到WebRTC AV1的研发和优化中。

对于开发者而言,这带来了新的决策点:是押注正在缓慢普及但仍有专利风险的H.265,还是等待并提前布局更开放但尚未成熟的AV1?我的建议是:对于中长期项目(生命周期超过2年),现在就应该开始调研和测试AV1在WebRTC中的进展。你可以通过浏览器的实验性标志(如Chrome的chrome://flags/#enable-av1-decoder)开启相关功能进行原型开发。AV1很可能成为解决当前编解码器分裂局面的终极答案。

4.3 给开发者的行动建议

面对这种快速变化的格局,最好的策略是保持代码的灵活性和可维护性。

  1. 抽象编解码器选择逻辑:不要将H.265或H.264的配置硬编码在业务逻辑里。将其抽象成一个“编解码器协商模块”,这个模块负责检测、排序和配置。未来要加入AV1支持时,你只需要更新这个模块。
  2. 建立监控与数据收集:在你的应用里,匿名收集用户实际使用的编解码器、浏览器版本、操作系统等信息。这些数据是你判断技术趋势、做出架构决策的最宝贵依据。你会发现,真实用户的环境分布可能和你的测试机有很大不同。
  3. 拥抱转码与转封装:在服务端,考虑使用像GStreamer、FFmpeg这样强大的媒体处理框架。即使客户端百花齐放,服务端也可以作为一个“统一接口”,接收一种格式(如H.265),然后转码或转封装成其他格式(如H.264、VP8)分发给不支持的客户端。虽然这会增加服务器开销,但在混合客户端环境中是提供一致体验的有效手段。
  4. 保持耐心,持续观望:Web平台的多媒体演进从来不是一蹴而就的。WebRTC H.265的全面普及,需要芯片厂商、操作系统、浏览器开发商、标准组织乃至法律层面的多方协同。作为一线开发者,我们既要积极尝试新技术带来的红利,也要清醒地认识到生态成熟的周期,做好打“持久战”和“兼容战”的准备。
Logo

火山引擎视频云技术社区,是面向 AI 音视频开发者的技术交流平台。这里汇聚源自抖音、豆包等亿级 DAU 产品的 RTC、直播、点播、AI 媒体处理、音视频互动技术,提供接入指南、最佳实践、性能调优、场景案例、Demo 代码、开源项目、白皮书和 API 文档。社区汇聚官方工程师与一线开发者,为 AI 视频通话、数字人、AI 视频处理等应用的开发与落地提供技术支持。

更多推荐