检测 RTP 流中的 MPEG4/H264 I 帧 (IDR)

发布于 2024-08-16 04:28:53 字数 97 浏览 6 评论 0原文

我需要检测 RTP 数据包中的 MPEG4 I 帧。我知道如何删除 RTP 标头并获取其中的 MPEG4 帧,但我不知道如何识别 I 帧。

它有特定的签名/标头吗?

I need to detect MPEG4 I-Frame in RTP packet. I know how to remove RTP header and get the MPEG4 frame in it, but I can't figure out how to identify the I-Frame.

Does it have a specific signature/header?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

腻橙味 2024-08-23 04:28:53

好的,我想出了 h264 流的方法。

如何检测 I 帧:

  • 删除 RTP 标头
  • 检查 h264 有效负载中第一个字节的值
  • 如果该值为 124 (0x7C),则它是一个 I 帧

我无法弄清楚 MPEG4-ES 流...有什么建议?

编辑:H264 IDR

适用于我的 h264 流 (fmtp:96 packetization-mode=1; profile-level-id=420029;) 。您只需传递表示通过 RTP 接收到的 h264 片段的字节数组。如果您想传递整个 RTP,只需更正 RTPHeaderBytes 值即可跳过 RTP 标头。我总是得到 I 帧,因为它是唯一可以分段的帧,请参见 此处。我在我的服务器中使用这段(简化的)代码,它的工作就像一个魅力!如果 I 帧 (IDR) 未分段,则 fragment_type 将为 5,因此此代码将为分段和非分段 IDR 返回 true

public static bool isH264iFrame(byte[] paket)
    {
        int RTPHeaderBytes = 0;

        int fragment_type = paket[RTPHeaderBytes + 0] & 0x1F;
        int nal_type = paket[RTPHeaderBytes + 1] & 0x1F;
        int start_bit = paket[RTPHeaderBytes + 1] & 0x80;

        if (((fragment_type == 28 || fragment_type == 29) && nal_type == 5 && start_bit == 128) || fragment_type == 5)
        {
            return true;
        }

        return false;
   }

以下是 NAL 单元类型表:

 Type Name
    0 [unspecified]
    1 Coded slice
    2 Data Partition A
    3 Data Partition B
    4 Data Partition C
    5 IDR (Instantaneous Decoding Refresh) Picture
    6 SEI (Supplemental Enhancement Information)
    7 SPS (Sequence Parameter Set)
    8 PPS (Picture Parameter Set)
    9 Access Unit Delimiter
   10 EoS (End of Sequence)
   11 EoS (End of Stream)
   12 Filter Data
13-23 [extended]
24-31 [unspecified] 

编辑 2:MPEG4 I-VOP

我忘记更新此...感谢 Che 和 ISO IEC 14496-2 文档,我设法解决了这个问题! Che 很仪式,但他的回答并不那么精确...所以这里是如何找到 I、P 和 B 帧(I-VOP、P-VOP、B-VOP),简而言之:

  1. VOP(视频对象平面 - 帧) ) 以代码 000001B6(十六进制)开头。对于所有 MPEG4 帧(I、P、B)都是相同的
  2. 接下来有更多信息,我不会在这里描述(请参阅 IEC 文档),但我们只(如 che 所说)需要更高的来自后续字节的 2 位(值为 B6 的字节之后的接下来两位)。这 2 位告诉您 VOP_CODING_TYPE,请参阅表格:

    VOP_CODING_TYPE(二进制) 编码方式
                          00 内部编码 (I)
                          01 预测编码(P)
                          10 双向预测编码 (B)
                          11 精灵 (S)
    

因此,要查找 I 帧,请查找以四个字节 000001B6 开头并具有下一个字节的高两位 00 的数据包。代码>.这将在 MPEG4 流中找到具有简单视频对象类型的 I 帧(不确定高级简单)。

对于任何其他问题,您可以查看提供的文档(ISO IEC 14496 -2),这里有您想了解的有关 MPEG4 的所有信息。 :)

Ok so I figured it out for h264 stream.

How to detect I-Frame:

  • remove RTP header
  • check the value of the first byte in h264 payload
  • if the value is 124 (0x7C) it is an I-Frame

I cant figure it out for the MPEG4-ES stream... any suggestions?

EDIT: H264 IDR

This works for my h264 stream (fmtp:96 packetization-mode=1; profile-level-id=420029;). You just pass byte array that represents the h264 fragment received through RTP. If you want to pass whole RTP, just correct the RTPHeaderBytes value to skip RTP header. I always get the I-Frame, because it is the only frame that can be fragmented, see here. I use this (simplified) piece of code in my server, and it works like a charm!!!! If the I-Frame (IDR) is not fragmented, the fragment_type would be 5, so this code would return true for the fragmented and not fragmented IDRs.

public static bool isH264iFrame(byte[] paket)
    {
        int RTPHeaderBytes = 0;

        int fragment_type = paket[RTPHeaderBytes + 0] & 0x1F;
        int nal_type = paket[RTPHeaderBytes + 1] & 0x1F;
        int start_bit = paket[RTPHeaderBytes + 1] & 0x80;

        if (((fragment_type == 28 || fragment_type == 29) && nal_type == 5 && start_bit == 128) || fragment_type == 5)
        {
            return true;
        }

        return false;
   }

Here's the table of NAL unit types:

 Type Name
    0 [unspecified]
    1 Coded slice
    2 Data Partition A
    3 Data Partition B
    4 Data Partition C
    5 IDR (Instantaneous Decoding Refresh) Picture
    6 SEI (Supplemental Enhancement Information)
    7 SPS (Sequence Parameter Set)
    8 PPS (Picture Parameter Set)
    9 Access Unit Delimiter
   10 EoS (End of Sequence)
   11 EoS (End of Stream)
   12 Filter Data
13-23 [extended]
24-31 [unspecified] 

EDIT 2: MPEG4 I-VOP

I forgot to update this... Thanx to Che and ISO IEC 14496-2 document, I managed to work this out! Che was rite, but not so precise in his answer... so here is how to find I, P and B frames (I-VOP, P-VOP, B-VOP) in short:

  1. VOP (Video Object Plane -- frame) starts with a code 000001B6(hex). It is the same for all MPEG4 frames (I,P,B)
  2. Next follows many more info, that I am not going to describe here (see the IEC doc), but we only (as che said) need the higher 2 bits from the following byte (next two bits after the byte with the value B6). Those 2 bits tell you the VOP_CODING_TYPE, see the table:

    VOP_CODING_TYPE (binary)  Coding method
                          00  intra-coded (I)
                          01  predictive-coded (P)
                          10  bidirectionally-predictive-coded (B)
                          11  sprite (S)
    

So, to find I-Frame find the packet starting with four bytes 000001B6 and having the higher two bits of the next byte 00. This will find I frame in MPEG4 stream with a simple video object type (not sure for advanced simple).

For any other problems, you can check the document provided (ISO IEC 14496-2), there is all you want to know about MPEG4. :)

你爱我像她 2024-08-23 04:28:53

据我所知,RTP负载中的MPEG4-ES流片段通常以MPEG4起始码开头,可以是以下之一:

  • 0x000001b0:visual_object_sequence_start_code(可能是关键帧)
  • 0x000001b6: vop_start_code(关键帧,如果接下来的两位为零)
  • 0x000001b3:group_of_vop_start_code,包含三个字节,然后希望 vop_start_code 可能属于也可能不属于关键帧(见上文)
  • 0x00000120< /code>:video_object_layer_start_code(可能是关键帧)
  • 0x00000100-0x0000011f:video_object_start_code(那些看起来也像关键帧)
  • 其他东西(可能不是关键帧)

我担心你需要解析流以确保:-/

As far as I know, MPEG4-ES stream fragments in RTP payload usually start with MPEG4 startcode, which can be one of these:

  • 0x000001b0: visual_object_sequence_start_code (probably keyframe)
  • 0x000001b6: vop_start_code (keyframe, if the next two bits are zero)
  • 0x000001b3: group_of_vop_start_code, which contains three bytes and then hopefully a vop_start_code that may or may not belong to a keyframe (see above)
  • 0x00000120: video_object_layer_start_code (probably keyframe)
  • 0x00000100-0x0000011f: video_object_start_code (those look like keyframes as well)
  • something else (probably not a keyframe)

I'm afraid that you'll need to parse the stream to be sure :-/

离笑几人歌 2024-08-23 04:28:53

实际上,对于 h264 流,您是正确的,如果 NAL 值(第一个字节)是 0x7C,则意味着 I 帧已分段。没有其他帧(P 和 B)可以分片,因此如果 SDP 中存在 packetization-mode=1,则表示 I 帧已分片,并且因此,如果您将 0x7C 读取为第一个字节,则它是 I 帧。在这里阅读更多内容: http://www.rfc-editor.org/rfc/rfc3984.txt

Actually, you was correct for h264 stream, if the NAL value (first byte) is 0x7C it means that the I-Frame is fragmented. No other frames (P and B) can be fragmented, so if there is packetization-mode=1 in SDP, then it means that the I-Frames are fragmented, and therefore if you read 0x7C as first byte, then it is I-Frame. Read more here: http://www.rfc-editor.org/rfc/rfc3984.txt.

深巷少女 2024-08-23 04:28:53

这对我有用:
- 找出“有效负载类型”,例如:有效负载类型:DynamicRTP-Type-96 (96)
- 告诉wireshark哪个流是H264:文件->首选项->协议->H264。输入 96 作为负载类型。
- 对 slice_type 进行过滤:“h264.slice_type eq 7”

This worked for me:
- Figure out the "payload type", for example: Payload type: DynamicRTP-Type-96 (96)
- Tell wireshark which stream is H264: File->preferences->protocols->H264. Enter 96 as payload type.
- Filter on slice_type:"h264.slice_type eq 7"

汐鸠 2024-08-23 04:28:53

对于 H264:

  1. 删除 RTP 标头。
  2. 如果块 NAL 类型(第一个字节)是 SPS (7) 或 PPS (8),则将帧标记为 IFrame(许多相机不使用 SPS 和 PPS(包括 Axis))。
  3. 如果块NAL类型是#28 FU A(分段单元A),则检查FU标头(下一个字节)是否是NAL类型IDR(5)(IDR(即时解码刷新)图片)是IFrame。

示例:

nal_ref_idc: 3, nal type: 7 (0x07) descripcion: 7 (SPS)<br>
00000000  24 00 00 2B 80 60 22 ED 96 57 3E 68 57 F3 22 B5  $..+.`"í.W>hWó"µ<br>
00000010  67 64 00 1E AD 84 01 0C 20 08 61 00 43 08 02 18  gd..­... .a.C...

00000020  40 10 C2 00 84 2B 50 5A 09 34 DC 04 04 04 08  @.Â..+PZ.4Ü....<br>
nal_ref_idc: 3, nal type: 8 (0x08) descripcion: 8 (PPS)<br>
00000000  24 00 00 10 80 60 22 EE 96 57 3E 68 57 F3 22 B5  $....`"î.W>hWó"µ
00000010  68 EE 3C B0  hî<°

FU_A (fragmentation unit A) 
nal_ref_idc: 3, nal type: 5 (0x05) descripcion: 5 (IDR (Instantaneous Decoding Refresh) Picture)
00000000  24 00 05 96 80 60 22 F1 96 57 3E 68 57 F3 22 B5  $....`"ñ.W>hWó"µ
00000010  7C 05 A0 AA 2F 81 92 AB CA FE 9E 34 D8 06 AD 74  |. ª/..«Êþ.4Ø.­t
...

For H264:

  1. Remove RTP header.
  2. If chunk NAL type (in first byte) is SPS (7) or PPS (8) mark the frame as IFrame (many cameras not use SPS and PPS (Axis included)).
  3. If chunk NAL type is #28 FU A (fragmentation unit A), check FU Header (next byte) if is NAL type IDR (5) (IDR (Instantaneous Decoding Refresh) Picture) is an IFrame.

Examples:

nal_ref_idc: 3, nal type: 7 (0x07) descripcion: 7 (SPS)<br>
00000000  24 00 00 2B 80 60 22 ED 96 57 3E 68 57 F3 22 B5  $..+.`"í.W>hWó"µ<br>
00000010  67 64 00 1E AD 84 01 0C 20 08 61 00 43 08 02 18  gd..­... .a.C...

00000020  40 10 C2 00 84 2B 50 5A 09 34 DC 04 04 04 08  @.Â..+PZ.4Ü....<br>
nal_ref_idc: 3, nal type: 8 (0x08) descripcion: 8 (PPS)<br>
00000000  24 00 00 10 80 60 22 EE 96 57 3E 68 57 F3 22 B5  $....`"î.W>hWó"µ
00000010  68 EE 3C B0  hî<°

FU_A (fragmentation unit A) 
nal_ref_idc: 3, nal type: 5 (0x05) descripcion: 5 (IDR (Instantaneous Decoding Refresh) Picture)
00000000  24 00 05 96 80 60 22 F1 96 57 3E 68 57 F3 22 B5  $....`"ñ.W>hWó"µ
00000010  7C 05 A0 AA 2F 81 92 AB CA FE 9E 34 D8 06 AD 74  |. ª/..«Êþ.4Ø.­t
...
时光礼记 2024-08-23 04:28:53

0x000001b6:vop_start_code(关键帧,如果接下来的两位为零)
这是 MPEG-4 的正确方法

0x000001b6: vop_start_code (keyframe, if the next two bits are zero)
this is correct way for MPEG-4

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文