现在来分析live555中关于H264的处理部分,主要包括从文件中读取数据进行并进行frame(NALU)的分割,然后对frame进行分片,这些工作都是在frame交给RTP sink之前完成的。接着上篇分析文章(RTP的打包与发送)中提到的MultiFramedRTP::packFrame函数进行分析。
getNextFrame是定义在FramedSource中的非虚函数,从source中获取下一个frame,然后调用回调函数afterGettingFrame。afterGettingFrame被定义为静态函数,因为在C++中类成员函数是不能作为回调用函数的。不过这里为什么要用回调函数回?
注意,对于H264来说,上面的fSource并不是MPEGVideoStreamFramer类,因为在 H264VideoRTPSink::continuePlaying()函数中改变了fSource的值。
fSource被指向了H264FUAFragmenter类,这个类主要实现了H264按照RFC3984进行RTP分包,不过这里的实现每个RTP中最多只包含一个NALU,没有实现组合封包的情形。这个类的继承关系如下:H264FUAFragmenter->FramedFilter->FramedSource。很明显,这是一个filter,包装了MPEGVideoStreamFramer类的对像。
先来看来看getNextFrame的实现
上面的函数主要是进行一些成员变量的初始化,获取到的frame需要保存到fTo地址中,然后调用fAfterGettingFunc函数,若文件读取完毕,还需要调用fOnCloseFunc函数。重要的工作还是在doGetNextFrame函数中完成,不过它是定义在FramedSource类中的纯虚函数,需要在子类中重新实现。
现在来看H264FUAFragmenter中对doGetNextFrame的实现
void MultiFramedRTPSink::packFrame() {
if (fOutBuf->haveOverflowData()) {
...
} else {
...
//
//从source中获取下一个frame
//
fSource->getNextFrame(fOutBuf->curPtr(), fOutBuf->totalBytesAvailable(),
afterGettingFrame, this, ourHandleClosure, this);
}
}
getNextFrame是定义在FramedSource中的非虚函数,从source中获取下一个frame,然后调用回调函数afterGettingFrame。afterGettingFrame被定义为静态函数,因为在C++中类成员函数是不能作为回调用函数的。不过这里为什么要用回调函数回?
注意,对于H264来说,上面的fSource并不是MPEGVideoStreamFramer类,因为在 H264VideoRTPSink::continuePlaying()函数中改变了fSource的值。
Boolean H264VideoRTPSink::continuePlaying() {
// First, check whether we have a 'fragmenter' class set up yet.
// If not, create it now:
if (fOurFragmenter == NULL) {
//创建一个辅助类H264FUAFragmenter,用于H264按照RFC3984进行RTP打包
fOurFragmenter = new H264FUAFragmenter(envir(), fSource, OutPacketBuffer::maxSize,
ourMaxPacketSize() - 12/*RTP hdr size*/);
fSource = fOurFragmenter;
}
// Then call the parent class's implementation:
return MultiFramedRTPSink::continuePlaying();
}
fSource被指向了H264FUAFragmenter类,这个类主要实现了H264按照RFC3984进行RTP分包,不过这里的实现每个RTP中最多只包含一个NALU,没有实现组合封包的情形。这个类的继承关系如下:H264FUAFragmenter->FramedFilter->FramedSource。很明显,这是一个filter,包装了MPEGVideoStreamFramer类的对像。
先来看来看getNextFrame的实现
void FramedSource::getNextFrame(unsigned char* to, unsigned maxSize,
afterGettingFunc* afterGettingFunc,
void* afterGettingClientData,
onCloseFunc* onCloseFunc,
void* onCloseClientData) {
// Make sure we're not already being read:
if (fIsCurrentlyAwaitingData) {
envir() << "FramedSource[" << this << "]::getNextFrame(): attempting to read more than once at the same time!\n";
envir().internalError();
}
fTo = to; //buffer地址
fMaxSize = maxSize; //buffer最大长度
fNumTruncatedBytes = 0; // by default; could be changed by doGetNextFrame()
fDurationInMicroseconds = 0; // by default; could be changed by doGetNextFrame()
fAfterGettingFunc = afterGettingFunc; //获取完一个frame后将执行这个函数
fAfterGettingClientData = afterGettingClientData; //这个参数就是MultiFramedRTPSink类型指针
fOnCloseFunc = onCloseFunc;
fOnCloseClientData = onCloseClientData;
fIsCurrentlyAwaitingData = True;
doGetNextFrame();
}
上面的函数主要是进行一些成员变量的初始化,获取到的frame需要保存到fTo地址中,然后调用fAfterGettingFunc函数,若文件读取完毕,还需要调用fOnCloseFunc函数。重要的工作还是在doGetNextFrame函数中完成,不过它是定义在FramedSource类中的纯虚函数,需要在子类中重新实现。
现在来看H264FUAFragmenter中对doGetNextFrame的实现
void H264FUAFragmenter::doGetNextFrame() {
if (fNumValidDataBytes == 1) {
//读取一个新的frame
// We have no NAL unit data currently in the buffer. Read a new one:
fInputSource->getNextFrame(&fInputBuffer[1], fInputBufferSize - 1,
afterGettingFrame, this,
FramedSource::handleClosure, this);
} else {
//
//现在buffer中已经存在NALU数据了,需要考虑三种情况
//1.一个新的NALU,且足够小能投递给RTP sink。
//2.一个新的NALU,但是比RTP sink要求的包大了,投递第一个分片作为一个FU-A packet, 并带上一个额外的头字节。
//3.部分NALU数据,投递下一个分片作为一个FU-A packet,并带上2个额外的头字节。
// We have NAL unit data in the buffer. There are three cases to consider:
// 1. There is a new NAL unit in the buffer, and it's small enough to deliver
// to the RTP sink (as is).
// 2. There is a new NAL unit in the buffer, but it's too large to deliver to
// the RTP sink in its entirety. Deliver the first fragment of this data,
// as a FU-A packet, with one extra preceding header byte.
// 3. There is a NAL unit in the buffer, and we've already delivered some
// fragment(s) of this. Deliver the next fragment of this data,
// as a FU-A packet, with two extra preceding header bytes.
if (fMaxSize < fMaxOutputPacketSize) { // shouldn't happen
envir() << "H264FUAFragmenter::doGetNextFrame(): fMaxSize ("
<< fMaxSize << ") is smaller than expected\n";
} else {
fMaxSize = fMaxOutputPacketSize;
}
fLastFragmentCompletedNALUnit = True; // by default
if (fCurDataOffset == 1) { // case 1 or 2
if (fNumValidDataBytes - 1 <= fMaxSize) { // case 1
//
//情况1, 处理整个NALU
//
memmove(fTo, &fInputBuffer[1], fNumValidDataBytes - 1);
fFrameSize = fNumValidDataBytes - 1;
fCurDataOffset = fNumValidDataBytes;
} else { // case 2
//