live555 基本框架
从程序的结构来看,live项目包括了四个基本库、程序入口类(在mediaServer中)和一些测试代码(在testProgs中)。四个基本库是UsageEnvironment,BasicUsageEnvironment、groupsock和liveMedia。
UsageEnvironment包括抽象类UsageEnvironment和抽象类TaskScheduler,这两个类用于事件调度,其中包括实现了对事件的异步读取、对事件句柄的设置及对错误信息的输出等;UsageEnvironment代表了整个系统运行的环境,它提供了错误记录和错误报告的功能,无论哪一个类要输出错误,就需要保存UsageEnvironment的指针.而TaskScheduler则提供了任务调度功能.整个程序的运行发动机就是它,它调度任务,执行任务(任务就是一个函数).TaskScheduler由于在全局中只有一个,所以保存在了UsageEnvironment中.而所有的类又都保存了UsageEnvironment的指针,所以谁想把自己的任务加入调度中,那是很容易的.在此还看到一个结论:整个live555(服务端)只有一个线程.
- class UsageEnvironment {
- public:
- void reclaim();
- // task scheduler:
- TaskScheduler& taskScheduler() const {return fScheduler;}
- // result message handling:
- typedef char const* MsgString;
- virtual MsgString getResultMsg() const = 0;
- virtual void setResultMsg(MsgString msg) = 0;
- virtual void setResultMsg(MsgString msg1, MsgString msg2) = 0;
- virtual void setResultMsg(MsgString msg1, MsgString msg2, MsgString msg3) = 0;
- virtual void setResultErrMsg(MsgString msg, int err = 0) = 0;
- // like setResultMsg(), except that an 'errno' message is appended. (If "err == 0", the "getErrno()" code is used instead.)
- virtual void appendToResultMsg(MsgString msg) = 0;
- virtual void reportBackgroundError() = 0;
- // used to report a (previously set) error message within
- // a background event
- virtual void internalError(); // used to 'handle' a 'should not occur'-type error condition within the library.
- // 'errno'
- virtual int getErrno() const = 0;
- // 'console' output:
- virtual UsageEnvironment& operator<<(char const* str) = 0;
- virtual UsageEnvironment& operator<<(int i) = 0;
- virtual UsageEnvironment& operator<<(unsigned u) = 0;
- virtual UsageEnvironment& operator<<(double d) = 0;
- virtual UsageEnvironment& operator<<(void* p) = 0;
- // a pointer to additional, optional, client-specific state
- void* liveMediaPriv;
- void* groupsockPriv;
- protected:
- UsageEnvironment(TaskScheduler& scheduler); // abstract base class
- virtual ~UsageEnvironment(); // we are deleted only by reclaim()
- private:
- TaskScheduler& fScheduler;
- 』
该库中还有一个HashTable,这是一个通用的HashTable,在整个项目中都可以使用它,当然该HashTable也是一个抽象类。
BasicUsageEnvironment中的类主要是对UsageEnvironment中对应类的实现。
groupsock,顾名思义,用于数据包的接收和发送,其同时支持多播和单播。groupsock库中包括了GroupEId、Groupsock、GroupsockHelper、NetAddress、NetInterface等类,其中Groupsock类有两个构造函数,一个是“for a source-independent multicast group”,另一个是“for a source-specific multicast group”;而GroupsockHelper类主要用于读写Socket。Groupsock的构造函数有一个参数是struct in_addr const& groupAddr,在构造函数中首先会调用父类构造函数创建socket对象,然后判断这个地址,若是多播地址,则加入多播组。Groupsock的两个成员变量destRecord* fDests和DirectedNetInterfaceSet fMembers都表示目的地址集和,但我始终看不出DirectedNetInterfaceSet fMembers有什么用,且DirectedNetInterfaceSet是一个没有被继承的虚类,看起来fMembers没有什么用。仅fDesk也够用了,在addDestination()和removeDestination()函数中就是操作fDesk,添加或删除目的地址。
Groupsock::changeDestinationParameters()函数
- //改变目的地址的参数
- //newDestAddr是新的目的地址
- //newDestPort是新的目的端口
- //newDestTTL是新的TTL
- void Groupsock::changeDestinationParameters(
- struct in_addr const& newDestAddr,
- Port newDestPort,
- int newDestTTL)
- {
- if (fDests == NULL)
- return;
- //获取第一个目的地址(此处不是很明白:fDest是一个单向链表,每次添加一个目的地址,
- //都会把它插入到最前目,难道这个函数仅改变最后一个添加的目的地址?)
- struct in_addr destAddr = fDests->fGroupEId.groupAddress();
- if (newDestAddr.s_addr != 0) {
- if (newDestAddr.s_addr != destAddr.s_addr
- && IsMulticastAddress(newDestAddr.s_addr))
- {
- //如果目的地址是一个多播地址,则离开老的多播组,加入新的多播组。
- socketLeaveGroup(env(), socketNum(), destAddr.s_addr);
- socketJoinGroup(env(), socketNum(), newDestAddr.s_addr);
- }
- destAddr.s_addr = newDestAddr.s_addr;
- }
- portNumBits destPortNum = fDests->fGroupEId.portNum();
- if (newDestPort.num() != 0) {
- if (newDestPort.num() != destPortNum &&
- IsMulticastAddress(destAddr.s_addr))
- {
- //如果端口也不一样,则先更改本身socket的端口
- //(其实是关掉原先的socket的,再以新端口打开一个socket)。
- changePort(newDestPort);
- //然后把新的socket加入到新的多播组。
- // And rejoin the multicast group:
- socketJoinGroup(env(), socketNum(), destAddr.s_addr);
- }
- destPortNum = newDestPort.num();
- fDests->fPort = newDestPort;
- }
- u_int8_t destTTL = ttl();
- if (newDestTTL != ~0)
- destTTL = (u_int8_t) newDestTTL;
- //目标地址的所有信息都在fGroupEId中,所以改变成员fGroupEId。
- fDests->fGroupEId = GroupEId(destAddr, destPortNum, destTTL);
- //(看起来这个函数好像只用于改变多播时的地址参数,
- //以上分析是否合理,肯请高人指点)
- }
liveMedia是很重要的一个库,其不仅包含了实现RTSP Server的类,还包含了针对不同流媒体类型(如TS流、PS流等)编码的类。在该库中,基类是Medium,层次关系非常清晰。在该库中,有几个很重要的类,如RTSPServer、ServerMediaSession、RTPSink、RTPInterface、FramedSource等。
在http://www.live555.com上的相关文档中提到穿透防火墙的问题,方法是开启一个HTTP的tunnel,然后我们可以在liveMedia库中找到一个RTSPOverHTTPServer的类,该类解决了这样的问题。
mediaServer下的live555MediaServer提供了main函数,DynamicRTSPServer继承了RTSPServer并重写了虚函数lookupServerMediaSession。
鉴于UsageEnvironment库、BasicUsageEnvironment库和groupsock库中的类较少,就暂且不作分析了。这里主要针对liveMedia库中的主要类结构进行分析。通过查看类关系图,可以从整体把握,但是苦于类太多,用类关系图看起来也不方便,于是就自己重新整理了一下,下面是 liveMedia库的主要类结构。(注:其他单类及结构体等不在此列出)
l Medium
n RTSPServer
n RTSPOverHTTPServer
n MediaSession
n ServerMediaSession
n ServerMediaSubsession
u OnDemandServerMediaSubsession
l FileServerMediaSubsession
n ADTSAudioFileServerMediaSubsession
n AMRAudioFileServerMediaSubsession
n H263plusVideoFileServerMediaSubsession
n MP3AudioFileServerMediaSubsession
n MPEG1or2VideoFileServerMediaSubsession
n MPEG2TransportFileServerMediaSubsession
n MPEG4VideoFileServerMediaSubsession
n WAVAudioFileServerMediaSubsession
l MPEG1or2DemuxedServerMediaSubsession
u PassiveServerMediaSubsession
n MediaSource
u FramedSource
l FramedFileSource
n ByteStreamFileSource
n ADTSAudioFileSource
n MP3FileSource
u MP3HTTPSource
l BasicUDPSource
l RTPSource
n MultiFramedRTPSource
u RawQCELPRTPSource
u AC3AudioRTPSource
u MPEG4GenericRTPSource
u RawAMRRTPSource
u H261VideoRTPSource
u H263plusVideoRTPSource
u H264VideoRTPSource
u JPEGVideoRTPSource
u MP3ADURTPSource
u MPEG1or2AudioRTPSource
u MPEG1or2VideoRTPSource
u MPEG4ESVideoRTPSource
u MPEG4GenericRTPSource
u MPEG4LATMAudioRTPSource
u DVVideoRTPSource
u QuickTimeGenericRTPSource
u SimpleRTPSource
l AMRAudioSource
n AMRDeinterleaver
n AMRAudioFileSource
l ByteStreamMultiFileSource
l DeviceSource
l JPEGVideoSource
l MPEG1or2DemuxedElementaryStream
l MPEG2TransportStreamMultiplexor
n MPEG2TransportStreamFromESSource
n MPEG2TransportStreamFromPESSource
l AudioInputDevice
n WAVAudioFileSource
l FramedFilter
n H264FUAFragmenter
n QCELPDeinterleaver
n AC3AudioStreamFramer
n ADUFromMP3Source
n uLawFromPCMAudioSource
n H264VideoStreamFramer
n MP3FromADUSource
u MP3Transcoder
n PCMFromuLawAudioSource
n MPEG2IFrameIndexFromTransportStream
n NetworkFromHostOrder16
n HostFromNetworkOrder16
n MP3ADUinterleaverBase
u MP3ADUinterleaver
u MP3ADUdeinterleaver
n MPEG2TransportStreamFramer
n EndianSwap16
n H263plusVideoStreamFramer
n MPEGVideoStreamFramer
u MPEG1or2VideoStreamFramer
l MPEG1or2VideoStreamDiscreteFramer
u MPEG4VideoStreamFramer
l MPEG4VideoStreamDiscreteFramer
n MPEG1or2AudioStreamFramer
n DVVideoStreamFramer
n MP3ADUTranscoder
n MPEG2TransportStreamTrickModeFilter
n MediaSink
u DummySink
u BasicUDPSink
u RTPSink
l MultiFramedRTPSink
n MPEG4GenericRTPSink
n VideoRTPSink
u H264VideoRTPSink
u MPEG1or2VideoRTPSink
u H263plusVideoRTPSink
u JPEGVideoRTPSink
u DVVideoRTPSink
u MPEG4ESVideoRTPSink
n AudioRTPSink
u AC3AudioRTPSink
u MPEG4LATMAudioRTPSink
u GSMAudioRTPSink
u MPEG1or2AudioRTPSink
u AMRAudioRTPSink
u MP3ADURTPSink
n SimpleRTPSink
u HTTPSink
l MPEG1or2VideoHTTPSink
u FileSink
l AMRAudioFileSink
l H264VideoFileSink
n RTCPInstance
n RTSPClient
n SIPClient
n DarwinInjector
n QuickTimeFileSink
n MPEG1or2Demux
n MPEG2TransportStreamIndexFile
n MPEG1or2FileServerDemux
n AVIFileSink
l BufferedPacketFactory
n QCELPBufferedPacketFactory
n AMRBufferedPacketFactory
n MPEG4GenericBufferedPacketFactory
n ADUBufferedPacketFactory
n QTGenericBufferedPacketFactory
n LATMBufferedPacketFactory
n H264BufferedPacketFactory
n JPEGBufferedPacketFactory
l BufferedPacket
n QCELPBufferedPacket
n AMRBufferedPacket
n MPEG4GenericBufferedPacket
n ADUBufferedPacket
n QTGenericBufferedPacket
n LATMBufferedPacket
n H264BufferedPacket
n JPEGBufferedPacket
l StreamParser
n AC3AudioStreamParser
n MPEGVideoStreamParser
u MPEG1or2VideoStreamParser
u MPEG4VideoStreamParser
n MPEG1or2AudioStreamParser
n H263plusVideoStreamParser
n MPEGProgramStreamParser
从上面这个主要的类结构可以看出,liveMedia库中的基类为Medium,其下又有几个非常重要的部分,一个是×××Subsession,除Medium父类外,所有的×××Subsession类都继承于ServerMediaSubsession;一个是×××Source,MediaSource的frameSource下主要包含FramedFileSource、RTPSource、FramedFilter等几个主要的部分;一个是MediaSink,以继承于RTPSink的类居多。
- class H264VideoFileServerMediaSubsession: public FileServerMediaSubsession {
- public:
- static H264VideoFileServerMediaSubsession*
- createNew(UsageEnvironment& env, char const* fileName, Boolean reuseFirstSource);
- // Used to implement "getAuxSDPLine()":
- void checkForAuxSDPLine1();
- void afterPlayingDummy1();
- protected:
- H264VideoFileServerMediaSubsession(UsageEnvironment& env,
- char const* fileName, Boolean reuseFirstSource);
- // called only by createNew();
- virtual ~H264VideoFileServerMediaSubsession();
- void setDoneFlag() { fDoneFlag = ~0; }
- protected: // redefined virtual functions
- virtual char const* getAuxSDPLine(RTPSink* rtpSink,
- FramedSource* inputSource);
- virtual FramedSource* createNewStreamSource(unsigned clientSessionId,
- unsigned& estBitrate);
- virtual RTPSink* createNewRTPSink(Groupsock* rtpGroupsock,
- unsigned char rtpPayloadTypeIfDynamic,
- FramedSource* inputSource);
- private:
- char* fAuxSDPLine;
- char fDoneFlag; // used when setting up "fAuxSDPLine"
- RTPSink* fDummyRTPSink; // ditto
- };
- #endif
此外,还包含了用于处理packet的BufferedPacketFactory和BufferedPacket及其相关子类,用于处理流分析的StreamParser及其子类。
基本上,整个liveMedia库的主要类结构就是这样。不过,类太多了,分析起来还是有较大的困难。于是乎,采取去掉枝叶保留主干的做法,将整个服务器精简成支持一种格式的服务器,如MP3流服务器。经过分离,一个基于MP3的测试服务器的主要类结构如下所示。(注:其他单类及结构体等不在此列出)
l Medium
n RTSPServer
n MediaSession
n ServerMediaSession
n ServerMediaSubsession
u OnDemandServerMediaSubsession
l FileServerMediaSubsession
n MP3AudioFileServerMediaSubsession
n MediaSource
u FramedSource
l FramedFileSource
n MP3FileSource
u MP3HTTPSource
l BasicUDPSource
l RTPSource
n MultiFramedRTPSource
u MP3ADURTPSource
u MPEG1or2AudioRTPSource
u SimpleRTPSource
l FramedFilter
n ADUFromMP3Source
n MP3FromADUSource
u MP3Transcoder
n MP3ADUinterleaverBase
u MP3ADUinterleaver
u MP3ADUdeinterleaver
n MP3ADUTranscoder
n MediaSink
u BasicUDPSink
u RTPSink
l MultiFramedRTPSink
n AudioRTPSink
u MPEG1or2AudioRTPSink
u MP3ADURTPSink
n RTCPInstance
l BufferedPacketFactory
n ADUBufferedPacketFactory
l BufferedPacket
n ADUBufferedPacket
根据上面这种相对简单的类结构,分析起来就方便多了。于是,开始进入具体的分析细节了,这是一个相对漫长的过程,再加上本人的C++水平有限,这又将是一个相对艰苦的过程,一切慢慢来吧……
末了,讲讲启动服务器的过程:
LIVE555是一个纯粹的RTSP服务器,其服务器主类为liveMedia库下的RTSPServer;mediaServer下的live555MediaServer为主程序的入口类,DynamicRTSPServer是RTSPServer的实现类。
从live555MediaServer类的入口函数main中可以非常清晰地分析出服务器的启动过程。
首先是createNew一个TaskSchedulers对象和一个UsageEnvironment对象,这是初始工作。
之后是一段访问控制的代码。然后开始进入创建RTSP服务器的代码段,服务器指定了一个默认端口554和一个可供替代的端口8554。
接下来,createNew一个DynamicRTSPServer,这里建立了Socket(ourSocket)在TCP的554端口(默认端口)进行监听,然后把连接处理函数句柄和socket句柄传给任务调度器(即taskScheduler),既是RTSPServer类中的这句代码:env.taskScheduler().turnOnBackgroundReadHandling(fServerSocket, (TaskScheduler::BackgroundHandlerProc*)&incomingConnectionHandler,this)。紧接着就是对socket句柄和incomingConnectionHandler句柄的处理,主要是进行关联等。
最后,进入主循环(即env->taskScheduler().doEventLoop();),等待客户端连接。服务器启动完毕。
文章的最后,需要说明的是,在编译运行的过程中,我是使用VLC播放器来进行测试的,同时通过使用Ethereal的网络分析工具抓包分析其建立到传输的过程,虽然在live555源代码中关于RTSP建立及收发数据包的过程已经用代码写得非常清楚(这个好好分析一下源码就可以了),但我想,学习使用一下一些网络分析工具对自身也是颇为有益的。
live555 基本框架的更多相关文章
- live555流媒体框架介绍
LIVE555 Streaming Media This code forms a set of C++ libraries for multimedia streaming, using open ...
- 用Darwin和live555实现的直播框架
我们在开发视频直播或者监控类项目的时候,如场馆监控.学校监控.车载监控等等,往往首先希望的是形成一个项目的雏形,然后再在这个框架的基础上进行不断的完善和扩展工作,那么我们今天要给大家介绍的就是,如何形 ...
- Live555流媒体服务器编译(Windows下)
最近在回顾之前做过的相关项目,其中包括live555流媒体服务器相关,今天先把live555开源框架在Windows下的编译方法记录一下. live555是一套使用使用开放的标准协议(RTP/RTCP ...
- Live555 实战之框架简单介绍
作者:咕唧咕唧liukun321 来自:http://blog.csdn.net/liukun321 上一篇文章简要介绍了怎样以共享库的方式交叉编译Live555,今天再来介绍live源代码框架. 先 ...
- 值得推荐的C/C++框架和库
值得推荐的C/C++框架和库 [本文系外部转贴,原文地址:http://coolshell.info/c/c++/2014/12/13/c-open-project.htm]留作存档 下次造轮子前先看 ...
- [转载]C/C++框架和库
C/C++框架和库 装载自:http://blog.csdn.net/xiaoxiaoyeyaya/article/details/42541419 值得学习的C语言开源项目 Webbench Web ...
- 最全面的 C++ 资源、框架大全
转载自 http://www.codeceo.com/article/cpp-resource-framework.html#0-tsina-1-99850-397232819ff9a47a7b7 ...
- 1.值得推荐的C/C++框架和库 (转)
值得学习的C语言开源项目 - 1. Webbench Webbench是一个在linux下使用的非常简单的网站压测工具.它使用fork()模拟多个客户端同时访问我们设定的URL,测试网站在压力下工作的 ...
- 转:值得推荐的C/C++框架和库(真的很强大)
目录(?)[+] 值得学习的C语言开源项目 - 1 Webbench - 2 Tinyhttpd - 3 cJSON - 4 CMockery - 5 Libev - 6 Memcached - 7 ...
随机推荐
- Oracle转换字符集操作到底发生了什么?
数据库当前字符集为AL32UTF8,若打算将字符集更换为ZHS16GBK,执行如下命令: "ALTER DATABASE NATIONAL CHARACTER SET INTERNAL_US ...
- 9. Scala隐式转换和隐式值
9.1 隐式转换 9.1.1 提出问题 先看一个案例演示,引出隐式转换的实际需要=>指定某些数据类型的相互转化 object boke_demo01 { def main(args: Array ...
- Java.util.Math类--数学相关的工具类
Math类--数学相关的工具类 java.util.Math类是数学相关的工具类,里面提供了大量的静态方法,完成与数学运算相关的操作. public static double abs(double ...
- 简洁的 Python Schema
目录 Python Schema使用说明 1. Schema是什么? 2. 安装 1. 给Schema类传入类型(int.str.float等) 2. 给Schema类传入可调用的对象(函数.带__c ...
- SQL Server外键关系是强制约束,外键值也可以是空(NULL)
在SQL Server中,实际上外键值可不可以为空(NULL),和外键关系是不是强制约束无关. 我们先在SQL Server数据库中建立两张表People和Car,一个People可以有多个Car,所 ...
- HTML 引用大全
路径logo <link rel="icon" href="../framework7-4.4.10/kitchen-sink/core/img/ztjs.png& ...
- 解决 win10 家庭版环境下 MySQL 的ODBC驱动下载及安装
目录 写在前面 下载安装 1.首先,我们需要去官网下载ODBC驱动. 配置 1.打开控制面板.查看方式:选择大图标. 2.选择管理工具的ODBC 数据源(64 位). 3.在驱动程序目录下.我们可以看 ...
- asp.net core 系列之允许跨域访问2之测试跨域(Enable Cross-Origin Requests:CORS)
这一节主要讲如何测试跨域问题 你可以直接在官网下载示例代码,也可以自己写,我这里直接使用官网样例进行演示 样例代码下载: Cors 一.提供服务方,这里使用的是API 1.创建一个API项目.或者直接 ...
- [Leetcode] Binary Tree Pruning
題目是說,如果左右子樹都不存在又自已為0,就去掉那個子樹(設為null) recursive後序,左子樹,右子樹,然後是根 自已同時又是別人的子樹,所以要告訢根自已是不是存在 從a開始,左右子樹都不存 ...
- java 枚举示例
public enum YNEnum { N(0,"否"), Y(1,"是"); private int code; private String name; ...