现在的位置: 首页 > 综合 > 正文

UDP分包重组算法和 基于RTP的H264视频数据分包重组

2013年12月08日 ⁄ 综合 ⁄ 共 14721字 ⁄ 字号 评论关闭

UDP分包重组算法 转自:http://blog.csdn.net/sxcong/archive/2009/02/12/3882721.aspx

使用jrtplib3.7.1的主要工作有两个:

一是发送接收数据需要分片和重组。开始采集双向链表,后来发现处理不够好,内存总出错(好久没研究数据结构了)。后来直接采用分配缓冲,发送数据时标志offset,接收数据 按offset直接填充,非常简单。当然接收时判断一下,有没有重复的数据。

二是继承RTPSession,写一个响应类,在这里接收和发送。

然后,写一个对话框程序,用 DirectShow调用摄像头, 用SampleGrabber的方式抓数据,然后用libavcodec压成264;用DirectSound采集声音,用Speex压缩。先在内网测试,两台PC(或虚拟机)之间,直接向对方IP和端口发音视频,收到后解码,效果非常好。

到此为止,jprtlib表现的非常完美,另外代码质量也非常。

不过再下一步就有点问题,我用jrtplib再写服务器端,协助双方打洞。比较奇怪的是,客户端和服务器端只不过发送很少的命令字,双方反应都相当慢。看了看jrtplib代码,修改了一下socket接收发送的缓冲也不行。时间有限,没有完全看下去。估计是rtp和rtcp做协调时影响了效率。

简单地总结一下:如果使用jrtplib传送音视频媒体数据,非常理想。但如果使用它用来做服务器处理命令,效率肯定不行(当然修改其源码也能解决问题)。

也有变通的方法:可以自己写一个简单的可靠UDP,专门用来负责命令通信,用它得到对方的IP和端口后,送给jrtplib,然后jrtplib向这个IP端口发送数据就可以了。

不过,这样一样,还不如参考jrtplib源码,自己封装一个更好一些的UDP传输库。

传输音视频,因为数据量大,基本上不需要重传,只要做好丢包控制和同步就行了,所以完全可以不用jrtplib.

jrtplib主要的问题就是重组。

重组算法后面附上,虽然是测试代码,不过也稳定。

UDP分包重组算法

//Packet.h

#include "InetAddr.h" //对socket地址操作封装的类,比如char*IP转成ULONG

#include
using namespace std;

//先定义包头

typedef struct _HeadExt

{

//每帧所有分片公用信息

char flag[5]; //可以任意字符或数字或其他方法,用来标志我们发送的数据

UINT m_nSeqNumber; //本帧序数

USHORT m_nTotalFragment; //本帧数据可分成的总片数

USHORT m_nTotalSize; //本帧数据总长度

//每片各自信息

USHORT m_nFragmentIndex; //每帧分片序数,0 1 2 ... ,/

USHORT m_usPayloadSize; //本片数据长度

USHORT m_usFragOffset; //本片数据相对总数据的偏移量

USHORT m_bLastFragment; //是否最后一帧

//上 述数据有些重复,可以精简,有时间再修改

}HeadExt;

//从socket接收到的数据

class PacketIn

{

public :

PacketIn(char* lpszBuffer=NULL, UINT usBufferSize=0, UINT nDataSize=0);

virtual ~PacketIn();

HeadExt head;

BYTE* m_lpszBuffer;

ULONG ip;

UINT port;

CVLInetAddr addr;

BOOL Normalize();

UINT m_nDataLen;

UINT m_usBufferSize;

};

//接收到数据后开始重组使用的一个中间缓冲区,多个PacketIn合成一个Packet

//发送时从一个Packet分割出多片,不过本程序里直接发送,没有封成Packet

class Packet

{

public:

enum { TIMEOUT_LOCKFRAGMENTS = 1000 };

Packet( );

~Packet();

void reset();

void Set(const CVLInetAddr& iaFrom, UINT nSeqNumber );

BOOL InsertFragment(PacketIn* const pFragment);

bool m_bUsed;

int recvedpacks;

int recvedbytes;

int seqnum;

BYTE* m_pBuffer;

//测试用程序,直接访问了类的变量,没有封装成函数。上述变量正常应该写成 SetXXX ,GetXXX

private:

BOOL IsFragComplete() const;

ULONG m_ip;

USHORT m_port;

UINT m_nSeqNumber;

vector SeqNumberList;

};

//Packet.cpp

#include "Packet.h"

PacketIn::PacketIn(char* lpszBuffer/*=NULL*/, UINT usBufferSize/*=0*/, UINT nDataSize/*=0*/)

{

m_lpszBuffer = (BYTE*)lpszBuffer;

m_usBufferSize = usBufferSize; //数据最大长度,其实没什么用,已经设置了这个值最大为64000

m_nDataLen = nDataSize;

}

PacketIn::~PacketIn()

{

}

BOOL PacketIn::Normalize() //判断收到的数据是否有效

{

const USHORT usHeaderSize = sizeof(HeadExt);

if ( !m_lpszBuffer || m_usBufferSize
{

return FALSE;

}

HeadExt* pHeader = (HeadExt*)( m_lpszBuffer );

if ( pHeader->m_usPayloadSize != m_nDataLen - usHeaderSize )

{

return FALSE;

}

head = *pHeader;

if ( pHeader->m_usPayloadSize > 0 )

{

memmove( m_lpszBuffer, m_lpszBuffer + usHeaderSize, pHeader->m_usPayloadSize );

}

return TRUE;

}

/////////////

//这里是重组数据的临时缓冲,只看这里必然迷惑,先看socket收数据那里,再回来查看

void Packet::Set( const CVLInetAddr& iaFrom, UINT nSeqNumber )

{

m_iaFrom = iaFrom;

m_nSeqNumber = nSeqNumber;

if(m_pBuffer)

delete []m_pBuffer;

}

void Packet::reset()

{

m_bUsed = false;

recvedpacks = 0;

seqnum = 0;

recvedbytes = 0;

m_pBuffer = NULL;

m_pBuffer = new BYTE[64000];

SeqNumberList.clear();

}

Packet::Packet()

{

//calculate the ttl

//m_nTTL = RUDP_REASSEMBLE_TIMEOUT*CRudpPeer::PR_SLOWHZ;

reset();

}

Packet::~Packet()

{

if(m_pBuffer)

delete []m_pBuffer;

}

BOOL Packet::InsertFragment(PacketIn* const pFragment)

{

int nSize = SeqNumberList.size();

for(int i = 0; i
{

if(nSize ==SeqNumberList[i] )//收到重复数据包

{

return FALSE;

}

}

SeqNumberList.push_back(pFragment->head.m_nFragmentIndex);

memcpy( m_pBuffer + pFragment->head.m_usFragOffset, pFragment->m_lpszBuffer, pFragment->head.m_usPayloadSize);

recvedbytes += pFragment->head.m_usPayloadSize;

recvedpacks++;

m_bUsed = true;

CString str;

str.Format("收到数据:m_nSeqNumber%d ,m_nTotalFragment %d,m_nFragmentIndex %d,m_usFragOffset %d,m_nTotalSize %d,recvedbytes %d/r/n",

pFragment->head.m_nSeqNumber,pFragment->head.m_nTotalFragment,pFragment->head.m_nFragmentIndex,pFragment->head.m_usFragOffset,pFragment->head.m_nTotalSize,pFragment->head.m_usPayloadSize);

OutputDebugString(str);

if(recvedbytes == pFragment->head.m_nTotalSize )

return TRUE;

return FALSE;

}

return;

}

if(pHead->m_nTotalFragment == 1)//只有一帧,不分片

{

//回调,上层处理

if(m_pfDispatch)

m_pfDispatch(pBuff+sizeof(HeadExt),nLen-sizeof(HeadExt),ip,port,m_lpParam);

return;

}

PacketIn data( (char*)pBuff, 64000, nLen );

if ( !data.Normalize() )

return;

if ( data.head.m_nTotalFragment>1 )

{

Packet* pTemp = GetPartialPacket( iaRemote, data.head.m_nSeqNumber );

if ( pTemp )

{

if ( pTemp ->InsertFragment( &data ) )

{

m_pfDispatch(pTemp ->m_pBuffer,

pTemp ->recvedbytes,ip,port,m_lpParam);

}

}//end of if

}

}

//上面用到的一些变量可以在一个.h里面定义,比如:

Packet TempPacket[16];//分配一个数组,每个节点是一个重组后临时缓冲

Packet* GetPartialPacket(const CVLInetAddr& iaFrom, UINT nSeqNumber);//从数组里取出一个缓冲节点

Packet* GetPartialPacket(const ULONG ip,USHORT port, UINT nSeqNumber)//根据这几个关键字查找,不过只用//到了nSeqNumber,要是3人以上的视频聊天,ip和port是必要的

{

Packet* tmp = NULL;

int i=0;

while(tmp==NULL && i
{

//该包所属的帧已有其它数据包到达

if(TempPacket[i].seqnum==nSeqNumber && TempPacket[i].recvedpacks>0)

{

tmp = &TempPacket[i];

break;

}

i++;

}

if(tmp == NULL) //新的帧

{

//查找空闲元素

for(i=0;i
{

if(!TempPacket[i].m_bUsed)

break;

}

if(i>=16)

{

//没有空闲的元素,丢掉一个最早

tmp = &TempPacket[0];

int j = 0;

for(i=1;i
{

if(TempPacket[i].seqnum seqnum)

{

tmp = &TempPacket[i];

j = i;

}

}

//找到最早的一帧

if(tmp->m_pBuffer)

{

delete []tmp->m_pBuffer;

tmp->reset();

}

}

else

tmp = &TempPacket[i];

}

InsertFragment

tmp->m_bUsed = true;

tmp->seqnum = nSeqNumber;

return tmp;

}

整个示例最重要的是两个函数:

GetPartialPacket:取到一个临时缓冲节点

InsertFragment:把收到的每个数据段插入临时缓冲组成一个完整帧

当然发送方也要按一定规则分割发送。

基于RTP的H264视频数据分包重组 转自:http://blog.csdn.net/dengzikun/archive/2010/08/12/5807694.aspx

最近考虑使用RTP替换原有的高清视频传输协议,遂上网查找有关H264视频RTP打包、解包的文档和代码。功夫不负有心人,找到不少有价值的文档和代码。参考这些资料,写了H264 RTP打包类、解包类,实现了单个NAL单元包和FU_A分片单元包。对于丢包处理,采用简单的策略:丢弃随后的所有数据包,直到收到关键帧。测试效果还不错,代码贴上来,若能为同道中人借鉴一二,足矣。两个类的使用说明如下(省略了错误处理过程):

DWORD H264SSRC ;

CH264_RTP_PACK pack ( H264SSRC ) ;

BYTE *pVideoData ;

DWORD Size, ts ;

bool IsEndOfFrame ;

WORD wLen ;

pack.Set ( pVideoData, Size, ts, IsEndOfFrame ) ;

BYTE *pPacket ;

while ( pPacket = pack.Get ( &wLen ) )

{

// rtp packet process

// ...

}

HRESULT hr ;

CH264_RTP_UNPACK unpack ( hr ) ;

BYTE *pRtpData ;

WORD inSize;

int outSize ;

BYTE *pFrame = unpack.Parse_RTP_Packet ( pRtpData, inSize, &outSize ) ;

if ( pFrame != NULL )

{

// frame process

// ...

}

view plaincopy to clipboardprint?

//////////////////////////////////////////////////////////////////////////////////////////

// class CH264_RTP_PACK start

class CH264_RTP_PACK

{

#define RTP_VERSION 2

typedef struct NAL_msg_s

{

bool eoFrame ;

unsigned char type; // NAL type

unsigned char *start; // pointer to first location in the send buffer

unsigned char *end; // pointer to last location in send buffer

unsigned long size ;

} NAL_MSG_t;

typedef struct

{

//LITTLE_ENDIAN

unsigned short cc:4; /* CSRC count */

unsigned short x:1; /* header extension flag */

unsigned short p:1; /* padding flag */

unsigned short v:2; /* packet type */

unsigned short pt:7; /* payload type */

unsigned short m:1; /* marker bit */

unsigned short seq; /* sequence number */

unsigned long ts; /* timestamp */

unsigned long ssrc; /* synchronization source */

} rtp_hdr_t;

typedef struct tagRTP_INFO

{

NAL_MSG_t nal; // NAL information

rtp_hdr_t rtp_hdr; // RTP header is assembled here

int hdr_len; // length of RTP header

unsigned char *pRTP; // pointer to where RTP packet has beem assembled

unsigned char *start; // pointer to start of payload

unsigned char *end; // pointer to end of payload

unsigned int s_bit; // bit in the FU header

unsigned int e_bit; // bit in the FU header

bool FU_flag; // fragmented NAL Unit flag

} RTP_INFO;

public:

CH264_RTP_PACK(unsigned long H264SSRC, unsigned char H264PAYLOADTYPE=96, unsigned short MAXRTPPACKSIZE=1472 )

{

m_MAXRTPPACKSIZE = MAXRTPPACKSIZE ;

if ( m_MAXRTPPACKSIZE > 10000 )

{

m_MAXRTPPACKSIZE = 10000 ;

}

if ( m_MAXRTPPACKSIZE
{

m_MAXRTPPACKSIZE = 50 ;

}

memset ( &m_RTP_Info, 0, sizeof(m_RTP_Info) ) ;

m_RTP_Info.rtp_hdr.pt = H264PAYLOADTYPE ;

m_RTP_Info.rtp_hdr.ssrc = H264SSRC ;

m_RTP_Info.rtp_hdr.v = RTP_VERSION ;

m_RTP_Info.rtp_hdr.seq = 0 ;

}

~CH264_RTP_PACK(void)

{

}

//传入Set的数据必须是一个完整的NAL,起始码为0x00000001。

//起始码之前至少预留10个字节,以避免内存COPY操作。

//打包完成后,原缓冲区内的数据被破坏。

bool Set ( unsigned char *NAL_Buf, unsigned long NAL_Size, unsigned long Time_Stamp, bool End_Of_Frame )

{

unsigned long startcode = StartCode(NAL_Buf) ;

if ( startcode != 0x01000000 )

{

return false ;

}

int type = NAL_Buf[4] & 0x1f ;

if ( type 12 )

{

return false ;

}

m_RTP_Info.nal.start = NAL_Buf ;

m_RTP_Info.nal.size = NAL_Size ;

m_RTP_Info.nal.eoFrame = End_Of_Frame ;

m_RTP_Info.nal.type = m_RTP_Info.nal.start[4] ;

m_RTP_Info.nal.end = m_RTP_Info.nal.start + m_RTP_Info.nal.size ;

m_RTP_Info.rtp_hdr.ts = Time_Stamp ;

m_RTP_Info.nal.start += 4 ; // skip the syncword

if ( (m_RTP_Info.nal.size + 7) > m_MAXRTPPACKSIZE )

{

m_RTP_Info.FU_flag = true ;

m_RTP_Info.s_bit = 1 ;

m_RTP_Info.e_bit = 0 ;

m_RTP_Info.nal.start += 1 ; // skip NAL header

}

else

{

m_RTP_Info.FU_flag = false ;

m_RTP_Info.s_bit = m_RTP_Info.e_bit = 0 ;

}

m_RTP_Info.start = m_RTP_Info.end = m_RTP_Info.nal.start ;

m_bBeginNAL = true ;

return true ;

}

//循环调用Get获取RTP包,直到返回值为NULL

unsigned char* Get ( unsigned short *pPacketSize )

{

if ( m_RTP_Info.end == m_RTP_Info.nal.end )

{

*pPacketSize = 0 ;

return NULL ;

}

if ( m_bBeginNAL )

{

m_bBeginNAL = false ;

}

else

{

m_RTP_Info.start = m_RTP_Info.end; // continue with the next RTP-FU packet

}

int bytesLeft = m_RTP_Info.nal.end - m_RTP_Info.start ;

int maxSize = m_MAXRTPPACKSIZE - 12 ; // sizeof(basic rtp header) == 12 bytes

if ( m_RTP_Info.FU_flag )

maxSize -= 2 ;

if ( bytesLeft > maxSize )

{

m_RTP_Info.end = m_RTP_Info.start + maxSize ; // limit RTP packetsize to 1472 bytes

}

else

{

m_RTP_Info.end = m_RTP_Info.start + bytesLeft ;

}

if ( m_RTP_Info.FU_flag )

{ // multiple packet NAL slice

if ( m_RTP_Info.end == m_RTP_Info.nal.end )

{

m_RTP_Info.e_bit = 1 ;

}

}

m_RTP_Info.rtp_hdr.m = m_RTP_Info.nal.eoFrame ? 1 : 0 ; // should be set at EofFrame

if ( m_RTP_Info.FU_flag && !m_RTP_Info.e_bit )

{

m_RTP_Info.rtp_hdr.m = 0 ;

}

m_RTP_Info.rtp_hdr.seq++ ;

unsigned char *cp = m_RTP_Info.start ;

cp -= ( m_RTP_Info.FU_flag ? 14 : 12 ) ;

m_RTP_Info.pRTP = cp ;

unsigned char *cp2 = (unsigned char *)&m_RTP_Info.rtp_hdr ;

cp[0] = cp2[0] ;

cp[1] = cp2[1] ;

cp[2] = ( m_RTP_Info.rtp_hdr.seq >> 8 ) & 0xff ;

cp[3] = m_RTP_Info.rtp_hdr.seq & 0xff ;

cp[4] = ( m_RTP_Info.rtp_hdr.ts >> 24 ) & 0xff ;

cp[5] = ( m_RTP_Info.rtp_hdr.ts >> 16 ) & 0xff ;

cp[6] = ( m_RTP_Info.rtp_hdr.ts >> 8 ) & 0xff ;

cp[7] = m_RTP_Info.rtp_hdr.ts & 0xff ;

cp[8] = ( m_RTP_Info.rtp_hdr.ssrc >> 24 ) & 0xff ;

cp[9] = ( m_RTP_Info.rtp_hdr.ssrc >> 16 ) & 0xff ;

cp[10] = ( m_RTP_Info.rtp_hdr.ssrc >> 8 ) & 0xff ;

cp[11] = m_RTP_Info.rtp_hdr.ssrc & 0xff ;

m_RTP_Info.hdr_len = 12 ;

/*!

* /n The FU indicator octet has the following format:

* /n

* /n +---------------+

* /n MSB |0|1|2|3|4|5|6|7| LSB

* /n +-+-+-+-+-+-+-+-+

* /n |F|NRI| Type |

* /n +---------------+

* /n

* /n The FU header has the following format:

* /n

* /n +---------------+

* /n |0|1|2|3|4|5|6|7|

* /n +-+-+-+-+-+-+-+-+

* /n |S|E|R| Type |

* /n +---------------+

*/

if ( m_RTP_Info.FU_flag )

{

// FU indicator F|NRI|Type

cp[12] = ( m_RTP_Info.nal.type & 0xe0 ) | 28 ; //Type is 28 for FU_A

//FU header S|E|R|Type

cp[13] = ( m_RTP_Info.s_bit

m_RTP_Info.s_bit = m_RTP_Info.e_bit= 0 ;

m_RTP_Info.hdr_len = 14 ;

}

m_RTP_Info.start = &cp[m_RTP_Info.hdr_len] ; // new start of payload

*pPacketSize = m_RTP_Info.hdr_len + ( m_RTP_Info.end - m_RTP_Info.start ) ;

return m_RTP_Info.pRTP ;

}

private:

unsigned int StartCode( unsigned char *cp )

{

unsigned int d32 ;

d32 = cp[3] ;

d32
d32 |= cp[2] ;

d32
d32 |= cp[1] ;

d32
d32 |= cp[0] ;

return d32 ;

}

private:

RTP_INFO m_RTP_Info ;

bool m_bBeginNAL ;

unsigned short m_MAXRTPPACKSIZE ;

};

// class CH264_RTP_PACK end

//////////////////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////////////////

// class CH264_RTP_UNPACK start

class CH264_RTP_UNPACK

{

#define RTP_VERSION 2

#define BUF_SIZE (1024 * 500)

typedef struct

{

//LITTLE_ENDIAN

unsigned short cc:4; /* CSRC count */

unsigned short x:1; /* header extension flag */

unsigned short p:1; /* padding flag */

unsigned short v:2; /* packet type */

unsigned short pt:7; /* payload type */

unsigned short m:1; /* marker bit */

unsigned short seq; /* sequence number */

unsigned long ts; /* timestamp */

unsigned long ssrc; /* synchronization source */

} rtp_hdr_t;

public:

CH264_RTP_UNPACK ( HRESULT &hr, unsigned char H264PAYLOADTYPE = 96 )

: m_bSPSFound(false)

, m_bWaitKeyFrame(true)

, m_bPrevFrameEnd(false)

, m_bAssemblingFrame(false)

, m_wSeq(1234)

, m_ssrc(0)

{

m_pBuf = new BYTE[BUF_SIZE] ;

if ( m_pBuf == NULL )

{

hr = E_OUTOFMEMORY ;

return ;

}

m_H264PAYLOADTYPE = H264PAYLOADTYPE ;

m_pEnd = m_pBuf + BUF_SIZE ;

m_pStart = m_pBuf ;

m_dwSize = 0 ;

hr = S_OK ;

}

~CH264_RTP_UNPACK(void)

{

delete [] m_pBuf ;

}

//pBuf为H264 RTP视频数据包,nSize为RTP视频数据包字节长度,outSize为输出视频数据帧字节长度。

//返回值为指向视频数据帧的指针。输入数据可能被破坏。

BYTE* Parse_RTP_Packet ( BYTE *pBuf, unsigned short nSize, int *outSize )

{

if ( nSize
{

return NULL ;

}

BYTE *cp = (BYTE*)&m_RTP_Header ;

cp[0] = pBuf[0] ;

cp[1] = pBuf[1] ;

m_RTP_Header.seq = pBuf[2] ;

m_RTP_Header.seq
m_RTP_Header.seq |= pBuf[3] ;

m_RTP_Header.ts = pBuf[4] ;

m_RTP_Header.ts
m_RTP_Header.ts |= pBuf[5] ;

m_RTP_Header.ts
m_RTP_Header.ts |= pBuf[6] ;

m_RTP_Header.ts
m_RTP_Header.ts |= pBuf[7] ;

m_RTP_Header.ssrc = pBuf[8] ;

m_RTP_Header.ssrc
m_RTP_Header.ssrc |= pBuf[9] ;

m_RTP_Header.ssrc
m_RTP_Header.ssrc |= pBuf[10] ;

m_RTP_Header.ssrc
m_RTP_Header.ssrc |= pBuf[11] ;

BYTE *pPayload = pBuf + 12 ;

DWORD PayloadSize = nSize - 12 ;

// Check the RTP version number (it should be 2):

if ( m_RTP_Header.v != RTP_VERSION )

{

return NULL ;

}

/*

// Skip over any CSRC identifiers in the header:

if ( m_RTP_Header.cc )

{

long cc = m_RTP_Header.cc * 4 ;

if ( Size
{

return NULL ;

}

Size -= cc ;

p += cc ;

}

// Check for (& ignore) any RTP header extension

if ( m_RTP_Header.x )

{

if ( Size
{

return NULL ;

}

Size -= 4 ;

p += 2 ;

long l = p[0] ;

l
l |= p[1] ;

p += 2 ;

l *= 4 ;

if ( Size
{

return NULL ;

}

Size -= l ;

p += l ;

}

// Discard any padding bytes:

if ( m_RTP_Header.p )

{

if ( Size == 0 )

{

return NULL ;

}

long Padding = p[Size-1] ;

if ( Size
{

return NULL ;

}

Size -= Padding ;

}*/

// Check the Payload Type.

if ( m_RTP_Header.pt != m_H264PAYLOADTYPE )

{

return NULL ;

}

int PayloadType = pPayload[0] & 0x1f ;

int NALType = PayloadType ;

if ( NALType == 28 ) // FU_A

{

if ( PayloadSize
{

return NULL ;

}

NALType = pPayload[1] & 0x1f ;

}

if ( m_ssrc != m_RTP_Header.ssrc )

{

m_ssrc = m_RTP_Header.ssrc ;

SetLostPacket () ;

}

if ( NALType == 0x07 ) // SPS

{

m_bSPSFound = true ;

}

if ( !m_bSPSFound )

{

return NULL ;

}

if ( NALType == 0x07 || NALType == 0x08 ) // SPS PPS

{

m_wSeq = m_RTP_Header.seq ;

m_bPrevFrameEnd = true ;

pPayload -= 4 ;

*((DWORD*)(pPayload)) = 0x01000000 ;

*outSize = PayloadSize + 4 ;

return pPayload ;

}

if ( m_bWaitKeyFrame )

{

if ( m_RTP_Header.m ) // frame end

{

m_bPrevFrameEnd = true ;

if ( !m_bAssemblingFrame )

{

m_wSeq = m_RTP_Header.seq ;

return NULL ;

}

}

if ( !m_bPrevFrameEnd )

{

m_wSeq = m_RTP_Header.seq ;

return NULL ;

}

else

{

if ( NALType != 0x05 ) // KEY FRAME

{

m_wSeq = m_RTP_Header.seq ;

m_bPrevFrameEnd = false ;

return NULL ;

}

}

}

///////////////////////////////////////////////////////////////

if ( m_RTP_Header.seq != (WORD)( m_wSeq + 1 ) ) // lost packet

{

m_wSeq = m_RTP_Header.seq ;

SetLostPacket () ;

return NULL ;

}

else

{

// 码流正常

m_wSeq = m_RTP_Header.seq ;

m_bAssemblingFrame = true ;

if ( PayloadType != 28 ) // whole NAL

{

*((DWORD*)(m_pStart)) = 0x01000000 ;

m_pStart += 4 ;

m_dwSize += 4 ;

}

else // FU_A

{

if ( pPayload[1] & 0x80 ) // FU_A start

{

*((DWORD*)(m_pStart)) = 0x01000000 ;

m_pStart += 4 ;

m_dwSize += 4 ;

pPayload[1] = ( pPayload[0] & 0xE0 ) | NALType ;

pPayload += 1 ;

PayloadSize -= 1 ;

}

else

{

pPayload += 2 ;

PayloadSize -= 2 ;

}

}

if ( m_pStart + PayloadSize
{

CopyMemory ( m_pStart, pPayload, PayloadSize ) ;

m_dwSize += PayloadSize ;

m_pStart += PayloadSize ;

}

else // memory overflow

{

SetLostPacket () ;

return NULL ;

}

if ( m_RTP_Header.m ) // frame end

{

*outSize = m_dwSize ;

m_pStart = m_pBuf ;

m_dwSize = 0 ;

if ( NALType == 0x05 ) // KEY FRAME

{

m_bWaitKeyFrame = false ;

}

return m_pBuf ;

}

else

{

return NULL ;

}

}

}

void SetLostPacket()

{

m_bSPSFound = false ;

m_bWaitKeyFrame = true ;

m_bPrevFrameEnd = false ;

m_bAssemblingFrame = false ;

m_pStart = m_pBuf ;

m_dwSize = 0 ;

}

private:

rtp_hdr_t m_RTP_Header ;

BYTE *m_pBuf ;

bool m_bSPSFound ;

bool m_bWaitKeyFrame ;

bool m_bAssemblingFrame ;

bool m_bPrevFrameEnd ;

BYTE *m_pStart ;

BYTE *m_pEnd ;

DWORD m_dwSize ;

WORD m_wSeq ;

BYTE m_H264PAYLOADTYPE ;

DWORD m_ssrc ;

};

// class CH264_RTP_UNPACK end

//////////////////////////////////////////////////////////////////////////////////////////

Powered by Zoundry Raven

抱歉!评论已关闭.