DSS 代码分析【reflector反射之推流转发分析】

客户端使用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 below
			if (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 effect
	if (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);
	}
#endif

	fSleepTime = 0;
	//Now that we've gotten all available packets, have the streams reflect
	for (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 DEBUG
	theMilliseconds = 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;
#endif

	return 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 bookmark
						firstPacket = 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 packet
	QTSS_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/43564747

QTSSReflectorModule的Setup消息处理

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












  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值