Live555 Streaming Media学习(一)——openRTSP分析

live555是一个开源的流媒体库,支持RTP/RTCP,RTSP,SIP。它提供了一套可供开发调用的库,同时还提供了很多例子,在testProgs文件夹下。开发人员只需要依葫芦画瓢,就可以写出自己的代码。要想学习live555的代码,最好也以这些例子为入口,去分析live555的代码结构。

本文就分析下openRTSP这个例子。在切入主题之前,有一些基础知识需要准备。

select()

select()是一个系统调用,它可以使进程检测同时等待多个I/O设备。当没有设备准备好时,select()阻塞,当任一设备准备好时,select()就返回。其中I/O设备以文件描述符来表示。它的调用形式:

#include<sys/select.h>

#include<sys/time.h>

intselect(int maxfd, fd_set *readfds, fd_set *writefds, fe_set *exceptfds, conststruct timeval *timeout);

 

参数:

maxfd:文件描述符集中要被检测的比特数,这个值必须至少比待检测的最大文件描述符大1

readfds:被读监控的文件描述符集。

writefds被写监控的文件描述符集。

exceptfds:被例外条件监控的文件描述符集。

timeout:定时器,到了指定时间,无论是否有设备准备好,都返回调用。

 

timeout取不同的值,该调用就表现不同的性质:

1.    timeout0,调用立即返回;

2.    timeoutNULLselect()调用就阻塞,直到有文件描述符就绪;

3.    timeout为正整数,就是一般的定时器。

select调用返回时,除了那些已经就绪的描述符外,select将清除readfdswritefdsexceptfds中的所有没有就绪的描述符。

select的返回值有如下情况:

1.正常情况下返回就绪的文件描述符个数;

2.经过了timeout时长后仍无设备准备好,返回值为0

3.如果select被某个信号中断,它将返回-1并设置errnoEINTR

4.如果出错,返回-1并设置相应的errno

 

上面多次提到文件描述符,socket也是可以用文件描述符来表示的,所以select才可以用在网络通信中,判断哪个socket准备好了,有数据可写或可读。所谓文件描述符集,故名思议,就是文件描述符的集合,但是他的元素却不是文件描述符。一个文件描述符(后面以fd代替)对应文件描述符集(后面以fdset代替)中的一位,0代表没有准备好,1代表准备好了。系统提供了四个宏对文件描述符集进行操作:

 

void FD_SET(int fd, fd_set *fdset); // 设置fd_set中对应fd的位(置为1

void FD_CLR(int fd, fd_set *fdset); // 清除fd_set中对应fd的位(置为0

void FD_ISSET(int fd, fd_set *fdset); //检测fd_set中对应fd的位是否被设置

void FD_ZERO(fd_set *fdset); // 设置所有位为0

 

到这里,select()的工作机制就好理解了。它等待fd_set中的某一位被置1,说明该位对应的socket可读(readfds被置位)or可写(writefds被置位)或出现异常(exceptfds被置位)。然后返回,用户就可以根据被置位的情况去做相应的处理。

REF:
http://hi.baidu.com/bimufo/item/139700e4d880cba1c00d755c

rtsp协议

RTSP是由Realnetwork Netscape共同提出的如何有效地在IP网络上传输流媒体数据的应用层协议。他是建立在其他传输协议之上的,它的流传输可能使用RTP协议,控制信息的传输可能使用RTCP协议。具体传输协议可以灵活设置,因为RTSP并不依赖具体的传输机制。

REF:
http://www.cnblogs.com/Jimmly/archive/2009/07/27/1531999.html

http://www.cnblogs.com/wyqfighting/archive/2013/01/24/2874958.html

live555openRTSP

live555官网:http://www.live555.com/liveMedia/

live555代码包含以下几个库:

  Groupsock: 封装了网络接口和套接字,还封装了用于多播的接口。

  liveMedia:以”Medium”类为基类,完成了各种流媒体的编解码。

  UsageEnvironment&TaskScheduler: 提供了一套消息机制,用于分发事件,安排处理函数。

BasicUsageEnvironment:UsageEnvironment&TaskScheduler的实现类,使用select()来读取和处理事件,实现简单的控制台程序。

 

openRTSP是testProgs中一个例子,它从头到尾都是一个单线程。它的入口在playCommon::main()中 。它的流程:

1.       create BasicUsageEnvironmentand BasicTaskScheculer

2.       处理输入参数,初始化环境变量

3.       CreateClient

4.       调用continueAfterClientCreation1() à getOption()à sendOptionsCommand()à sendRequest()à 发送OPTIONS消息,把回调加到事件队列中,同时把对应的socket加到文集描述符集中。

5.       调用taskScheduler().doEventLoop(),进入消息循环。

6.       doEventLoop()的处理函数在singleStep()中,它调用select()进入阻塞,等待有socket准备好。一旦文件描述符集中有socket可读或者可写,就调用该socket对应的回调函数。在客户端开始接收视频流之前,所有的回调最终都是做了两件事a) sendRequest, b) 把回调加到事件对列中。之后又进入select()阻塞状态,等待下一个socket准备好。

整个事件驱动机制就是在doEventLoop()中完成的。在发完OPTIONS消息之后,客户端的流程是这样的:

1.       call getOption()to send OPTIONS request. Callback is continueAfterOPTIONS().

2.       Receive OPTIONSresponse, call  continueAfterOPTIONS().  This callback call getSDPDescribe() to send DESCRIBErequest.  Callback iscontinueAfterDESCRIBE().

3.       Receive DESCRIBEresponse, call continueAfterDESCRIBE() to create Media session and subsession.Then call setupStream(), send SETUP message to setup each subsession.  Callback is continueAfterSETUP().

4.       ReceiveSETUP response, call setupStream() again. If there’s subsession havn’t beensetup,  send SETUP message to setupanother subsession until there no subsession left.

5.       Then createoutput file(the sink) which will be used to save streaming data. CallStartPlayingSession() , send PLAY message. Callback is continueAfterPLAY().

6.       Recevie PLAYresponse, call continueAfterPLAY() to save streaming data, waiting for nextframe coming, call continueAfterPLAY…

基本流程就是遵循RTSP协议,发送OPTIONS消息,server端响应 à 发送DESCRIBE消息,server端响应  à  发送SETUP消息,server端响应  à  发送PLAY 消息,server端响应 à开始接收streaming data.

这里有几个问题比较不容易理解:

1.       一般的消息循环机制是一个线程处理queue中的消息,其他线程往queue里面发送消息。但是openRTSP中从头到尾都只有一个线程,所以他的消息机制有点特别。它使用select()等待有socket准备好,一旦有可读或者可写的socket,他不是把处理函数扔给其他线程去处理,而是自己去处理,处理完了之后,再回到select()去等待。由于RTSP协议的特点,允许这个消息机制正确运行,但是,如果客户端cpu的处理能力不够,这种机制很容易导致丢包现象的发生。

2.       一次singleStep()循环负责处理三种类型的事件,HandlerSet中的事件(通过BasicTaskScheduler::setBackgroundHandling()加入的),fTriggeredEventHandlers中的事件,以及DelayQueue中的事件。

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值