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

时间:2012-03-08 13:26:45

标签: c++ h.264 rtsp rtp

我有一个来自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 ProtocolRTSP。此外,在开始使用视频流之前,相机会在两条单个消息中发送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?

如果我的SPS和我的PPS没有更改它应该足以让它们在我的文件的最开头写入而已经没有了?

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

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

2 个答案:

答案 0 :(得分:12)

  1. 您应该在流的开头编写SPS和PPS,并且只有当它们在流中间发生变化时才会写。

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

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

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

      

    分段的NAL单位类型八位字节   NAL单元不包含在碎片单元有效载荷中,   而是NAL单位类型八位字节的信息   分段的NAL单元在FU的F和NRI字段中传送   碎片单元的指示符八位字节和类型字段   FU标题。

  5. 编辑:有关碎片单元的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)

  1. 如果SPS和PPS没有改变,你可以省略它们,除了第一个。
  2. 您需要解析每个NAL的nal_unit_type字段,对于SPS,nal_unit_type == 7;对于PPS,nal_unit_type == 8.
  3. 我记得,nal_unit_type是一帧第一个字节的低5位。

    nal_unit_type = frame[0] & 0x1f;