Featured image of post 深入理解 HTTP Range 与视频流媒体播放机制

深入理解 HTTP Range 与视频流媒体播放机制

详细解析HTTP Range请求原理、MP4文件结构与浏览器视频加载机制的关系,以及如何优化视频流媒体体验

MP4 文件结构深入解析

  • 如果是元数据在文件开头,那么[mdat]和[moov]替换位置
+---------------------------------------------------------------+
|                         MP4 文件结构                           |
|                                                               |
|  +--------+          +--------+          +--------+           |
|  | [ftyp] | -------> | [mdat] | -------> | [moov] |           |
|  +--------+          +--------+          +--------+           |
|  文件类型标识           媒体数据            元数据容器           |
|                                             |                 |
|                      +---------------------+                  |
|                      |                                        |
|  +--------------------------------------------------+         |
|  |                     [moov]                       |         |
|  |  +-----------------------------+                 |         |
|  |  |           [mvhd]           |                 |          |
|  |  +-----------------------------+                 |         |
|  |        影片头部信息                               |         |
|  |                                                  |         |
|  |  +-----------------------------+                 |         |
|  |  |           [trak]           |                 |          |
|  |  +-----------------------------+                 |         |
|  |        轨道信息                                  |          |
|  |       /                \                        |          |
|  |      /                  \                       |          |
|  |  +-------------+    +-------------+             |          |
|  |  |   [tkhd]    |    |   [mdia]    |             |          |
|  |  +-------------+    +-------------+             |          |
|  |    轨道头信息          媒体信息                    |         |
|  |                        |                        |          |
|  |                        |                        |          |
|  |              +------------------+               |          |
|  |              |      [minf]      |               |          |
|  |              +------------------+               |          |
|  |                 媒体信息容器                     |          |
|  |                /          \                     |          |
|  |               /            \                    |          |
|  |      +-------------+    +-------------+         |          |
|  |      | [vmhd/smhd] |    |   [stbl]    |         |          |
|  |      +-------------+    +-------------+         |          |
|  |       视频/音频信息         样本表                |          |
|  |                            |                    |          |
|  |                  +------------------+           |          |
|  |                  |                  |           |          |
|  |                  |  +-------------+ |           |          |
|  |                  |  |   [stsd]    | |           |          |
|  |                  |  +-------------+ |           |          |
|  |                  |     样本描述      |           |          |
|  |                  |                  |           |          |
|  |                  |  +-------------+ |           |          |
|  |                  |  |   [stts]    | |           |          |
|  |                  |  +-------------+ |           |          |
|  |                  |  时间到样本映射    |           |          |
|  |                  |                  |           |          |
|  |                  |  +-------------+ |           |          |
|  |                  |  |   [stss]    | |           |          |
|  |                  |  +-------------+ |           |          |
|  |                  |   同步样本表      |           |          |
|  |                  |                  |           |          |
|  |                  |  +-------------+ |           |          |
|  |                  |  |   [stsz]    | |           |          |
|  |                  |  +-------------+ |           |          |
|  |                  |    样本大小       |           |          |
|  |                  +------------------+           |          |
|  +--------------------------------------------------+         |
|                                                               |
+---------------------------------------------------------------+

HTTP Range 请求机制详解

HTTP Range请求是HTTP/1.1协议中的一个重要特性,允许客户端请求资源的部分内容。这对于大型媒体文件(如视频)的传输尤为重要。

Range 请求头格式与语法

Range: bytes=<start>-<end>

播放支持 http-range 的视频

1. 发送一个 GET 请求 (with range)
Chrome                                          Server
+----------------------------+                  +--------------------------------------------------+     
| GET    /video.mp4 HTTP/1.1 |                  | HTTP/1.1 206 Partial Content                     |
| Host:  cdn.com             |   <-------->     | Accept-Ranges: bytes                             |
| Range: bytes=0-            |                  | Content-Range: bytes 0-11799707/828908176        |
+--------------------------+                    | Content-Length: 827040401                        |
                                                | (body: .........)                                |
                                                +--------------------------------------------------+

2. 当你快进播放的时候

Chrome                                         Server
+--------------------------------+                +-----------------------------------------------------+
| GET /a.mp4 HTTP/1.1            |   <-------->   | HTTP/1.1 206 Partial Content                        |
| Host: cdn.com                  |                | Accept-Ranges: bytes                                |
| Range: bytes=1867776-828908176 |                | Content-Range: bytes 1867776-828908176/828908177    |
+--------------------------------+                | Content-Length: 827040400                           |
                                                  | (body: .........)                                   |
                                                  +-----------------------------------------------------+

播放不支持 http-range 的视频

  • GET视频流式播放, 不能快进快退, 每次从头开始播放
  • 服务器需要配置 Accept-Ranges: none 或不返回 Accept-Ranges
  • 浏览器检测到不支持 Range 请求时,会采用线性播放模式

元数据位置对播放的影响

  • MP4文件中moov box的位置对视频播放有重大影响:
  1. 元数据在文件开头 (faststart) :

    • 浏览器可以立即获取视频的关键信息
    • 无需下载整个文件即可开始播放
    • 支持快速定位到任意时间点
  2. 元数据在文件结尾 :

    • 浏览器需要下载完整文件或使用Range请求获取文件末尾
    • 在获取元数据前无法确定视频时长和其他关键信息
    • 影响用户体验,尤其是大文件

生成视频测试

## ## 元数据在开始
ffmpeg -f lavfi -i testsrc=duration=60:size=1920x1080:rate=30 -c:v libx264 -c:a aac -movflags +faststart meta_at_start.mp4
## 元数据在末尾
ffmpeg -f lavfi -i testsrc=duration=60:size=1920x1080:rate=30 -c:v libx264 -c:a aac -movflags empty_moov+default_base_moof meta_at_end.mp4

测试结果

  • 下面表格的顺序是上面的图
视频 描述 播放过程
meta_at_start.mp4 元信息在开头 一开始就能播放, 不能快进快退(只能流式播放)
meta_at_end.mp4 元信息在结尾 一开始就能播放, 不能快进快退(显示视频时长 0:08 有问题,因为没加载元信息)
meta_at_start_with_range.mp4 元信息在开头并且支持 range 一开始就能播放, 可以快进快退
meta_at_end_with_range.mp4 元信息在结尾并且支持 range 一开始不能播放,必须下载完成才能播放 (下载完了可以快进快退)

HLS 与 M3U8 流媒体技术

除了基于 HTTP Range 的视频流媒体播放,另一种广泛使用的技术是 HTTP Live Streaming (HLS),它使用 M3U8 播放列表文件来管理视频分片。

+--------------------------------------------------------------------------------------+
|                                    M3U8 文件结构                                      |
|                                                                                      |
|  主播放列表 (master.m3u8)                                                             |
|  +--------------------------------------------------------------------------------+  |
|  | #EXTM3U                                                                        |  |
|  | #EXT-X-VERSION:3                                                               |  |
|  | #EXT-X-STREAM-INF:BANDWIDTH=5000000,RESOLUTION=1920x1080                       |  |
|  | stream_0.m3u8                                                                  |  |
|  | #EXT-X-STREAM-INF:BANDWIDTH=3000000,RESOLUTION=1280x720                        |  |
|  | stream_1.m3u8                                                                  |  |
|  | #EXT-X-STREAM-INF:BANDWIDTH=1000000,RESOLUTION=640x360                         |  |
|  | stream_2.m3u8                                                                  |  |
|  +--------------------------------------------------------------------------------+  |
|                                       |                                              |
|            +-------------+-------------------------------------------+               |
|            |                          |                              |                |
|            v                          v                              v                |
|  +------------------------+  +------------------------+ +------------------------+    |
|  | 高清播放列表            |  | 标清播放列表             | | 低清播放列表           |     |
|  | stream_0.m3u8          |  | stream_1.m3u8          | | stream_2.m3u8          |    |
|  |                        |  |                        | |                        |    |
|  | #EXTM3U                |  | #EXTM3U                | | #EXTM3U                |    |
|  | #EXT-X-VERSION:3       |  | #EXT-X-VERSION:3       | | #EXT-X-VERSION:3       |    |
|  | #EXT-X-TARGETDURATION:6|  | #EXT-X-TARGETDURATION:6| | #EXT-X-TARGETDURATION:6|     |
|  | #EXT-X-MEDIA-SEQUENCE:0|  | #EXT-X-MEDIA-SEQUENCE:0| | #EXT-X-MEDIA-SEQUENCE:0|     |
|  | #EXTINF:6.0,           |  | #EXTINF:6.0,           | | #EXTINF:6.0,           |     |
|  | data000.ts             |  | data000.ts             | | data000.ts             |     |
|  | #EXTINF:6.0,           |  | #EXTINF:6.0,           | | #EXTINF:6.0,           |     |
|  | data001.ts             |  | data001.ts             | | data001.ts             |     |
|  | ...                    |  | ...                    | | ...                    |     |
|  | #EXT-X-ENDLIST         |  | #EXT-X-ENDLIST         | | #EXT-X-ENDLIST         |     |
|  +------------------------+  +------------------------+ +--------------------+         |
|           |                              |                      |                      |
|           v                              v                      v                      |
|     +------------+                  +------------+        +------------+               |
|     | 高清片段     |                | 标清片段     |        | 低清片段     |             |
|     | data000.ts  |                | data000.ts  |        | data000.ts  |              |
|     | data001.ts  |                | data001.ts  |        | data001.ts  |              |
|     | ...         |                | ...         |        | ...         |              |
|     +------------+                 +------------+          +------------+              |
|                                                                                        |
+----------------------------------------------------------------------------------------+
  1. 视频分段:将视频切分为多个小片段(通常为 .ts 文件)

    • 每个片段通常为 6-10
    • 片段时长影响延迟带宽适应性
    • 较短片段利于快速切换,但会增加请求次数
    • 较长片段减少请求次数,但增加首次加载延迟
  2. 创建索引文件:生成 .m3u8 文件,包含所有片段的信息和播放顺序

    • 主播放列表master.m3u8):包含所有清晰度版本信息
    • 媒体播放列表stream_N.m3u8):包含具体片段信息
    • 播放列表定期更新,支持直播场景
  3. 自适应比特率:为同一视频提供多种分辨率和比特率的版本

    • 高清流1080p):BANDWIDTH=5000000, RESOLUTION=1920x1080
    • 标清流720p):BANDWIDTH=3000000, RESOLUTION=1280x720
    • 低清流360p):BANDWIDTH=1000000, RESOLUTION=640x360
    • 播放器根据网络状况自动切换合适的清晰度
  4. 客户端请求:播放器先请求 .m3u8 文件,然后根据需要下载各个片段

    • 首次请求 master.m3u8 获取可用清晰度列表
    • 根据当前网络状况选择合适的清晰度流
    • 请求对应的 stream_N.m3u8 获取片段列表
    • 按需下载 .ts 片段文件
    • 网络状况变化时自动切换清晰度

与 HTTP Range 的比较

对比维度 HLS (M3U8) HTTP Range
文件格式 将视频分割为多个 .ts 片段 使用单一 MP4 文件
优点 • 支持自适应码率
广泛兼容各种设备
• 原生支持直播场景
• 支持清晰度动态切换
延迟低,精确请求
存储高效,单一文件
实现简单
• 支持精确定位
带宽利用率高
缺点 延迟较高(至少一个片段)
存储开销
实现复杂
• 存在带宽冗余
• 不支持自适应码率
兼容性受限
缓存效率较低
• 不适合直播场景
适用场景 直播业务
多设备支持
不稳定网络环境
• 需要多码率支持
点播业务
低延迟要求
存储受限场景
简单播放需求
技术复杂度 :需要完整的转码和分发系统 :仅需支持 Range 请求
运维成本 :需要维护转码集群和存储系统 :普通 Web 服务器即可

参考