因为需要从海康ps流中提取H264数据并进行解码播放,才有了这篇文章.因为是视频编解码领域的纯入门新手,个别理解或者方法有误,需要自行判断,不过相关方法已经测试通过,对于
像我这样的新手还是有一定的借鉴的.断断续续搞了很长一段时间,把相关经验分享给各个新手.
---------------------------------------------------------------------------------------------------------
分为3个部分来说吧,仅供参考.
1. 接收并且解析RTP流部分
2. 解析ps流部分,包括解析海康部分私有格式
3. 将提取的标准H264流进行解码播放
--------------------------------------------------------------------------------------------------------
接收并且解析RTP流:
当时想到了两种方案:1.编写udp-socket来接受流,然后自己解析rtp包. 2.使用jrtplib库来接受流,自动解析rtp包. 由于第二种方案简单易用,使用了第二种方案.实验过程发现jrtplib会
出现丢包的情况,导致花屏的出现.具体丢包原因未查明.(jrtplib使用了最简单的框架,摘自jrtplib的其中一个example,未精简,未使用thread,效果还可以)
//该函数主要作用是使用jrtplib接收rtp流,并且解析出H264,将一帧帧的H264存入一个deque中
DWORD WINAPI GetSocketData(LPVOID lpparentet)
{
//jrtplib的相关初始化
WSADATA dat;
WSAStartup(MAKEWORD(2,2),&dat);
RTPSession session;
RTPSessionParams sessionparams;
sessionparams.SetOwnTimestampUnit(1.0/3600.0);
sessionparams.SetUsePollThread(true);
RTPUDPv4TransmissionParams transparams;
transparams.SetPortbase(6000);
session.SetMaximumPacketSize(sessionparams.GetMaximumPacketSize()+1000);
transparams.SetRTPReceiveBuffer(transparams.GetRTCPReceiveBuffer()*3);
transparams.SetRTCPReceiveBuffer(transparams.GetRTCPReceiveBuffer()*3);
int status = session.Create(sessionparams,&transparams);
if (status < 0)
{
std::cerr << RTPGetErrorString(status) << std::endl;
exit(-1);
}
uint8_t localip[]={127,0,0,1};
RTPIPv4Address addr(localip,9000);
status = session.AddDestination(addr);
if (status < 0)
{
std::cerr << RTPGetErrorString(status) << std::endl;
exit(-1);
}
session.SetDefaultPayloadType(96);
session.SetDefaultMark(false);
session.SetDefaultTimestampIncrement(160);
uint8_t silencebuffer[160];
for (int i = 0 ; i < 160 ; i++)
silencebuffer[i] = 128;
RTPTime delay(0.02);
RTPTime starttime = RTPTime::CurrentTime();
/收到rtp包之后进行数据处理
bool full=true;
bool done = false;
int i=0;
while (!done)
{
session.BeginDataAccess();
if (session.GotoFirstSource())
{
do
{
RTPPacket *packet;
while ((packet = session.GetNextPacket()) != 0)
{
//查找ps头 0x000001BA
if (packet->GetPacketData()[12]==0x00 && packet->GetPacketData()[13]==0x00 && packet->GetPacketData()[14]==0x01 && packet->GetPacketData()[15]==0xba)
{
if (i!=0)
{
//此包为ps新的一帧,每次到这里都先处理存储好的前一帧
int iPsLength=0;
GetH246FromPs(jimbak,jimlen,&returnps,&iPsLength); //从ps流中提取h264
//海康流特殊处理部分:分界符数据(nal_unit_type=9)或补充增强信息单元(nal_unit_type=6),如果直接送入解码器,有可能会出现问题,直接舍弃.00 00 01 bd和 00 00 01 c0为私有标志和