使用FFmpeg将RTP的数据包保存为mp4文件

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用FFmpeg将RTP的数据包保存为mp4文件相关的知识,希望对你有一定的参考价值。

参考技术A 1、根据RTSP的Announce请求中的sdp信息和RTP包中的信息初始化音视频编解码器

2、将RTP包中的音视频数据提取出来

使用 FFmpeg 进行 H.264 转换(来自 RTP 流)

【中文标题】使用 FFmpeg 进行 H.264 转换(来自 RTP 流)【英文标题】:H.264 conversion with FFmpeg (from a RTP stream) 【发布时间】:2012-07-17 15:13:07 【问题描述】:

环境:

我有一个 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:

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

带起始位的分片

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

没有起始位的分片

    写入原始数据

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

[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写的有以下区别:

    标头:FFmpeg 文件有大约 0x30 字节的标头 页脚:FFmpeg 文件也有页脚 更改了前缀和 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 实际上做了什么?为什么它会改变视频数据中的一些字节?

【问题讨论】:

你能做到吗?如果是,您愿意分享解决方案吗?谢谢! 我也在寻找类似的解决方案。你能解决这个问题吗,你愿意分享吗? 我知道这是一个超级老问题,但在分析有效载荷的Byte 2 时,您似乎有错误的顺序。它应该是[Start Bit | End Bit | Reserved Bit | 5 NAL Unit Bits] - 所以你已经用结束位重新排序了保留位 【参考方案1】:

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

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

【讨论】:

【参考方案2】:

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

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

【讨论】:

【参考方案3】:

您可以在打开的h264 specs 中阅读有关您所做更改的更多信息。附录B。

【讨论】:

以上是关于使用FFmpeg将RTP的数据包保存为mp4文件的主要内容,如果未能解决你的问题,请参考以下文章

如果利用ffmpeg来实现rtp/rtcp实时数据上传至服务器,那么那个AVFormatContext如何初始化?求助!!

ffmpeg仅将传入的RTP音频流保存到文件中

使用命名管道使用 FFMPEG 记录 RTP VP8 数据包

C#使用ffmpeg image2pipe将图片保存为mp4视频

C#使用ffmpeg image2pipe将图片保存为mp4视频

C#使用ffmpeg image2pipe将图片保存为mp4视频