标签: 格式

HTML5 <audio> 粗考

HTML 5 提供的 <audio> 给了前端相当多的方便,不再需要 js 库和 swf 作为播放器。但是新带来的坑也是坑得我要死要活的。

这是 W3School 提供的一张简表:

Browser MP3 Wav Ogg
Internet Explorer YES NO NO
Chrome YES YES YES
Firefox YES YES YES
Safari YES YES NO
Opera YES YES YES

信了你就掉坑了。

HTML5 的 <audio> 有着比看起来的大得多的坑。主要在于各浏览器的实现上有区别,自带的音频解码器各有不同,导致实际支持的格式各有不一。

并且,在宣称支持的格式里,各浏览器也只支持其中一部分编码格式。例如:

Firefox、Chrome 可以正常播放 Microsoft PCM, 16 bit, mono 8000 Hz 的wav,但是无法播放 GSM 6.10, mono 8000 Hz 的wav

以及来自于 这篇文章 的:

Playing MP3 files in Firefox is actually OS/hardware dependent. That’s right, instead of using a built in, true native support, we have to rely on outside variables that we have no control over. Kind of defeats the purpose of that whole no extensions, native support thing that HTML5 is good for. Yes, this is to avoid patent issues (and so Mozilla doesn’t have to pay licensing fees). If you are serving to a lucky person below, here’s the real MP3 support for Firefox:

  • Windows 7+ (Firefox 21.0)
  • Windows Vista (Firefox 22.0)
  • Android (Firefox 20.0)
  • Firefox OS (Firefox 15.0)
  • OS X 10.7 (Firefox 22.0)

大意是 Firefox  的 MP3 播放支持其实是依赖于系统和硬件的,这样可以免去专利费。相应的,支持列表就变得有点复杂了。

这里有几个测试页, 可以大致用来测试主流浏览器的音频文件支持情况,但是也不完全。就如上文所述,Chrome 对 wav 文件只能说部分支持。

测试页一:http://hpr.dogphilosophy.net/test/

测试页二:https://html5test.com/

所以在实际测试中,某浏览器播放不了指定音频有两种可能性:

  • 音频格式不支持
  • 音频编码格式不支持

对于相关的编码格式,大致查了一下,列表如下:

OGG

同样后缀名为 .ogg 的音频文件,可能有以下几种编码格式: Vorbis, speex, OggPCM, FLAC,其中,Vorbis 是被建议的。

WAV

.wav 文件通常被理解为原始采样,未经压缩。但其实并不一定如此。最广泛标准的 .wav 文件是指微软 PCM 编码的音频文件(其实也已经编码过了,毕竟从模拟信号转数字信号无论如何都会有一个采样过程。)PCM 细分又可分为定长(16bit、32bit 等)和浮点两类。另外.wav 还可能是 GSM 编码格式,这种格式广泛使用于通讯网络,但在互联网上并不常用,最有可能的来源是电话录音导入电脑。

MP3

MP3 规范并没有详细规定如何编码,但却有细致的解码定义。也就是说『符合这一类规范的才叫 MP3』。因此,MP3 的格式反而才是最一致的,除了采样率、变长/定长和声道数量外,不存在其它变化。

Opus

Opus 是设计为同时包含音频和视频的编码格式。* 可以取代复杂的编码后封装方案。但实际上普及率很低,支持也不好。

AAC

AAC (Advanced Audio Coding)主要是得到了苹果的支持。但除此以外,在互联网的使用并不广泛。

Mozilla 提供了另一张更为详细的表格:(注意这个表还是只能作为参考)

Feature Chrome Firefox (Gecko) Internet Explorer Opera Safari
Basic support 3.0 3.5 (1.9.1) 9.0 10.50 3.1
<audio>: PCM in WAVE (Yes) 3.5 (1.9.1) Not supported 10.50 3.1
<audio>: Vorbis in WebM (Yes) 4.0 (2.0) Not supported 10.60 3.1
<audio>: Streaming Vorbis in WebM via MSE ? 36.0 (36.0) ? ? ?
<audio>: Vorbis in Ogg (Yes) 3.5 (1.9.1) Not supported 10.50 Not supported
<audio>: MP3 (Yes) (Yes) 9.0 (Yes) 3.1
<audio>: MP3 in MP4 ? ? ? ? (Yes)
<audio>: AAC in MP4 (Yes) (Yes) 9.0 (Yes) 3.1
<audio>: Opus in Ogg 27.0 15.0 (15.0) ? ? ?
<video>: VP8 and Vorbis in WebM 6.0 4.0 (2.0) 9.0 10.60 3.1
<video>: VP9 and Opus in WebM 29.0 28.0 (28.0) ? (Yes) ?
<video>: Streaming VP9 and Opus/VP8 and Opus in WebM via MSE ? 36.0 (36.0) ? ? ?
<video>: Theora and Vorbis in Ogg (Yes) 3.5 (1.9.1) Not supported 10.50 Not supported
<video>: H.264 and MP3 in MP4 (Yes) (Yes) 9.0 (Yes) (Yes)
<video>: H.264 and AAC in MP4 (Yes) (Yes) 9.0 (Yes) 3.1
any other format Not supported Not supported Not supported Not supported 3.1

 

所以解决方案大概就是先通过测试确定一两种被绝大部分浏览器支持的音频编码格式,然后服务器后端将音频文件转码为这一到两种适用的音频格式再传递给前端。

看起来最通用的是 MP3?简单地说,是的。但要注意的是不是任意一种 mp3 编码格式都支持,最优化编码的 VBR 支持性就存疑。同时,由于 Firefox 的 MP3 支持是基于系统的,所以假如 Ubuntu 没有安装 ubuntu-restricted-extra 包也可能出现支持性问题。

 

* 附:

更复杂的是 <video> 标签,由于视频通常是包含声音和图像两部分的,因此实际上视频文件数据是由已经编码的视频数据和已经编码的音频数据,再次进行数据交错编制而成的。因此除 编码格式 外,又衍伸出 封装格式 的概念。深受大家喜爱的 .avi 格式,即 Audio Video Interleave 的简写,就是一种封装格式。当你使用 avi 封装器折开文件后,就会见到一个无声的视频文件和一个无图像的音频文件。至于各自的编码格式又五花八门了。因此对于 <video> 标签的支持更加混乱,几乎必然需要通过服务器转码才能确保在尽可能多的浏览器上前端一致,这也是各视频网站为什么会有大量集群转码处理用户上传的视频的原因。

将图片信息写入 HTML 和 CSS

通常来说 HTML 和 CSS 中引用图片都用的是 <img src=”…”> 和 url(…) 的引用办法。有时为了节约连接数,在诸如图标库等特殊用途 css 中,也会使用一张大图片通过 position 定位到不同位置的办法,来把所有图标放在同一张图片上。

不过还有一种办法是直接把图片通过 base64 编码以后写到文本中。对于非常静态化的需求,比如电子书、自制在线简历、email 投递、网络隐私安全病患者等等,或者各种原因在输入端只支持文本的场合,有时也是一种不错的选择。

这种办法其实很简单,就是把原来写 url 的位置替换成图片 base64 编码以后的文本。

比如我有一张图片,,把它用 base64 编码以后就成了一长串文本:(编译工具用百度一搜就行,在线的,本地的多得去了,在 Github 上还能搜到完全基于 JS 的。)

这串文本很长,不过相比于图片本身的体积,其实并没有大多少。这种体积的变化详细涉及到信息论和压缩原理,这篇文章先不写了。

然后我们在长串文本前再添加一些说明文字,供浏览器识别:

然后就可以直接替换原 url 了,就像这样:

编码头的标准格式是

理论上方括号是可以省略的,同时也可以看到还有其它编码形式,比如base85、base16 等,尽管没有什么实际意义甚至有反效果。(比如有浏览器兼容性、超出合法字符区间等情况)。

好处与坏处:

  • 更新:保证网页上的重要图片不会加载失败。当 HTML 加载完毕或 CSS 加载完毕时,图片一定可以正常显示。不会出现 HTML+CSS 加载成功,但图片没有显示的问题。特别适合于类似评分星级、打标等功能。
  • 节约连接数:http 协议下,每个单独资源在客户端都呈现为一个独立文件(在服务器端部分是),都需要握手协议开销和传输开销,而使用 base64 以后,就变成了 “文件内部” 数据,不需要额外开销。而在呈现上没有变化。这在某网页有大量小文件的静态资源时尤其有用。但随着 cdn 的发展,这种情况又少下去了。
  • 图片过滤无效:有时候用户因为某些原因会屏蔽网页上的图片呈现,这些屏蔽方式通常都是通过匹配 html/css/js 中的资源路径实现的,但在 base64 编码下这种方式会无效。但相应的,基于服务器代理转码的浏览器(UC 之类通常是手机端浏览器),以前也无法转换,现在应该改进了吧。是好是坏看具体场景了。
  • 不方便编辑:这个主要出现在常用的文本编辑器里,在成熟的 IDE 环境中则不存在这种问题,鼠标移到 base64 图片上同样会有预览。有些文件编辑器也通过插件来解决类似问题。
  • 其它:呃…… 少量增加整个网页体积,等。

最后是 php 版的 base64 图片生成:

用的也是现成库,别的代码版本就不写了。