H.264 over RTP - 识别SPS和PPS帧

Tob*_*oby 13 c++ rtp rtsp h.264

我有一个来自IP摄像机的原始H.264流,包含在RTP帧中.我想将原始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]
....
Run Code Online (Sandbox Code Playgroud)

所以我得到的SPSPPSSession 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
Run Code Online (Sandbox Code Playgroud)

然后有一些带有负载的帧,在某些时候有一个带有的RTP帧Marker Bit = 1.这意味着(如果我做对了)我有一个完整的视频帧.在此之后,我再次编写前缀序列(00 00 01)和NAL有效载荷,然后继续执行相同的过程.

现在我的相机向我的每8个完整的视频帧后SPSPPS试.(再次在两个RTP帧中,如上例所示).我知道特别是PPS流媒体之间可以改变,但这不是问题.

我现在的问题是:

1.我是否需要每隔8个视频帧写一次SPS/PPS?

如果我SPS和我的PPS不改变它应该足以让它们在我的文件的最开始写,仅此而已?

2.如何区分SPS/PPS和普通RTP帧?

在我解析传输数据的C++代码中,我需要在具有正常有效负载的RTP帧与带有该传输数据的RTP帧之间进行区分SPS/PPS.我该如何区分它们?好吧,SPS/PPS帧通常会更小,但这不是一个依赖的保存呼叫.因为如果我忽略它们,我需要知道我可以丢弃哪些数据,或者如果我需要编写它们,我需要将00 00 01前缀放在它们前面.?或者它是每隔8个视频帧出现的固定规则吗?

cip*_*hor 13

  1. 如果SPS和PPS没有改变,你可以省略它们,除了第一个.
  2. 您需要解析每个NAL的nal_unit_type字段,对于SPS,nal_unit_type == 7; 对于PPS,nal_unit_type == 8.

我记得,nal_unit_type是帧的第1个字节的低5位.

nal_unit_type = frame[0] & 0x1f;
Run Code Online (Sandbox Code Playgroud)

  • 有关nal_unit_type的详细定义,您可以参考H.264文档.顺便说一句,(payload [0]&0x1f)== 28意味着这是一个支离破碎的视频帧,在这种情况下,实际的nal_unit_type应该是(payload [1]&0x1f).这在RFC3984中定义. (2认同)

ara*_*rdi 12

  1. 您应该在流的开头编写SPS和PPS,并且只有在流中间更改时才编写SPS和PPS.

  2. SPS和PPS帧打包在STAP NAL单元(通常为STAP-A)中,NAL类型24(STAP-A)或25(STAP-B)STAP格式在RFC-3984第5.7.1节中描述

  3. 不要依赖标记位,使用NAL头中的起始位和结束位.

  4. 对于分段视频帧,您应该使用第一个片段(F,NRI)的3个NAL单元位和有效负载中的第一个字节的5个NAL类型位重新生成NAL单元(仅适用于起始位设置为1的数据包)检查RFC-3984第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   |
+---------------+---------------+
Run Code Online (Sandbox Code Playgroud)

要构建NAL单元,你应该从"FU Header"中取"Type",从"FU指示器"取"F"和"NRI"

是一个简单的实现