我试图解析RTP AVC视频流为H264解码器做准备。
这是我的数据包流捕获的Wireshark首先,我试图找到IDR切片,SPS和PPS参数,所以这就是它https://dl.dropboxusercontent.com/u/76817805/frame.pcapng
接下来我要做的是:
1)查找PPS和SPS数据并将其复制到NAL单元到解包缓冲区中,起始序列为[0x00 0x00 0x01]。
[00 00 01 | SPS] [00 00 01 | PPS)
2)对于以[0x7C 0x85]开始的数据包(起始位= 1),我正在重建第一个NAL标头(我的情况是0x65)并将数据后面的0x7C 0x85复制到具有开始序列的解包缓冲区中。
[00 00 01 65 |视频数据 ......]
3)对于以[0x7C 0x05]开头的数据包,我正在复制除前2个字节外的数据到解包缓冲区。
[…视频数据.....]
4)对于以[0x7C 0x45]开始的数据包(停止位= 1)我正在复制数据,除了2个第一个字节到解包缓冲区。[…视频数据(最后一个字节)]
5)对于不分片的数据包,我只是将数据复制到具有开始序列的解包缓冲区中。
[00 00 01 | NALu]
所以在解析示例视频流结束时,我得到了这个二进制文件 https://dl.dropboxusercontent.com/u/76817805/raw.264,但它不能被正确解码。[1]
谁能帮助我,请找到错误在我的算法?我做错了什么?谢谢大家。
UInt32 parseRTP( Uint8 * buf, int inputDataLen, Uint32 curAdr)
{
int result_len = 0;
// filter zero bytes at the end of packet
for (i = inputDataLen-1; i>0; i--)
{
if (buf[i] == 0x00) inputDataLen--;
else break;
}
// get NAL type
nal = buf[0];
type = (nal & 0x1f);
if ((buf[0] == 0x7C) && (buf[1] == 0x85)) IFrameisOK = 1; // Start of I frame
if (type == 6)
return 0;
if (type == 7) // new SPS
{
memcpy((void*)sps, start_sequence, sizeof(start_sequence));
memcpy((void*)(sps + sizeof(start_sequence)), buf, inputDataLen);
sps_len = inputDataLen + sizeof(start_sequence);
SPSisOK = 1;
return 0;
}
if (type == 8) // new PPS
{
memcpy((void*)pps, start_sequence, sizeof(start_sequence));
memcpy((void*)(pps + sizeof(start_sequence)), buf, inputDataLen);
pps_len = inputDataLen + sizeof(start_sequence);
PPSisOK = 1;
return 0;
}
if (SPSisOK == 1 && PPSisOK == 1)
{
if (IFrameisOK == 0) return 0; // wait I-frame
/* Simplify the case.
These are all the nal types used internally by the h264 codec
*/
if (type >= 1 && type <= 23) type = 1;
switch (type)
{
case 0: // undefined;
break;
case 1:
// copy start sequence
memcpy((void*)curAdr, start_sequence, sizeof(start_sequence));
curAdr += sizeof(start_sequence);
// copy data
memcpy((void*)curAdr, buf, inputDataLen);
curAdr += inputDataLen;
result_len = sizeof(start_sequence) + inputDataLen;
break;
case 24: // STAP-A (one packet, multiple nals) not used in this project
break;
case 25: // STAP-B
case 26: // MTAP-16
case 27: // MTAP-24
case 29: // FU-B
//not used in this project
break;
case 28: // FU-A (fragmented nal)
inputDataLen -= 2; // delete 2 first bytes for fragmented units
//skip the fu_indicator
buf++;
Uint8 fu_indicator = nal;
Uint8 fu_header = *buf; // read the fu_header.
Uint8 start_bit = fu_header >> 7;
Uint8 reconstructed_nal;
Uint8 nal_type = (fu_header & 0x1f);
/* reconstruct this packet's true nal; only the
data follows..*/
reconstructed_nal = fu_indicator & (0xe0);
/*the original nal forbidden bit and NRI are stored in this
packet's nal*/
reconstructed_nal |= nal_type;
// skip the fu_header...
buf++;
if(start_bit)
{
if (NEED_CONFIGS)
{
// copy SPS and PPS first
memcpy((void*)curAdr, sps, sps_len);
curAdr += sps_len;
memcpy((void*)curAdr, pps, pps_len);
curAdr += pps_len;
}
// copy in the start sequence
memcpy((void*)curAdr, start_sequence, sizeof(start_sequence));
curAdr += sizeof(start_sequence);
// copy reconstructed nal
memcpy((void*)curAdr,&reconstructed_nal, sizeof(reconstructed_nal));
curAdr += sizeof(reconstructed_nal);
// copy payload
memcpy((void*)curAdr,buf, inputDataLen);
curAdr += inputDataLen;
if (NEED_CONFIGS)
{
result_len = (sps_len + pps_len + sizeof(start_sequence) + sizeof(reconstructed_nal) + inputDataLen);
NEED_CONFIGS = 0;
}
else
{
result_len += (sizeof(start_sequence) + sizeof(reconstructed_nal) + inputDataLen);
}
}
else
{
memcpy((void*)curAdr,buf, inputDataLen);
curAdr += inputDataLen;
result_len = inputDataLen;
}
break;
default:
break;
}
return result_len;
}
else
{
return 0;
}
}
解封规则在RFC 6184 - H.264视频的RTP有效载荷格式中有描述,你应该遵循它们,而不是试图自己发明。
你认为在片段前加上00 00 01 65
是在重建NAL单元的假设是不正确的。
这个想法是,这个NAL单元太大,不能容纳单个数据包,然后它被分割成几个部分。您将收到几个RTP片段,然后将它们合并为一个NAL单元,完整地重建它,并保持其原始状态。参见5.8. 碎片单元(FUs)的详细信息。
您只需将00 00 01 65
添加到NAL单元的每个部分,而不是遵循上面提到的步骤—这预计不会产生可解码的输出。
参见:
- 如何处理原始UDP数据包,以便它们可以被直接解码器过滤器解码显示源过滤器;部分