//顾名思义,就是用来生成sdp描述信息的。
char* ServerMediaSession::generateSDPDescription() {
//获取本地IP地址
AddressString ipAddressStr(ourIPAddress(envir()));
unsigned ipAddressStrSize = strlen(ipAddressStr.val()); //不会执行到ssm里面,还不知道SSM是什么
// For a SSM sessions, we need a "a=source-filter: incl ..." line also:
char* sourceFilterLine;
if (fIsSSM) {
char const* const sourceFilterFmt =
"a=source-filter: incl IN IP4 * %s\r\n"
"a=rtcp-unicast: reflection\r\n";
unsigned const sourceFilterFmtSize = strlen(sourceFilterFmt) + ipAddressStrSize + ; sourceFilterLine = new char[sourceFilterFmtSize];
sprintf(sourceFilterLine, sourceFilterFmt, ipAddressStr.val());
} else {
sourceFilterLine = strDup("");
} char* rangeLine = NULL; // for now
char* sdp = NULL; // for now /*
* 有2种级别的sdp信息,一个叫子媒体级别的sdp,一个叫会话级别的sdp。
* 先计算保存sdp可能需要的内存空间大小,然后再格式化生成sdp字符串放入内存中保存起来。
*/
do {
// Count the lengths of each subsession's media-level SDP lines.
// (We do this first, because the call to "subsession->sdpLines()"
// causes correct subsession 'duration()'s to be calculated later.)
unsigned sdpLength = ;
ServerMediaSubsession* subsession;
for (subsession = fSubsessionsHead; subsession != NULL;
subsession = subsession->fNext) {
//遍历子媒体会话,获取各个子会话的sdp描述信息长度。
char const* sdpLines = subsession->sdpLines();
if (sdpLines == NULL) continue; // the media's not available
sdpLength += strlen(sdpLines);
}
if (sdpLength == ) break; // the session has no usable subsessions //获取媒体时长的sdp描述
// Unless subsessions have differing durations, we also have a "a=range:" line:
float dur = duration();
if (dur == 0.0) {
rangeLine = strDup("a=range:npt=0-\r\n");
} else if (dur > 0.0) {
char buf[];
sprintf(buf, "a=range:npt=0-%.3f\r\n", dur);
rangeLine = strDup(buf);
} else { // subsessions have differing durations, so "a=range:" lines go there
rangeLine = strDup("");
} //根会话级别的sdp固定格式
char const* const sdpPrefixFmt =
"v=0\r\n"
"o=- %ld%06ld %d IN IP4 %s\r\n"
"s=%s\r\n"
"i=%s\r\n"
"t=0 0\r\n"
"a=tool:%s%s\r\n"
"a=type:broadcast\r\n"
"a=control:*\r\n"
"%s"
"%s"
"a=x-qt-text-nam:%s\r\n"
"a=x-qt-text-inf:%s\r\n"
"%s"; //计算需要多大的内存空间来存储生成的完整sdp信息。
sdpLength += strlen(sdpPrefixFmt)
+ + + + ipAddressStrSize
+ strlen(fDescriptionSDPString)
+ strlen(fInfoSDPString)
+ strlen(libNameStr) + strlen(libVersionStr)
+ strlen(sourceFilterLine)
+ strlen(rangeLine)
+ strlen(fDescriptionSDPString)
+ strlen(fInfoSDPString)
+ strlen(fMiscSDPLines);
//适度地增加一点内存空间,防止后面子会话级别sdp和上面计算的长度不同。
sdpLength += ; // in case the length of the "subsession->sdpLines()" calls below change
//申请一段内存空间,用来存放后面生成的整个sdp字符串。
sdp = new char[sdpLength];
if (sdp == NULL) break; /*
* 完整的sdp的组成格式是:一个根会话sdp + 多个子媒体sdp。
*
*/ //格式化生成根媒体会话sdp
// Generate the SDP prefix (session-level lines):
snprintf(sdp, sdpLength, sdpPrefixFmt,
fCreationTime.tv_sec, fCreationTime.tv_usec, // o= <session id>
, // o= <version> // (needs to change if params are modified)
ipAddressStr.val(), // o= <address>
fDescriptionSDPString, // s= <description>
fInfoSDPString, // i= <info>
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) //接着,把全部的子媒体级别sdp拼接起来,放到跟会话级别sdp的后面。
// Then, add the (media-level) lines for each subsession:
char* mediaSDP = sdp;
for (subsession = fSubsessionsHead; subsession != NULL;
subsession = subsession->fNext) {
unsigned mediaSDPLength = strlen(mediaSDP);
mediaSDP += mediaSDPLength;
sdpLength -= mediaSDPLength;
if (sdpLength <= ) break; // the SDP has somehow become too long //获取子媒体sdp
char const* sdpLines = subsession->sdpLines();
if (sdpLines != NULL) snprintf(mediaSDP, sdpLength, "%s", sdpLines);
}
} while (); delete[] rangeLine; delete[] sourceFilterLine;
//返回完整sdp信息。
return sdp;
}

完。

ServerMediaSession::generateSDPDescription分析的更多相关文章

  1. rtsp 学习之路一

    http://baijiahao.baidu.com/s?id=1587715130853990653&wfr=spider&for=pc https://www.cnblogs.co ...

  2. (转)live555学习笔记9-h264 RTP传输详解(1)

    九 h264 RTP传输详解(1) 前几章对Server端的介绍中有个比较重要的问题没有仔细探究:如何打开文件并获得其SDP信息.我们就从这里入手吧. 当RTSPServer收到对某个媒体的DESCR ...

  3. 【视频开发】RTSP SERVER(基于live555)详细设计

    /* *本文基于LIVE555的嵌入式的RTSP流媒体服务器一个设计文档,个中细节现剖于此,有需者可参考指正,同时也方便后期自己查阅.(本版本是基于2011年的live555) 作者:llf_17@q ...

  4. (转)基于live555的流媒体代理转发服务器

    对于并发量并不大而且对性能要求不是很高的流媒体传输模块,live555还是很好的选择,下面说一下我所实现的流媒体代理服务器(目前只能实现对H264单视频的转发)代理转发主要 对于并发量并不大而且对性能 ...

  5. Live555 分析(一):类介绍

    从程序的结构来看,live项目包括了四个基本库.程序入口类(在mediaServer中)和一些测试代码(在testProgs中). 四个基本静态库是UsageEnvironment.BasicUsag ...

  6. Live555 分析(二):服务端

    live555支持单播和组播,我们先分析单播的流媒体服务端,后面分析组播的流媒体服务端. 一.单播的流媒体服务端: // Create the RTSP server: RTSPServer* rts ...

  7. live555 源代码简单分析1:主程序

    live555是使用十分广泛的开源流媒体服务器,之前也看过其他人写的live555的学习笔记,在这里自己简单总结下. live555源代码有以下几个明显的特点: 1.头文件是.hh后缀的,但没觉得和. ...

  8. (转)Live555中RTSPClient分析

    有RTSPServer,当然就要有RTSPClient. 如果按照Server端的架构,想一下Client端各部分的组成可能是这样:因为要连接RTSP server,所以RTSPClient要有TCP ...

  9. 【VS开发】【Live555-rtsp】RTSP服务器实例live555源代码分析

    原文地址:RTSP服务器实例live555源代码分析作者:mozheer 1. RTSP连接的建立过程 RTSPServer类用于构建一个RTSP服务器,该类同时在其内部定义了一个RTSPClient ...

随机推荐

  1. 快速理解Docker - 容器级虚拟化解决方案

    是什么 简单的说Docker是一个构建在LXC之上的,基于进程容器(Processcontainer)的轻量级VM解决方案 拿现实世界中货物的运输作类比, 为了解决各种型号规格尺寸的货物在各种运输工具 ...

  2. mysql 恢复

    一.备份的目的 做灾难恢复:对损坏的数据进行恢复和还原需求改变:因需求改变而需要把数据还原到改变以前测试:测试新功能是否可用 二.备份需要考虑的问题 可以容忍丢失多长时间的数据:恢复数据要在多长时间内 ...

  3. 敏捷BI——岂止于快

    信息爆炸的时代,唯有分析快,才可以把握住可能分分钟流失的数据信息,唯有钻取深,才可以挖掘出海量信息中蕴藏的财富.是时候为您的企业上一套敏捷BI了. [敏捷BI的产生背景] 传统BI由IT人员做报表,业 ...

  4. Speed-BI数据分析案例:2016年8月汽车销量排行榜

    据中国汽车工业协会统计分析,2016年8月,乘用车市场表现较好,当月销量环比和同比均呈较快增长.1-8月,乘用车销量总体呈稳定增长,增幅比1-7月继续小幅提升.      8月,乘用车共销售179.5 ...

  5. JQuery 操作HTML元素 示例

    http://www.w3school.com.cn/jquery/jquery_dom_add.asp http://www.w3school.com.cn/jquery/jquery_dom_re ...

  6. oracle恢复备份数据

    sqlplus链接数据库: 1.sqlplus 用户名/密码@IP地址/数据库名称 2.sqlplus 用户名/密码@数据库名称 注:第二种方法要在tnsnames.oRA文件中配置数据库名称 链接断 ...

  7. javascript设计模式学习之十六——状态模式

    一.状态模式的定义 状态模式的关键是区分事务内部和外部的状态,事务内部状态改变往往会带来事务的行为改变. 状态模式中有意思的一点是,一般我们谈到封装,都是优先封装对象的行为,而非对象的状态.但在状态模 ...

  8. Java基础之处理事件——使用适配器类(Sketcher 3 using an Adapter class)

    控制台程序. 适配器类是指实现了监听器接口的类,但监听器接口中的方法没有内容,所以它们什么也不做.背后的思想是:允许从提供的适配器类派生自己的监听器类,之后再实现那些自己感兴趣的类.其他的空方法会从适 ...

  9. Java基础之一组有用的类——使用正则表达式搜索子字符串(TryRegex)

    控制台程序. 正则表达式只是一个字符串,描述了在其他字符串中搜索匹配的模式.但这不是被动地进行字符序列匹配,正则表达式其实是一个微型程序,用于一种特殊的计算机——状态机.状态机并不是真正的机器,而是软 ...

  10. Lintcode: Nth to Last Node in List

    Find the nth to last element of a singly linked list. The minimum number of nodes in list is n. Exam ...