流媒体Live555(四)——LiveMediaServer流程分析

来源:互联网 发布:舞蹈软件下载 编辑:程序博客网 时间:2024/04/24 06:47

Live555MediaServer

1、初始化

BasicTaskschedular

BasicUsageEnvironment

RTSPServer

|--------new RTSPServer

|------setupOurSocket创建监听客户端连接用的socket

|------turnOnBackgroundhandling(socket)将监听socket加入计划任务,等待连接

2、接受客户端连接 incomingConnectionHandlerRTSP

RTSPServer将监听socket加入计划任务后,调度机制会不断查询,如果收到连接请求,就会调用该回掉函数

Tips:在Live555中监听任务的执行都是通过相应的静态全局回掉函数,在回掉函数内部再强制转换到相应的类函数)

incomingConnectionHandlerRTSP中会clientSocket = accept()得到连接的socket、地址,设置参数等

之后创建一个客户连接管理createNewClientConnection()

|----new RTSPClientConnection

|---setBackgroundHandling将连接的socket加入计划任务

TipsturnonBackgroundHandling只让socket可读,内部会调用setBackgroundHandling进行设置,如需其他属性,如可写、异常等都需要通过setBackgroundHandling设置)

3、响应请求过程

3.1 一般过程

incomingRequestHandler

|---readSocket() 读取数据

|---handleRequestBytes() 解析数据并做相应的处理

|---parseRTSPRequestString() 解析请求

|---handleCmd_XXX() 根据不同的RTSP协议命令去处理

|---send(fResponseBuffer) 构造好回应字段后,发送回应

3.2具体过程

3.2.1 handleCmd_DESCRIBE

handleCmd_DESCRIBE

|---urlTotalSuffix 提取streamName

|---authenticationOK 验证用户,这里只保留了接口,未进行实现

|---fOurServer.lookupServerMediaSession(streamName)

这个用来获取ServerMediaSession,一般不同类型的服务器会有不同的实现策略,如Live555MediaServer只用来流化本地文件,所以有了继承类DynamicRTSPServer,重写lookupServerMediaSession方法,本来找不到session实例会返回NULL,而在这里将查找当前目录下对应的本地文件,然后去创建相应的session,这也就是为什么要将文件与程序放在同一目录下的原因。

这里的ServerMediaSession在创建时会同时添加ServerMediasubsession,因为是服务器,所以一定知道自己应该创建些什么subsession

|---sdpDescription =session->generateSDPDescription() 获取SDP描述信息

|---snprintf() 组建回复字符串

3.2.1.1 generateSDPDescription过程

generateSDPDescription

|---foreach subsession sdpLines =subsession->sdpLines() 获取每个subsessiondsdp描述

|---sdpLines() 过程

|---onDemandServerMediasubsession 为点播式流媒体服务创建的中间继承类,Live555Mediasever中的subsession都继承自此类

|---FrameSource createNewStreamSource 创建一个数据源的Souce

|---RTPSink createNewRTPSink 创建RTPSink

|---setSDPLinesFromRTPSink(source, sink)从临时的sourcesink中获取sdp

TipscreateNewStreamSourcecreateNewRTPSink都是抽象方法,需要子类去实现,之后会从setSDPLinesFromRTPSink(source, sink)中得到sdp信息,从这里也可以看出sdp信息由RTPSink获得。Live555服务器的机制是sinksource中获取数据,创建sink的时候会将source作为参数传入,因为服务器知道创建了什么类型的subSession,所以对一般的媒体信息sink都会具备,唯一需要获取的是getAuxSDPLine()OnDemandServerMediasubsession默认的处理方式是从RTPSink中的auxSDPLine获取,如果没有就返回NULL,对Live555MediaServer来说,传输H264文件时是无法得到spspps信息的,必须通过读取文件,所以在H264subsession中就选择创建SourceSink读取一段信息后解析获得)

3.2.2 handleCmd_SETUP

handleCmd_SETUP

|---sessionID 找一个唯一的sessionID,用于标识当前的subsession

|---fourServer.createNewClientSession(sessionID)

|---clientSession.handleCmd_SETUP() 转到RTSPClientSession中去处理

|---fOurServerMediaSubsession = sms =fourSrever.lookupServerMediasession

|---创建streamState结构

|---fStreamStates = new struct streamState[fNumStreamStates]

|---foreach subSessionfstreamState[i].subsession = subsession subsession装进streamState结构

|---trackIDsubsession->trackID 通过trackID寻找对应的subSession

|---parseTransportHeader 解析Transport参数

|---subsession->getStreamParameters 在这里将建立真正的FrameSourceRTPSink

|---FrameSource *mediaSource = createNewStreamSource()

|---rtoGroupsock = new GroupSock(serverRTPPort)

|---rtcpGroupsock = new Groupsock(serverRTPPort)

|---rtpSink = creatNewRTPSink(rtpGroupsock, mediaSource)

|---streamToken = new StreamState(rtpSink, mediaSource, rtpsock,rtcpsock)

|---fDestinationHashTable->add(sessionId, destination)

3.2.3handleCmd_PLAY

handleCmd_PLAY

|---RTSPClientSession中,处理PLAYPAUSETEARDOWN用同一个函数接口handle_CmdwithinSession,只是在里面又进行了区分

|---找到对应的subsession->startStream()这里将启动流传输数据

|---streamState.startPlaying() 开始传输

|---如果没有fRTCPInstance就创建一个RTCPInstance::createNew(fRTPSink)

|---fRTPgs->addDestination()

|---fRTCPgs->addDestination()

|---fRTPSink->startPlaying()

|---MediaSink::continuePlay() 到这里就是各个子类实现了,纯虚函数

|---MuliFramedRTPSink::continuePlaying()这里针对的是H264文件的解析

|---buildAndSendPacket()

|---准备RTP包头

|---packFrame 打包帧数据

|---分两种情况:一是上一次没打包完,还有数据;二是一个全新的帧

|---对情况二,会调用fSource->getNextFrame()里面加入的回调函数afterGettingFrame,实际是调用sink->afterGettingFrame1

|---最终会依情况打包

|---sendPacketIfNecessary()

sendPacketIfNecessary中会调用fRTPInterface.sendPacket()发送数据,之后安排一个延时任务回调sendNext函数,在sendNext中又会调用buildAndSendPacket,从而形成一个回路来不断发送数据,知道检测到fNoFrameLeft

原创粉丝点击