使用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 VP8 数据包
C#使用ffmpeg image2pipe将图片保存为mp4视频