流媒体学习笔记2(live555中的Session)

来源:互联网 发布:系统备份还原软件 编辑:程序博客网 时间:2024/04/30 12:57

毕业课题打算从最原始的地方做起。好吧,那就从live555采集转发本地摄像头视频开始吧。首先从源码开始吧,今天看了点liveMedia中的session,这里做个总结。

整个源码中的继承顺序为

H264VideoFileServerMediaSubsession::FileServerMediaSubsession::                                                                       OnDemandServerMediaSubsession::ServerMediaSubsession ::Medium

ServerMediaSession ::Medium

Medium:抽象了基本的接口,包括环境,task和媒体名和媒体查找函数以及一些辅助函数,几乎所有得处理单元都继承自Medium类。

ServerMediaSession:添加了子会话链表,SDP(Session Description Protocol 会话协议)描述以及一些媒体相关处理函数。其中静态成员函数lookupByName可以从session链表中找到对应的媒体

ServerMediaSubsession:定义了指向ServerMediaSession的父指针,指向下个一个对象的指针。该媒体的SDP信息,该媒体的读取定位函数等。

ServerMediaSubsessionIterator:一个迭代器类,用来遍历subsession链表。

程序为容器中的每一个流建立一个subseesion,然后通过 ServerMediaSession::addSubsession 函数,将subsession 加入到ServerMediaSession。具体代码如下

ServerMediaSession::addSubsession(ServerMediaSubsession* subsession) {  if (subsession->fParentSession != NULL) return False; // it's already used  if (fSubsessionsTail == NULL) {    fSubsessionsHead = subsession;  } else {    fSubsessionsTail->fNext = subsession;  }  fSubsessionsTail = subsession;  subsession->fParentSession = this;  subsession->fTrackNumber = ++fSubsessionCounter;  return True;}

ServerMediaSession与流名字所指定与文件是没有关系的,也就是说它不会操作文件,而文件的操作是放在 ServerMediaSubsession中的。具体应该是在ServerMediaSubsession的sdpLines()函数中打开。sdpLines()是在派生类OnDemandServerMediaSubsession中实现,代码如下

char const*OnDemandServerMediaSubsession::sdpLines() {  if (fSDPLines == NULL) {    // We need to construct a set of SDP lines that describe this    // subsession (as a unicast stream).  To do so, we first create    // dummy (unused) source and "RTPSink" objects,    // whose parameters we use for the SDP lines://构建一套SDP行来描述这个Subsession。创建未使用的source和RTPSink对象    unsigned estBitrate;    FramedSource* inputSource = createNewStreamSource(0, estBitrate);    if (inputSource == NULL) return NULL; // file not found    struct in_addr dummyAddr;    dummyAddr.s_addr = 0;    Groupsock dummyGroupsock(envir(), dummyAddr, 0, 0);    unsigned char rtpPayloadType = 96 + trackNumber()-1; // if dynamic    RTPSink* dummyRTPSink      = createNewRTPSink(&dummyGroupsock, rtpPayloadType, inputSource);//Sink中的到SDP    setSDPLinesFromRTPSink(dummyRTPSink, inputSource, estBitrate);    Medium::close(dummyRTPSink);    closeStreamSource(inputSource);  }  return fSDPLines;}

OnDemandServerMediaSubsession类继承 ServerMediaSubsession类,OnDemand实际上用来描述需求,Subsession表示只是一种类型媒体的会话。所以可以通过继承OnDemandServerMediaSubsession来实现不同类型的媒体转发,比如OnDemandServerMediaSubsession的两个子类

1.ProxyServerMediaSubsession:用于实现一个单播RTSP的服务器代理另一个RTSP流

2.FileServerMediaSubsession:虚基类,不同类型媒体通过继承它来实现对于需求,比如音频,视频,比如h263,h264编解码。FileServerMediaSubsession类只是添加了两个成员变量 fFileName,fFileSize用来描述转发的媒体。构造函数如下:

FileServerMediaSubsession::FileServerMediaSubsession(UsageEnvironment& env, char const* fileName,    Boolean reuseFirstSource)  : OnDemandServerMediaSubsession(env, reuseFirstSource),    fFileSize(0) {  fFileName = strDup(fileName);}

而H264VideoFileServerMediaSubsession类继承了FileServerMediaSubsession,它将构造函数放入protected中,并用静态的成员方法createNew来实例对象,这是设计模式的工厂模式。createNew(env, fileName, reuseSource)是每一种类型的流媒体自己的subsession实现。如果 reuseSource == True,则多个客户端共享 StreamState 对象,也即意味着多个客户端播放同一流文件时,服务器端使用同一FileSource 对象对该流文件进行数据读取操作,使用同一RTPSink 对象对流数据进行封装发送操作,这时,多个客户端播放的内容就是同步的,这适合于实时数据播放;如果reuseSource==False,则对每个客户端,服务器端单独维护一个StreamState 对象进行播放操作,此时,多个客户端播放的内容就是独立的,这适合于数据回放。

当然,单看session看不出什么门道来,那看下面

SDP消息组装过程:
      ServerMediaSession负责产生会话公共描述信息,子会话描述由H264VideoFileServerMediaSubsession产生。 H264VideoFileServerMediaSubsession在其父类成员函数OnDemandServerMediaSubsession::sdpLines()中生成会话描述信息。在sdpLines()实现里面,创建一个FramedSource(具体实现类为H264VideoStreamFramer)和RTPSink(具体实现类为H264VideoRTPSink),最后调用OnDemandServerMediaSubsession::setSDPLinesFromRTPSink(...)成员函数生成子会话描述。

好吧,这样思路基本清楚了点,以后要写自己需要的编解码类,那就继承OnDemandServerMediaSubsession吧。对于souce-sink 机制下次讲了....

原创粉丝点击