Live555源码分析:generateSDPDescription

 [3]generateSDPDescription
有了上述知识,我们继续看一下RTSPServer::RTSPClientConnection::handleCmd_DESCRIBE的处理.
[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. void RTSPServer::RTSPClientConnection::handleCmd_DESCRIBE(char const* urlPreSuffix, char const* urlSuffix, char const* fullRequestStr)  
  2. {  
  3.     char* sdpDescription = NULL;  
  4.     char* rtspURL = NULL;  
  5.     do {  
  6.         char urlTotalSuffix[RTSP_PARAM_STRING_MAX];  
  7.         if (strlen(urlPreSuffix) + strlen(urlSuffix) + 2 > sizeof urlTotalSuffix)  
  8.         {  
  9.             handleCmd_bad();  
  10.             break;  
  11.         }  
  12.         urlTotalSuffix[0] = '\0';  
  13.         if (urlPreSuffix[0] != '\0')  
  14.         {  
  15.             strcat(urlTotalSuffix, urlPreSuffix);  
  16.             strcat(urlTotalSuffix, "/");  
  17.         }  
  18.         strcat(urlTotalSuffix, urlSuffix);  //格式化请求流信息  
  19.         if (!authenticationOK("DESCRIBE", urlTotalSuffix, fullRequestStr)) break;  //用户鉴权  
  20.         // We should really check that the request contains an "Accept:" #####  
  21.         // for "application/sdp", because that's what we're sending back #####  //可惜现在代码没校验吧  
  22.         // Begin by looking up the "ServerMediaSession" object for the specified "urlTotalSuffix":  
  23.         ServerMediaSession* session = fOurServer.lookupServerMediaSession(urlTotalSuffix);  
  24. //根据请求中指定的流查找ServerMediaSession会话。在目前分析的是testOnDemandRTPServer中使用的是RTSPServer::lookupServerMediaSession, 只从已创建回话中查找。而DynamicRTSPServer的重载了此函数,首先调用父类RTPServer的lookupServerMediaSession,然后检查存在与否,如果不存在则创建一个新的。  
  25.         if (session == NULL)  
  26.         {  
  27.             handleCmd_notFound();  
  28.             break;  
  29.         }  
  30.         // Then, assemble a SDP description for this session:  
  31.         sdpDescription = session->generateSDPDescription();//获取SDP描述信息,describe命令主要内容  
  32.         if (sdpDescription == NULL)  
  33.         {  
  34.             // This usually means that a file name that was specified for a  
  35.             // "ServerMediaSubsession" does not exist.  
  36.             setRTSPResponse("404 File Not Found, Or In Incorrect Format");  
  37.             break;  
  38.         }  
  39.         unsigned sdpDescriptionSize = strlen(sdpDescription);  
  40.         // Also, generate our RTSP URL, for the "Content-Base:" header  
  41.         // (which is necessary to ensure that the correct URL gets used in subsequent "SETUP" requests).  
  42.         rtspURL = fOurServer.rtspURL(session, fClientInputSocket); 生成Content-Base内容:RTSP URL  
  43.         snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,  
  44.             "RTSP/1.0 200 OK\r\nCSeq: %s\r\n"  
  45.             "%s"  
  46.             "Content-Base: %s/\r\n"  
  47.             "Content-Type: application/sdp\r\n"  
  48.             "Content-Length: %d\r\n\r\n"  
  49.             "%s",  
  50.             fCurrentCSeq,  
  51.             dateHeader(),  
  52.             rtspURL,  
  53.             sdpDescriptionSize,  
  54.             sdpDescription);                             //拼接DESCRIBE的response  
  55.     } while (0);  
  56.     delete[] sdpDescription;  
  57.     delete[] rtspURL;  
  58. }  


在对describe命令的处理过程中,主要内容一是鉴权,这个在上一篇Live555源码分析[2]:RTSPServer中的用户认证中讲过.另一个就是返回请求流的sdp信息. 这个通过generateSDPDescription来实现


在ServerMediaSession::generateSDPDescription()中基本都是固定字符串的拼接,需要我们重点关注的是
   
[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. // Count the lengths of each subsession's media-level SDP lines.  
  2.    // (We do this first, because the call to "subsession->sdpLines()"  
  3.    // causes correct subsession 'duration()'s to be calculated later.)  
  4. /生成sdpLines并计算其长度,拼接过程在最后,但在此做的目的是顺便调用subsession的duration接口以便返回媒体文件的长度  
  5.    unsigned sdpLength = 0;  
  6.    ServerMediaSubsession* subsession;  
  7.    for (subsession = fSubsessionsHead; subsession != NULL;  
  8.  subsession = subsession->fNext) {  
  9.      char const* sdpLines = subsession->sdpLines();   //此时返回的虽然没有使用,但内部是保存好了,后面拼接时虽然再次调用,但也是直接返回而已。事实上,live555默认并没有删除用完的SMS及SMSS,因而在第二次再次请求此媒体流时,这个也不会再次生成了  
  10.      if (sdpLines == NULL) continue// the media's not available  
  11.      sdpLength += strlen(sdpLines);  
  12.    }  
  13.    if (sdpLength == 0) break// the session has no usable subsessions  
  14.   
  15.   
  16.    // Unless subsessions have differing durations, we also have a "a=range:" line:  
  17.    float dur = duration();   //返回媒体时长  




OnDemandServerMediaSubsession::sdpLines()的实现如下
[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. char const* OnDemandServerMediaSubsession::sdpLines()   
  2. {  
  3.     if (fSDPLines == NULL) {  
  4.         // We need to construct a set of SDP lines that describe this subsession (as a unicast stream). To do so, we first create  
  5.         // dummy (unused) source and "RTPSink" objects, whose parameters we use for the SDP lines:  
  6.         unsigned estBitrate;  
  7.         FramedSource* inputSource = createNewStreamSource(0, estBitrate);  
  8.         if (inputSource == NULL) return NULL; // file not found  
  9.   
  10.   
  11.         struct in_addr dummyAddr;  
  12.         dummyAddr.s_addr = 0;  
  13.         Groupsock dummyGroupsock(envir(), dummyAddr, 0, 0);  
  14.         unsigned char rtpPayloadType = 96 + trackNumber()-1; // if dynamic  
  15.         RTPSink* dummyRTPSink  
  16.             = createNewRTPSink(&dummyGroupsock, rtpPayloadType, inputSource);  
  17.         if (dummyRTPSink != NULL && dummyRTPSink->estimatedBitrate() > 0) estBitrate = dummyRTPSink->estimatedBitrate();  
  18.   
  19.   
  20.         setSDPLinesFromRTPSink(dummyRTPSink, inputSource, estBitrate);  
  21.         Medium::close(dummyRTPSink);  
  22.         closeStreamSource(inputSource);  
  23.     }  
  24.   
  25.   
  26.     return fSDPLines;  
  27. }  


其中createNewStreamSource与createNewRTPSink均为虚函数,由具体ServerMediaSubsession负责实现。
其中FramedSource的子类FramedFilter提供一种抽象数据源的功能,其继承关系MediaSource->FramedSource->FramedFilter, 由其屏蔽不同类型数据源的区别。RTPSource则是负责RTP协议报文封装之类的处理了
创建完临时的Source和Sink之后, 从Sink中获取SDPLine, 其中有的媒体类型读取文件头即可, 有的需要先播放一段视频,如H.264。。。以此才能正确的获取到SDP信息...具体细节还没研究,
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值