live555工作流程简介

基本概念
先来熟悉在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 类的基类。Sink 类实现对数据的处理是通过实现纯虚函数continuePlaying(),通常情况下continuePlaying 调用fSource->getNextFrame 来为Source 设置数据缓冲区,处理数据的回调函数等,fSource是MediaSink 的类型为FramedSource*的类成员。

基本控制流程
基于liveMedia 的应用程序的控制流程如下:
应用程序是事件驱动的,使用如下方式的循环

while (1) {
通过查找读网络句柄的列表和延迟队列(delay queue)来发现需要完成的任务
完成这个任务
}

对于每个sink,在进入这个循环之前,应用程序通常调用下面的方法来启动需要做的生成任务: someSinkObject->startPlaying()。任何时候,一个Module 需要获取数据都通过调用刚好在它之前的那个Module 的FramedSource::getNextFrame() 方法。这是通过纯虚函数FramedSource::doGetNextFrame() 实现的,每一个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. Note that the
flow of data from ‘sources’ to ‘sinks’ happens within each
application, and doesn’t necessarily correspond to the sending or
receiving of network packets. For example, a server application (such
as “testMP3Streamer”) that sends RTP packets will do so using one or
more “RTPSink” modules. These “RTPSink” modules receive data from
other, “*Source” modules (e.g., to read data from a file), and, as a
side effect, transmit RTP packets.

RTSP 连接的建立过程

RTSPServer 类用于构建一个RTSP 服务器,该类同时在其内部定义了一个RTSPClientSession类,用于处理单独的客户会话。
首先创建RTSP 服务器( 具体实现类是DynamicRTSPServer) , 在创建过程中, 先建立Socket(ourSocket) 在TCP 的554 端口进行监听, 然后把连接处理函数句柄(RTSPServer::incomingConnectionHandler)和socket 句柄传给任务调度器(taskScheduler)。
任务调度器把socket 句柄放入后面select 调用中用到的socket 句柄集(fReadSet)中,同时将socket 句柄和incomingConnectionHandler 句柄关联起来。接着,主程序开始进入任务调度器的主循环(doEventLoop),在主循环中调用系统函数select 阻塞,等待网络连接。
当RTSP 客户端输入(rtsp://192.168.1.109/1.mpg)连接服务器时,select 返回对应的scoket,进而根据前面保存的对应关系, 可找到对应处理函数句柄, 这里就是前面提到的incomingConnectionHandler 了。在incomingConnectionHandler 中创建了RTSPClientSession,开始对这个客户端的会话进行处理。

DESCRIBE 请求消息处理过程

RTSP 服务器收到客户端的DESCRIBE 请求后,根据请求URL(rtsp://192.168.1.109/1.mpg),找到对应的流媒体资源, 返回响应消息。live555中的ServerMediaSession 类用来处理会话中描述,它包含多个(音频或视频)的子会话描述(ServerMediaSubsession)。
上节我们谈到RTSP 服务器收到客户端的连接请求,建立了RTSPClientSession 类,处理单独的客户会话。在建立RTSPClientSession 的过程中,将新建立的socket 句柄(clientSocket)和RTSP 请求处理函数句柄RTSPClientSession::incomingRequestHandler 传给任务调度器,由任务调度器对两者进行一对一关联。当客户端发出RTSP 请求后,服务器主循环中的select调用返回,根据socket 句柄找到对应的incomingRequestHandler,开始消息处理。先进行消息的解析,如果发现请求是DESCRIBE 则进入handleCmd_DESCRIBE 函数。根据客户端请求URL 的后缀(例如是1.mpg), 调用成员函数DynamicRTSPServer::lookupServerMediaSession查找对应的流媒信息ServerMediaSession。如果ServerMediaSession 不存在,但是本地存在1.mpg 文件,则创建一个新的ServerMediaSession。在创建ServerMediaSession 过程中,
根据文件后缀.mpg,创建媒体MPEG-1or2的解复用器(MPEG1or2FileServerDemux)。再由MPEG1or2FileServerDemux 创建一个子会话描述MPEG1or2DemuxedServerMediaSubsession。最后由ServerMediaSession 完成组装响应消息中的SDP 信息(SDP 组装过程见下面的描述),然后将响应消息发给客户端,完成一次消息交互。

SDP 消息组装过程

ServerMediaSession 负责产生会话公共描述信息, 子会话描述由MPEG1or2DemuxedServerMediaSubsession 产生。MPEG1or2DemuxedServerMediaSubsession在其父类成员函数OnDemandServerMediaSubsession::sdpLines()中生成会话描述信息。在sdpLines() 实现里面, 创建一个虚构(dummy) 的FramedSource( 具体实现类为MPEG1or2AudioStreamFramer 和MPEG1or2VideoStreamFramer)和RTPSink(具体实现类为MPEG1or2AudioRTPSink 和MPEG1or2VideoRTPSink ) , 最后调用setSDPLinesFromRTPSink(…)成员函数生成子会话描述。

以上涉及到的类以及继承关系:

Medium <- ServerMediaSession
Medium <- ServerMediaSubsession <- OnDemandServerMediaSubsession <-MPEG1or2DemuxedServerMediaSubsession
Medium <- MediaSource <- FramedSouse <- FramedFileSource <- ByteStreamFileSource
Medium <- MediaSource <- FramedSouse <- MPEG1or2DemuxedElementaryStream
Medium <- MPEG1or2FileServerDemux
Medium <- MPEG1or2Demux
Medium <- MediaSource <- FramedSouse <- MPEG1or2DemuxedElementaryStream
Medium <- MediaSource <- FramedSouse <- FramedFilter <- MPEGVideoStreamFramer <-MPEG1or2VideoStreamFramer
Medium <- MediaSink <- RTPSink <- MultiFramedRTPSink <- VideoRTPSink <-MPEG1or2VideoRTPSink

SETUP 和PLAY 请求消息处理过程

前面已经提到RTSPClientSession 类, 用于处理单独的客户会话。其类成员函数handleCmd_SETUP()处理客户端的SETUP 请求。调用parseTransportHeader()对SETUP 请求的传输头解析,调用子会话(这里具体实现类为OnDemandServerMediaSubsession)的getStreamParameters()函数获取流媒体发送传输参数。将这些参数组装成响应消息,返回给客户端。

获取发送传输参数的过程:

调用子会话( 具体实现类MPEG1or2DemuxedServerMediaSubsession) 的createNewStreamSource(…) 创建MPEG1or2VideoStreamFramer,选择发送传输参数,并调用子会话的createNewRTPSink(…)创建MPEG1or2VideoRTPSink。同时将这些信息保存在StreamState 类对象中,用于记录流的状态。
客户端发送两个SETUP 请求,分别用于建立音频和视频的RTP 接收。

PLAY 请求消息处理过程:

RTSPClientSession 类成员函数handleCmd_PLAY()处理客户端的播放请求。首先调用子会话的startStream(), 内部调用MediaSink::startPlaying(…) , 然后是MultiFramedRTPSink::continuePlaying() , 接着调用MultiFramedRTPSink::buildAndSendPacket(…)。buildAndSendPacke 内部先设置RTP 包头,内
部再调用MultiFramedRTPSink::packFrame()填充编码帧数据。
packFrame 内部通过FramedSource::getNextFrame(), 接着MPEGVideoStreamFramer::doGetNextFrame() , 再接着经过MPEGVideoStreamFramer::continueReadProcessing() , FramedSource::afterGetting(…),MultiFramedRTPSink::afterGettingFrame(…),MultiFramedRTPSink::afterGettingFrame1(…) 等一系列繁琐调用,最后到了MultiFramedRTPSink::sendPacketIfNecessary(), 这里才真正发送RTP 数据包。然后是计算下一个数据包发送时间,把MultiFramedRTPSink::sendNext(…)函数句柄传给任务调度器, 作为一个延时事件调度。在主循环中, 当MultiFramedRTPSink::sendNext() 被调度时, 又开始调用MultiFramedRTPSink::buildAndSendPacket(…)开始新的发送数据过程,这样客户端可以源源不断的收到服务器传来的RTP 包了。
发送RTP 数据包的间隔计算方法:

Update the time at which the next packet should be sent, based on the duration of the frame that we just packed into it.

涉及到一些类有:

MPEGVideoStreamFramer: A filter that breaks up an MPEG video elementary stream into headers and frames

MPEG1or2VideoStreamFramer: A filter that breaks up an MPEG 1 or 2 video elementary stream into frames for: Video_Sequence_Header, GOP_Header, Picture_Header

MPEG1or2DemuxedElementaryStream: A MPEG 1 or 2 Elementary Stream, demultiplexed from a Program Stream

MPEG1or2Demux: Demultiplexer for a MPEG 1 or 2 Program Stream 

ByteStreamFileSource: A file source that is a plain byte stream (rather than frames)

MPEGProgramStreamParser: Class for parsing MPEG program stream

StreamParser: Abstract class for parsing a byte stream

StreamState: A class that represents the state of an ongoing stream

你可能感兴趣的:(live555)