我有一个来自RTP帧中的IP相机的原始H.264流。我希望将原始H.264数据放入文件中,以便我可以使用ffmpeg
转换它。
因此,当我想将数据写入我的原始H.264文件时,我发现它必须如下所示:
00 00 01 [SPS]
00 00 01 [PPS]
00 00 01 [NALByte]
[PAYLOAD RTP Frame 1] // Payload always without the first 2 Bytes -> NAL
[PAYLOAD RTP Frame 2]
[... until PAYLOAD Frame with Mark Bit received] // From here its a new Video Frame
00 00 01 [NAL BYTE]
[PAYLOAD RTP Frame 1]
....
因此,我从前面的SPS
通信中获取PPS
中的Session Description Protocol
和RTSP
。此外,在开始使用视频流之前,相机会在两条单个消息中发送SPS
和PPS
。
所以我按照这个顺序捕获消息:
1. Preceding RTSP Communication here ( including SDP with SPS and PPS )
2. RTP Frame with Payload: 67 42 80 28 DA 01 40 16 C4 // This is the SPS
3. RTP Frame with Payload: 68 CE 3C 80 // This is the PPS
4. RTP Frame with Payload: ... // Video Data
然后出现一些带有有效载荷的帧,在某些时候有一个带有Marker Bit = 1
的RTP帧。这意味着(如果我做对了)我有一个完整的视频帧。在此之后,我再次从有效负载中编写前缀序列(00 00 01
)和NAL
,然后继续执行相同的过程。
现在,我的相机会在每8个完整的视频帧后发送给我SPS
和PPS
。 (再次在两个RTP帧中,如上例所示)。我知道尤其是PPS
可以在流媒体之间进行更改,但这不是问题。
我现在的问题是:
1。我是否需要每隔8个视频帧写一次SPS / PPS?
如果我的SPS
和我的PPS
没有更改它应该足以让它们在我的文件的最开头写入而已经没有了?
2。如何区分SPS / PPS和普通RTP帧?
在我解析传输数据的C ++代码中,我需要区分具有正常有效负载的RTP帧和带有SPS/PPS
的RTP帧。我该如何区分它们?好吧SPS/PPS
帧通常更小,但这不是一个依赖的保存调用。因为如果我忽略它们,我需要知道我可以丢弃哪些数据,或者如果我需要编写它们,我需要将00 00 01
前缀放在它们前面。 ?或者它是每隔8个视频帧发生的固定规则吗?
答案 0 :(得分:12)
您应该在流的开头编写SPS和PPS,并且只有当它们在流中间发生变化时才会写。
SPS和PPS帧打包在STAP NAL单元(通常为STAP-A)中,在RFC-3984 section 5.7.1 <中描述了NAL类型24(STAP-A)或25(STAP-B)STAP格式/ p>
不要依赖标记位,使用NAL标头中的起始位和结束位。
对于分段视频帧,您应该使用第一个片段(F,NRI)的3个NAL单元位和有效负载中第一个字节的5个NAL类型位重新生成NAL单元(仅适用于起始位设置为1的数据包)检查RFC-3984 section 5.8:
分段的NAL单位类型八位字节 NAL单元不包含在碎片单元有效载荷中, 而是NAL单位类型八位字节的信息 分段的NAL单元在FU的F和NRI字段中传送 碎片单元的指示符八位字节和类型字段 FU标题。
编辑:有关碎片单元的NAL单元构造的更多解释:
这是FU-A有效载荷的前两个字节(紧跟在rtp标题之后):
| FU indicator | FU header |
+---------------+---------------+
|0|1|2|3|4|5|6|7|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|F|NRI| Type |S|E|R| Type |
+---------------+---------------+
要构建NAL单元,您应该从“FU Header”中取“Type”,从“FU指示器”中取“F”和“NRI”
here是一个简单的实现
答案 1 :(得分:11)
我记得,nal_unit_type是一帧第一个字节的低5位。
nal_unit_type = frame[0] & 0x1f;