19

环境:

我有一个 IP 摄像机,它能够通过 RTP 以 H.264 编码格式传输数据。此原始流是从以太网记录的。有了这些数据,我必须工作。

目标:

最后,我想要一个 *.mp4 文件,我可以使用常见的媒体播放器(如 VLC 或 Windows MP)播放它。

到目前为止我做了什么:

我获取我拥有的原始流数据并对其进行解析。由于数据是通过 RTP 传输的,我需要处理 NAL 字节、SPS 和 PPS。

1.写一个原始文件

首先,我确定通过以太网接收的每个帧的类型。为此,我解析每个 RTP Payload 的前两个字节,因此我可以获得 8 个 NAL 单元位、片段类型位以及开始、保留和结束位。在有效载荷中,它们的排列方式如下:

Byte 1: [          3 NAL Unit Bits          | 5 Fragment Type Bits]
Byte 2: [Start Bit | Reserved Bit | End Bit | 5 NAL Unit Bits]

由此我可以确定:

  • 视频帧的开始和结束 -> 开始位和结束位
  • 有效负载的类型 -> 5 个片段类型位
  • NAL 单位字节

在我的情况下需要的片段类型是:

Fragment Type  7 = SPS
Fragment Type  8 = PPS
Fragment Type 28 = Video Fragment

NAL 字节是通过将字节 1 和 2 中的 NAL 单元位放在一起创建的。

现在根据碎片类型,我执行以下操作:

SPS/PPS:

  1. 写入 NAL 前缀 ( 0x00 0x00 0x01),然后写入 SPS 或 PPS 数据

带起始位的分片

  1. 写 NAL 前缀
  2. 写入 NAL 单元字节
  3. 写入剩余的原始数据

没有起始位的分片

  1. 写入原始数据

这意味着我的原始文件看起来像这样:

[NAL Prefix][SPS][NAL Prefix][PPS][NAL Prefix][NAL Unit Byte][Raw Video Data][Raw Video Data]....[NAL Prefix][NAL Unit Byte][Raw Video Data]...

对于我在流数据中找到的每个 PPS 和 SPS,我只需编写一个 NAL 前缀 ( 0x00 0x00 0x01 ),然后是 SPS/PPS 本身。

现在我无法使用某些媒体播放器播放这些数据,这导致我:

2.转换文件

因为我想避免大量使用编解码器,所以我只使用了现有的应用程序 -> FFmpeg。我用这些参数调用:

ffmpeg.exe -f h264 -i <RawInputFile> -vcodec copy -r 25 <OutPutFilename>.mp4

-f h264:这应该告诉 ffmpeg 我有一个 h264 编码流

-vcodec copy:从手册页引用:

Force video codec to codec. Use the "copy" special value to tell that the raw codec data must be copied as is.

-r 25:将帧速率设置为 25 FPS。

当我使用这些参数调用 ffmpeg 时,我得到一个 .mp4 文件,我可以使用 VLC 和 Windows MP 播放该文件,因此它确实有效。但是该文件现在看起来与我的原始文件有点不同。

这引出了我的问题:

我实际上做了什么?

我的问题不在于它不起作用。我只是想/需要知道我在调用 ffmpeg 时实际上做了什么。我有一个无法播放的原始 H264 文件。使用 FFmpeg 后,我可以播放它。

原始原始文件(我已经编写)和 FFmpeg 编写的原始文件之间存在以下差异:

  1. 标头:FFmpeg 文件具有大约 0x30 字节的标头
  2. 页脚:FFmpeg 文件也有页脚
  3. 更改了前缀和 2 个新字节:

虽然原始文件中的新视频帧像 [NAL Prefix][NAL Unit Byte][Raw Video Data]在新文件中一样开始,但它看起来像这样:

[0x00 0x00][2 "Random" Bytes][NAL Unit Byte][Raw Video Data].....[0x00 0x00[2 other "Random" Bytes][NAL Unit Byte][Raw Video Data]...

我知道视频流需要一个容器格式(如果我错了,请纠正我,但我认为新的页眉和页脚对此负责)。但为什么它实际上改变了原始数据中的一些字节?它不能是一些解码,因为流本身应该由播放器而不是 ffmpeg 解码。

正如你所看到的,我不需要一个新的解决方案来解决我的问题,而不仅仅是解释(所以我可以自己解释)。ffmpeg 实际上做了什么?为什么它会改变视频数据中的一些字节?

4

3 回答 3

4

除了添加 MP4 容器外,ffmpeg 还将您的 H.264 Annex B 字节流(带有 NAL 前缀)转换为长度前缀格式。

您的 [0x00 0x00][2 "Random" Bytes] 是一个 32 位整数,以字节为单位给出以下 NAL 单元的长度。

于 2013-08-28T11:55:46.237 回答
0

看起来流被打包了。许多容器格式将比特流分成数据包并添加一些信息,例如时间戳、数据包长度等。这为解码器提供了挂钩,可以跳过文件而不解码所有内容,在数据包丢失时重新同步,同步音频/视频,组合多个流等

查看 MP4 文件格式信息以获取更多信息:
http ://en.wikipedia.org/wiki/MPEG-4_Part_14

于 2012-07-26T21:09:07.827 回答
-2

您可以阅读更多关于您在开放h264 规范中所做的更改。附录 B 章。

于 2014-04-10T15:28:38.707 回答