我从RTSP流中得到了H264 RTP数据包。所以我想要检测这个帧是否是i帧。
下面是我第一次打开流时收到的第一个包。所以我相信这是一个I-框架。以下是前160个字节:
packet:
00 00 00 01 67 4D 00 1F : 95 A8 14 01 6E 40 00 00
00 01 68 EE 3C 80 00 00 : 00 01 06 E5 01 33 80 00
00 00 01 65 B8 00 00 08 : 52 90 9F F6 BE D6 C6 9C
3D F6 D4 2F 49 FB F7 13 : F2 A9 C7 27 2D A4 75 59
6C DB FF 35 27 A4 C7 B6 : E7 69 A2 E0 FB 0E FF 2D
0E E0 6F 25 43 78 BF B9 : 69 22 1B 24 E3 CA 60 56
44 16 6C 15 44 DA 55 29 : C2 39 24 86 CE D6 75 BB
E0 0C F4 F4 EC C5 76 E4 : 7B 59 B9 40 2D B3 ED 19
E4 1D 94 B7 54 9B B3 D0 : 8F 24 58 CD 3C F3 FA E0
D4 7D 88 70 0E 49 79 12 : B2 14 92 BA B6 9C 3A F7
8D 13 78 6B 4C CD C0 CC : C8 39 6A AC BE 3D AA 00
9A DB D2 68 70 5F C4 20 : B7 5C FC 45 93 DB 00 12
9F 87 5A 66 2C B2 B8 E7 : 63 C4 87 0B A4 AA 2E 6D
AB 42 3F 02 C2 A6 F9 41 : E5 FE 80 64 49 14 38 3D
52 4B F6 B2 E7 53 DD 3E : F6 BB A8 EB 13 23 BB 71
B1 C9 90 06 92 3E 5F 15 : F2 C0 39 43 EA 24 5A 86
AE 11 27 D4 C5 4B 5C CD : 6C 90 2B 44 80 18 76 95
6E 16 DF 5D 86 49 25 5A : B6 66 23 E6 40 D4 25 6B
CE A2 4C EE 13 DD 7B 88 : FF A0 64 EC 33 44 B1 DC
B7 0B 89 5B 8F 85 68 3C : 65 3E 55 0F 41 4B 32 C9
C8 56 78 1A 15 14 8C C7 : F5 17 40 D4 EC BC 5B 62
8A 24 66 6A C3 7E 3B DB : 44 A8 EC D8 EE 37 E0 DE
.. .. .. .. .. .. .. .. : .. .. .. .. .. .. .. ..
然后,我使用下面的代码来确定框架:
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;
}
我的问题是,我无法知道RTPHeaderByte
的确切值。在这种情况下,我的数据包总是以“00000001”开头。
发布于 2014-10-25 20:05:37
您必须解析有效负载。见“所以回答”Possible Locations for Sequence/Picture Parameter Set(s) for H.264 Stream。对于IDR,所有的VCL NALU都是类型5。至于B/P,您需要解析exp-golmb编码的数据才能找到片类型。
发布于 2021-08-10 03:59:15
实际上,这看上去不对:
int fragment_type = paket[RTPHeaderBytes + 0] & 0x1F;
int nal_type = paket[RTPHeaderBytes + 1] & 0x1F;
int start_bit = paket[RTPHeaderBytes + 1] & 0x80;
首先是NAL类型,然后是其他东西,NAL类型的字节的第7位总是0。
事实是,您可以简单地搜索两个或三个零,后面跟着一个1,这是NAL的标记。NAL紧随其后。目前我还不清楚2和3 0之间的区别是什么。
因此,在您的示例中,您有以下NAL:
00 00 00 01 67 4D 00 1F : 95 A8 14 01 6E 40 00 00
^^ ^^ ^^ ^^ ^^ ^^ ^^
00 01 68 EE 3C 80 00 00 : 00 01 06 E5 01 33 80 00
^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^
00 00 01 65 B8 00 00 08 : 52 90 9F F6 BE D6 C6 9C
^^ ^^ ^^ ^^
3D F6 D4 2F 49 FB F7 13 : F2 A9 C7 27 2D A4 75 59
.. .. .. .. .. .. .. .. : .. .. .. .. .. .. .. ..
这意味着您有0x67,0x68,0x06,0x65,作为per the link given by szatmary,您有(即我们做type = (byte & 0x1F)
):
7 Sequence parameter set non-VCL
8 Picture parameter set non-VCL
6 Supplemental enhancement information (SEI) non-VCL
5 Coded slice of an IDR picture VCL
5表示你有一个I-帧。
查看我的一个文件,下一组NAL使用0x41或0x01,这是非IDR图片(即B帧)的编码片段。偶尔,我会看到5而不是1(即i帧)。默认情况下,x264每250个左右帧生成一个新的i帧.你可以改变这个参数。
因此,您的代码将检测这组NAL是否代表一个i帧或另一个框架是否需要搜索框架中的所有NAL并找到1(B-框架)或5(i-框架)。
in.open("source-file.h264");
while(in)
{
char marker[4];
in.read(marker, 3);
for(;;)
{
in.read(marker + 3, 1);
if(marker[0] == 0
&& marker[1] == 0
&& marker[2] == 1)
{
// found one! (short one)
break;
}
if(marker[0] == 0
&& marker[1] == 0
&& marker[2] == 0
&& marker[3] == 1)
{
// found one! (long one)
break;
}
}
in.read(marker, 1);
type = marker[0] & 0x1F;
if(type == 1)
{
return B_FRAME;
}
if(type == 5)
{
return I_FRAME;
}
}
return NOT_FOUND;
警告:--除非您的in
文件中有一个好的侧缓冲区,否则代码会很慢。这是C++代码。如果缓冲区中已经有数据,则应该将in
文件替换为缓冲区中的指针或索引,这肯定会非常快。
注意: H.264格式的确保插入一个3,如果它碰巧有0x000x000x00或0x000x000x01序列。也就是说,任何一个都是这样的: 0x00 0x00 0x03 0x00和0x00 0x00 0x03 0x01。您可以尝试压缩纯黑色帧,您将看到许多0x03出现在NAL图片数据中。
https://stackoverflow.com/questions/26558271
复制相似问题