用live555开发应用程序(一)

转载自:http://www.rosoo.net/a/201210/16304.html,尊重原创!

 liveMedia项目的源代码包括四个基本的库,各种测试代码以及IVE555 Media Server。
一、基本库介绍
四个基本的库分别是UsageEnvironment&TaskScheduler,groupsock,liveMedia,BasicUsageEnvironment。

1、UsageEnvironment
和TaskScheduler类用于事件的调度,实现异步读取事件的句柄的设置以及错误信息的输出。另外,还有一个HashTable类定义了一个通用的
hash表,其它代码要用到这个表。这些都是抽象类,在应用程序中基于这些类实现自己的子类。

2、groupsock类是对网络接口的封装,用于收发数据包。正如名字本身,Groupsock主要是面向多播数据的收发的,它也同时支持单播数据的收发。Groupsock定义了两个构造函数
    Groupsock(UsageEnvironment& env, struct in_addr const& groupAddr, Port port, u_int8_t ttl); 
    Groupsock(UsageEnvironment& env, struct in_addr const& groupAddr, struct in_addr const& sourceFilterAddr,Port port);
前者是用于SIM(source-independent multicast)组,后者用于SSM(source-specific multicast)组。

groupsock库中的Helper例程提供了读写socket等函数,并且屏蔽了不同的操作系统之间的区别,这是在 GroupsockHelper.cpp文件中实现的。

3、liveMedia库中有一系列类,基类是Medium,这些类针对不同的流媒体类型和编码。

4、各种测试代码在testProgram目录下,比如openRTSP等,这些代码有助于理解liveMedia的应用。

5、LIVE555 Media Server是一个纯粹的RTSP服务器。支持多种格式的媒体文件:
      * TS流文件,扩展名ts。
      * PS流文件,扩展名mpg。
      * MPEG-4视频基本流文件,扩展名m4e。
      * MP3文件,扩展名mp3。     
      * WAV文件(PCM),扩展名wav。
      * AMR音频文件,扩展名.amr。
      * AAC文件,ADTS格式,扩展名aac。


用live555开发应用程序

基于liveMedia的程序,需要通过继承UsageEnvironment抽象类和TaskScheduler抽象类,定义相应的类来处理事件调度,数据读写以及错误处理。live项目的源代码里有这些类的一个实现,这就是“BasicUsageEnvironment”库。
BasicUsageEnvironment主要是针对简单的控制台应用程序,利用select实现事件获取和处理。这个库利用Unix或者
Windows的控制台作为输入输出,处于应用程序原形或者调试的目的,可以用这个库用户可以开发传统的运行与控制台的应用。


通过使用自定义的“UsageEnvironment”和“TaskScheduler”抽象类的子类,这些应用程序就可以在特定的环境中运行,不需要做过多的修改。需要指出的是在图形环境(GUI toolkit)下,抽象类 TaskScheduler 的子类在实现
doEventLoop()的时候应该与图形环境自己的事件处理框架集成。

先来熟悉在liveMedia库中Source,Sink以及 Filter等概念。Sink就是消费数据的对象,比如把接收到的数据存储到文件,这个文件就是一个Sink。Source就是生产数据的对象,比如通过
RTP读取数据。数据流经过多个'source'和'sink's,下面是一个示例:

      'source1' -> 'source2'
(a filter) -> 'source3' (a filter) ->
'sink'

从其它Source接收数据的source也叫做"filters"。Module是一个sink或者一个filter。

数据接收的终点是Sink类,MediaSink是所有Sink类的基类。MediaSink的定义如下:

MediaSink
 1 class MediaSink: public Medium {
 2 public:
 3     static Boolean lookupByName(UsageEnvironment& env, char const* sinkName,
 4                                 MediaSink*& resultSink);
 5 
 6     typedef void (afterPlayingFunc)(void* clientData);
 7     Boolean startPlaying(MediaSource& source,
 8                          afterPlayingFunc* afterFunc,
 9                          void* afterClientData);
10     virtual void stopPlaying();
11 
12     // Test for specific types of sink:
13     virtual Boolean isRTPSink() const;
14 
15     FramedSource* source() const {return fSource;}
16 
17 protected:
18     MediaSink(UsageEnvironment& env); // abstract base class
19     virtual ~MediaSink();
20 
21     virtual Boolean sourceIsCompatibleWithUs(MediaSource& source);
22         // called by startPlaying()
23     virtual Boolean continuePlaying() = 0;
24         // called by startPlaying()
25 
26     static void onSourceClosure(void* clientData);
27         // should be called (on ourselves) by continuePlaying() when it
28         // discovers that the source we're playing from has closed.
29 
30     FramedSource* fSource;
31 
32 private:
33     // redefined virtual functions:
34     virtual Boolean isSink() const;
35 
36 private:
37     // The following fields are used when we're being played:
38     afterPlayingFunc* fAfterFunc;
39     void* fAfterClientData;
40 };

Sink 类实现对数据的处理是通过实现纯虚函数continuePlaying(),通常情况下continuePlaying调用
fSource->getNextFrame来为Source设置数据缓冲区,处理数据的回调函数等,fSource是MediaSink的类型为
FramedSource*的类成员;

基于liveMedia的应用程序的控制流程如下:
  应用程序是事件驱动的,使用如下方式的循环      
  while (1) {
          通过查找读网络句柄的列表和延迟队列(delay queue)来发现需要完成的任务          
         完成这个任务     
 }

对于每个sink,在进入这个循环之前,应用程序通常调用下面的方法来启动需要做的生成任务:
  someSinkObject->startPlaying();

任何时候,一个Module需要获取数据都通过调用刚好在它之前的那个Module的FramedSource::getNextFrame()方法。这是通过纯虚函数FramedSource:
oGetNextFrame()实现的,每一个Source module都有相应的实现。

Each 'source' module's implementation of "doGetNextFrame()" works by arranging for an 'after getting' function to be called (from an event handler)

when new data becomes available for the caller.

注意,任何应用程序都要处理从'sources'到'sinks'的数据流,但是并非每个这样的数据流都与从网络接口收发数据相对应。
比如,一个服务器应用程序发送RTP数据包的时候用到一个或多个"RTPSink"
modules。这些"RTPSink" modules以别的方式接收数据,通常是文件 "*Source" modules (e.g., to read data
from a file), and, as a side effect, transmit RTP packets.

原文地址:https://www.cnblogs.com/wyqfighting/p/2875091.html