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

H.264 over RTP - Identify SPS and PPS Frames

本文关键字:PPS SPS 识别 over RTP-      更新时间:2023-10-16

我有一个来自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]
....

因此,我从先前的RTSP通信中从Session Description Protocol获得SPSPPS。此外,在开始视频流本身之前,摄像机在两个单独的消息中发送SPSPPS

因此,我按照以下顺序捕获消息:

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个完整的视频帧后再次发送SPSPPS。(同样在两个RTP帧中,如上面的示例所示)。我知道,尤其是PPS可以在流媒体之间切换,但这不是问题所在。

我现在的问题是:

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

如果我的SPSPPS没有更改,那么在我的文件一开始就把它们写出来就足够了,什么都不做?

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

在我解析传输数据的C++代码中,我需要在具有正常有效载荷的RTP帧和携带SPS/PPS的RTP框架之间做出区分。我如何区分它们?好吧,SPS/PPS帧通常要小得多,但这不是一个可以依赖的保存调用。因为如果我忽略它们,我需要知道我可以丢弃哪些数据,或者如果我需要写入它们,我就需要在它们前面加上00 00 01前缀?还是每8个视频帧出现一次是固定的规则?

  1. 如果SPS和PPS没有更改,则可以省略它们(第一个除外)
  2. 您需要解析每个nal的nal_unit_type字段,对于SPS,nal_unitype==7;对于PPS,nal_unit_type==8

我记得,nal_unit_type是帧的第一个字节的低5位。

nal_unit_type = frame[0] & 0x1f;
  1. 您应该在流的开头写入SPS和PPS,并且只有当它们在流的中间发生变化时才写入。

  2. SPS和PPS帧被封装在NAL类型为24(STAP-a)或25(STAP-B)的STAP NAL单元(通常为STAP-a

  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   |
+---------------+---------------+

为了构建NAL单元;类型";从";FU标题";以及";F";以及";NRI";从";FU指示器";

这里有一个简单的实现