在音视频开发中音视频的传输主要用UDP来发送视频当发送的数据大于1500时分包发送保证每包小于1500关键是视频接收时的处理。
本文依据UDP库数据传输作为代码演示.
intCUDPSession::SplitData(char* pBuff, uint32_t nLen)
{
int nBlockNum =nLen / UDP_BLOCK_SIZE;
if (nLen %UDP_BLOCK_SIZE != 0)
{
nBlockNum++;
}
int sendlen = 0;
for (int i = 0; i< nBlockNum; i++)
{
int poayload_size =UDP_BLOCK_SIZE;
char* payload =pBuff + UDP_BLOCK_SIZE * (i);
if (nLen -UDP_BLOCK_SIZE * (i) < UDP_BLOCK_SIZE)
poayload_size =nLen - UDP_BLOCK_SIZE * (i);
CPackOut* pack =new CPackOut;
(*pack) <<PACK_TYPE_DATA;
(*pack) <<m_nFrameIndex;
if (i == nBlockNum- 1)
{
(*pack) << 1;
}
else
{
(*pack) << 0;
}
(*pack) <<poayload_size;
(*pack).SetBuffer(payload,poayload_size);
int ret =SendPacket(pack, m_destIP, m_destPort);
printf("SendPacketret = %d
", ret);
sendlen += ret;
delete pack;
pack = NULL;
}
return sendlen;
}
以下具体说一下接收端,由于UDP是不可靠的不保证数据帧一定正常到达即使收到顺序也可能发生变化比方先发的后到当然丢包的可能最大乱序的情况比較少。
正确的处理方法是
如果一个port仅仅接收固定一个对方数据源,这样收到一个数据包放到缓冲里然后在缓冲里依据帧的序号排序(每一帧的大序号是同样的自己能够给每个小片加上小序号,包头里能够加上本次数据帧一共分多少片收到一片就统计一下推断是否收齐)。
当收齐后这个帧去掉包头回调给上层。
当在一定时间内该帧数据还没有收齐就说明传输过程有丢包了把已收到的都丢掉就能够。
当上层的应该收到回调的数据后能够进行解码播放。
在解码之前先推断一下帧序列是否连续。
假设中间有缺少的就把这一序列都丢掉直到下一个I帧。每一个帧的序号最好收发之间协商好在发送的时候带上。
假设把上面整个过程都实现全然自己写的话须要几天的时间。只是从非常多RTP开源库里发现处理的都非常easy非常多都没有管乱序情况简单地来一份数据就向缓冲里追加一份直到发现mark为1。我们这里做为简单使用的项目也採用了这样的简单方法先把功能完毕之后有时间再来优化。
简单的重组代码:
intCUDPSession::Reassemble(CPackIn& pack, uint32_t ip, uint32_t port)
{
int nSeq = 0;
int nMark = 0;
int nLen = 0;
pack >> nSeq;
pack >> nMark;
pack >> nLen;
if(m_nRecvFrameIndex != nSeq)
{
if (m_buffer)
{
evbuffer_free(m_buffer);
m_buffer = NULL;
}
m_nRecvFrameIndex =nSeq;
}
if (m_buffer ==NULL)
{
m_buffer =evbuffer_new();
}
char* pBuf = 0;
int nSize;
pack.GetBuffer(pBuf,nSize);
evbuffer_add(m_buffer,pBuf, nSize);
if (nMark == 1)
{
//回调
if (m_pCB)
{
m_pCB(m_udpIO.m_handle,(char*)(m_buffer->buffer), m_buffer->off, ip, port,
m_pParam);
}
evbuffer_free(m_buffer);
m_buffer = NULL;
}
return 0;
}
程序里使用的evbuffer是从libevent里面拿来的主要用来处理数据缓冲非常好用效率也非常好见evbuffer.h和buffer.cpp。
完整代码在git上这次实现的功能是本机UDP bind5500port-->摄像机採集-->编码-->发送给本机的5500port-->收到后再解码-->显示。
发送的代码m_Sess.Send((char*)pData, nLen, inet_addr("127.0.0.1"), 5500);
这个程序能够分别执行在两台机器上一台是发送还有一台是接收。发送方仅仅要把上面这一句里面的127.0.0.1换上你目标的ip还有一台机器就能够接收并解码了。
本文结束后完整的client功能基本就差点儿相同了下一步開始完毕server端的stun,协商穿透, 实p2p和中转视频。假设对音视频开发还有其它疑问能够登录该论坛进行咨询http://bbs.anychat.cn/forum.php
!fryuage:ZH-CN;mso-bidi-language:AR-SA'>stun,协商穿透, 实p2p和中转视频。假设对音视频开发还有其它疑问能够登录该论坛进行咨询http://bbs.anychat.cn/forum.php