MP4 是不是该退休了?
背景
对于视频的在线播放,根据视频内容的传输模式可以分为点播和直播,分别用于预先录制内容的传输和实时传输,比如新闻报道、体育赛事都属于直播场景,电影、电视剧、课程视频都属于点播场景。
在 2000 年代初期,Flash 技术开始在 Web 上流行起来,它成为在网页上展示视频的主要选择,因为当时没有其他方式能够在浏览器上流式的传输视频。
随着 HTML5 技术的逐渐成熟,HTML5 的 video 标签开始允许在没有 Flash 插件的情况下在浏览器中直接播放视频。
视频的在线播放主要的技术环节在于视频的解码、显示效率以及数据的传输效率,而 HTML5 的 video 标签将这两个环节进行解藕,开发人员不需要关心视频数据的解码、显示,只需要关心如何去优化数据的获取。
在点播的场景下,因为视频数据已经提前准备好,开发人员只需要制定 video 标签的 src 属性为对应的视频资源地址即可,但是在一些复杂的场景下比如需要根据网络状况做自适应码率、需要优化视频的首屏时间等,那么则需要对视频的一些规格参数以及相关的技术点做进一步的了解。
视频基础
视频帧率
视频的播放原理类似于幻灯片的快速切换。
每一次画面的切换称作为一帧,而帧率表示每秒切换的帧数,单位数 FPS,人类对画面切换频率感知度是有一个范围的,一般 60 FPS 左右是一个比较合适的范围,但这也需要结合具体的场景,比如在捕捉一个事物快速变化的瞬间时,需要准备足够的帧数才能捕捉到细微的变化,但是当需要拍摄一个缓慢的镜头效果时,帧率不需要太高。
帧率除了要考虑不通场景的播放内容,还需要结合播放设备的刷新频率,如果设备的刷新频率过低,多余的帧就会被丢弃。
视频分辨率
视频在播放时,显示在屏幕中的每一帧中的像素点数量都是相同的,像素是显示设备上发光原件的最小单位,最终呈现的画面是由若干个像素组合起来所展示的。
视频的分辨率是指视频每一帧画面的像素数量,通常以水平方向像素数量 x 垂直高度像素数量的形式表示。分辨率决定了图像的清晰度和细节程度,常见的分辨率有 1080P = 1920 * 1080,这是标准的纯高清分辨率,p 表示是逐行扫描的,与之对应的是 i
表示的是隔行扫描。
左边一列是逐行扫描,中间一列是隔行扫描,在隔行扫描中会丢失一些页面信息从而加快页面信息的收集。
当设备的分辨率高于视频的分辨率时,设备上的像素点就会多于视频显示所需的像素点,这时就会使用补间算法来为设备上那些未被利用的像素点生成色值信息,否则将导致屏幕上出现黑点,此时人从感官上就会觉得清晰度有所下降。如果视频的分辨率高于设备的分辨率时,则视频多出的信息会被丢弃。
视频格式
视频格式是一种特定的文件格式,用于存储和传输视频数据,它包含了视频图像、音频、字幕和其他相关媒体数据的编码信息,不同的视频格式采用不同的压缩算法和编码方式,以便在存储和传输的过程中有效的减少文件大小并保持高质量的图像。
常见的视频格式有 MP4、AVI、MOV 等,每种视频格式都有其特定的优势和使用场景,比如 MOV 在 Mac 系统上有很好的兼容性,适用于视频编辑。
MP4视频结构
MP4 文件由许多 Box 数据块组成,每个 Box 可以嵌套包含其他 Box,一级嵌套一级来存放媒体信息,这种层次化的结构使得 MP4 文件能够组织和存储各种不同类型的媒体数据和元数据,使其在播放和传输过程中具有灵活性和可扩展性。
虽然 Box 的类型非常多,但是并不是都是必须的,一般的 MP4 文件都是含有必须的 Box 和个别非必须 Box,下面使用 MP4Box.js 查看 MP4 的具体结构并介绍几个必须 Box:
ftyp
File Type Box,一般在文件的开始位置,描述的文件的版本、兼容协议等。
mdat
Media Data Box,媒体数据内容,是实际的视频的内容存储区域。该区域通常占整个文件99%+大小。
moov
MP4 的媒体数据信息主要存放在 Moov Box 中,是我们需要分析的重点。moov 的主要组成部分如下:
mvhd
Movie Header Box,记录整个媒体文件的描述信息,如创建时间、修改时间、时间度量标尺、可播放时长等。
udta
保存自定义数据
track
对于媒体数据来说,track 表示一个视频或音频序列,trak 区域至少存在一个,大部分情况是两个(音频和视频)。
形象点来说,moov 可以比如成是整个视频的目录,想要播放视频的话,必须要先加载 moov 区域拿到视频文件目录才能播放视频内容。
为什么MP4视频首屏慢?
当我们在浏览器中打开一个 MP4 视频文件时,浏览器根据就会开始获取视频信息,下载视频 chunk,开始播放视频,通过抓包能够大致了解浏览加载视频过程:
从请求列表中可知,浏览器发送了三个请求,总耗时 55s ,该视频文件的 box 结构如下:
下面来具体看一下这三个请求:
第一次请求
浏览器第一次请求时尝试通过 HTTP range request(范围请求)下载整个视频,但是实际只下载了 135 KB 整个请求就完成了,来分析一下具体流程:
- 浏览器通过 Range: bytes= 0- 首先获取到了 ftyp 信息,这里 ftyp-box 大小为 32 字节;
- 接下来继续尝试查找 free-box 区域,如果没有就跳过,这里 free-box 大小为 8 字节;
- 接着尝试查找下一个区域(moov 或 mdat),结果不幸匹配到的区域是 mdat 区域,这时浏览器就会主动终止请求,尝试从尾部查找视频的 moov 区域,因为上面我们讲过 moov 作为视频文件的目录,在播放视频数据前必须先获取 moov 数据,紧接着开始了第二次请求。
第二次请求
在第一次请求中已经知道了整个视频文件的大小了,如何去确定请求的范围呢?由于 MP4 是由 Box 组成的,标准的 Box 开头的4个字节(32位)为这个 Box 的大小,该大小包括 Box Header 和 Box Body,这样浏览器在第一次请求后就可以确定文件中剩下未解析到的 Box 的开始的 Range 值了。
计算过程(单位字节):
moov 大小 = 视频文件大小 - ftyp大小 - free大小 - mdat大小 = 22251375 - 32 - 8 - 22224468 = 26867。也就是说这一次请求的 range 的开始值最大值不能高于 22251375-26867 = 22251415。
可以看到发出去的请求 Range: bytes=22251374-∞ ,上面计算的 22251415-∞ 包含在内 ,请求到数据后,接下来就是解析 moov-box了,然后根据视频”目录“发起第三次请求。
第三次请求
根据第二次请求的 moov 解析后,开始下载”真正“的视频的内容准备播放,在第三次请求中,浏览器必须要缓存 4MB 左右才开始播放,
原因分析
过多的数据请求。
由于 MP4 文件的特殊性,浏览器必须先将 ftyp 、moov 等资源加载完毕之后才能去播放视频,而浏览器是从头部开始依次去加载这些资源,一旦视频资源存放顺序不对,浏览器会发送多次请求分别加载对应的资源。
全量解析 moov
播放 Mp4 音视频数据前需要先加载并解析 moov 数据,moov 的大小和视频长度成正比,更坏的情况是如果此时服务器没有配置 HTTP range request,浏览器无法跳过查找 moov 这一步,以至于需要下载整个文件。
如何借助HLS 优化视频播放的?
什么是HLS?
HLS 全称是 HTTP Live Streaming,是一个由 Apple 公司提出的基于 http 的媒体流传输协议,用于实时音视频流的传输,HLS 最初是为苹果设备和平台(如iOS和macOS)设计的,但如今已被广泛应用于各种平台和设备上,成为流媒体传输的主要标准之一。
HLS 协议由三部分组成:http、m3u8、ts,这三部分中,http 是传输协议,m3u8 是索引文件,ts是音视频的媒体信息。
HLS的优势和特点是什么?
分段传输
HLS 将整个音频或视频流切分成短的分段,通常每个分段持续几秒钟,这种分段的方式使得视频内容可以逐段加载和播放,从而提供更好的适应性和流畅性。
基于HTTP协议
HLS 使用 http 协议进行数据传输,这意味着它能够在标准的 http 服务器上运行,不需要专门的流媒体服务器。
自适应码率
HLS 支持自适应码率,根据网络带宽和设备性能,动态地选择合适的分辨率和比特率,以提供更好的观看体验。
多码率支持
媒体源可以同时提供不同分辨率和比特率的视频流,使得用户可以根据网络状况选择合适的码率。
兼容性好
由于 HLS 使用标准的 HTTP 协议,它在各种设备和平台上具有很好的兼容性,包括苹果设备、Android 设备、PC、智能电视等。在使用 http 播放 MP4 视频时,需要代理服务器支持 http range request 以获取视频的某一部分,但不是所有的代理服务器都对此有良好的支持,而 HLS 不需要,它对代理服务器的要求小很多。
HLS为什么首屏比MP4快?
上面讲过如果要播放 MP4 需要等待整个 moov box 加载完成,这个过程比较消耗时间和带宽,而在 HLS 协议中,分段传输是一个非常重要的特性,HLS 将整个音视频流切分成多个小的分段(ts 文件),这些分段可以被独立的下载和播放。
具体来说,HLS 的工作流程如下:
切分分段:
原始的音视频流被切分成短小的分段( .ts 文件),每个分段都包含了一小段时间范围内的音视频数据。
m3u8 文件:
服务器生成一个 .m3u8 文件,它是一个播放列表,包含了所有分段的信息,如地址、时长等。播放器通过请求 .m3u8 文件来获取分段列表。
分段请求:
播放器根据 .m3u8 文件中的分段信息,逐个请求并加载 .ts 分段。
逐段播放:
播放器逐个播放已经加载的分段,实现连续的音视频播放。
因此,HLS 首屏播放的实现方式不需要像 MP4 那样等待整个文件的基本信息加载完成,而是通过分段传输的方式逐段加载和播放。这使得首屏播放更快速和响应,同时也为流媒体的适应性提供了更好的支持。
为什么选择TS格式文件?
TS(Transport Stream,传输流)是一种封装的格式,它的全称为 MPEG2-TS,主要应用于数字广播系统,譬如 DVB、ATSC 与 IPTV,传输流最初是为广播而设计的,后来通过在标准的188字节数据包中添加4字节的时间码(TC),从而使该数据包成为192字节的数据包,使其适用于数码摄像机,录像机和播放器。
TS(Transport Stream)流在流媒体领域具有多种优点,使得它成为广泛应用于数字电视、流媒体、广播等领域的传输格式之一。以下是TS流的一些优点:
分段传输:
TS 流将媒体数据切分成小的分段(Packet),每个分段通常持续数毫秒至几十毫秒。这种分段传输使得数据能够按需传输和加载,从而实现快速启动播放和逐段加载,提高了用户体验。
容错性强:
每个 TS 分段都具有自己的包头信息和校验机制,这使得 TS 流具有较强的容错性。即使在传输过程中发生丢包或错误,也只会影响某个分段,不会影响整个媒体流的播放。
多路复用:
多路复用的目的一般为了在一个文件流中能同时存储视频、音频、字幕等内容,而TS 流就支持将多个音视频流混合在一个文件中,每个流都有自己的 PID(Packet Identifier)。这使得 TS 流适用于同时传输多个媒体流的场景,如电视广播、有线电视等,提高了传输效率。
支持多种编码格式:
TS 流可以支持多种音视频编码格式,如H.264、H.265、AAC、MP3等,使其能够适应各种类型的媒体内容。
M3U8格式文件的构成
以下为一个 m3u8 格式文件内容的示例:
#EXTM3U
#EXT-X-VERSION:6
#EXT-X-KEY:METHOD=AES-128,URI="<https://xxxx?token=xxx>"
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-TARGETDURATION:19
#EXTINF:12.000,
<https://xxxx/test/1.ts>
#EXTINF:7.500,
<https://xxxx/test/2.ts>
#EXTINF:13.000,
<https://xxxx/test/3.ts>
#EXTINF:9.720,
<https://xxxx/test/4.ts>
#EXT-X-ENDLIST
在以上示例中包含了 m3u8 文件常见的字段下面为一个M3U8文件可包含的基本字段及含义解释:
#EXTM3U
表明该文件是一个 m3u8 文件。每个 M3U8 文件必须将该标签放置在第一行。#EXT-X-VERSION
指定 M3U8 版本号。#EXT-X-KEY
媒体片段可以进行加密,而该标签可以指定解密方法。例如在上面的示例中,该字段指定了加密算法为AES-128
,密钥通过请求https:xxxx?token=xxx
获取,以用于解密后续下载的ts
文件。EXT-X-MEDIA-SEQUENCE:
第一个 TS 分片的序列号。每个 TS 分片都拥有一个唯一的整型序列号,每个 TS 分片序列号按出现顺序依次加 1,如果该分片未指定则默认序列号从 0 开始。对于视频点播资源该字段一般是 0,但是在直播场景下,这个序列号标识直播段的起始位置。#EXT-X-TARGETDURATION:
每个 TS 分片的最大的时长,单位为秒。#EXT-X-DISCONTINUITY:
该标签表明其前一个切片与下一个切片之间存在中断。#EXT-X-PLAYLIST-TYPE:
指定流媒体类型。#EXT-X-ENDLIST:
M3作者:西陵U8 文件结束符。
来源:juejin.cn/post/7268658252567691322