服务器启动 DynamicRTSPServer::createNew(*env, rtspServerPortNum, authDB); env->taskScheduler().doEventLoop() 有链接了! select(fMaxNumSockets, &readSet, NULL, NULL,&tv_timeToDelay) 创建好了RTSPClientSession void RTSPServer::RTSPClientSession::incomingRequestHandler(void* instance, int /*mask*/) void RTSPServer::RTSPClientSession::incomingRequestHandler1() 重点在于 对 DESCRIBE 信令的处理: void RTSPServer::RTSPClientSession::handleCmd_DESCRIBE(char const* cseq, char const* urlSuffix, char const* fullRequestStr) 需要一次 rtsp 会话了: ServerMediaSession* session = fOurServer.lookupServerMediaSession(urlSuffix); { 当前目录下检查文件 FILE* fid = fopen(streamName, "rb"); 再看看对这个 streamName ,RTSPServer 是不是已经有 SMS (ServerMediaSession*)(fServerMediaSessions->Lookup(streamName)) 没有,就创建吧!这里,还可以看出 RTSPClientSession 是标志一次 RSTP 会话,而 SMS 则是一种媒体会话 sms = createNewSMS(envir(), streamName, fid); 添加对应的 subsession MPEG4VideoFileServerMediaSubsession::createNew(env, fileName, reuseSource) FileServerMediaSubsession(env, fileName, reuseFirstSource) OnDemandServerMediaSubsession(env, reuseFirstSource) 看到了吧,OnDemandServerMediaSubsession 与具体媒体文件无关的,很抽象的东东,但和 sdp 很有联系,它有很长的初始化列表 ServerMediaSubsession(env),=>{ Medium(env), fIsSSM(isSSM), fSubsessionsHead(NULL), fSubsessionsTail(NULL), fSubsessionCounter(0), fReferenceCount(0), fDeleteWhenUnreferenced(False) }//也是很长的初始化列表 fSDPLines(NULL), => 这个就是 SDP fReuseFirstSource(reuseFirstSource), fInitialPortNum(initialPortNum), fLastStreamToken(NULL) } 以上都是为了获得 SDP sdpDescription = session->generateSDPDescription() 这时,因为 subsession 是链表的原因,因此,遍历链表 ,得到每个 subsession 的 sdpLines sdpLines = subsession->sdpLines() 用 float dur = duration() 获得播放的帧数 range ,还有等等整个 sdp 构成就是: fCreationTime.tv_sec, fCreationTime.tv_usec, // o= 1, // o= // (needs to change if params are modified) ipAddressStr, // o= fDescriptionSDPString, // s= fInfoSDPString, // i= libNameStr, libVersionStr, // a=tool: sourceFilterLine, // a=source-filter: incl (if a SSM session) rangeLine, // a=range: line fDescriptionSDPString, // a=x-qt-text-nam: line fInfoSDPString, // a=x-qt-text-inf: line fMiscSDPLines,// miscellaneous session SDP lines (if any) 还有最重要的 每个subsession->sdpLines() 这个就是来源于 OnDemandServerMediaSubsession::sdpLines() 嗯嗯,一个和具体文件无关的 OnDemandServerMediaSubsession,,但是它里面却是通过 dummy 的FramedSource 和 RTPSink 在实际实现的时候,调用具体的实现,如 MPEG4ESVideoStreamFramer 等获取 sdpline。如下: OnDemandServerMediaSubsession::sdpLines() { 把 媒体文件 二进制化成 ByteStreamFileSource ,再用它来创建 MPEG4VideoStreamFramer ,这个在另一篇博文中提过,是用来产生 头和帧 的。但是,这个 estBitrate 倒是不懂怎么设定的?????? FramedSource* inputSource = createNewStreamSource(0, estBitrate); unsigned char rtpPayloadType = 96 + trackNumber()-1; // if dynamic 这个是关于 Sink 的创建 RTPSink* dummyRTPSink = createNewRTPSink(&dummyGroupsock, rtpPayloadType, inputSource); 用以上的信息产生 SDP setSDPLinesFromRTPSink(dummyRTPSink, inputSource, estBitrate); 如果说之前那些应该是整个会话的信息,而下面是对应媒体 subsession tarck信息: mediaType, // m= fPortNumForSDP, // m= rtpPayloadType, // m= ipAddressStr, // c= address estBitrate, // b=AS: rtpmapLine, // a=rtpmap:... (if present) rangeLine, // a=range:... (if present) auxSDPLine, // optional extra SDP line trackId()); // a=control: } 备注:如果你要做 264 的话,要注意264 在 Sink 的初始化的时候,和 Mpeg4 不同 264 设了 unsigned profile_level_id, char const* sprop_parameter_sets_str ,其实这两个参数我现在还不是很懂,要查下 码流 才能确定》》》》》求助《《《《《《《《《 如果有知道的,希望能留言告诉我。 auxSDPLine, // optional extra SDP line 这一行的 auxSDPLine 就是 调用OnDemandServerMediaSubsession::getAuxSDPLine 得到的,而它的信息来自于 sink 的getAuxSDPLine ,而这个东东,对应于264 ,就是上面两个参数,所以很重要的。 》》》》》求助《《《《《《《《《这两个参数有多重要,希望知道的各位大虾能留言给我 ok ,到此为止 DESCRIBE 分析完毕接着就是 handleCmd_SETUP fStreamStates = new struct streamState[fNumStreamStates]; 记录 SMS 下的subsession 的信息 ,这里为什么要记录? 我认为是这样的:Server 对每个 streamName 有且仅有维持一个 SMS ,那对每个 Client 如何记录状态呢,就是靠这个 fStreamStates 。而且感觉这个是整个 SETUP 的重点,同时,它从 subsession 中取信息 , subsession->getStreamParameters(fOurSessionId, fClientAddr.sin_addr.s_addr, clientRTPPort, clientRTCPPort, tcpSocketNum, rtpChannelId, rtcpChannelId, destinationAddress, destinationTTL, fIsMulticast, serverRTPPort, serverRTCPPort, fStreamStates[streamNum].streamToken); 获取流媒体发送传输参数。将这些参数组 装成响应消息,返回给客户端 获取发送传输参数的过程:调用子会话(如具体实现类MPEG1or2DemuxedServerMediaSubsession)的 createNewStreamSource(...)创建MPEG1or2VideoStreamFramer,选择发送传输参数,并调用子会话的 createNewRTPSink(...)创建MPEG1or2VideoRTPSink。同时将这些信息保存在StreamState类对象中,用于 记录流的状态 ( A class that represents the state of an ongoing stream)。从 StreamState 的成员变量都可以看出一些端倪: { OnDemandServerMediaSubsession& fMaster; Boolean fAreCurrentlyPlaying; unsigned fReferenceCount; Port fServerRTPPort, fServerRTCPPort; RTPSink* fRTPSink; BasicUDPSink* fUDPSink; float fStreamDuration; unsigned fTotalBW; RTCPInstance* fRTCPInstance; FramedSource* fMediaSource; Groupsock* fRTPgs; Groupsock* fRTCPgs; } PLAY fStreamStates[i].subsession->startStream(fOurSessionId, fStreamStates[i].streamToken, (TaskFunc*)noteClientLiveness, this, rtpSeqNum, rtpTimestamp); MediaSink::startPlaying(...) MultiFramedRTPSink::continuePlaying() MultiFramedRTPSink::buildAndSendPacket(...){ buildAndSendPacke内部先设置RTP包头, 内部再调用MultiFramedRTPSink::packFrame()填充编码帧数据{ FramedSource::getNextFrame() MPEGVideoStreamFramer::doGetNextFrame() MPEGVideoStreamFramer::continueReadProcessing() FramedSource::afterGetting(...) MultiFramedRTPSink::afterGettingFrame(...), MultiFramedRTPSink::afterGettingFrame1(...) ... MultiFramedRTPSink::sendPacketIfNecessary(), } } 然后是计算下一个数据包发送时间,把MultiFramedRTPSink::sendNext(...)函数句柄传给任务调度器,作为一个延时事件调度。在主循环中,当MultiFramedRTPSink::sendNext()被调度时,又开始调用 MultiFramedRTPSink::buildAndSendPacket(...)开始新的发送数据过程,这样客户端可以源源不断的收到服务器传来的RTP包了。 http://hi.baidu.com/amixyue/blog/item/df5d0a37a87f96305ab5f50e.html