live555源代码简介

文章出自:http://blog.csdn.net/imliujie/archive/2008/01/30/2072657.aspx

live555源代码简介
liveMedia项目的源代码包括四个基本的库,各种测试代码以及IVE555 Media Server。

四个基本的库分别是UsageEnvironment&TaskScheduler,groupsock,liveMedia,BasicUsageEnvironment。

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

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文件中实现的。

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

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

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的定义如下:

class MediaSink: public Medium {
public:
    static Boolean lookupByName(UsageEnvironment& env, char const* sinkName,
                                MediaSink*& resultSink);

    typedef void (afterPlayingFunc)(void* clientData);
    Boolean startPlaying(MediaSource& source,
                         afterPlayingFunc* afterFunc,
                         void* afterClientData);
    virtual void stopPlaying();

    // Test for specific types of sink:
    virtual Boolean isRTPSink() const;

    FramedSource* source() const {return fSource;}

protected:
    MediaSink(UsageEnvironment& env); // abstract base class
    virtual ~MediaSink();

    virtual Boolean sourceIsCompatibleWithUs(MediaSource& source);
        // called by startPlaying()
    virtual Boolean continuePlaying() = 0;
        // called by startPlaying()

    static void onSourceClosure(void* clientData);
        // should be called (on ourselves) by continuePlaying() when it
        // discovers that the source we're playing from has closed.

    FramedSource* fSource;

private:
    // redefined virtual functions:
    virtual Boolean isSink() const;

private:
    // The following fields are used when we're being played:
    afterPlayingFunc* fAfterFunc;
    void* fAfterClientData;
};

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.

一个简单的RTSP客户端程序
在另一个文章里,给出了这个简单的客户端的程序的代码,可以通过修改Makefile来裁剪liveMedia,使得这个客户端最小化。此客户端已经正常运行。

首先是OPTION
然后是DESCRIBE
      建立Media Session,调用的函数是 MediaSession::createNew,在文件liveMedia/MediaSession.cpp中实现。
      为这个Media Session建立RTPSource,这是通过调用 MediaSubsession::initiate来实现的的,这个方法在liveMedia/MediaSession.cpp中实现。
在然后是SETUP
最后是PLAY

rtp数据的句柄:MultiFramedRTPSource::networkReadHandler 在liveMedia/MultiFramedRTPSource.cpp中
rtcp数据处理的句柄:RTCPInstance::incomingReportHandler 在liveMedia/RTCP.cpp中

rtp数据处理的句柄的设置:MultiFramedRTPSource:oGetNextFrame 在liveMedia/MultiFramedRTPSource.cpp中, 被FileSink::continuePlaying调用在FileSink.cpp中.

rtcp数据处理的句柄设置fRTCPInstance = RTCPInstance::createNew 在/liveMedia/MediaSession.cpp中调用,
createNew调用了构造函数RTCPInstance::RTCPInstance,这个构造函数有如下调用
TaskScheduler::BackgroundHandlerProc* handler = (TaskScheduler::BackgroundHandlerProc*)&incomingReportHandler;  


*********************************************************************************************************************
通过分析live库提供的例子程序OpenRTSP,可以清晰地了解客户端接收来自网络上媒体数据的过程。注意,RTP协议和RTCP协议接收的数据分别是视音频数据和发送/接收状况的相关信息,其中,RTP协议只负责接收数据,而RTCP协议除了接收服务器的消息之外,还要向服务器反馈。
A.        main函数流程
main(int argc,char *argv[])
{
1.            创建BasicTaskScheduler对象
2.            创建BisicUsageEnvironment对象
3.            分析argv参数,(最简单的用法是:openRTSP rtsp://172.16.24.240/mpeg4video.mp4)以便在下面设置一些相关参数
4.            创建RTSPClient对象
5.            由RTSPClient对象向服务器发送OPTION消息并接受回应
6.            产生SDPDescription字符串(由RTSPClient对象向服务器发送DESCRIBE消息并接受回应,根据回应的信息产生SDPDescription字符串,其中包括视音频数据的协议和解码器类型)
7.            创建MediaSession对象(根据SDPDescription在MediaSession中创建和初始化MediaSubSession子会话对象)
8.            while循环中配置所有子会话对象(为每个子会话创建RTPSource和RTCPInstance对象,并创建两个GroupSock对象,分别对应 RTPSource和RTCPInstance对象,把在每个GroupSock对象中创建的socket描述符置入 BasicTaskScheduler::fReadSet中,RTPSource对象的创建的依据是SDPDescription,例如对于MPEG4 文件来说,视音频RTPSource分别对应MPEG4ESVideoRTPSource和MPEG4GenericRTPSource对象。 RTCPInstance对象在构造函数中完成将Socket描述符、处理接收RTCP数据的函数 (RTCPInstance::incomingReportHandler)以及RTCPInstance本身三者绑定在一个 HandlerDescriptor对象中,并置入BasicTaskScheduler::fReadHandler中。完成绑定后会向服务器发送一条消息。)
9.            由RTSPClient对象向服务器发送SETUP消息并接受回应。
10.        while循环中为每个子会话创建接收器(FileSink对象),在FileSink对象中根据子会话的codec等属性缺省产生记录视音频数据的文件名,视音频文件名分别为:video-MP4V-ES-1和audio-MPEG4-GENERIC-2,无后缀名
11.        while循环中为每个子会话的视音频数据装配相应的接收函数,将每个子会话中的RTPSource中的GroupSock对象中的SOCKET描述符,置入BasicTaskScheduler::fReadSet中,并将描述符、处理接收RTP数据的函数 (MultiFramedRTPSource::networkReadHandler)以及RTPSource本身三者绑定在一个 HandlerDescriptor对象中,并置入BasicTaskScheduler::fReadHandler中,并将FileSink的缓冲区和包含写入文件操作的一个函数指针配置给RTPSource对象,这个缓冲区将会在networkReadHandler中接收来自网络的视音频数据(分析和去掉RTP包头的工作由RTPSource完成),而这个函数指针在networkReadHandler中被调用以完成将缓冲区中的数据写入文件。
12.        由RTSPClient对象向服务器发送PLAY消息并接受回应。
13.        进入while循环,调用BasicTaskScheduler::SingleStep()函数接受数据,直到服务器发送TREADOWN消息给客户端,客户端接收到该消息后释放资源,程序退出。

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/455398.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

并发无锁队列学习(单生产者单消费者模型)

1、引言 本文介绍单生产者单消费者模型的队列。依据写入队列的内容是定长还是变长,分为单生产者单消费者定长队列和单生产者单消费者变长队列两种。单生产者单消费者模型的队列操作过程是不须要进行加锁的。生产者通过写索引控制入队操作,消费者通过读索…

ecshop 收货人信息电话必填改为手机必填

首先通过在flow.dwt中,查找flow.php?stepconsignee中的关键字 consignee(结算中心)查找所在模板/Library/consignee.lbi 大概57行 把必填去掉,其次 在js/shopping_flow.js里边注释掉 if (Utils.isEmpty(frm.elements[‘tel’].v…

流媒体传输协议

1.流媒体( Streaming Media) 1.1流媒体概念 流媒体技术是网络技术和多媒体技术发展到一定阶段的产物。术语流媒体既可以指在网上传输连续时基媒体的流式技术,也可以指使用流式技术的连续时基媒体本身。在网上传输音频、视频等多媒体信息目前主要有两种方式:下载和流…

关闭浏览器网页触发事件_浅析浏览器渲染和 script 加载

前言前端代码离不开浏览器环境,理解 js、css 代码如何在浏览器中工作是非常重要的。如何优化渲染过程中的回流,重绘?script 脚本在页面中是怎么个加载顺序?了解这些对前端性能优化起着非常大的作用。借着这篇文章,让自…

Open vSwitch实验常用命令

1. 基本架构 ovs-vsctl: 管理ovsdb-server的配置,提供OVSDB的配置方法,包括创建和删除网桥、端口等; ovs-ofctl: 提供ovs-vswitchd的流表配置方法; ovs-dpctl: 配置OVS内核模块,提供缓存流表的操作方法&#xff1b…

记IOS8中碰到的一个JS bug

IOS8的JS版本过低导致 var id "123"; var temp1 {id, "left": "200"}; // error in IOS8 var temp2 {"id":id, "left": "200"};平时还是多写ES5的代码,es6的语法总能碰到兼容的坑。 改了好几天。…

Emmet的html语法

Emmet的html语法 所有操作按下“tab”键即可瞬间完成 元素 1.在编辑器中输入元素名称,即可自动补全生成 HTML 标签,即使不是标准的 HTML 标签。 2.输入:! 或者 html:5 或者 html:4s 或者 html:4t 将自动补全html基本结构 嵌套操作 1.使用…

RTP Payload Format for H.264 Video

H.264 RTP协议的封装格式rfc3984 英文原版:http://tools.ietf.org/html/rfc3984 部分中文翻译: H.264 视频 RTP 负载格式 1. 网络抽象层单元类型 (NALU) NAL单元1字节包头负载 NALU 头由一个字节组成, 它的语法如下: —————|0|1|2|3|4|5|6|7|------…

js字符串、数组和数字常用方法总结

https://github.com/AnHyun/blog/issues/3 一、string 常用方法: 1.substring(start开始位置的索引,end结束位置索引) 截取的位置不包含结束位置的字符,只写一个参数表示从开始位置截取到最后,输入负值时将负值变为0,哪个较小作为开始位置 va…

Oracle 存储过程错误之PLS-00201: 必须声明标识符

转自:http://blog.csdn.net/u010678947/article/details/20702149 错误: ORA-06550: 第 1 行, 第 7 列: PLS-00201: 必须声明标识符ZUO.PROCE_TESTORA-06550: 第 1 行, 第 7 列: PL/SQL: Statement ignored 解决方法: (1&#x…

mysql中如何把两个查询结果列数不同并成一张表_MySQL

引言本文整理了MySQL相关的知识,方便以后查阅。 基础架构下图是 MySQL 的一个简要架构图,从下图你可以很清晰的看到用户的 SQL 语句在 MySQL 内部是如何执行的。 先简单介绍一下下图涉及的一些组件的基本作用帮助大家理解这幅图。 - 连接器: …

JavaWeb笔记01-XML

今日内容 XML 概念语法解析 XML: 概念: Extensible Markup Language 可扩展标记语言 可扩展:标签都是自定义的.<user><student> 功能 存储数据 配置文件在网络中传输 一个故事 由于浏览器之间的竞争,导致HTML发展的十分不顺利 用户:唉,这怎么报错了呢?…

centos下如何使用sendmail发送邮件

最近在实施服务端日志监控脚本&#xff0c;需要对异常情况发送邮件通知相关责任人&#xff0c;记录下centos通过sendmail发送邮件的配置过程。一. 安装sendmail和mailx1、安装sendmail&#xff1a;1): centos下可以安装命令:yum install -y sendmail service sendmail start yu…

H.263 H.263+ Payload Type

h263 rtp协议封装协议英文版&#xff1a;rfc4629:http://tools.ietf.org/html/rfc4629 以下文章是部分参考翻译&#xff1a; 文章出处&#xff1a; http://blog.csdn.net/zblue78/archive/2009/04/09/4059414.aspxGeneral H.263 Payload Header The H.263 payload header is s…

OC 中 load 方法和 initialize 方法的异同

(void)load; 当类对象被引入项目时, runtime 会向每一个类对象发送 load 消息load 方法会在每一个类甚至分类被引入时仅调用一次,调用的顺序:父类优先于子类, 子类优先于分类load 方法不会被类自动继承 (void)initialize; 也是在第一次使用这个类的时候会调用这个方法 转载于:h…

scrapy框架_Python学习之Scrapy框架

爬虫界江湖地位No.1说起Python&#xff0c;不得不说到它的爬虫应用&#xff0c;由于Python的短小精悍&#xff0c;用它来开发爬虫应用是最合适不过了&#xff0c;基于Python抓取网页的库有很多&#xff0c;例如requests,beatifulsoup等等&#xff0c;但是要说到有哪一个框架&am…

JavaWeb笔记03-Servlet

今日内容 ServletHTTP协议Request Servlet 概念 步骤 执行原理 生命周期 Servlet3.0注解配置 Servlet的体系结构 Servlet – 接口 GenericServlet – 抽象类:将Servlet接口中其他方法做了默认空实现,只将service()方法作为抽象 将来定义Servlet类时候,可以继承Generic…

Android开发中无处不在的设计模式——动态代理模式

继续更新设计模式系列。写这个模式的主要原因是近期看到了动态代理的代码。 先来回想一下前5个模式&#xff1a; - Android开发中无处不在的设计模式——单例模式 - Android开发中无处不在的设计模式——Builder模式 - Android开发中无处不在的设计模式——观察者模式 - A…

用于MPEG-4视听流的RTP负载格式

MPEG-4的rtp协议封装英文原版 RFC 3016&#xff1a;http://www.rfc-editor.org/rfc/rfc3016.txt中文翻译&#xff1a;组织&#xff1a;中国互动出版网&#xff08;http://www.china-pub.com/&#xff09;RFC文档中文翻译计划&#xff08;http://www.china-pub.com/compters/emo…

pycharm python 模板配置_windows下pycharm安装、创建文件、配置默认模板

本文为大家分享了windows下pycharm安装、创建文件、配置默认模板的具体步骤&#xff0c;供大家参考&#xff0c;具体内容如下步骤&#xff1a;下包 —->安装——>创建文件—->定制模板一、下包官方地址这里有企业版和社区版&#xff0c;老司机都知道社区版是免费的&am…