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()进行处理

[plain] view plain copy
  1. SInt64 RTSPSession::Run()  
  2. {  
  3. ......  
  4.         case kReadingRequest:  
  5.             {  
  6.                 // We should lock down the session while reading in data,  
  7.                 // because we can't snarf up a POST while reading.  
  8.                 OSMutexLocker readMutexLocker(&fReadMutex);  
  9.   
  10.                 if ((err = fInputStream.ReadRequest()) == QTSS_NoErr)  
  11.                 ......  
  12.             }  
  13.   
  14.         ......  
  15.         case kFilteringRequest:  
  16.             {  
  17.                 // We received something so auto refresh  
  18.                 // The need to auto refresh is because the api doesn't allow a module to refresh at this point  
  19.                 //   
  20.   
  21.                 // 刷新超时任务fTimeoutTask,运转RTSP会话的超时机制  
  22.                 fTimeoutTask.RefreshTimeout();  
  23.   
  24.                 //  
  25.                 // Before we even do this, check to see if this is a *data* packet,  
  26.                 // in which case this isn't an RTSP request, so we don't need to go  
  27.                 // through any of the remaining steps  
  28.   
  29.                 // 判断当前数据是否是一个数据包,而不是一个RTSP请求  
  30.                 if (fInputStream.IsDataPacket()) // can this interfere with MP3?  
  31.                 {  
  32.                     this->HandleIncomingDataPacket();  
  33.                     fState = kCleaningUp;  
  34.                     break;  
  35.                 }  
  36.                 ......  
  37.             }  
  38. ......  
  39. }  

2.RTSPRequestStream::ReadRequest()读取客户端发送来的数据时,如果数据的第一个字节为$,后面的内容就作为RTP包数据读取。

[plain] view plain copy
  1. QTSS_Error RTSPRequestStream::ReadRequest()  
  2. {  
  3.     while (true)  
  4.     {  
  5.     ......  
  6.         // See if this is an interleaved data packet  
  7.         if ('$' == *(fRequest.Ptr))  
  8.         {  
  9.             if (fRequest.Len < 4)  
  10.                 continue;  
  11.             UInt16* dataLenP = (UInt16*)fRequest.Ptr;  
  12.             UInt32 interleavedPacketLen = ntohs(dataLenP[1]) + 4;  
  13.             if (interleavedPacketLen > fRequest.Len)  
  14.                 continue;  
  15.   
  16.             //put back any data that is not part of the header  
  17.             fRetreatBytes += fRequest.Len - interleavedPacketLen;  
  18.             fRequest.Len = interleavedPacketLen;  
  19.   
  20.             fRequestPtr = &fRequest;  
  21.             fIsDataPacket = true;  
  22.             return QTSS_RequestArrived;  
  23.         }  
  24.     ......  
  25.     }  
  26.     ......  
  27. }  

3.RTSPSession::HandleIncomingDataPacket()首先调用RTPStream::ProcessIncomingInterleavedData解析RTP流数据;

然后将解析后的RTP包转发给注册了QTSS_RTSPIncomingData_Role角色的处理模块,QTSSReflectorModule注册了QTSS_RTSPIncomingData_Role并实现了相应的处理函数ProcessRTPData。当客户端使用RTSP方式推流(annouce-->setup-->play)给DSS 服务器进行流转发时就走的这个流程。

[plain] view plain copy
  1. void RTSPSession::HandleIncomingDataPacket()  
  2. {  
  3.     // Attempt to find the RTP session for this request.  
  4.     UInt8   packetChannel = (UInt8)fInputStream.GetRequestBuffer()->Ptr[1];  
  5.     StrPtrLen* theSessionID = this->GetSessionIDForChannelNum(packetChannel);  
  6.   
  7.     if (theSessionID == NULL)  
  8.     {  
  9.         Assert(0);  
  10.         return;  
  11.         theSessionID = &fLastRTPSessionIDPtr;  
  12.     }  
  13.   
  14.     // RTP会话表中功能查找SessionID对应的引用  
  15.     OSRefTable* theMap = QTSServerInterface::GetServer()->GetRTPSessionMap();  
  16.     OSRef* theRef = theMap->Resolve(theSessionID);  
  17.   
  18.     if (theRef != NULL)  
  19.         fRTPSession = (RTPSession*)theRef->GetObject();  
  20.   
  21.     if (fRTPSession == NULL)  
  22.         return;  
  23.   
  24.     StrPtrLen packetWithoutHeaders(fInputStream.GetRequestBuffer()->Ptr + 4, fInputStream.GetRequestBuffer()->Len - 4);  
  25.   
  26.     OSMutexLocker locker(fRTPSession->GetMutex());  
  27.     fRTPSession->RefreshTimeout();  
  28.     // 通过packetChannel找到对应的RTP流数据  
  29.     RTPStream* theStream = fRTPSession->FindRTPStreamForChannelNum(packetChannel);  
  30.     //解析RTP流数据  
  31.     theStream->ProcessIncomingInterleavedData(packetChannel, this, &packetWithoutHeaders);  
  32.   
  33.     //  
  34.     // We currently don't support async notifications from within this role  
  35.     QTSS_RoleParams packetParams;  
  36.     packetParams.rtspIncomingDataParams.inRTSPSession = this;  
  37.   
  38.     packetParams.rtspIncomingDataParams.inClientSession = fRTPSession;  
  39.     packetParams.rtspIncomingDataParams.inPacketData = fInputStream.GetRequestBuffer()->Ptr;  
  40.     packetParams.rtspIncomingDataParams.inPacketLen = fInputStream.GetRequestBuffer()->Len;  
  41.   
  42.     //调用所有注册了kRTSPIncomingDataRole角色的模块  
  43.     UInt32 numModules = QTSServerInterface::GetNumModulesInRole(QTSSModule::kRTSPIncomingDataRole);  
  44.     for (; fCurrentModule < numModules; fCurrentModule++)  
  45.     {  
  46.         QTSSModule* theModule = QTSServerInterface::GetModule(QTSSModule::kRTSPIncomingDataRole, fCurrentModule);  
  47.         (void)theModule->CallDispatch(QTSS_RTSPIncomingData_Role, &packetParams);  
  48.     }  
  49.     //将当前模块数置0  
  50.     fCurrentModule = 0;  
  51. }  

4.RTPStream::ProcessIncomingInterleavedData调用ProcessIncomingRTCPPacket只解析到来的是RTCP类型的数据包

[plain] view plain copy
  1. void RTPStream::ProcessIncomingInterleavedData(UInt8 inChannelNum, RTSPSessionInterface* inRTSPSession, StrPtrLen* inPacket)  
  2. {  
  3.     if (inChannelNum == fRTPChannel)  
  4.     {  
  5.         //  
  6.         // Currently we don't do anything with incoming RTP packets. Eventually,  
  7.         // we might need to make a role to deal with these  
  8.     }  
  9.     else if (inChannelNum == fRTCPChannel)  
  10.         this->ProcessIncomingRTCPPacket(inPacket);  
  11. }  

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);......}


7.ReflectorStream::PushPacket中在调用玩ProcessPacket后会接着调用((ReflectorSocket*)fSockets->GetSocketA())->Signal(Task::kIdleEvent),ReflectorSocket类继承自IdleTask,因此ReflectorSocket实例会被加入到IdleThread的线程队列中去执行ReflectorSocket::Run函数

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消息处理

转载: http://blog.csdn.net/longlong530/article/details/43489181

QTSSReflectorModule的Describe消息处理

转载: http://blog.csdn.net/longlong530/article/details/43564747

QTSSReflectorModule的Setup消息处理

转载:http://blog.csdn.net/longlong530/article/details/43667533












原创粉丝点击