DSS 代码分析【reflector反射之推流转发分析】
来源:互联网 发布:matlab plot函数矩阵 编辑:程序博客网 时间:2024/04/28 05:19
客户端使用RTP over RTSP方式推流(annouce-->setup-->play)给DSS 服务器进行流转发流程如下:
1. 当有RTSP请求消息到来时,相应的RTSPSession会被加入的TaskThread线程队列中等待执行,接着RTSPSession::Run()会被调用。
在RTSPSession::Run()状态机跳转中kReadingRequest状态时会调用RTSPRequestStream::ReadRequest()读取客户端发送来的数据。
数据读取完毕后 在kFilteringRequest状态时会判断接收的数据是否为RTP数据包,如果是RTP包则调用HandleIncomingDataPacket()进行处理
2.RTSPRequestStream::ReadRequest()读取客户端发送来的数据时,如果数据的第一个字节为$,后面的内容就作为RTP包数据读取。
3.RTSPSession::HandleIncomingDataPacket()首先调用RTPStream::ProcessIncomingInterleavedData解析RTP流数据;
然后将解析后的RTP包转发给注册了QTSS_RTSPIncomingData_Role角色的处理模块,QTSSReflectorModule注册了QTSS_RTSPIncomingData_Role并实现了相应的处理函数ProcessRTPData。当客户端使用RTSP方式推流(annouce-->setup-->play)给DSS 服务器进行流转发时就走的这个流程。
4.RTPStream::ProcessIncomingInterleavedData调用ProcessIncomingRTCPPacket只解析到来的是RTCP类型的数据包
5.QTSSReflectorModule调用ProcessRTPData处理接收到的RTP包。
QTSS_Error QTSSReflectorModuleDispatch(QTSS_Role inRole, QTSS_RoleParamPtr inParams){switch (inRole){case QTSS_Register_Role:return Register(&inParams->regParams);case QTSS_Initialize_Role:return Initialize(&inParams->initParams);case QTSS_RereadPrefs_Role:return RereadPrefs();case QTSS_RTSPRoute_Role:return RedirectBroadcast(&inParams->rtspRouteParams);case QTSS_RTSPPreProcessor_Role:return ProcessRTSPRequest(&inParams->rtspRequestParams);case QTSS_RTSPIncomingData_Role:return ProcessRTPData(&inParams->rtspIncomingDataParams);case QTSS_ClientSessionClosing_Role:return DestroySession(&inParams->clientSessionClosingParams);case QTSS_Shutdown_Role:return Shutdown();case QTSS_RTSPAuthorize_Role:return ReflectorAuthorizeRTSPRequest(&inParams->rtspRequestParams);case QTSS_Interval_Role:return IntervalRole();}return QTSS_NoErr;}ProcessRTPData实现如下,通过PacketChannel对应的index在ReflectorSession取出相应的ReflectorStream,接着调用ReflectorStream::PushPacket将RTP放入到转发队列中去。
QTSS_Error ProcessRTPData(QTSS_IncomingData_Params* inParams){......UInt32 inIndex = packetChannel / 2; // one stream per every 2 channels rtcp channel handled belowif (inIndex < numStreams){ReflectorStream* theStream = theSession->GetStreamByIndex(inIndex);if (theStream == NULL) return QTSS_Unimplemented;SourceInfo::StreamInfo* theStreamInfo = theStream->GetStreamInfo();UInt16 serverReceivePort = theStreamInfo->fPort;Bool16 isRTCP = false;if (theStream != NULL){if (packetChannel & 1){serverReceivePort++;isRTCP = true;}theStream->PushPacket(rtpPacket, packetDataLen, isRTCP);//qtss_printf("QTSSReflectorModule.cpp:ProcessRTPData Send RTSP packet channel=%u to UDP localServerAddr=%" _U32BITARG_ " serverReceivePort=%" _U32BITARG_ " packetDataLen=%u \n", (UInt16) packetChannel, localServerAddr, serverReceivePort,packetDataLen);}}......}6.ReflectorStream::PushPacket实现如下,ReflectorStream类中的成员变量fSocket是UDPSocketPair的实例,包含两个ReflectorSocket类型的成员变量,SocketA用来转发RTP包,SocketB用来转发RTCP包,调用ReflectorSocket::ProcessPacket会将包加入到发送队列里。
void ReflectorStream::PushPacket(char *packet, UInt32 packetLen, Bool16 isRTCP){FU_Head *head = (FU_Head*)&packet[13];if (packetLen > 0){ReflectorPacket* thePacket = NULL;if (isRTCP){//qtss_printf("ReflectorStream::PushPacket RTCP packetlen = %" _U32BITARG_ "\n",packetLen);thePacket = ((ReflectorSocket*)fSockets->GetSocketB())->GetPacket();if (thePacket == NULL){//qtss_printf("ReflectorStream::PushPacket RTCP GetPacket() is NULL\n");return;}OSMutexLocker locker(((ReflectorSocket*)(fSockets->GetSocketB()))->GetDemuxer()->GetMutex());thePacket->SetPacketData(packet, packetLen);((ReflectorSocket*)fSockets->GetSocketB())->ProcessPacket(OS::Milliseconds(), thePacket, 0, 0);((ReflectorSocket*)fSockets->GetSocketB())->Signal(Task::kIdleEvent);}else{//qtss_printf("ReflectorStream::PushPacket RTP packetlen = %" _U32BITARG_ "\n",packetLen);thePacket = ((ReflectorSocket*)fSockets->GetSocketA())->GetPacket();if (thePacket == NULL){//qtss_printf("ReflectorStream::PushPacket GetPacket() is NULL\n");return;}OSMutexLocker locker(((ReflectorSocket*)(fSockets->GetSocketA()))->GetDemuxer()->GetMutex());thePacket->SetPacketData(packet, packetLen);//if(this->fStreamInfo.fPayloadName.Equal("H264/90000"))//{//if(head->nalu_type != 0)//{//pkeyFrameCache->PutOnePacket(packet,packetLen,head->nalu_type,head->s);//}//}((ReflectorSocket*)fSockets->GetSocketA())->ProcessPacket(OS::Milliseconds(), thePacket, 0, 0);((ReflectorSocket*)fSockets->GetSocketA())->Signal(Task::kIdleEvent);}}}
ReflectorSocket::ProcessPacket可以看出一个ReflectorSocket有一个ReflectorSender对应与其对应。最终数据包会被放入ReflectorSender的fPacketQueue队列里。
Bool16 ReflectorSocket::ProcessPacket(const SInt64& inMilliseconds, ReflectorPacket* thePacket, UInt32 theRemoteAddr, UInt16 theRemotePort){...... // Find the appropriate ReflectorSender for this packet.ReflectorSender* theSender = (ReflectorSender*)this->GetDemuxer()->GetTask(theRemoteAddr, 0);// If there is a generic sender for this socket, use it.if (theSender == NULL)theSender = (ReflectorSender*)this->GetDemuxer()->GetTask(0, 0);......thePacket->fStreamCountID = ++(theSender->fStream->fPacketCount);thePacket->fBucketsSeenThisPacket = 0;thePacket->fTimeArrived = inMilliseconds;theSender->fPacketQueue.EnQueue(&thePacket->fQueueElem);......}
SInt64 ReflectorSocket::Run(){//We want to make sure we can't get idle events WHILE we are inside//this function. That will cause us to run the queues unnecessarily//and just get all confused.this->CancelTimeout();Task::EventFlags theEvents = this->GetEvents();//if we have been told to delete ourselves, do so.if (theEvents & Task::kKillEvent)return -1;OSMutexLocker locker(this->GetDemuxer()->GetMutex());SInt64 theMilliseconds = OS::Milliseconds();//Only check for data on the socket if we've actually been notified to that effectif (theEvents & Task::kReadEvent)this->GetIncomingData(theMilliseconds);#if DEBUG//make sure that we haven't gotten here prematurely! This wouldn't mess//anything up, but it would waste CPU.if (theEvents & Task::kIdleEvent){SInt32 temp = (SInt32)(fSleepTime - theMilliseconds);char tempBuf[20];qtss_sprintf(tempBuf, "%" _S32BITARG_ "", temp);WarnV(fSleepTime <= theMilliseconds, tempBuf);}#endiffSleepTime = 0;//Now that we've gotten all available packets, have the streams reflectfor (OSQueueIter iter2(&fSenderQueue); !iter2.IsDone(); iter2.Next()){ReflectorSender* theSender2 = (ReflectorSender*)iter2.GetCurrent()->GetEnclosingObject();if (theSender2 != NULL && theSender2->ShouldReflectNow(theMilliseconds, &fSleepTime))theSender2->ReflectPackets(&fSleepTime, &fFreeQueue);}#if DEBUGtheMilliseconds = OS::Milliseconds();#endif//For smoothing purposes, the streams can mark when they want to wakeup.if (fSleepTime > 0)this->SetIdleTimer(fSleepTime);#if DEBUG//The debugging check above expects real time.fSleepTime += theMilliseconds;#endifreturn 0;}
在ReflectorSocket::Run中会调用ReflectorSocket::ReflectPackets将可用的包转发,首先通过ReflectorStream找出ReflectorOutput对象,接着调用SendPacketsToOutput实现代码如下:
void ReflectorSender::ReflectPackets(SInt64* ioWakeupTime, OSQueue* inFreeQueue){...... ReflectorOutput* theOutput = fStream->fOutputArray[bucketIndex][bucketMemberIndex];if (theOutput != NULL){if (false == theOutput->IsPlaying())continue;{OSMutexLocker locker(&theOutput->fMutex);OSQueueElem* packetElem = theOutput->GetBookMarkedPacket(&fPacketQueue);if (packetElem == NULL) // should only be a new output{packetElem = fFirstPacketInQueueForNewOutput; // everybody starts at the oldest packet in the buffer delay or uses a bookmarkfirstPacket = true;theOutput->setNewFlag(false);}SInt64 bucketDelay = ReflectorStream::sBucketDelayInMsec * (SInt64)bucketIndex;packetElem = this->SendPacketsToOutput(theOutput, packetElem, currentTime, bucketDelay, firstPacket);if (packetElem){OSQueueElem* newElem = NeedRelocateBookMark(packetElem);ReflectorPacket* thePacket = (ReflectorPacket*)newElem->GetEnclosingObject();thePacket->fNeededByOutput = true; // flag to prevent removal in RemoveOldPackets(void)theOutput->SetBookMarkPacket(newElem); // store a reference to the packet}}}......}SendPacketsToOutput中接着调用ReflectorOutput::ReflectorOutput,由于该函数为纯虚函数,实际要调用的是RTPSessionOutput的ReflectorOutput
QTSS_Error RTPSessionOutput::WritePacket(StrPtrLen* inPacket, void* inStreamCookie, UInt32 inFlags, SInt64 packetLatenessInMSec, SInt64* timeToSendThisPacketAgain, UInt64* packetIDPtr, SInt64* arrivalTimeMSecPtr, Bool16 firstPacket){...... //make sure all RTP streams with this ID see this packetQTSS_RTPStreamObject *theStreamPtr = NULL;for (UInt32 z = 0; QTSS_GetValuePtr(fClientSession, qtssCliSesStreamObjects, z, (void**)&theStreamPtr, &theLen) == QTSS_NoErr; z++){if (this->PacketMatchesStream(inStreamCookie, theStreamPtr)){......writeErr = QTSS_Write(*theStreamPtr, &thePacket, inPacket->Len, NULL, inFlags | qtssWriteFlagsWriteBurstBegin);......}......}RTPSessionOutput::ReflectorOutput会获取请求该转发流的所有客户端对应的RTPStream,并通过调用QTSS_Write,该函数最终会调用RTPStream::write发送数据给请求的客户端。
RTPSessionOutput对象是在QTSSReflectorModule处理客户端 Setup请求建立的,并被加入到ReflectorSession。
ReflectorSession::AddOutput实际上调用ReflectorStream::AddOutput将RTPSessionOutput保存在fOutputArray中。
ReflectorSession,ReflectorStream是在推流端 Setup的时候建立的。详细请参照下面的链接
QTSSReflectorModule的Announce消息处理
QTSSReflectorModule的Describe消息处理
转载: http://blog.csdn.net/longlong530/article/details/43564747QTSSReflectorModule的Setup消息处理
转载:http://blog.csdn.net/longlong530/article/details/43667533- DSS 代码分析【reflector反射之推流转发分析】
- DSS 代码分析【RTSP announce推流报文分析】
- DSS 代码分析【TimeoutTask】
- DSS 代码分析【服务器架构】
- DSS 代码分析【点播请求】
- DSS 代码分析【BufferWindow实现】
- DSS 代码分析【Reliable UDP之数据重传】
- DSS 代码分析【Reliable UDP之超时时间计算】
- DSS 代码分析【Reliable UDP之拥塞控制】
- DSS 代码分析【启动、初始化流程】
- DSS 代码分析【EventThread与EventContext】
- DSS 代码分析【TaskThread与Task】
- DSS 代码分析【RTSP消息交互过程】
- DSS 代码分析【学习资料分享】
- DSS 代码分析【SR包发送】
- DSS 代码分析【RTP over tcp实现】
- DSS源码分析
- DSS源码分析
- 关于大型网站技术演进的思考(十九):网站静态化处理—Web前端优化—上(11)
- Kafka producer无法发送消息解决办法
- vue-router 2.0 常用基础知识点之导航钩子
- android studio 导入第三方jar包
- Shader Forge中文帮助手册
- DSS 代码分析【reflector反射之推流转发分析】
- 543. Diameter of Binary Tree
- Hive2.1.1环境部署
- 关于大型网站技术演进的思考(十六)--网站静态化处理—前后端分离—下(8)
- 大白话讲解Promise(二)理解Promise规范
- Eclipse转化为android版本
- Android访问WCF服务(使用json实现参数传递)
- 深度学习的实践方面Quiz 3
- 包装对象