您的位置:首页 > 其它

live555 流程重要函数整理

2012-04-09 14:09 253 查看
http://hi.baidu.com/amixyue/blog/item/df5d0a37a87f96305ab5f50e.html

live555 流程重要函数整理

2010-02-02 21:54
服务器启动

DynamicRTSPServer::createNew(*env, rtspServerPortNum, authDB);

env->taskScheduler().doEventLoop()

有链接了!

select(fMaxNumSockets, &readSet, NULL, NULL,&tv_timeToDelay)

创建好了RTSPClientSession

void RTSPServer::RTSPClientSession::incomingRequestHandler(void* instance, int /*mask*/)

void RTSPServer::RTSPClientSession::incomingRequestHandler1()

重点在于 对 DESCRIBE 信令的处理:

void RTSPServer::RTSPClientSession::handleCmd_DESCRIBE(char const* cseq, char const* urlSuffix,

char const* fullRequestStr)

需要一次 rtsp 会话了:

ServerMediaSession* session = fOurServer.lookupServerMediaSession(urlSuffix);

{

当前目录下检查文件

FILE* fid = fopen(streamName, "rb");

再看看对这个 streamName ,RTSPServer 是不是已经有 SMS

(ServerMediaSession*)(fServerMediaSessions->Lookup(streamName))

没有,就创建吧!

这里,还可以看出 RTSPClientSession 是标志一次 RSTP 会话,而 SMS 则是一种媒体会话

sms = createNewSMS(envir(), streamName, fid);

添加对应的 subsession

MPEG4VideoFileServerMediaSubsession::createNew(env, fileName, reuseSource)

FileServerMediaSubsession(env, fileName, reuseFirstSource)

OnDemandServerMediaSubsession(env, reuseFirstSource)

看到了吧,OnDemandServerMediaSubsession 与具体媒体文件无关的,很抽象的东东,但和 sdp 很有联系,它有很长的初始化列表

ServerMediaSubsession(env),=>{

Medium(env),

fIsSSM(isSSM),

fSubsessionsHead(NULL),

fSubsessionsTail(NULL),

fSubsessionCounter(0),

fReferenceCount(0),

fDeleteWhenUnreferenced(False)

}//也是很长的初始化列表

fSDPLines(NULL), => 这个就是 SDP

fReuseFirstSource(reuseFirstSource),

fInitialPortNum(initialPortNum),

fLastStreamToken(NULL)

}

以上都是为了获得 SDP

sdpDescription = session->generateSDPDescription()

这时,因为 subsession 是链表的原因,因此,遍历链表 ,得到每个 subsession 的 sdpLines

sdpLines = subsession->sdpLines()

用 float dur = duration() 获得播放的帧数 range ,还有等等

整个 sdp 构成就是:

fCreationTime.tv_sec, fCreationTime.tv_usec, // o= <session id>

1, // o= <version> // (needs to change if params are modified)

ipAddressStr, // o= <address>

fDescriptionSDPString, // s= <description>

fInfoSDPString, // i= <info>

libNameStr, libVersionStr, // a=tool:

sourceFilterLine, // a=source-filter: incl (if a SSM session)

rangeLine, // a=range: line

fDescriptionSDPString, // a=x-qt-text-nam: line

fInfoSDPString, // a=x-qt-text-inf: line

fMiscSDPLines,// miscellaneous session SDP lines (if any)

还有最重要的 每个subsession->sdpLines()

这个就是来源于 OnDemandServerMediaSubsession::sdpLines() 嗯嗯,一个和具体文件无关的 OnDemandServerMediaSubsession,,但是它里面却是通过 dummy 的FramedSource 和 RTPSink 在实际实现的时候,调用具体的实现,如 MPEG4ESVideoStreamFramer 等获取 sdpline。如下:

OnDemandServerMediaSubsession::sdpLines() {

把 媒体文件 二进制化成 ByteStreamFileSource ,再用它来创建 MPEG4VideoStreamFramer ,这个在另一篇博文中提过,是用来产生 头和帧 的。

但是,这个 estBitrate 倒是不懂怎么设定的??????

FramedSource* inputSource = createNewStreamSource(0, estBitrate);

unsigned char rtpPayloadType = 96 + trackNumber()-1; // if dynamic

这个是关于 Sink 的创建

RTPSink* dummyRTPSink = createNewRTPSink(&dummyGroupsock, rtpPayloadType, inputSource);

用以上的信息产生 SDP

setSDPLinesFromRTPSink(dummyRTPSink, inputSource, estBitrate);

如果说之前那些应该是整个会话的信息,而下面是对应媒体 subsession tarck信息:

mediaType, // m= <media>

fPortNumForSDP, // m= <port>

rtpPayloadType, // m= <fmt list>

ipAddressStr, // c= address

estBitrate, // b=AS:<bandwidth>

rtpmapLine, // a=rtpmap:... (if present)

rangeLine, // a=range:... (if present)

auxSDPLine, // optional extra SDP line

trackId()); // a=control:<track-id>

}

备注:如果你要做 264 的话,要注意264 在 Sink 的初始化的时候,和 Mpeg4 不同

264 设了 unsigned profile_level_id, char const* sprop_parameter_sets_str ,其实这两个参数我现在还不是很懂,要查下 码流 才能确定

》》》》》求助《《《《《《《《《 如果有知道的,希望能留言告诉我。

auxSDPLine, // optional extra SDP line 这一行的 auxSDPLine 就是 调用OnDemandServerMediaSubsession::getAuxSDPLine 得到的,而它的信息来自于 sink 的getAuxSDPLine ,而这个东东,对应于264 ,就是上面两个参数,所以很重要的。

》》》》》求助《《《《《《《《《这两个参数有多重要,希望知道的各位大虾能留言给我

ok ,到此为止 DESCRIBE 分析完毕

接着就是 handleCmd_SETUP

fStreamStates = new struct streamState[fNumStreamStates];

记录 SMS 下的subsession 的信息 ,这里为什么要记录? 我认为是这样的:Server 对每个 streamName 有且仅有维持一个 SMS ,那对每个 Client 如何记录状态呢,就是靠这个 fStreamStates 。

而且感觉这个是整个 SETUP 的重点,同时,它从 subsession 中取信息 ,

subsession->getStreamParameters(fOurSessionId, fClientAddr.sin_addr.s_addr,

clientRTPPort, clientRTCPPort,

tcpSocketNum, rtpChannelId, rtcpChannelId,

destinationAddress, destinationTTL, fIsMulticast,

serverRTPPort, serverRTCPPort,

fStreamStates[streamNum].streamToken);

获取流媒体发送传输参数。将这些参数组 装成响应消息,返回给客户端

获取发送传输参数的过程:调用子会话(如具体实现类MPEG1or2DemuxedServerMediaSubsession)的 createNewStreamSource(...)创建MPEG1or2VideoStreamFramer,选择发送传输参数,并调用子会话的 createNewRTPSink(...)创建MPEG1or2VideoRTPSink。同时将这些信息保存在StreamState类对象中,用于 记录流的状态 ( A class that represents the state of an ongoing
stream)。

从 StreamState 的成员变量都可以看出一些端倪:

{

OnDemandServerMediaSubsession& fMaster;

Boolean fAreCurrentlyPlaying;

unsigned fReferenceCount;

Port fServerRTPPort, fServerRTCPPort;

RTPSink* fRTPSink;

BasicUDPSink* fUDPSink;

float fStreamDuration;

unsigned fTotalBW; RTCPInstance* fRTCPInstance;

FramedSource* fMediaSource;

Groupsock* fRTPgs; Groupsock* fRTCPgs;

}

PLAY

fStreamStates[i].subsession->startStream(fOurSessionId,

fStreamStates[i].streamToken,

(TaskFunc*)noteClientLiveness,

this,

rtpSeqNum,

rtpTimestamp);

MediaSink::startPlaying(...)

MultiFramedRTPSink::continuePlaying()

MultiFramedRTPSink::buildAndSendPacket(...){

buildAndSendPacke内部先设置RTP包头, 内部再调用MultiFramedRTPSink::packFrame()填充编码帧数据{

FramedSource::getNextFrame()

MPEGVideoStreamFramer::doGetNextFrame()

MPEGVideoStreamFramer::continueReadProcessing()

FramedSource::afterGetting(...)

MultiFramedRTPSink::afterGettingFrame(...),

MultiFramedRTPSink::afterGettingFrame1(...)

...

MultiFramedRTPSink::sendPacketIfNecessary(),

}

}

然后是计算下一个数据包发送时间,把MultiFramedRTPSink::sendNext(...)函数句柄传给任务调度器,作为一个延时事件调度。在主循环中,当MultiFramedRTPSink::sendNext()被调度时,又开始调用 MultiFramedRTPSink::buildAndSendPacket(...)开始新的发送数据过程,这样客户端可以源源不断的收到服务器传来的RTP包了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: