ngx_rtmp_mp4.c 实现了 Nginx RTMP 模块中的 MP4 支持,主要用于将音视频流保存为 MP4 文件格式。MP4 文件格式被广泛应用于视频流的存储与播放,它包括了多个结构化的数据块(boxes),如 ftyp
、moov
、mdat
等。Nginx RTMP 使用该模块将实时的 RTMP 流转换为 MP4 文件,以便可以进行进一步的处理和播放。
1. 核心数据结构与常量
1.1 ngx_rtmp_mp4_sample_t
这个结构体用于表示一个 MP4 样本(sample),它包含:
-
size
:样本的大小。 -
duration
:样本的时长。 -
delay
:样本的延迟时间。 -
timestamp
:样本的时间戳。 -
key
:标记该样本是否是关键帧(keyframe)。
1.2 ngx_rtmp_mp4_file_type_t
这个枚举类型用于表示 MP4 文件的类型:
-
NGX_RTMP_MP4_FILETYPE_INIT
:初始化文件(通常是init.mp4
)。 -
NGX_RTMP_MP4_FILETYPE_SEG
:片段文件(通常是流的实际数据片段)。
1.3 ngx_rtmp_mp4_track_type_t
这个枚举类型表示 MP4 中的轨道类型:
-
NGX_RTMP_MP4_VIDEO_TRACK
:视频轨道。 -
NGX_RTMP_MP4_AUDIO_TRACK
:音频轨道。
2. MP4 文件结构与写入
MP4 文件是由多个盒子(boxes)组成的,每个盒子包含不同的元数据或媒体数据。以下是一些常见的盒子类型和它们的功能:
2.1 ngx_rtmp_mp4_field_*
系列函数
这些函数用于将不同长度的数据写入到缓冲区 ngx_buf_t *b
中。它们按照大端格式将数据拆解为字节并写入:
-
ngx_rtmp_mp4_field_32
:写入 4 字节的数据。 -
ngx_rtmp_mp4_field_24
:写入 3 字节的数据。 -
ngx_rtmp_mp4_field_16
:写入 2 字节的数据。 -
ngx_rtmp_mp4_field_8
:写入 1 字节的数据。
这些函数确保数据按照指定格式被正确地写入 MP4 文件的缓冲区中。
2.2 ngx_rtmp_mp4_start_box
和 ngx_rtmp_mp4_update_box_size
-
ngx_rtmp_mp4_start_box
:用于开始一个新的 MP4 盒子。它首先写入盒子的大小(初始为 0),然后写入盒子的类型(如ftyp
、moov
等)。返回指向缓冲区当前位置的指针,方便后续填充内容。 -
ngx_rtmp_mp4_update_box_size
:用于更新盒子的大小。每个盒子的大小是动态计算的,因此在写入完成后,调用此函数来修正盒子的大小。
2.3 ngx_rtmp_mp4_write_ftyp
和 ngx_rtmp_mp4_write_styp
-
ngx_rtmp_mp4_write_ftyp
:写入ftyp
盒子,它是 MP4 文件的第一个盒子,包含文件类型和兼容的品牌信息。 -
ngx_rtmp_mp4_write_styp
:写入styp
盒子,类似于ftyp
,用于指示文件的类型和兼容性。
2.4 ngx_rtmp_mp4_write_mvhd
和 ngx_rtmp_mp4_write_tkhd
-
ngx_rtmp_mp4_write_mvhd
:写入mvhd
盒子,它是 MP4 文件的“视频文件头”,包括时间轴、时长、视频的编码方式等元数据。 -
ngx_rtmp_mp4_write_tkhd
:写入tkhd
盒子,表示一个轨道(track)的基本信息。每个轨道都有一个tkhd
盒子,用于定义该轨道的 ID、时长、类型等信息。
2.5 ngx_rtmp_mp4_write_mdhd
和 ngx_rtmp_mp4_write_hdlr
-
ngx_rtmp_mp4_write_mdhd
:写入mdhd
盒子,表示媒体头部信息,包含该媒体的时间尺度和持续时间。 -
ngx_rtmp_mp4_write_hdlr
:写入hdlr
盒子,表示该轨道的处理器类型(如视频处理器或音频处理器)。
2.6 ngx_rtmp_mp4_write_minf
, ngx_rtmp_mp4_write_mdia
, ngx_rtmp_mp4_write_trak
-
ngx_rtmp_mp4_write_minf
:写入minf
盒子,包含媒体数据的信息,如视频或音频的编解码器、压缩格式等。 -
ngx_rtmp_mp4_write_mdia
:写入mdia
盒子,包含关于轨道(如视频或音频)的完整描述。 -
ngx_rtmp_mp4_write_trak
:写入trak
盒子,表示一个轨道的完整信息,包括tkhd
、mdia
等。
3. 视频和音频轨道
3.1 ngx_rtmp_mp4_write_video
和 ngx_rtmp_mp4_write_audio
-
ngx_rtmp_mp4_write_video
:用于写入视频轨道的相关信息。包括视频的编码信息、宽高、分辨率等。 -
ngx_rtmp_mp4_write_audio
:用于写入音频轨道的相关信息。包括音频的编码信息、采样率、声道数等。
3.2 ngx_rtmp_mp4_write_esds
esds
盒子是音频流的一个描述符,包含了音频的配置信息,尤其是 AAC 音频流的相关参数。ngx_rtmp_mp4_write_esds
会解析并写入 esds
盒子。
4. DASH 和 HLS 相关操作
MP4 模块也涉及到生成与 DASH(动态自适应流媒体)和 HLS(HTTP Live Streaming)兼容的文件。这些文件通常包含音频和视频轨道的描述,并被切割为多个片段(segment)以适应不同网络条件下的流媒体播放。
5. 总结
这段代码实现了 Nginx RTMP 模块中的 MP4 文件生成支持。MP4 文件格式由多个盒子(boxes)组成,每个盒子保存不同类型的元数据或媒体数据。Nginx 使用这个模块将实时的 RTMP 流转换为 MP4 格式,这对于流媒体分发和存储非常有用。初学者需要重点理解 MP4 文件的盒子结构以及如何将音视频数据写入到这些盒子中。
关键要点:
-
MP4 文件盒子结构:了解
ftyp
、moov
、mdat
、stsd
等盒子的作用。 -
视频和音频轨道描述:每个轨道(视频或音频)都有详细的描述信息,如
tkhd
(轨道头)、mdhd
(媒体头)等。 -
数据写入与更新:通过
ngx_rtmp_mp4_field_*
系列函数将数据写入到缓冲区,并更新盒子的大小。
这段代码对于实现 MP4 文件格式的流媒体存储与播放至关重要,适用于与 DASH 或其他流媒体协议兼容的使用场景。