碎片化的 MP4 中的曲目 运行 是否必须以关键帧开头?

Does a track run in a fragmented MP4 have to start with a key frame?

我正在摄取 RTMP 流并将其转换为 JavaScript 中的碎片化 MP4 文件。这花了一周的时间,但我几乎完成了这项任务。我正在生成一个有效的 ftyp 原子、moov 原子和 moof 原子,视频的第一帧在进入无限缓冲之前实际播放(带音频),没有错误列于 chrome://media-internals

将视频插入 ffprobe,我收到类似于以下内容的错误:

[mov,mp4,m4a,3gp,3g2,mj2 @ 0x558559198080] Failed to add index entry
    Last message repeated 368 times
[h264 @ 0x55855919b300] Invalid NAL unit size (-619501801 > 966).
[h264 @ 0x55855919b300] Error splitting the input into NAL units.

这让我开始大量寻找 tfhdtrun 原子中的数据对齐问题或无效字节偏移,但是无论我在哪里查看或如何分割数据,我都无法在moof原子中没有发现任何问题。

然后我使用以下命令将原始 FLV 文件转换为 ffmpeg 中的 MP4:

ffmpeg -i ~/Videos/rtmp/big_buck_bunny.flv -c copy -ss 5 -t 10 -movflags frag_keyframe+empty_moov+faststart test.mp4

我在原子解析文件中打开了我正在创建的 MP4 和 ffmpeg 输出的 MP4 并比较了两者:

首先让我震惊的是 ffmpeg 生成的文件每个 moof 都有多个视频样本。具体来说,每个 moof 从 1 个关键帧开始,然后包含所有差异帧,直到下一个关键帧(用作以下 moof 原子的开始)

将此与我生成 MP4 的方式进行对比。每次 FLV VIDEODATA 数据包到达时,我都会创建一个 moof 原子。这意味着我的 moof 可能不包含关键帧(通常不包含)

这就是我遇到麻烦的原因吗?或者还有什么我想念的吗?

有问题的视频文件可以在这里下载:

我注意到的另一个问题是 ffmpegtfhd 原子中大量使用 base_data_offset。但是,当我尝试跟踪附加的字节总数并自己设置 base_data_offset 时,我在 Chrome 中收到了一个错误,大致如下:"MSE doesn't support base_data_offset"。根据 ISO/IEC 14996-10 规范:

If not provided, the base-data-offset for the first track in the movie fragment is the position of the first byte of the enclosing Movie Fragment Box, and for second and subsequent track fragments, the default is the end of the data defined by the preceding fragment.

这个措辞让我相信第一个 trun 原子中的 data_offset 应该等于 moof 原子的大小,而 data_offset 中的 data_offset第二个 trun 原子应该是 0(从前面片段定义的数据末尾算起 0 个字节)。但是,当我尝试这样做时,出现无法解析视频数据的错误。 did 导致可以解析的数据是 moof 原子的长度加上第一轨道的总长度(如如果基本偏移量是封闭 moof 框的第一个字节,与第一条轨道相同)

不,moof 不需要从关键帧开始。您正在生成的文件会产生无效的 NALU 大小错误,因为它具有无效的最终大小。每个 nal(在 mdat 中)都必须在其前面加上大小。查看您的文件,mdat 后的前 4 个字节是 0x21180C68,它太大而不是有效大小。