如何将 RTP/H264 流写入文件
Posted
技术标签:
【中文标题】如何将 RTP/H264 流写入文件【英文标题】:How to write RTP/H264 stream as a file 【发布时间】:2012-03-23 19:37:56 【问题描述】:我找不到my previous question 的解决方案,所以我决定逐步尝试。
我现在想做的是将 RTP/H264 流存储为文件。
到目前为止,我发现如下:
(首先我的 RTP/H264 是 FU-A 的形式)
| RTP HEADER 12bytes long | FU INDICATOR 1byte | FU HEADER 1byte | FU payload |
根据我对 RFC 6184 文档的理解,我开始一个 NAL 的数据包在 FU 标头的第一位具有“1”,并附加以下在第一位设置“0”的数据包,直到最后一个数据包具有'1' 在 FU Header 的第二位。
我认为这是在 FU-A 打包之前获得完整 NAL 的方法,而且我发现我需要将“起始位”(0x00000001) 放在每个完整 NAL 的前面。
但到目前为止还没有运气。以下是日志的一部分
========= 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
...
我的问题是,
如果我可以通过 FU-A 从分片的数据包中获取完整的 NAL,如何将其制作为能够由 VLC 或其他播放器运行的文件?
我仍然对是否必须保留 FU 指示器和 FU 标头感到困惑。有人说我只需要在第一个数据包中使用它们(在 FU 标头处以 '1' 开头)
任何建议将不胜感激。
谢谢。
【问题讨论】:
嘿,我正在尝试做完全相同的事情。我阅读了 RFC 6184 并尝试按照相同的步骤将其存储到文件中。但我的文件似乎无法播放全部...您能发布您使用的解决方案吗?这个问题有超过 7k 的浏览量.. 这对我们所有人都有帮助.. 【参考方案1】:-
一种选择是将数据多路复用为文件格式,例如 mp4 或 avi,以便能够使用 VLC 播放它。 AFAIR avi 不适合 H.264(不记得原因)。有免费的库,例如libmp4,或者如果你在使用 DirectShow 的 Windows 上,Geraint's mp4mux。
另一种选择是使用 ffmpeg 将 .264 文件转换为 mp4
ffmpeg -i test.264 test.mp4
这假定 .264 文件包含由起始代码分隔的 NAL 单元。
-
来自RFC6184
FU 有效载荷由分片的有效载荷的片段组成 NAL 单元,因此如果分片单元有效载荷连续 FUs 顺序连接,分片 NAL 的有效载荷 单元可以重构。分片的 NAL 单元类型八位字节 NAL 单元不包含在分段单元有效负载中, 而是 NAL 单元类型八位字节的信息 分段的 NAL 单元在 FU 的 F 和 NRI 字段中传送 分片单元的指示八位字节和在类型字段中 FU 标头。一个 FU 有效载荷可以有任意数量的八位字节并且可以 为空。
如果您采用 1 中概述的第二种方法,则需要在将其写入 .264 文件之前重建原始 NAL 单元。
【讨论】:
再次感谢 Ralf,顺便说一句,我真的很想知道我应该如何处理 sps,pps。目前我正在重建的完整 NAL 没有 sps、pps 数据包。我想我必须将它们放在流的第一个数据包之前,或者需要使用 sps、pps 初始化 AVCodecContext。你觉得怎么样?? 好的,我取得了一些进展。我将sps,pps数据包放在流的开头,并将每个重建的单个nal的标头从2字节(它仍然由FU指示符,FU标头组成)编辑成原来的1字节。现在 elecard 流分析器读取文件,但对于 vlc 或任何其他播放器仍然不可读,但如果我通过 'ffmpeg -i src.mp4 con.mp4' 将其转换为 mp4,则 con.mp4 可以由一般视频播放器播放。 但是我需要在自己的播放器中通过ffmpeg api解码文件,所以我必须让它在没有转换的情况下运行。它应该由 ffmpeg api avcodec_decode_video2() 解码。有什么建议吗???? 只需将重建的 NAL 单元传递给 avcodec_decode_video2() 如果您需要,我可以发送示例代码。 自从我写这篇文章很久之后,我才访问了这篇文章。感谢您所有的帮助。我当时解决了它,实际上我需要做的最后一步是重命名输出文件的扩展名。如果文件具有不同的扩展名,玩家就无法识别出文件是完美无缺的。【参考方案2】:FU、STAP 和 MTAP NAL 单元仅特定于 RTP 数据包化,因为它们旨在促进网络传输。换句话说,不要指望解码器正确解析它们。最终,您需要像 FU 数据包那样重新组装 NAL 单元,或者像 STAP/MTAP 那样将它们分解成多个 NAL 单元。
一旦您有了 NAL 单元(这包括 PPS、SPS、SEI、切片分区以及 1-23 范围内的所有其他类型),您就可以将每个单元的“0001”起始代码写入磁盘H.264 附件 B。
可以使用各种命令行工具将 H.264 附件 B 流放入 MPEG-4 等容器中(我很确定 ffmpeg 可以做到)。
【讨论】:
以上是关于如何将 RTP/H264 流写入文件的主要内容,如果未能解决你的问题,请参考以下文章
通过 gstreamer udpsink 流式传输 h.264 时如何解决图像问题
如何将 BIM 360 文件的内容作为文件流读取并将其写入另一个流