H.265/HEVC在Web视频播放的实践

10,206 阅读8分钟

H.265

以下是百度百科对于H.265的介绍: H.265是ITU-T VCEG继H.264之后所制定的新的视频编码标准。H.265标准围绕着现有的视频编码标准H.264,保留原来的某些技术,同时对一些相关的技术加以改进。新技术使用先进的技术用以改善码流、编码质量、延时和算法复杂度之间的关系,达到最优化设置。具体的研究内容包括:提高压缩效率、提高鲁棒性和错误恢复能力、减少实时的时延、减少信道获取时间和随机接入时延、降低复杂度等。H.264由于算法优化,可以低于1Mbps的速度实现标清(分辨率在1280P720以下)数字图像传送;H.265则可以实现利用1~2Mbps的传输速度传送720P(分辨率1280720)普通高清音视频传送。

相比H.264带来了很多质的提升,相关对比可以访问H.265与H.264的差异详解。总之,H.265, HEVC 作为当前非常火的视频压缩方式,相对于大家熟知的 H.264 ,平均可以带来接近于 50% 的宽度节省。

在这里插入图片描述

相关知识

视频播放器架构

一个典型的现代播放器可以分为三个部分:UI、多媒体引擎和解码器,架构模型如下图:

在这里插入图片描述

硬解码支持

随着 4K 视频越来越流行,Apple公司的最新的操作系统版本(Mac Hight Sierra和iOS 11)迎来了 HEVC (高效视频编码,也称 H.265) 这一新的行业标准[6]。与现行的 H.264 视频压缩标准相比,它的视频压缩率最高可提升 50% 之多。使用H.265,在保持视频画质不变的情况下,视频流媒体传输效果更好。而在相同码率下,能给质量带来近两倍的提升。下图是两张相同码率相同分辨率(400kpbs 1080p)的图片,左边的采用H.265编码,右边的采用H.264编码。

在这里插入图片描述
一般来说操作系统借助硬件(显卡)进行H.265编码视频的解码工作,其好处是硬解的功耗低,解码速度快。但目前H.265编码在浏览器中的硬件解码支持情况并不普及。经测试只在定制的Chromium[7] 及Edge 14浏览器中支持,可以通过此页面,测试浏览器对H.265编码的点播视频的播放情况。下图是H.265视频在Chromium 64中播放的截图:
在这里插入图片描述
需要注意的是硬件解码需要用户的显卡支持H.265 codec, 目前支持H.265解码的显卡主要包括:Intel HD Graphic 4400/4600/5000/5500/6000/620, Iris Graphics 5100/5200/6100,NVIDIA GeForce GTX 745, GTX 750, GTX 750 Ti, GTX 850M, GTX 860M,GeForce 830M, 840M,GeForce GTX 970, GTX 980, GTX 970M, GTX 980M,GeForce GTX TITAN X, GeForce GTX 980 Ti, GeForce GTX 750 SE, GTX 950, GTX 960, GeForce GTX 1070, GTX 1080, GeForce GTX 1060, NVIDIA TITAN XP, GeForce GTX 1050, GTX 1050 Ti。

Web软解方案

除了硬解码方案之外,软件解码也成为一种有效的选择,由于H.265视频的解码是一个对性能要求很高的CPU密集任务,Web端脚本语言实现的解码器的性能很难达到要求。基于此,我们可以通过基于Flash的H.265解码方案,即通过FlasCC[11]编译器把C语言编写的解码器编译成swc库,然后在Flash播放器中用Action Script调用swc库。

另一种方案是基于HTML5的,即通过WebAssembly技术将金山云自研的高性能解码器编译为wasm库,wasm文件是以二进制形式存在的,其中包含平台无关的虚拟指令(类似汇编指令)。这也是很多移动平台采用的方案。

相关HTML5技术

下图是播放器内核主要模块与依赖的背景技术。

在这里插入图片描述
其中Audio MSE Controller依赖于Media Source Extension API,Stream Loader依赖于Stream标准,H.265 Decoder依赖于WebAssembly技术,而各个模块被划分在不同的线程中,依赖于Web Workers。

Media Source Extensions(简称MSE):

提供了实现无插件且基于 Web 的流媒体的功能。使用MSE API(主要包括:Media Source,Source Buffer等),媒体流能够通过 JavaScript 创建,并且能通过HTMLMediaElement元素(包括:video和audio元素)进行播放。IE11(win8+)及其他现代浏览器都支持。

Streams

标准提供了一套API,来创建和操作流数据,具体地,包括ReadableStream, WritableStream, 以及TransformStream。这允许我们可以增量地处理数据,而不必将所有数据缓存到内存中统一处理。我们可以采用Fetch API获取视频数据,返回的body是一个ReadableStream对象。该对象代表一个数据源,内部维护了一个队列来记录尚未被读取的底层数据源。可以通过ReadableStream的getReader()接口读取内部队列中chunk数据。

Web Workers

让单线程的JavaScript具备了多线程编程的能力,让视频播放器内核可以分离解复用、解码、渲染、UI操作监听等任务到不同的线程中,并行地处理计算密集型任务和界面显示等。worker间通信是通过MessageChannel进行。IE10+及其他现代浏览器都支持。

WebAssembly

是Web端的字节码技术,它定义了一个通用的、体积紧凑、加载迅捷的二进制格式为编译目标,能发挥通用硬件的性能,以更接近原生应用的速度运行。在浏览器中对H.265编码的视频进行软件解码,是一项对性能非常有挑战的任务,JavaScript等脚本语言无法胜任此项工作。因此可以将C/C++语言编写的高性能解码库编译成字节码,再通过JavaScript调用来运行。目前此项技术在Chrome、Firefox、Safari和Edge浏览器的较新版本中都可以使用(如Chrome57+,Firefox 52+)。

H.265 Vs H.264

关于H.265 与 H.264更详细的差异,可以访问H.265与H.264的差异详解

H.265/HEVC的编码架构大致上和H.264/AVC的架构相似,主要也包含:帧内预测(intra prediction)、帧间预测(inter prediction)、转换(transform)、量化(quantization)、去区块滤波器(deblocking filter)、熵编码(entropy coding)等模块。

在这里插入图片描述

在HEVC编码架构中,整体被分为了三个基本单位,分别是编码单位(coding unit, CU)、预测单位(predict unit, PU)和转换单位(transform unit, TU)。比起H.264/AVC,H.265/HEVC提供了更多不同的工具来降低码率,以编码单位来说,H.264中每个宏块(macroblock/MB)大小都是固定的16x16像素,而H.265的编码单位可以选择从最小的8x8到最大的64x64。

同时,H.265的帧内预测模式支持33种方向(H.264只支持8种),并且提供了更好的运动补偿处理和矢量预测方法。 反复的质量比较测试已经表明,在相同的图象质量下,相比于H.264,通过H.265编码的视频大小将减少大约39-44%。由于质量控制的测定方法不同,这个数据也会有相应的变化。

支持情况

ios

目前,根据苹果官网的资料,对于HEVC的支持情况可以用下面的一句话来说明: iOS 11 and macOS High Sierra introduced support for these new, industry-standard media formats。 也即是说,下面的设备都是支持的。

  • iPhone 7 or iPhone 7 Plus or later
  • iPad (6th generation)
  • iPad Pro (10.5 inch)
  • iPad Pro 12.9-inch (2nd generation)

Android

在这里插入图片描述

浏览器

目前,浏览器对于H.265支持的并不是很友好:

在这里插入图片描述

实战

目前,HEVC 的普及速度还没有那么快,不过我们还是可以尝试在 Web 中优雅的播放 H265 视频。

判断是否支持播放

要判断平台是否支持H.265格式的视频,可以通过H265 的 mimetype 值来判断:type="video/mp4; codecs=hevc"。例如:

var supportHEVC = function(video) {  
    if (typeof video.canPlayType == ‘ function’) {
        var playable = elem.canPlayType('video/mp4; codecs="hevc"');
        if ((playable.toLowerCase() == 'maybe') || (playable.toLowerCase() == 'probably')) {
            return true;
        }
    }
    return false;
};

如果,使用H.265无法播放视频,则使用H.264进行播放,所以我们可以通过 source 设置多种格式:

<video controls autoplay>  
    <source src="your_video.mp4" type="video/mp4; codecs=hevc">
    <source src="your_video.webm" type="video/webm; codecs=vp9">
    <source src="your_video.mp4" type="video/mp4; codecs=avc1">
</video>  

对于web平台来说,我们用到的是libde265.js,它是一个通过 JS 来解码 H.265 视频的库,它通过将 视频的 frame data 转化为 rgba 像素,然后绘制到 Canvas 上。下面是使用示例:

<canvas id="canvas"></canvas>

<script src="./libde265.min.j"></script>  
<script>  
var VIDEO_URL = 'h265-test-640.mp4'  
var video = document.getElementById('canvas')  
 // var fpsWrap = document.querySelector('.hevc-fps')
  var status = document.querySelector('.hevc-status')
  var playback = function (event) {
    // event.preventDefault()
    if (player) {
      player.stop()
    }

    player = new libde265.RawPlayer(video)
    player.set_status_callback(function (msg, fps) {
      player.disable_filters(true)
      console.log(msg);
      switch (msg) {
        case 'loading':
          status.innerHTML = 'Loading movie...'
          break
        case 'initializing':
          status.innerHTML = 'Initializing...'
          break
        case 'playing':
          status.innerHTML = 'Playing...'
          break
        case 'stopped':
          status.innerHTML = 'stopped'
          break
        case 'fps':
          // fpsWrap.innerHTML = Number(fps).toFixed(2) + ' fps'
          break
        default:
          status.innerHTML = msg
      }
    })
    player.playback(VIDEO_URL)
  }
  playback()
</script>  

测试地址:events.jackpu.com/h265。

在这里插入图片描述
可以发现,canvas 绘制和 video 原生解码差距还是很大,但是我们可以看到 Video 的大小相比原有的缩小了 31% ,因此 H265 的前景值得期待的。

参考:H.265 / HEVC WiKi H.265 Vs H.264