如何将RTP / H264流写入文件

11

我之前的问题没有找到解决方案,所以我决定逐步尝试。

现在我想要做的事情是将RTP/H264流存储为文件。

目前我找到的是以下内容:

(首先我的RTP/H264是FU-A格式)

| RTP HEADER 12bytes long | FU INDICATOR 1byte | FU HEADER 1byte | FU payload |

根据我理解RFC 6184文档,我将使用在FU头的第一个比特为'1'的数据包开启NAL,并附加接下来的数据包,在最后一个数据包的FU头的第二个比特位设定'1'。

我认为这是在进行FU-A封装之前获取完整的NAL的方法,同时我发现需要在每个完整的NAL前面放置“起始比特”(0x00000001)。

但到目前为止还没有成功。以下是日志的一部分

 ========= the new NAL is as 1400
 [0]0/0 [1]0/0 [2]0/0 [3]1/1 [4]7C/1111100 [5]85/10000101 [6]B8/10111000 [7]40/1000000 ...
 ========= adding the next NAL as 1400
 [0]0/0 [1]0/0 [2]0/0 [3]1/1 [4]7C/1111100 [5]85/10000101 [6]B8/10111000 [7]40/1000000 ...
 ========= adding the next NAL as 1400
 [0]0/0 [1]0/0 [2]0/0 [3]1/1 [4]7C/1111100 [5]85/10000101 [6]B8/10111000 [7]40/1000000 ...
 ========= adding the next NAL as 716
 [0]0/0 [1]0/0 [2]0/0 [3]1/1 [4]7C/1111100 [5]85/10000101 [6]B8/10111000 [7]40/1000000 ...
 ========= a NAL is summed up as 4866
 ========= the new NAL is as 1400
 [0]0/0 [1]0/0 [2]0/0 [3]1/1 [4]5C/1011100 [5]81/10000001 [6]E2/11100010 [7]20/100000 ...
 ========= adding the next NAL as 1400
 [0]0/0 [1]0/0 [2]0/0 [3]1/1 [4]5C/1011100 [5]81/10000001 [6]E2/11100010 [7]20/100000 ...
 ========= adding the next NAL as 1400
 [0]0/0 [1]0/0 [2]0/0 [3]1/1 [4]5C/1011100 [5]81/10000001 [6]E2/11100010 [7]20/100000 ...
 ========= adding the next NAL as 1400
 [0]0/0 [1]0/0 [2]0/0 [3]1/1 [4]5C/1011100 [5]81/10000001 [6]E2/11100010 [7]20/100000 ...
 ========= adding the next NAL as 1400
 [0]0/0 [1]0/0 [2]0/0 [3]1/1 [4]5C/1011100 [5]81/10000001 [6]E2/11100010 [7]20/100000 ...
 ========= adding the next NAL as 139
 [0]0/0 [1]0/0 [2]0/0 [3]1/1 [4]5C/1011100 [5]81/10000001 [6]E2/11100010 [7]20/100000 ...
 ========= a NAL is summed up as 7061
 ========= the new NAL is as 1377
 [0]0/0 [1]0/0 [2]0/0 [3]1/1 [4]41/1000001 [5]E4/11100100 [6]40/1000000 [7]1A/11010 ...
 ========= a NAL is summed up as 1369
 ========= the new NAL is as 1400
 [0]0/0 [1]0/0 [2]0/0 [3]1/1 [4]5C/1011100 [5]81/10000001 [6]E6/11100110 [7]60/1100000 ...
 ========= adding the next NAL as 94
 [0]0/0 [1]0/0 [2]0/0 [3]1/1 [4]5C/1011100 [5]81/10000001 [6]E6/11100110 [7]60/1100000 ...
 ========= a NAL is summed up as 1472
 ========= the new NAL is as 447
 [0]0/0 [1]0/0 [2]0/0 [3]1/1 [4]41/1000001 [5]E8/11101000 [6]80/10000000 [7]16/10110 ...
 ========= a NAL is summed up as 439
 ========= the new NAL is as 1400
 [0]0/0 [1]0/0 [2]0/0 [3]1/1 [4]5C/1011100 [5]81/10000001 [6]EA/11101010 [7]A0/10100000  ...
 ========= adding the next NAL as 1174
 [0]0/0 [1]0/0 [2]0/0 [3]1/1 [4]5C/1011100 [5]81/10000001 [6]EA/11101010 [7]A0/10100000 ...
 ========= a NAL is summed up as 2552
 ========= the new NAL is as 1400
 [0]0/0 [1]0/0 [2]0/0 [3]1/1 [4]5C/1011100 [5]81/10000001 [6]EC/11101100 [7]C0/11000000 ...
 ========= adding the next NAL as 1364
 [0]0/0 [1]0/0 [2]0/0 [3]1/1 [4]5C/1011100 [5]81/10000001 [6]EC/11101100 [7]C0/11000000 ...
 ========= a NAL is summed up as 2742
 ========= the new NAL is as 1400
 ...

我的问题是,

  1. 如果我可以通过FU-A从分片数据包中获取完整的NAL单元,那么我该如何将其制作成能够在VLC或其他播放器中运行的文件?

  2. 我仍然不确定是否需要保留FU指示符和FU头部。有人说我只需要在第一个分片数据包(以FU头部的'1'开头)中保留它们。

非常感谢任何建议。

谢谢。


嘿,我正在尝试做完全相同的事情...我阅读了RFC 6184并尝试按照相同的步骤将其存储到文件中...但我的文件似乎根本无法播放...你能否请发布您使用的解决方案?这个问题已经有超过7k的浏览量...对我们所有人都会有帮助... - Sandeep
2个回答

6
FU、STAP和MTAP NAL单元仅适用于RTP编包,因为它们旨在促进网络传输。换句话说,不要指望解码器能正确解析它们。最终,您需要重新组装NAL单元,如FU数据包的情况,或在STAP / MTAP情况下将其拆分成多个NAL单元。

一旦您有了NAL单元(这包括PPS、SPS、SEI、切片分区和所有其他类型的1-23范围内),则可以根据H.264附录B每个NAL单元之前的“0001”起始码写入磁盘。

将H.264附录B流放入诸如MPEG-4之类的容器中可以使用各种命令行工具完成(我相信ffmpeg可以做到)。


5
  1. 一种选择是将数据混合到文件格式中,例如mp4或avi,以便使用VLC播放。据我所知,avi不适用于H.264(无法立即记起原因)。有免费的库,例如libmp4,或者如果您在Windows上使用DirectShow,则可以使用Geraint's mp4mux

另一种选择是使用ffmpeg将.264文件转换为mp4

ffmpeg -i test.264 test.mp4

这里假设.264文件包含由起始码分隔的NAL单元。
2. 来自RFC6184 FU有效载荷由分片NAL单元的片段组成,因此如果连续的FU的分片单元有效载荷按顺序连接,则可以重建分片NAL单元的有效载荷。 分片NAL单元的NAL单元类型八位字节不作为分片单元有效载荷的一部分包含在内,而是分片单元的FU指示器八位字节中的F和NRI字段以及FU头的类型字段中传递分片NAL单元的NAL单元类型八位字节的信息。 FU有效载荷可以具有任意数量的八位字节,并且可以为空。
如果采用1中概述的第二种方法,则需要在将其写入.264文件之前重建原始NAL单元。

再次感谢Ralf,顺便说一句,我真的很想知道我应该如何处理sps、pps。目前,我正在重建的完整NAL没有sps、pps数据包。我认为我必须将它们放在流的第一个数据包之前,或者需要使用已初始化了sps、pps的AVCodecContext。你怎么看? - Jun
好的,我取得了一些进展。我将SPS、PPS数据包放在流的头部,并将每个重构的单个NAL的头部从2字节(仍由FU指示器、FU头构成)编辑为原始的1字节。现在,Elecard流分析器可以读取该文件,但对于VLC或任何其他播放器仍然无法读取。但是,如果我通过“ffmpeg -i src.mp4 con.mp4”将其转换为MP4格式,那么con.mp4可以被普通视频播放器播放。 - Jun
但是我需要在自己的播放器中使用FFmpeg API解码文件,因此我必须使其在不进行转换的情况下运行。它应该通过FFmpeg API avcodec_decode_video2()进行解码... 有什么建议吗??? - Jun
如果需要,我可以发送示例代码,但只需将重构的NAL单元传递给avcodec_decode_video2()即可。 - arash kordi
我很久没看这篇文章了,感谢你们的所有帮助。当时我解决了它,实际上我需要做的最后一步是重命名输出文件的扩展名。如果文件有不同的扩展名,玩家们并不聪明地认为文件是完美无缺的。 - Jun
@Jun,很高兴你解决了这个问题。你知道如何在读取早期段的同时尝试将H.264流写入mp4文件吗? - noelicus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接