H.265/HEVC Web端直播播放器内核开发解密

H5视频播放器内核的开发对于前端工程师来说算是一个比较少涉足的领域,恰好工作中有所研究,分享出来给感兴趣的同学。简单的说,播放器内核的功能类似于一个video标签,它负责视频资源的解封装、解码和播放。

视频播放器架构


图1 视频播放器架构

一个典型的现代播放器可以分为三个部分:UI、多媒体引擎和解码器[1] 。本文要讲的视频播放器内核,其主要工作在图1中处于下面两层,主要包括:解码器、渲染器、网络管理引擎和媒体管理引擎。

相关背景技术

直播是目前最流行的一种信息传播和社交方式,区别于录制的点播视频,它要求播放器可以实时的获取并播放流式视频数据。为了实现直播播放,播放器内核需要借助一些HTML5的技术。如下图所示:

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

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

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

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

H.265/HEVC编码与硬解平台支持

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

图3 相同数据量下H.265和H.264图像质量对比

一般来说操作系统借助硬件(显卡)进行H.265编码视频的解码工作,其好处是硬解的功耗低,解码速度快。但目前H.265编码在浏览器中的硬件解码支持情况并不普及。经测试只在定制的Chromium[7] 及Edge 14浏览器中支持,可以通过此页面,测试浏览器对H.265编码的点播视频的播放情况。下图是H.265视频在Chromium 64中播放的截图。

图4 H.265视频文件播放

需要注意的是硬件解码需要用户的显卡支持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

在直播场景下,视频流需要通过MSE接口发送给HTMLMediaElement播放,因而需要MediaSource接口也支持H.265的媒体类型字符串。目前只有Edge浏览器宣称支持H.265编码的流媒体播放,实测MediaSource.isTypeSupported('video/mp4; codecs="hvc1.xxx"')也确实返回true,但实际通过video标签播放H.265编码mp4封装的视频数据时,黑屏无画面。另外测试了其他两个宣传支持HEVC编码的Web播放器Radiant Media Player[9] 和Bitmovin Video Player[10],也是同样的现象。

Web端软解方案

由于直播的Web端硬解方案目前限于浏览器支持情况无法实现,软件解码便成为了唯一的选择。由于H.265视频的解码是一个对性能要求很高的CPU密集任务,Web端脚本语言实现的解码器的性能很难达到要求。我们团队之前尝试过基于Flash的H.265解码方案,即通过FlasCC[11]编译器把C语言编写的解码器编译成swc库,然后在Flash播放器中用Action Script调用swc库。测试结果显示1080p高清视频每秒只能解码渲染10帧左右,无法达到应用要求。

另一种方案是基于HTML5的,即通过WebAssembly技术将金山云自研的高性能解码器编译为wasm库,wasm文件是以二进制形式存在的,其中包含平台无关的虚拟指令(类似汇编指令)。目前WebAssembly技术已经被四大主流浏览器的新版本所支持。基于该技术的播放器内核的实现如下图所示(图中虚线表示对象引用关系,实现表示数据传递):

图5 H.265直播播放器实现

该实现中包含4个线程,分别是转封装/转复用worker(TransmuxingWorker)、解码worker(H265decodingWorker)、颜色空间转换worker(RGBConvertingWorker)和负责渲染和播放控制的主线程。在TransmuxingWorker中,通过DownloadController下载流式媒体数据(在Safari、Chrome和Edge浏览器中我们使用Stream API实现下载,而在Firefox中可以基于XMLHttpRequest下载数据),然后根据视频封装格式的不同通过解复用器(Demuxer)分离音视频数据(http-flv流的解复用方法可参照flv.js相关代码,HLS流的解复用请参考hls.js相关代码[12])。之后将音频数据重新封装成Fragmented MP4格式[13](其媒体类型为mp4a)。最后将mp4a音频数据发回主线程交给AudioMSEController,AudioMSEController将音频数据通过MSE接口传递给audio标签并播放。

另一方面,解封装出的视频数据通过MessageChannel发送到解码worker(H265decodingWorker),放入H265Decoder的待解码数据队列。H265Decoder基于WebAssembly技术调用底层解码器解码,输出YUV[14]数据。然后再发送给RGBConvertingWorker中的RGBConverter,进行YUV到RGB颜色空间的转换。最后将RGB数据帧发送给主线程中的音视频同步渲染器(AVSyncRender),保存到待渲染队列中。

音视频同步渲染采用视频同步到音频的策略,即音频正常播放,不断地检查待渲染视频队列中队首的视频帧,比较视频帧的展示时间戳(pts)与音频当前时间戳(currentTime),如果视频时间戳小于音频时间戳,就渲染当前待渲染队列队首的视频帧。否则要等到满足上述条件时再渲染该帧视频。如果待渲染队列空了,则等待固定时间(例如10ms)再恢复前述操作。这里的图像渲染是在canvas上渲染,目前在主流浏览器上canvas渲染是有GPU硬件加速的。经测试其渲染帧率在该场景下,甚至优于WebGL[15]渲染。另外出于性能上的原因,在worker间通信传递数据时需要采用零拷贝方式(又称Transferable Objects[16])。

播放效果如下图所示:

图6 Chrome上拉流播放效果

对于画面比较简单的高清(1080p)视频,在Mac笔记本上(配置见图7)能够渲染到每秒40几帧。

图7 测试环境机器配置

这里需要说明一下的是,由于Adobe的FLV格式并没有对H.265编码的官方支持,我们联合友商对FLV容器格式进行了扩展,并以草案的形式发布,参见HVCPacketTypeffmpeg patch)。

本文介绍了Web端直播播放器的相关背景技术,及H.265 codec的Web端软硬解方案的探索,并对软解方案的一种实现进行了说明。分享于此,抛砖引玉,不详之处欢迎留言交流,也可加入金山云技术交流QQ群:574179720。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容