美文网首页
Live555 源代码分析(三)

Live555 源代码分析(三)

作者: RonZheng2010 | 来源:发表于2020-09-22 23:18 被阅读0次

1 发送数据帧

1.1 MP3SreamState

MP3StreamState直接读MP3文件。MP3FrameParams保存帧数据。

  • 成员fFid是文件指针。
  • 成员fCurrentFrame存放从文件读出的帧数据。
  • 成员函数assignStream()指定MP3文件作为媒体源。

成员函数findNextHeader()和readFrame()配合使用,可以读取一帧数据。

  • findNextHeader()从文件中找到下一帧的头,读到成员fCurrentFrame中,这是一个MP3FrameParams实例。
  • readFrame()从成员fCurrentFrame得到帧。

1.2 MediaSource

MediaSource定义媒体源访问接口。(从命名看是这样,但实际上它没定义什么。)

FramedSource定义以帧为基础的媒体源接口。

  • 成员函数getNextFrame()得到下一个帧。
    • 调用getNextFrame时需要指定一个回调函数,在得到帧之后会调用它。为了调用方便,getNextFrame()把这个回调函数保存在成员fAfterGettingFunc中。

FramedFileSource是基于文件的FramedSource。

  • 除了定义成员fFid保存文件指针,没有加其他东西。

MP3FileSource是MP3文件的媒体源的访问接口。

  • 成员fStreamState是一个MP3StreamState实例。MP3FileSource将大部分工作委托给它。
  • 成员函数assignStream()绑定一个MP3文件,成员函数initializeStream()初始化媒体源,也就是初始化成员fStreamState。
  • 成员函数seekWithinFile()在文件中定位读位置。

用MP3FileSource::createNew()创建MP3FileSource实例。

  • 调用OpenInputFile()打开MP3文件,文件名是createNew()的参数。它内部调用fopen()。
  • 创建MP3FileSource实例,其中包括创建MP3StreamState实例。
  • 用打开文件的指针调用assignStream(),给MP3StreamState指定媒体源的文件指针。
  • 调用intializeStream()。
    • 调用MP3StreamState::findNextHeader()尝试读一个帧。
    • 调用MP3StreamState::checkForXingHeader()检查读到的帧格式是否正确。

以MP3FileSource为例说明成员函数getNextFrame(),它负责从媒体源中读取下一帧。

  • 调用MP3FileSource::doGetNextFrame()。
    • 调用MP3StreamState::findNextHeader(),从文件中读帧数据到成员fCurrentFrame。
    • 调用MP3StreamState::readFrame(),将成员fCurrentFrame中的数据复制出来。
  • 加入一个延时任务,延时调用FramedSource::afterGetting()。

在延时任务FramedSource::afterGetting()中,

  • 调用成员fAfterGetttingFunc指定的回调函数。这是调用getNextFrame()时指定的回调函数。这样异步通知getNextFrame()的调用者,“读取已经完成”。

1.3 MediaSink

1.3.1 MediaSink接口

MediaSource是数据源,MediaSink则访问这个数据源,对外提供数据。

MediaSink定义了访问接口。

  • startPlaying()开始播放数据。它调用虚拟函数continuePlaying(),派生类可以定制后者。
  • stopPlaying()停止播放。

RTPSink在MediaSink基础上,

  • 增加成员fRTPInterface,以便通过网络发送接收数据。
  • 构造RTPSink时,需要提供GroupSock实例作为参数。这个实例是UDP目标,它用于构造成员fRTPInterface。
  • addStreamSocket()、removeStreamSocket()用于增加和删除TCP目标。

1.3.2 MultiFrameRTPSink

MultiFramedRTPSink实现了continuePlaying()和stopPlaying()。

  • MediaSink定义的成员fSource是FramedSource实例。
  • 构造的帧存放在成员fOutBuf中。

以MultiFrameRTPSink为例,说明成员函数startPlaying()。它开始播放,也就是解析帧并发送给客户端。

  • 调用sourceIsCompatibleWithUs()检查兼容,也就是支持相关函数调用。

  • 调用MutliFrameRTPSink::continuePlaying()。它调用buildAndSendPacket()解析并发送帧。

  • 在buildAndSendPacket()中,构造OutPacketBuffer实例,这是要发送的帧。

    • 先调用OutPacketBuffer::enqueueWord()构造一部分,再调用packFrame()继续构造其他部分。
  • 在packFrame()中,调用FramedSource::getNextFrame()继续构造,这里指定回调函数MultiFramedRTPSink::afterGettingFrame()。

    • 前面说明过getNextFrame()。这个过程是异步进行的,构造全部完成后,在一个被延迟的任务中,调用MultiFramedRTPSink::afterGettingFrame()。

在MultiFramedRTPSink::afterGetttingFrame()中,调用sendPacketIfNecessary()。后者调用RTPInterface::sendPacket()将帧发送出去。

1.3.3 MPEG1or2AudioRTPSink

MultiFramedRTPSink也定义一个虚拟函数doSpecialFramedHandling()。这个函数在afterGettingFrame1()中被调用,以便它的派生类,比如MPEG1or2AudioRTPSink,对构造数据包的过程做更多定制。

1.4 另一种MediaSource

1.4.1 FramedFilter

FramedFilter是另一种MediaSource,更准确地说,是另一种FramedSource。

  • 成员fInputSource指向另外一个FramedSource实例,比如MP3FileSource的实例。它自身不提供数据源,只是对fInputSource数据源做一些变换,再重新提供出去。这个概念类似于Decorate设计模式。(当然不是标准的Decorate,毕竟接口有变动)

1.4.2 Segment和SegmentQueue

Segment用于保存MP3帧的数据。

  • 成员buf保存整个帧,包括帧头和帧数据部分。
  • frameSize、descriptorSize、sizeInfoSize和aduSize是从buf中提取的元数据。

SegmentQueue是一个Segment的容器。

  • 成员s是一个Segment数组。这里当做环形缓存使用。
    • fNextFreeIndex是空闲元素的起始索引,fHeadIndex是已使用元素的起始位置。fTotalDataSize是所有帧数据(不包括帧头)的大小之和。
  • 成员函数enqueueNewSegment()从FramedSource得到segment,并推入环形缓存s[]。headSegment()得到下一个segment。dequeue()则将segment从缓存剔除。
  • fUsingSource是依赖的FramedSource实例。

成员函数enqueueNewSegment()从FramedSource实例中读取帧,写入成员s的下一个空闲元素。

  • 这个FramedSource实例是函数的参数。将它保存在成员fUsingSource中,是为了便于引用。
  • 调用nextFreeSegment()得到下一个空闲的Segment元素。
  • 调用FramedSource::getNextFrame()读下一帧,到刚得到的Segment元素中。指定SegmentQueue::sqAfterGettingSegment()为完成后的回调函数。

读帧完成后,sqAfterGettingSegment()函数被调用。

  • 调用nextFreeSegment()得到刚刚写入的Segment元素。
  • 调用sqAfterGettingCommon(),解析帧,得到帧的元信息,保存在Segment的frameSize等成员中。除此之外,还调用nextIndex()得到下一个空闲位置,将fNextFreeIndex指向它。

1.4.3 ADUFromMP3Source和MP3FromADUSource

MP3FromADUSource和MP3FromADUSource是FramedFilter的两个例子。

ADUFromMP3Source::createNew()创建ADUFromMP3Source实例。

  • 其中创建SegmentQueue实例,也就是它的成员fSegments。

ADUFromMP3Source定制了虚拟成员函数doGetNextFrame()。

  • 调用SegmentQueue::enqueueNewSegment(),从成员fInputSource中读出帧,暂存在成员fSegments中。
  • 调用doGetNextFrame1()。
    • 调用memmove(),从fSegments中读出帧,然后调用SegmentQueue::dequeue(),并从fSegments从移除它。

相关文章

网友评论

      本文标题:Live555 源代码分析(三)

      本文链接:https://www.haomeiwen.com/subject/sodpyktx.html