流媒体协议原理及应用
本文包含 RTP/RTSP,私有协议(通信及流封装协议),MP4 内容。
RTP/RTCP
介绍
RTP/RTCP 的规范可以参考 RFC 1889。RTP(Real-time Transport Protocol,实时传输协议)主要用于为音视频数据包添加序列号和时间戳,提供丢包检测、乱序重组、播放时序管理、负载类型标识以及媒体流区分等功能。RTCP(RTP Control Protocol,RTP 控制协议)则与 RTP 配合使用,定期在会话中传输控制信息,用于反馈传输质量(如丢包率、抖动、时延)和同步不同媒体流(如音视频同步),从而实现对 RTP 传输质量的控制与监控。两者共同构成了实时通信中可靠的传输与反馈机制。在传输中,RTP/RTCP 通常运行在 UDP 之上,采用相邻的一对端口:偶数端口用于 RTP,下一个奇数端口用于 RTCP。
RTP 数据传输协议
参与角色
- Mixer:从一个或多个源接收 RTP 包,混合后发送一个新的 RTP 包。会进行时序调整,更换 SSRC,并把源的 SSRC 写入 CSRC 中。
- Translator:转发 RTP 包,或转换编码但不混合。保持 SSRC 不变,即时序不变。
- Monitor:通过接收 RTCP 包监控媒体质量。
固定头部字段
RTP 固定头部具有以下格式:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|V=2|P|X| CC |M| PT | sequence number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| timestamp |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| synchronization source (SSRC) identifier |
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
| contributing source (CSRC) identifiers |
| .... |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
每个 RTP 包都包含固定的前 12 字节,且只有 mixer 才会附带 CSRC 标识。字段含义如下:
-
version (V): 2 bit
RTP 版本号,目前为 2。(值 1 用于 RTP 首个草案版本,值 0 用于“vat”音频工具。)
-
padding (P): 1 bit
填充位,启用后在 RTP 包末尾填充若干随机字节,其中最后一个字节标明填充的总长度(包含该字节本身),因此最大填充长度为 255 字节。该机制主要用于满足加密算法要求输入数据为固定块大小的要求,或在单个底层协议数据单元中固定长度地封装多个 RTP 数据包。
-
extension (X): 1 bit
扩展位,启用后在固定头部后面增加一个扩展头部。
-
CSRC count (CC): 4 bits
贡献源计数,表示 CSRC 标识数量。
-
marker (M): 1 bit
标记位,表示关键事件,与负载类型相关。比如当负载为 H.264 时,可以代表一帧结束。
-
payload type (PT): 7 bits
负载类型,参考 RFC 3551,静态映射可直接使用,动态映射需要通过 SDP 等协议协商。
PT encoding media type clock rate channels name (Hz) ______________________________________________________ 0 PCMU A 8,000 1 1 reserved A 2 reserved A 3 GSM A 8,000 1 4 G723 A 8,000 1 5 DVI4 A 8,000 1 6 DVI4 A 16,000 1 7 LPC A 8,000 1 8 PCMA A 8,000 1 9 G722 A 8,000 1 10 L16 A 44,100 2 11 L16 A 44,100 1 12 QCELP A 8,000 1 13 CN A 8,000 1 14 MPA A 90,000 (see text) 15 G728 A 8,000 1 16 DVI4 A 11,025 1 17 DVI4 A 22,050 1 18 G729 A 8,000 1 19 reserved A 20 unassigned A 21 unassigned A 22 unassigned A 23 unassigned A dyn G726-40 A 8,000 1 dyn G726-32 A 8,000 1 dyn G726-24 A 8,000 1 dyn G726-16 A 8,000 1 dyn G729D A 8,000 1 dyn G729E A 8,000 1 dyn GSM-EFR A 8,000 1 dyn L8 A var. var. dyn RED A (see text) dyn VDVI A var. 1 24 unassigned V 25 CelB V 90,000 26 JPEG V 90,000 27 unassigned V 28 nv V 90,000 29 unassigned V 30 unassigned V 31 H261 V 90,000 32 MPV V 90,000 33 MP2T AV 90,000 34 H263 V 90,000 35-71 unassigned ? 72-76 reserved N/A N/A 77-95 unassigned ? 96-127 dynamic ? dyn H263-1998 V 90,000 -
sequence number: 16 bits
序列号,初始值随机,每发送一个 RTP 包加 1,接收端可用序列号来检测数据包丢失和恢复数据包顺序。
-
timestamp: 32 bits
时间戳,初始值随机,代表 RTP 包中第一个字节的采样时间。时间戳的推进规律也就是时序。比如,8000Hz 的 PCMA 音频,采样间隔为
1 / 8000 = 125 μs,每秒时间戳增加 8000;90000Hz 30fps 的 H.264 视频,每秒时间戳增加 90000,每帧所需的时间戳为90000 / 30 = 3000。此外,同一视频帧的多个 RTP 包可能时间戳相同,插帧可能导致时间戳不单调。 -
SSRC: 32 bits
同步源,随机生成,RTP 会话内唯一,用于分别同一 RTP 会话中的同步源。
-
CSRC list: 0 to 15 items, 32 bits each
贡献源,随机生成,RTP 会话内唯一,用于分别一个 mixer 混合的贡献源。
头部扩展字段
不推荐使用扩展头部,额外字段最好在负载中实现。
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| defined by profile | length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| header extension |
| .... |
如果 RTP 固定头部中的 X 位为 1,则在 RTP 固定头部之后附加一个可变长度的头部扩展。如果存在 CSRC,头部扩展将放在 CSRC 之后。头部扩展的头部包含 16 位类型,16 位头部扩展长度(头部扩展中 32 位字的数量,不包括 32 位头部扩展的头部,故可为 0)。每个 RTP 包只有一个头部扩展。
RTCP 包格式
基本类型
-
SR(PT = 200):发送端报告,用于正在主动发送媒体数据的参与者,上报发送与接收统计信息。包括:64 位 NTP 时间戳(高 32 位为秒,低 32 位为小数秒)、32 位 RTP 时间戳、32 位累计发送 RTP 包数、32 位累计发送 RTP 包负载字节数、以及 RR 内容。
0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |V=2|P| RC | PT=SR=200 | length | header +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | SSRC of sender | +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ | NTP timestamp, most significant word | sender +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ info | NTP timestamp, least significant word | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | RTP timestamp | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | sender's packet count | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | sender's octet count | +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ | SSRC_1 (SSRC of first source) | report +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block | fraction lost | cumulative number of packets lost | 1 -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | extended highest sequence number received | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | interarrival jitter | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | last SR (LSR) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | delay since last SR (DLSR) | +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ | SSRC_2 (SSRC of second source) | report +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block : ... : 2 +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ | profile-specific extensions | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -
RR(PT = 201):接收端报告,用于并未主动发送媒体数据的参与者,上报其接收统计信息。包括:8 位丢包率、24 位累计丢包数、32 位序列号(还是 RTP 的序列号,但避免回绕)、32 位网络抖动、32 位最近收到的 SR 时间戳的中间 32 位,以及 32 位从该时间戳到当前时刻经过的时间(单位为 1/65536 秒)。
0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |V=2|P| RC | PT=RR=201 | length | header +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | SSRC of packet sender | +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ | SSRC_1 (SSRC of first source) | report +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block | fraction lost | cumulative number of packets lost | 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | extended highest sequence number received | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | interarrival jitter | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | last SR (LSR) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | delay since last SR (DLSR) | +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ | SSRC_2 (SSRC of second source) | report +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block : ... : 2 +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ | profile-specific extensions | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -
SDES(PT = 202):源描述项,包括 CNAME。因为 SSRC 可变,所以用 CNAME 固定值给 SSRC 命名,比如电话号码、地理位置等。
-
BYE(PT = 203):表示参与结束。
-
APP(PT = 204):应用特定功能。
往返时延
RTT(round-trip time)计算方法:
[10 Nov 1995 11:33:25.125] [10 Nov 1995 11:33:36.5]
n SR(n) A=b710:8000 (46864.500 s)
---------------------------------------------------------------->
v ^
ntp_sec =0xb44db705 v ^ dlsr=0x0005.4000 ( 5.250s)
ntp_frac=0x20000000 v ^ lsr =0xb705:2000 (46853.125s)
(3024992016.125 s) v ^
r v ^ RR(n)
---------------------------------------------------------------->
|<-DLSR->|
(5.250 s)
A 0xb710:8000 (46864.500 s)
DLSR -0x0005:4000 ( 5.250 s)
LSR -0xb705:2000 (46853.125 s)
-------------------------------
delay 0x 6:2000 ( 6.125 s)
传输间隔
推荐的传输方式,一个 UDP 包中包含多个 RTCP 包,若加密则首先是 32 位随机数,之后是一个 SR/RR,一个 SDES,若退出则再加上一个 BYE。
if encrypted: random 32-bit integer
|
|[------- packet -------][----------- packet -----------][-packet-]
|
| receiver reports chunk chunk
V item item item item
--------------------------------------------------------------------
|R[SR|# sender #site#site][SDES|# CNAME PHONE |#CNAME LOC][BYE##why]
|R[ |# report # 1 # 2 ][ |# |# ][ ## ]
|R[ |# # # ][ |# |# ][ ## ]
|R[ |# # # ][ |# |# ][ ## ]
--------------------------------------------------------------------
|<------------------ UDP packet (compound packet) --------------->|
#: SSRC/CSRC
RTSP
介绍
RTSP 的规范可以参考 RFC 2326。RTSP(Real Time Streaming Protocol,实时流协议)主要用于控制音视频媒体的点播与直播,它采用类似 HTTP 的请求-响应模型,通过 C/S 架构使用 TCP(默认 554 端口)来建立会话并发送 PLAY、PAUSE、SETUP、TEARDOWN 等命令,从而实现对流媒体播放、暂停、定位等交互控制。但 RTSP 自身通常不传输媒体数据,而是依赖 RTP 承载实际音视频内容,并常配合 RTCP 进行质量反馈。
协议指令
RTSP 协议格式类似于 HTTP,但是 RTSP 是有状态的,使用 Session ID。具体指令如下:
OPTIONS
询问服务器支持哪些方法。
C->S: OPTIONS rtsp://example.com/media.mp4 RTSP/1.0
CSeq: 1
Require: implicit-play // 服务器需支持 implicit-play, 即 SETUP 后自动 PLAY
Proxy-Require: gzipped-messages // 中间代理需支持 gzip
S->C: RTSP/1.0 200 OK
CSeq: 1
Public: DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE
DESCRIBE
请求媒体描述信息。
C->S: DESCRIBE rtsp://example.com/media.mp4 RTSP/1.0
CSeq: 2
Accept: application/sdp, application/rtsl, application/mheg
S->C: RTSP/1.0 200 OK
CSeq: 2
Content-Base: rtsp://example.com/media.mp4
Content-Type: application/sdp
Content-Length: 376
m=video 0 RTP/AVP 96
a=control:streamid=0
a=range:npt=0-7.741000
a=length:npt=7.741000
a=rtpmap:96 MP4V-ES/5544
a=mimetype:string;"video/MP4V-ES"
a=AvgBitRate:integer;304018
a=StreamName:string;"hinted video track"
m=audio 0 RTP/AVP 97
a=control:streamid=1
a=range:npt=0-7.712000
a=length:npt=7.712000
a=rtpmap:97 mpeg4-generic/32000/2
a=mimetype:string;"audio/mpeg4-generic"
a=AvgBitRate:integer;65790
a=StreamName:string;"hinted audio track"
SETUP
建立 RTP 传输通道。使用 SDP 中的 streamid 区分 track。如果定义了 port 将覆盖 SDP 中的 port。
C->S: SETUP rtsp://example.com/media.mp4/streamid=0 RTSP/1.0
CSeq: 3
Transport: RTP/AVP;unicast;client_port=4588-4589 // 这里还可以附加很多种参数, 还是要参考 RFC 2326
S->C: RTSP/1.0 200 OK
CSeq: 3
Transport: RTP/AVP;unicast;client_port=4588-4589;server_port=6256-6257
Session: 12345678
PLAY
开始播放。可以指定播放范围:
C->S: PLAY rtsp://example.com/media.mp4 RTSP/1.0
CSeq: 4
Session: 12345678
Range: npt=5-20
S->C: RTSP/1.0 200 OK
CSeq: 4
PAUSE
暂停播放。
C->S: PAUSE rtsp://example.com/media.mp4 RTSP/1.0
CSeq: 5
Session: 12345678
S->C: RTSP/1.0 200 OK
CSeq: 5
TEARDOWN
关闭会话。
C->S: TEARDOWN rtsp://example.com/media.mp4 RTSP/1.0
CSeq: 6
Session: 12345678
S->C: RTSP/1.0 200 OK
CSeq: 6
GET_PARAMETER
获取参数。
S->C: GET_PARAMETER rtsp://example.com/media.mp4 RTSP/1.0
CSeq: 7
Content-Type: text/parameters
Session: 12345678
Content-Length: 15
packets_received
jitter
C->S: RTSP/1.0 200 OK
CSeq: 7
Content-Length: 46
Content-Type: text/parameters
packets_received: 10
jitter: 0.3838
SET_PARAMETER
设置参数。
C->S: SET_PARAMETER rtsp://example.com/media.mp4 RTSP/1.0
CSeq: 8
Content-length: 20
Content-type: text/parameters
barparam: barstuff
S->C: RTSP/1.0 451 Invalid Parameter
CSeq: 8
Content-length: 10
Content-type: text/parameters
barparam
ANNOUNCE
通知 SDP 变更。既可以由客户端发送给服务器,用来发布一个即将推送的媒体流,也可以由服务器发送给客户端,用于通知会话中发生了改变。
C->S: ANNOUNCE rtsp://example.com/media.mp4 RTSP/1.0
CSeq: 9
Date: 23 Jan 1997 15:35:06 GMT
Session: 47112344
Content-Type: application/sdp
Content-Length: 332
v=0
o=mhandley 2890844526 2890845468 IN IP4 126.16.64.4
s=SDP Seminar
i=A Seminar on the session description protocol
u=http://www.cs.ucl.ac.uk/staff/M.Handley/sdp.03.ps
e=mjh@isi.edu (Mark Handley)
c=IN IP4 224.2.17.12/127
t=2873397496 2873404696
a=recvonly
m=audio 3456 RTP/AVP 0
m=video 2232 RTP/AVP 31
S->C: RTSP/1.0 200 OK
CSeq: 9
REDIRECT
通知客户端连接另一个服务器。客户端将先 TEARDOWN 当前会话,并 SETUP 与另一个服务器的新会话。
S->C: REDIRECT rtsp://example.com/media.mp4 RTSP/1.0
CSeq: 10
Location: rtsp://bigserver.com:8001
Range: clock=19960213T143205Z- // 生效时间
RECORD
开始录制。可使用 Range 指定范围。
C->S: RECORD rtsp://example.com/media.mp4.bak RTSP/1.0
CSeq: 11
Session: 12345678
S->C: RTSP/1.0 200 OK
CSeq: 11
通信流程
通信流程如下:
C S
|-------- OPTIONS ------->|
|<------- 200 OK --------|
| |
|-------- DESCRIBE ------->|
|<------- SDP 信息 --------|
| |
|-------- SETUP ------->|
|<------- Session ID --------|
| |
|-------- PLAY ------->|
|<------- 200 OK --------|
| |
|<======= RTP/RTCP ========|
| |
|-------- PAUSE ------->|
|<------- 200 OK --------|
| |
|-------- PLAY ------->|
|<------- 200 OK --------|
| |
|<======= RTP/RTCP ========|
| |
|-------- TEARDOWN ------->|
|<------- 200 OK --------|
此外,需要定时发送 OPTIONS 或 GET_PARAMETER 维持连接活跃。理论上应该使用 GET_PARAMETER,但 OPTIONS 兼容性更好。
传输方式
通常,RTSP 流媒体数据通过 UDP 传输,但也支持基于 TCP 的“嵌入式(交错式)二进制数据”传输方式,即 RTP over RTSP(TCP)。其格式为:以 ASCII 字符 $(0x24)为起始标志,紧接着一个字节的信道标识符,随后是二进制数据的长度(以网络字节顺序表示的两个字节),最后是数据本身(无 CRLF,包含上层协议头)。每个 $ 块仅包含一个上层协议数据单元(例如一个完整的 RTP 包)。
C->S: SETUP rtsp://example.com/media.mp4/streamid=0 RTSP/1.0
CSeq: 3
Transport: RTP/AVP/TCP;interleaved=0-1 // 0-RTP 1-RTCP
S->C: RTSP/1.0 200 OK
CSeq: 3
Date: 05 Jun 1997 18:57:18 GMT
Transport: RTP/AVP/TCP;interleaved=0-1
Session: 12345678
C->S: PLAY rtsp://example.com/media.mp4/streamid=0 RTSP/1.0
CSeq: 4
Session: 12345678
S->C: RTSP/1.0 200 OK
CSeq: 4
Session: 12345678
Date: 05 Jun 1997 18:59:15 GMT
RTP-Info: url=rtsp://example.com/media.mp4/streamid=0;seq=232433;rtptime=972948234
S->C: $\000{2 byte length}{"length" bytes data, w/RTP header}
S->C: $\000{2 byte length}{"length" bytes data, w/RTP header}
S->C: $\001{2 byte length}{"length" bytes RTCP packet}
私有协议(通信及流封装协议)
私有
MP4
介绍
MP4(MPEG-4 Part 14)是一种基于 ISO/IEC 14496-14 标准的多媒体容器格式,广泛用于存储视频、音频、字幕及元数据。它采用面向对象的文件结构,将数据组织为一系列称为“Box”或“Atom”的层次化数据块,支持高效的本地播放和流媒体渐进式下载。MP4 通常使用 H.264 或 H.265 进行视频编码,AAC 进行音频编码,具有高压缩率和良好的画质音质平衡。MP4 也是互联网和移动设备上最通用的视频格式之一,兼容 HTML5、iOS、Android 等主流平台。
结构
BOX 通用结构
+--------------------------+
| size (4 bytes) |
+--------------------------+
| type (4 bytes) |
+--------------------------+
| largesize (8 bytes) | // size = 0 时, 附加
+--------------------------+
| extended_type (16 bytes) | // type = uuid 时, 附加
+--------------------------+
| version (1 bytes) | // version 和 flags 可选
+--------------------------+ // 携带这两个的叫 FullBox
| flags (3 bytes) | // FullBox 常用在 moov
+--------------------------+ // 用于版本升级与功能开关
| data / children |
| |
+--------------------------+
BOX 嵌套结构
+-------------+ +-------------+ +-------------+
| | | | | +-----+ |
| BOX | | BOX | | BOX | BOX | |
| | | | | +-----+ |
+-------------+ +-------------+ +-------------+
MP4 文件结构
+-------------------+
| ftyp | // file type and compatibility
+-------------------+
| free | // free space
+-------------------+
| mdat | // media data container
+-------------------+
| moov | // container for all the metadata
| + mvhd | // movie header, overall declarations
| + trak | // container for an individual track or stream
| | + tkhd | // track header, overall information about the track
| | + edts | // edit list container
| | + mdia | // container for the media information in a track
| + trak |
| + udta | // user-data
+-------------------+
- ftyp (File Type Box):用于声明文件类型和兼容规范。播放器会通过它判断这是 MP4、MOV、ISOM 还是其他 BMFF 派生格式。
- free (Free Space Box):预留的空闲空间。通常用于后续修改文件时避免整体移动数据,也可作为占位填充。
- mdat (Media Data Box):存放真正的音视频数据。例如 H264/H265 码流、AAC 音频帧等通常都在这里。
- moov (Movie Box):MP4 的核心元数据区域。相当于整个文件的“目录”。
- mvhd (Movie Header Box):整个影片的全局信息。包括总时长、时间基(timescale)、播放速率等。
- trak (Track Box):表示一个独立轨道。一个视频轨、音频轨、字幕轨通常各对应一个 trak。
- tkhd (Track Header Box):当前轨道的基本属性。例如 track id、宽高、音量、显示层级等。
- edts (Edit Box):定义轨道时间编辑规则。可用于控制起播时间、裁剪、延迟同步等。
- mdia (Media Box):轨道的媒体信息容器。内部包含编码格式、时间信息、sample 索引等内容。
- udta (User Data Box):用户自定义数据区域。可存储额外信息,例如标题、作者、设备信息、GPS、注释等。
fMP4
fMP4(Fragmented MP4,分片 MP4)是一种流式封装格式,它通过将原本完整的 MP4 文件切割为一系列更小的独立片段来优化流媒体传输效率。与普通 MP4 需要完整的 moov 索引框才能开始解码不同,fMP4 将元数据与媒体数据交替组织成若干对“moof + mdat”,其中 moof 包含当前片段的解码信息,mdat 存储实际的音视频帧,使得播放器在下载完第一个片段后即可立即开始播放,无需等待完整的文件。
+-------------------+
| ftyp | // file type and compatibility
+-------------------+
| moov | // container for all the metadata
+-------------------+
| styp (可选) | // segment type
+-------------------+
| sidx (可选) | // segment index
+-------------------+
| moof | // movie fragment
| + mfhd | // movie fragment header
| + traf | // track fragment
| + tfhd | // track fragment header
| + tfdt | // track fragment decode time
| + trun | // track fragment run
+-------------------+
| mdat | // media data container
+-------------------+
| styp (可选) |
+-------------------+
| sidx (可选) |
+-------------------+
| moof |
+-------------------+
| mdat |
+-------------------+
... repeat
+-------------------+
| mfra (可选) | // movie fragment random access
+-------------------+
- styp (Segment Type Box):分片级别的 ftyp,基本上与 ftyp 相同。
- sidx (Segment Index Box):提供当前分片内各子片段的字节偏移和时长索引,使得客户端能够在不解析完整文件的情况下,快速定位特定时间范围对应的数据位置。
- moof (Movie Fragment Box):负责存放一个分片内所有轨道片段的元数据。
- mfhd (Movie Fragment Header Box):位于 moof 内部,记录当前分片的序列号(sequence number),用于唯一标识该分片在整体流中的顺序,便于播放器按序组装和解码连续片段。
- traf (Track Fragment Box):包含在 moof 中,对应单个轨道的分片元数据,内部封装了 tfhd、tfdt 和 trun 等 Box,用于描述该轨道在当前分片内所有采样的具体属性和解码时序。
- tfhd (Track Fragment Header Box):定义当前轨道片段的默认设置,如是否使用默认 base 偏移、默认采样大小、是否包含 sample duration 等标志位,为后续 trun 提供解析该片段数据的上下文基础。
- tfdt (Track Fragment Base Media Decode Time Box):记录当前轨道分片中第一个采样的解码时间(以媒体时间坐标系为准),用于建立从片段序列号到实际解码时间戳的绝对映射,是音视频同步和连续播放的关键依据。
- trun (Track Fragment Run Box):详细列出当前轨道分片中一个连续采样序列(run)的各项信息,包括每个采样的偏移量、大小、时长、关键帧标志等,是实际描述媒体数据如何填入 mdat 的核心索引表。
- mfra (Movie Fragment Random Access Box):通常位于 fMP4 文件末尾,汇总所有分片的随机访问点(如关键帧)位置及其对应的字节偏移和时间戳。
虽然 mfra 提供了全局索引能力,但如果已发送 sidx,也可直接利用其实现跳转,因此两者通常只需使用其中一种。