通过 RTP 发布解码 H264
Issue decoding H264 over RTP
在研究了 RTP rfc 和 ISO 13818-1 (MPEG2-TS) 之后,我试图从 MPEG2-TS 流(通过 HLS)读取 H264 帧并卡住了。我已经从 MPEG-TS 流中解析了 PES 数据包,并试图读取 RTP/H264 有效载荷,但它似乎没有正确解码(我可能遗漏了一些东西)。 00 00 00 01的第一个开始标记符合预期,但后面的字节(0xE0)似乎无效。 188字节的数据包中还有多个起始标记后面跟着很少的数据:
单个 188 字节数据包:
47 41 00 30 07 50 00 00 00 00 FE 00 00 00 01 E0 00 00 80 80 05 21 00 01 00 03 00 00 00 01 09 F0 00 00 00 01 67 64 00 2A AC 2C 6A 81 E0 08 9F 97 01 6E 02 02 02 80 00 00 03 00 80 00 00 1E 42 00 00 00 01 68 EE 3C B0 00 00 00 01 06 E5 01 6C 80 00 00 00 01 65 B8 00 00 1C D9 C0 00 05 FF 6D 0B 52 D2 A2 D1 EF 11 EC FF C5 4A EC 63 C1 47 9F A7 78 36 7B 1F 30 0A 24 C8 0C 35 2D 96 BD BC 97 B5 E0 AA 40 A3 9F 3E 4A 42 C2 9B D0 43 63 6F 82 CD 94 2C 3C 7F A2 C1 A4 29 DE 73 80 5E BF 1C 1B E9 73 0B F5 FE FD BC 92 ED 11 67 8C 94 63 AB CE 40 4C 5C D2 68 DC 2D 91 CE 19 2E BB 98
我在开始标记 (0xE0) 之后将 NAL 单元 header 的第一个字节解码为:
// forbidden_zero_bit = 1 bit (for error checking, should be 0)
// ref_idc = 2 bits: is a reference field / frame / picture
// unit_type = 5 bits: Specifies the NAL payload type.
var nalUnitHeader = 0xE0; // 1110 0000
var forbidden_zero = nalUnitHeader.GetBits(1, 1); // 0000 0001, 1 bit (is invalid)
var ref_idc = nalUnitHeader.GetBits(2, 2); // 0000 0011, next 2 bits
var nalUnitType = nalUnitHeader.GetBits(5, 4); // 0000 0000, next 5 bits
规范说 forbidden_zero 字段必须始终为 0,所以看起来我遗漏了什么。上面,GetBits()
是一个只计算掩码和移位偏移量的助手,我确认它是正确的,除非字节顺序是另一种方式,但我检查了其他人是如何做的,与他们的结果相比看起来是正确的。
事实证明这是我用来处理 MPEG2-TS 流中的传输数据包的 TsDecoder 库中的一个错误,它没有正确处理 adaption_field_length。它只偏离了 1 个字节,但这最终给了我一个不正确的偏移量,我认为 NAL 单元的开始实际上是未处理的字节 00
和 Pes 数据包的开始 header 00 00 01 E0
。令人困惑,因为它确实看起来很像 NAL 单元开始标记 00 00 00 01
!
在研究了 RTP rfc 和 ISO 13818-1 (MPEG2-TS) 之后,我试图从 MPEG2-TS 流(通过 HLS)读取 H264 帧并卡住了。我已经从 MPEG-TS 流中解析了 PES 数据包,并试图读取 RTP/H264 有效载荷,但它似乎没有正确解码(我可能遗漏了一些东西)。 00 00 00 01的第一个开始标记符合预期,但后面的字节(0xE0)似乎无效。 188字节的数据包中还有多个起始标记后面跟着很少的数据:
单个 188 字节数据包:
47 41 00 30 07 50 00 00 00 00 FE 00 00 00 01 E0 00 00 80 80 05 21 00 01 00 03 00 00 00 01 09 F0 00 00 00 01 67 64 00 2A AC 2C 6A 81 E0 08 9F 97 01 6E 02 02 02 80 00 00 03 00 80 00 00 1E 42 00 00 00 01 68 EE 3C B0 00 00 00 01 06 E5 01 6C 80 00 00 00 01 65 B8 00 00 1C D9 C0 00 05 FF 6D 0B 52 D2 A2 D1 EF 11 EC FF C5 4A EC 63 C1 47 9F A7 78 36 7B 1F 30 0A 24 C8 0C 35 2D 96 BD BC 97 B5 E0 AA 40 A3 9F 3E 4A 42 C2 9B D0 43 63 6F 82 CD 94 2C 3C 7F A2 C1 A4 29 DE 73 80 5E BF 1C 1B E9 73 0B F5 FE FD BC 92 ED 11 67 8C 94 63 AB CE 40 4C 5C D2 68 DC 2D 91 CE 19 2E BB 98
我在开始标记 (0xE0) 之后将 NAL 单元 header 的第一个字节解码为:
// forbidden_zero_bit = 1 bit (for error checking, should be 0)
// ref_idc = 2 bits: is a reference field / frame / picture
// unit_type = 5 bits: Specifies the NAL payload type.
var nalUnitHeader = 0xE0; // 1110 0000
var forbidden_zero = nalUnitHeader.GetBits(1, 1); // 0000 0001, 1 bit (is invalid)
var ref_idc = nalUnitHeader.GetBits(2, 2); // 0000 0011, next 2 bits
var nalUnitType = nalUnitHeader.GetBits(5, 4); // 0000 0000, next 5 bits
规范说 forbidden_zero 字段必须始终为 0,所以看起来我遗漏了什么。上面,GetBits()
是一个只计算掩码和移位偏移量的助手,我确认它是正确的,除非字节顺序是另一种方式,但我检查了其他人是如何做的,与他们的结果相比看起来是正确的。
事实证明这是我用来处理 MPEG2-TS 流中的传输数据包的 TsDecoder 库中的一个错误,它没有正确处理 adaption_field_length。它只偏离了 1 个字节,但这最终给了我一个不正确的偏移量,我认为 NAL 单元的开始实际上是未处理的字节 00
和 Pes 数据包的开始 header 00 00 01 E0
。令人困惑,因为它确实看起来很像 NAL 单元开始标记 00 00 00 01
!