用jrtp xvid directshow 做的视频传输 demo ,视频总是一卡一卡

playStudy 2011-03-25 05:08:57
我用jrtp xvid directshow 做的视频传输 demo ,视频总是一卡一卡的。

实现是这样的,发送端
Graph 是这样的 usb视频设备->xivd mpeg-4 codec->RtpRender(自己写的filter)

接收端
RtpSource(自己写的filter)->xvid mpeg-4 video Decoder->Video Render

用GraphEdit测试 视频总是一卡一卡的。
DoRenderSample 代码
发送端的部分代码如下:
HRESULT CRtpRender::DoRenderSample( IMediaSample *pSample )
{
HRESULT hr;
ValidateReadPtr(pSample,sizeof(IMediaSample));
//Add media sample data
byte* pbPayload=0;
hr=pSample->GetPointer(&pbPayload);
if(FAILED(hr))
{
return hr;
}
int status=0;
size_t dataLength;
dataLength=pSample->GetActualDataLength();

//把pSample分块发送
SendDismantleFrame(dataLength,pbPayload,1024,sess);
checkerror(status);
return hr;
}

//这个函数是进行分块发送,可能是所谓的拆帧
void CRtpRender::SendDismantleFrame( int count,byte* buf,int groupCount,RTPSession& sess )
{
int status=0;
int sumCount=count;
if(count<=groupCount)
{
status = sess.SendPacket(buf,count,0,false,33);//发送数据包

}
else
{
int packetCount=0;
int curCount=0;
while(sumCount>0)
{
if(sumCount-groupCount<=0)
{
status = sess.SendPacket(buf,sumCount,0,false,33);//发送数据包
sumCount=0;
}
else
{
status = sess.SendPacket(buf,groupCount,0,false,0);//发送数据包
sumCount=sumCount-groupCount;
buf=&buf[groupCount];

}
packetCount++;

}

}
}

//初始化Session
STDMETHODIMP CRtpRender::Initialize()
{
#ifdef WIN32
WSADATA dat;
WSAStartup(MAKEWORD(2,2),&dat);//指示程序所采用的socket的版本
#endif // WIN32
uint16_t portbase,destport;
uint32_t destip;
std::string ipstr;
int status,i,num;
portbase=6000;
ipstr="127.0.0.1";
destip = inet_addr(ipstr.c_str());
if (destip == INADDR_NONE)
{
std::cerr << "Bad IP address specified" << std::endl;
return -1;
}
destip = ntohl(destip);
destport=8000;
RTPUDPv4TransmissionParams transparams;
RTPSessionParams sessparams;

// IMPORTANT: The local timestamp unit MUST be set, otherwise
// RTCP Sender Report info will be calculated wrong
// In this case, we'll be sending 10 samples each second, so we'll
// put the timestamp unit to (1.0/10.0)
sessparams.SetOwnTimestampUnit(1.0/33.0);//设置发送频率

sessparams.SetAcceptOwnPackets(true);//允许接受自身的的数据包
transparams.SetPortbase(portbase);//设置端口用于接受数据或发送数据
status = sess.Create(sessparams,&transparams); //创建RTP任务
checkerror(status);

//RTPIPv4Address addr(destip,destport);//目标地址

//status = sess.AddDestination(addr);//将目标地址添加会话中


return NOERROR;
}




接收端....


//接收数据线程函数
DWORD WINAPI ReceiveData( LPVOID lpParameter )
{
while(TRUE)
{
g_pRtpStream->sess.Poll();
g_pRtpStream->sess.BeginDataAccess();//对访问的数据进行加锁
uint32_t intTimestampPrev=0;
uint32_t intTimestamp;
byte* sumByte=NULL;
byte* sumByteBegin=NULL;
UINT intSumCount=0;


// check incoming packets
if (g_pRtpStream->sess.GotoFirstSourceWithData())//遍历数据源中的所有数据
{
do
{

RTPPacket *pack;
while ((pack = g_pRtpStream->sess.GetNextPacket()) != NULL)
{
intTimestamp = pack->GetTimestamp();
UINT segmentCount=pack->GetPacketLength();
segmentCount=pack->GetPayloadLength();
byte* bufByte=NULL;
intSumCount+=segmentCount;
bufByte=(byte *)pack->GetPayloadData();//获得数据
if (intTimestamp!=intTimestampPrev)
{
if (sumByte!=NULL)
{

InsertFrameHead(sumByte,intSumCount-segmentCount);//加入一个链表
intSumCount=segmentCount;
}
sumByte=(byte*)malloc(segmentCount);
}
else
{
sumByte=(byte *)realloc((void*)sumByte,intSumCount);
}

memcpy(sumByte+intSumCount-segmentCount,bufByte,segmentCount);
intTimestampPrev=intTimestamp;
g_pRtpStream->sess.DeletePacket(pack);
//delete buf;

}

} while (g_pRtpStream->sess.GotoNextSourceWithData());
free((void*) sumByte);

}

g_pRtpStream->sess.EndDataAccess();//解锁

RTPTime::Wait(RTPTime(1,0));
}
return 0;
}

HRESULT CRtpStream::FillBuffer( IMediaSample *pms )
{
CheckPointer(pms,E_POINTER);
Frame* frameData=NULL;
frameData=(Frame*)malloc(sizeof(Frame));
while (1)
{



GetHeadFrame(frameData);
Sleep(10);
if(frameData->count<0)
continue;
else
break;
}


HRESULT hr=S_OK;
byte* payload;
hr = pms->GetPointer(&payload);
if(FAILED(hr))
{
return hr;
}
pms->SetActualDataLength(frameData->count);

long pmsSize;
pmsSize=pms->GetSize();

memcpy((void*)payload,(void*)frameData->data,frameData->count>pmsSize?pmsSize:frameData->count);

free(frameData->data);
free(frameData);

return NOERROR;
}


实现是这样的,发送端
Graph 是这样的 usb视频设备->xivd mpeg-4 codec->RtpRender(自己写的filter)

接收端
RtpSource(自己写的filter)->xvid mpeg-4 video Decoder->Video Render

用GraphEdit测试 视频总是一卡一卡的。
DoRenderSample 代码
发送端的部分代码如下:
HRESULT CRtpRender::DoRenderSample( IMediaSample *pSample )
{
HRESULT hr;
ValidateReadPtr(pSample,sizeof(IMediaSample));
//Add media sample data
byte* pbPayload=0;
hr=pSample->GetPointer(&pbPayload);
if(FAILED(hr))
{
return hr;
}
int status=0;
size_t dataLength;
dataLength=pSample->GetActualDataLength();

//把pSample分块发送
SendDismantleFrame(dataLength,pbPayload,1024,sess);
checkerror(status);
return hr;
}

//这个函数是进行分块发送,可能是所谓的拆帧
void CRtpRender::SendDismantleFrame( int count,byte* buf,int groupCount,RTPSession& sess )
{
int status=0;
int sumCount=count;
if(count<=groupCount)
{
status = sess.SendPacket(buf,count,0,false,33);//发送数据包

}
else
{
int packetCount=0;
int curCount=0;
while(sumCount>0)
{
if(sumCount-groupCount<=0)
{
status = sess.SendPacket(buf,sumCount,0,false,33);//发送数据包
sumCount=0;
}
else
{
status = sess.SendPacket(buf,groupCount,0,false,0);//发送数据包
sumCount=sumCount-groupCount;
buf=&buf[groupCount];

}
packetCount++;

}

}
}

//初始化Session
STDMETHODIMP CRtpRender::Initialize()
{
#ifdef WIN32
WSADATA dat;
WSAStartup(MAKEWORD(2,2),&dat);//指示程序所采用的socket的版本
#endif // WIN32
uint16_t portbase,destport;
uint32_t destip;
std::string ipstr;
int status,i,num;
portbase=6000;
ipstr="127.0.0.1";
destip = inet_addr(ipstr.c_str());
if (destip == INADDR_NONE)
{
std::cerr << "Bad IP address specified" << std::endl;
return -1;
}
destip = ntohl(destip);
destport=8000;
RTPUDPv4TransmissionParams transparams;
RTPSessionParams sessparams;

// IMPORTANT: The local timestamp unit MUST be set, otherwise
// RTCP Sender Report info will be calculated wrong
// In this case, we'll be sending 10 samples each second, so we'll
// put the timestamp unit to (1.0/10.0)
sessparams.SetOwnTimestampUnit(1.0/33.0);//设置发送频率

sessparams.SetAcceptOwnPackets(true);//允许接受自身的的数据包
transparams.SetPortbase(portbase);//设置端口用于接受数据或发送数据
status = sess.Create(sessparams,&transparams); //创建RTP任务
checkerror(status);

//RTPIPv4Address addr(destip,destport);//目标地址

//status = sess.AddDestination(addr);//将目标地址添加会话中


return NOERROR;
}




接收端....


//接收数据线程函数
DWORD WINAPI ReceiveData( LPVOID lpParameter )
{
while(TRUE)
{
g_pRtpStream->sess.Poll();
g_pRtpStream->sess.BeginDataAccess();//对访问的数据进行加锁
uint32_t intTimestampPrev=0;
uint32_t intTimestamp;
byte* sumByte=NULL;
byte* sumByteBegin=NULL;
UINT intSumCount=0;


// check incoming packets
if (g_pRtpStream->sess.GotoFirstSourceWithData())//遍历数据源中的所有数据
{
do
{

RTPPacket *pack;
while ((pack = g_pRtpStream->sess.GetNextPacket()) != NULL)
{
intTimestamp = pack->GetTimestamp();
UINT segmentCount=pack->GetPacketLength();
segmentCount=pack->GetPayloadLength();
byte* bufByte=NULL;
intSumCount+=segmentCount;
bufByte=(byte *)pack->GetPayloadData();//获得数据
if (intTimestamp!=intTimestampPrev)
{
if (sumByte!=NULL)
{

InsertFrameHead(sumByte,intSumCount-segmentCount);//加入一个链表
intSumCount=segmentCount;
}
sumByte=(byte*)malloc(segmentCount);
}
else
{
sumByte=(byte *)realloc((void*)sumByte,intSumCount);
}

memcpy(sumByte+intSumCount-segmentCount,bufByte,segmentCount);
intTimestampPrev=intTimestamp;
g_pRtpStream->sess.DeletePacket(pack);
//delete buf;

}

} while (g_pRtpStream->sess.GotoNextSourceWithData());
free((void*) sumByte);

}

g_pRtpStream->sess.EndDataAccess();//解锁

RTPTime::Wait(RTPTime(1,0));
}
return 0;
}

HRESULT CRtpStream::FillBuffer( IMediaSample *pms )
{
CheckPointer(pms,E_POINTER);
Frame* frameData=NULL;
frameData=(Frame*)malloc(sizeof(Frame));
while (1)
{



GetHeadFrame(frameData);
Sleep(10);
if(frameData->count<0)
continue;
else
break;
}


HRESULT hr=S_OK;
byte* payload;
hr = pms->GetPointer(&payload);
if(FAILED(hr))
{
return hr;
}
pms->SetActualDataLength(frameData->count);

long pmsSize;
pmsSize=pms->GetSize();

memcpy((void*)payload,(void*)frameData->data,frameData->count>pmsSize?pmsSize:frameData->count);

free(frameData->data);
free(frameData);

return NOERROR;
}
...全文
320 11 打赏 收藏 转发到动态 举报
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
playStudy 2011-04-15
  • 打赏
  • 举报
回复
您的意思是在发送端,控制一秒发送30帧
「已注销」 2011-04-11
  • 打赏
  • 举报
回复
应该在发送端控制帧率,你发送了很高帧率的视频,接收端又sleep,那不白发送了吗,全被丢弃了
[Quote=引用 9 楼 playstudy 的回复:]

我发现卡的原因好像是播放太快了,所以我在
FillBuffer 函数里面加了 sleep(33) 好像就不怎么卡了,求解释!
[/Quote]
playStudy 2011-04-11
  • 打赏
  • 举报
回复
我发现卡的原因好像是播放太快了,所以我在
FillBuffer 函数里面加了 sleep(33) 好像就不怎么卡了,求解释!
woainihaha 2011-03-31
  • 打赏
  • 举报
回复
一般来说,缓冲大小要根据你的网络条件和视频效果要求来定。通常实时通讯缓冲要小些,对丢帧处理要多些,尤其是视频。缓冲大延迟就高,但连续性较好。你设置了300缓冲还卡可能有两个原因:你的带宽或处理能力不足,缓冲播放机制不对。播放缓冲需要一定的数量才开始,但你实际运行过程中缓冲可以多一些以充分利用网络,同时只有缓冲全部使用完才能停止。
playStudy 2011-03-28
  • 打赏
  • 举报
回复
我用链表缓存了300帧,可是还是一卡一卡的,需要在 FillBuffer 方法中 Sleep 下吗?;还是有什么方法同步什么的!另丢帧是怎么处理啊,不处理吗?我没考虑丢帧!
woainihaha 2011-03-28
  • 打赏
  • 举报
回复
我觉得首先你发送分包大小需要确定下,1024是否合适,要知道这工具协议本身也有头;很有习能造成一桢需要发两次。其次,最重要的是你程序根本没有缓冲机制,你的发送接收速度远没有播放的快,在本机上也许不太明显。另外,你需要处理适当丢桢,否则你的程序将不能进行实时通讯!从你描述的现象来看,最大可能是没有缓冲!
如果还有其他问题,请发我油箱:wu_jian_bin@126.com
playStudy 2011-03-28
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 woainihaha 的回复:]
我觉得首先你发送分包大小需要确定下,1024是否合适,要知道这工具协议本身也有头;很有习能造成一桢需要发两次。其次,最重要的是你程序根本没有缓冲机制,你的发送接收速度远没有播放的快,在本机上也许不太明显。另外,你需要处理适当丢桢,否则你的程序将不能进行实时通讯!从你描述的现象来看,最大可能是没有缓冲!
如果还有其他问题,请发我油箱:wu_jian_bin@126.com
[/Quote]
一般要缓冲多少帧啊!
zoulie 2011-03-28
  • 打赏
  • 举报
回复
把时间戳打印出来,看帧率多少,看看帧率是不是太少了
「已注销」 2011-03-27
  • 打赏
  • 举报
回复
先测试一下每秒多少帧,每帧编码和解码各需要多长时间。
playStudy 2011-03-26
  • 打赏
  • 举报
回复
大家帮帮忙啊
playStudy 2011-03-25
  • 打赏
  • 举报
回复
大家帮帮忙啊

2,543

社区成员

发帖
与我相关
我的任务
社区描述
专题开发/技术/项目 多媒体/流媒体开发
社区管理员
  • 多媒体/流媒体开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧