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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9618369/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 13:04:57  来源:igfitidea点击:

H.264 over RTP - Identify SPS and PPS Frames

c++h.264rtsprtp

提问by Toby

I have a raw H.264 Stream from an IP Camera packed in RTP frames. I want to get raw H.264 data into a file so I can convert it with ffmpeg.

我有来自打包在 RTP 帧中的 IP 摄像机的原始 H.264 流。我想将原始 H.264 数据转换为一个文件,以便我可以将其转换为ffmpeg.

So when I want to write the data into my raw H.264 file I found out it has to look like this:

因此,当我想将数据写入原始 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]
....

So I get the SPSand the PPSfrom the Session Description Protocolout of my preceding RTSPcommunication. Additionally the camera sends the SPSand the PPSin two single messages before starting with the video stream itself.

所以我从之前的交流中得到了SPS和。此外,在开始处理视频流本身之前,摄像机会在两个单独的消息中发送和。PPSSession Description ProtocolRTSPSPSPPS

So I capture the messages in this order:

所以我按以下顺序捕获消息:

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

Then there come some Frames with Payload and at some point a RTP Frame with the Marker Bit = 1. This means ( if I got it right) that I have a complete video frame. Afer this I write the Prefix Sequence ( 00 00 01) and the NALfrom the payload again and go on with the same procedure.

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

Now my camera sends me after every 8 complete Video Frames the SPSand the PPSagain. ( Again in two RTP Frames, as seen in the example above ). I know that especially the PPScan change in between streaming but that's not the problem.

现在我的相机每8个完整的视频帧后,送我SPSPPS试。(再次在两个 RTP 帧中,如上例所示)。我知道尤其是PPS流媒体之间的变化,但这不是问题。

My questions are now:

我现在的问题是:

1. Do I need to write the SPS/PPS every 8th Video Frame?

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

If my SPSand my PPSdon't change it should be enough to have them written at the very beginning of my file and nothing more?

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

2. How to distinguish between SPS/PPS and normal RTP Frames?

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

In my C++ Code which parses the transmitted data I need make a difference between the RTP Frames with normal Payload an the ones carrying the SPS/PPS. How can I distinguish them? Okay the SPS/PPSframes are usually way smaller, but that's not a save call to rely on. Because if I ignore them I need to know which data I can throw away, or if I need to write them I need to put the 00 00 01Prefix in front of them. ? Or is it a fixed rule that they occur every 8th Video Frame?

在我解析传输数据的 C++ 代码中,我需要在 RTP 帧与普通有效负载之间进行区分,而那些携带SPS/PPS. 我如何区分它们?好的,SPS/PPS框架通常要小得多,但这不是一个可以依赖的保存调用。因为如果我忽略它们,我需要知道我可以丢弃哪些数据,或者如果我需要编写它们,我需要将00 00 01Prefix 放在它们前面。? 或者它们是每第 8 个视频帧发生一次的固定规则?

采纳答案by ciphor

  1. If the SPS and PPS do not change, you could omit them except the 1st ones.
  2. You need to parse the nal_unit_type field of each NAL, for SPS, nal_unit_type==7; for PPS, nal_unit_type==8.
  1. 如果 SPS 和 PPS 没有变化,除了第一个之外,您可以省略它们。
  2. 需要解析每个NAL的nal_unit_type字段,对于SPS,nal_unit_type==7;对于 PPS,nal_unit_type==8。

As I remember, nal_unit_type is the lower 5 bits of the 1st byte of a frame.

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

nal_unit_type = frame[0] & 0x1f;

回答by arash kordi

  1. You should write SPS and PPS at the start of stream, and only when they change in the middle of stream.

  2. SPS and PPS frames are packed in a STAP NAL unit (generally STAP-A) with NAL type 24 (STAP-A) or 25 (STAP-B) STAP format is described in RFC-3984 section 5.7.1

  3. Don't rely on marker bit, use start bit and end bit in NAL header.

  4. For fragmented video frames you should regenerate NAL unit using 3 NAL unit bits of first fragment (F, NRI) combined with 5 NAL type bits of first byte in payload (only for packets with start bit set to 1) check RFC-3984 section 5.8:

    The NAL unit type octet of the fragmented NAL unit is not included as such in the fragmentation unit payload, but rather the information of the NAL unit type octet of the fragmented NAL unit is conveyed in F and NRI fields of the FU indicator octet of the fragmentation unit and in the type field of the FU header.

  1. 您应该在流开始时编写 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 类型位(仅适用于起始位设置为 1 的数据包)重新生成 NAL 单元,请检查RFC-3984 第 5.8 节

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

EDIT:more explanation about NAL unit construction for fragmentation units:

编辑:关于碎片单元的 NAL 单元构造的更多解释:

this is first two bytes of a FU-A payload (right after rtp header):

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

to construct the NAL unit you should take "Type" from "FU Header" and "F" and "NRI" from "FU indicator"

要构建 NAL 单元,您应该从“FU Header”中获取“Type”,从“FU indicator”中获取“F”和“NRI”

hereis a simple implementation

是一个简单的实现