live555源码分析----H264的数据处理-2

标签:
live555流媒体it |
分类: 流媒体 |
H264FUAFragmenter::doGetNextFrame函数第一次执行时,执行条件1,需要调用
MPEGVideoStreamFramer::doGetNextFrame读取一个新的frame,获取frame的具体过程稍后再分析。现在先看获取frame之后的工作,afterGettingFrame函数
没什么好说的,再看afterGettingFrame1函数
上面的代码首先记录几个数据到成员变量中,fNumValidDataBytes很重要,表示读取到的frame长度+1。然后又一次调用了H264FUAFragmenter::doGetNextFrame(),这里将进入H264FUAFragmenter::doGetNextFrame函数中第二个条件分支,这种循环调用很容易把人弄迷糊了。
在H264FUAFragmenter::doGetNextFrame()最后调用了
FramedSource::afterGetting
上面的代码主要是调用了FramedSource::getNextFrame函数中传递下来的回调函数,这个回调函数就是MultiFramedRTPSink::afterGettingFrame,处理过程在上一篇文章"RTP的打包与发送"中已经分析过了。
现在来看MPEGVideoStreamFramer::doGetNextFrame获取Frame的过程。继承关系:H264VideoStreamFramer->MPEGVideoStreamFramer->FramedFilter->FramedSource。在继承路径中存在FrameFilter,这说明H264VideoStreamFramer包装了其它source(包装的是读取文件的字节流source)。doGetNextFrame函数首先在MPEGVideoStreamFramer中实现。
这里的MPEGVideoStreamFramer::fParser,是一个MPEGVideoStreamParser类型指针,作为语法分析器。再来看continueReadProcessing函数
函数中首先调用了MPEGVideoStreamParser::parse函数,将一个完整的Frame分析出来,并copy到了fTo(fTo就是OutPacketBuffer中的缓冲区)中,这其中肯定也实现了从文件中读取数据的过程。这里的fNumTruncatedBytes变量需要注意,fNumTruncatedBytes>0的话,表明Frame的实际长度大于fTo的最大长度,这将导致数据丢失,这时就要考虑增加缓冲区的长度了。成功获取一个Frame后,将调用afterGetting函数处理后续工作。
先来看parse函数,parse是定义在MPEGVideoStreamParser中的纯虚函数,在子类H264VideoStreamParser中实现。parse主要是从文件的字节流中,分离出一个个的Frame,对于H264而言其实就是对一个个的NALU。*.264文件的格式非常简单,每个NALU以
0x00000001 作为起始符号(中间的NALU也可以以0x000001作为起始符),顺序存放。
[cpp] view
plaincopyprint?
-
void
H264FUAFragmenter::afterGettingFrame( void*clientData, unsigned frameSize, -
unsigned numTruncatedBytes, -
struct timeval presentationTime, -
unsigned durationInMicroseconds) { -
H264FUAFragmenter* fragmenter = (H264FUAFragmenter*)clientData; -
fragmenter->afterGettingFrame1(frameSize, numTruncatedBytes, presentationTime, -
durationInMicroseconds); -
}
没什么好说的,再看afterGettingFrame1函数
[cpp] view
plaincopyprint?
-
void
H264FUAFragmenter::afterGettingFrame1(unsigned frameSize, -
unsigned numTruncatedBytes, -
struct timeval presentationTime, -
unsigned durationInMicroseconds) { -
fNumValidDataBytes += frameSize; //保存读到的frame长度 -
fSaveNumTruncatedBytes = numTruncatedBytes; -
fPresentationTime = presentationTime; -
fDurationInMicroseconds = durationInMicroseconds; -
-
-
// Deliver data to the client: -
doGetNextFrame(); -
}
[cpp] view
plaincopyprint?
-
void
FramedSource::afterGetting(FramedSource* source) { -
source->fIsCurrentlyAwaitingData = False; //表示已经获取到数据了,处于非等待状态 -
// indicates that we can be read again -
// Note that this needs to be done here, in case the "fAfterFunc" -
// called below tries to read another frame (which it usually will) -
-
-
//通过回调用进行后续处理 -
if (source->fAfterGettingFunc != NULL) { -
(*(source->fAfterGettingFunc))(source->fAfterGettingClientData, -
source->fFrameSize, source->fNumTruncatedBytes, -
source->fPresentationTime, -
source->fDurationInMicroseconds); -
} -
}
[cpp] view
plaincopyprint?
-
void
MPEGVideoStreamFramer::doGetNextFrame() { -
fParser->registerReadInterest(fTo, fMaxSize); //将目的buffer信息注册到语法分析类中 -
continueReadProcessing(); //继续进行读数据 -
}
[cpp] view
plaincopyprint?
-
void
MPEGVideoStreamFramer::continueReadProcessing() { -
unsigned acquiredFrameSize = fParser->parse(); //文件的语法分析(即demux) -
if (acquiredFrameSize > 0) { -
// We were able to acquire a frame from the input. -
// It has already been copied to the reader's space. -
fFrameSize = acquiredFrameSize; -
fNumTruncatedBytes = fParser->numTruncatedBytes(); -
-
-
// "fPresentationTime" should have already been computed. -
-
-
// Compute "fDurationInMicroseconds" now: -
fDurationInMicroseconds -
= (fFrameRate == 0.0 || ((int)fPictureCount) < 0) ? 0 -
: (unsigned)((fPictureCount*1000000)/fFrameRate); -
#ifdef
DEBUG -
fprintf(stderr, "%d bytes ,@%u.d, fDurationInMicroseconds: %d ((%d*1000000)/%f)\n" acquiredFrameSize, fPresentationTime.tv_sec, fPresentationTime.tv_usec, fDurationInMicroseconds, fPictureCount, fFrameRate); -
#endif
-
fPictureCount = 0; -
-
// -
//调用自身的afterGetting函数,因为这不一个"leaf" source, 所以可能直接调用, -
//而不用担心出现无限递归 -
// -
// Call our own 'after getting' function. Because we're not a 'leaf' -
// source, we can call this directly, without risking infinite recursion. -
afterGetting(this); -
} else { -
// We were unable to parse a complete frame from the input, because: -
// - we had to read more data from the source stream, or -
// - the source stream has ended. -
} -
}