我想实现一个UDP协议的网络视频程序,
发送端的GRAPH是:VideoCapture-> DivX;)Fast-Motion-> NetSender
接收端的GRAPH是:NetRecv-> DivX Devoder-> VideoRender
我的思路是:NetSender接到一个 MediaSample后,通过GetPoint和GetActualDataLength得到视频帖数据和实际长度,然后对数据按1024长度进行分片发送。其算法是:
#define LEN_PIECE1024
typedef struct _UDPMediaPacket//UDP数据包结构
{
DWORDdwFrameNo;//帧序号
WORDwMaxPiece;//本帧共多少片
WORDwPieceNo;//本片序号
CHARData[LEN_PIECE];//分片的压缩视频数据
}UDPMEDIAPACKET, *LPUDPMEDIAPACKET;
{
...
UDPMEDIAPACKET UDPMediaPacket;
UDPMediaPacket.dwFrameNo = m_nFrameVideo;//类成员变量,记录从发送开始到当前的帧序号
m_nFrameVideo ++;//帧序号加1
BYTE *pSourceBuf = NULL;
pSample-> GetPointer(&pSourceBuf);//取压缩视频数据起始指针
int nSampleLength = pSample-> GetActualDataLength();//取帧数据长度
if ((nSampleLength % LEN_PIECE) > 0)//计算本帧共多少片
{
UDPMediaPacket.wMaxPiece = 1 + nSampleLength / LEN_PIECE;
}
else
{
UDPMediaPacket.wMaxPiece = nSampleLength / LEN_PIECE;
}
SOCKADDR_IN remote;
remote.sin_addr.S_un.S_addr = ...
remote.sin_family = AF_INET;
remote.sin_port = ...;
int nPieceNo = 0, nByteSent = 0;
while (nSampleLength > 0)
{
UDPMediaPacket.wPieceNo = nPieceNo;
memset(UDPMediaPacket.Data, 0, LEN_PIECE);
int nLenPacket = 0;
if (nSampleLength > LEN_PIECE)
{
nLenPacket = LEN_PIECE;
}
else
{
nLenPacket = nSampleLength;
}
CopyMemory(UDPMediaPacket.Data, pSourceBuf, nLenPacket);
nByteSent = sendto(socket, (char*)&UDPMediaPacket, nLenPacket + 8, 0, (SOCKADDR*)&remote, sizeof(remote));
nByteSent -= 8;
nSampleLength -= nByteSent;
pSourceBuf += nByteSent;
nPieceNo ++;
}
pSample-> Release();//本帧发送完毕
...
}
在接收端的思路是,根据接收到的UDP包中包含的帧、片序号进行拼帧,考虑UDP包的无序性,如果收到的数据帧序号错或者片丢失,则丢弃本帧,始终以完整的帧递增地交给DivX Devoder解码。其算法是:
DWORD dwFrame = 0;
WORD wPiece = 0;
int nLenVideoBuf = 0;
BYTE VideoBuf[304130], *pVideoBuf = NULL;
pVideoBuf = VideoBuf;
while(...)
{
memset(Buf, 0, 1024);
nBytesRecved = recvfrom(socket, (char*)Buf, 1024, 0, (SOCKADDR*)&remote, &dwSender);
if (nBytesRecved <= 0)
{
continue;
}
else
{
nBytesRecved -= 8;
pUDPMediaPacket = (LPUDPMEDIAPACKET)Buf;
if ((pUDPMediaPacket-> dwFrameNo == dwFrame) &&//收到的数据帧序号与片序号与应该接收的一致
(pUDPMediaPacket-> wPieceNo == wPiece))
{
CopyMemory(pVideoBuf, pUDPMediaPacket-> Data, nBytesRecved);
pVideoBuf += nBytesRecved;