在上篇中分析了setup建立的过程,现在再来看看sink建立的过程。continueAfterSETUP之后直接就进入到了setupStreams。这里根据subsession->codecName()建立对应的fileSink。
fileSink = H264VideoFileSink::createNew(*env, outFileName,
subsession->fmtp_spropparametersets(),
fileSinkBufferSize, oneFilePerFrame);
这里以h264为例。fileSink创建的过程就一一分析,接着往下看。
subsession->sink->startPlaying(*(subsession->readSource()),
subsessionAfterPlaying,
subsession);
Boolean MediaSink::startPlaying(MediaSource& source,
afterPlayingFunc* afterFunc,
void* afterClientData) {
// Make sure we're not already being played:
if (fSource != NULL) {
envir().setResultMsg("This sink is already being played");
return False;
}
// Make sure our source is compatible:
if (!sourceIsCompatibleWithUs(source)) {
envir().setResultMsg("MediaSink::startPlaying(): source is not compatible!");
return False;
}
fSource = (FramedSource*)&source;
fAfterFunc = afterFunc;
fAfterClientData = afterClientData;
return continuePlaying();
}
这里的fSource就是fReadSource,也就是在上一篇中建立的H264VideoRTPSource。这里还做了其他一些赋值,接着就是执行continuePlaying在MediaSink中为虚函数,但是在FileSink中定义。
Boolean FileSink::continuePlaying() {
if (fSource == NULL) return False;
fSource->getNextFrame(fBuffer, fBufferSize,
afterGettingFrame, this,
onSourceClosure, this);
return True;
}
getNextFrame在FramedSource中定义,主要是把fBuffer赋值给fTo,把afterGettingFrame赋给fAfterGettingFrame。之后就是执行doGetNextFrame,这个在H264VideoRTPSource的父类MultiFrameRTPSource中定义。
void MultiFramedRTPSource::doGetNextFrame() {
if (!fAreDoingNetworkReads) {
// Turn on background read handling of incoming packets:
fAreDoingNetworkReads = True;
TaskScheduler::BackgroundHandlerProc* handler
= (TaskScheduler::BackgroundHandlerProc*)&networkReadHandler;
fRTPInterface.startNetworkReading(handler);
}
fSavedTo = fTo;
fSavedMaxSize = fMaxSize;
fFrameSize = 0; // for now
fNeedDelivery = True;
doGetNextFrame1();
}
这里的fRTPInterface是在建立H264VideoRTPSource在初始化父类RTPSource时初始化的,
RTPSource::RTPSource(UsageEnvironment& env, Groupsock* RTPgs,
unsigned char rtpPayloadFormat,
u_int32_t rtpTimestampFrequency)
: FramedSource(env),
fRTPInterface(this, RTPgs),
fCurPacketHasBeenSynchronizedUsingRTCP(False),
fLastReceivedSSRC(0),
fRTPPayloadFormat(rtpPayloadFormat),
fTimestampFrequency(rtpTimestampFrequency),
fSSRC(our_random32()) {
fReceptionStatsDB = new RTPReceptionStatsDB();
}
这里的参数RTPgs是fRTPSocket,来看看他的startNetWorkReading
void RTPInterface
::startNetworkReading(TaskScheduler::BackgroundHandlerProc* handlerProc) {
// Normal case: Arrange to read UDP packets:
envir().taskScheduler().
turnOnBackgroundReadHandling(fGS->socketNum(), handlerProc, fOwner);
// Also, receive RTP over TCP, on each of our TCP connections:
fReadHandlerProc = handlerProc;
for (tcpStreamRecord* streams = fTCPStreams; streams != NULL;
streams = streams->fNext) {
// Get a socket descriptor for "streams->fStreamSocketNum":
SocketDescriptor* socketDescriptor = lookupSocketDescriptor(envir(), streams->fStreamSocketNum);
// Tell it about our subChannel:
socketDescriptor->registerRTPInterface(streams->fStreamChannelId, this);
}
}
这里的turnOnBackgroundReadHandling在UsageEnvironment中定义
void turnOnBackgroundReadHandling(int socketNum, BackgroundHandlerProc* handlerProc, void* clientData) {
setBackgroundHandling(socketNum, SOCKET_READABLE, handlerProc, clientData);
}
但是setBackgroundHandling在UsageEnvironment中为纯虚函数,在BasicTaskScheduler中有定义在前面的分析见过这个方法,这里就是将SOCKET_READABLE加入到
socket的set集中,然后将handlerProc即networkReadHandler加入到fHandlers中,这样在eventloop中的singleSetup的时候有在socketNum上的read就会监听到。而这里的fGS->socketNum()就是H264VideoRTPSource的时候传入的,即在上一篇inital的时候创建的。
我们再来看看rtp数据接收到后处理的方法。
void MultiFramedRTPSource::networkReadHandler(MultiFramedRTPSource* source, int /*mask*/) {
source->networkReadHandler1();
}
可以看到networkReadHandler1中主要是对rtp的拆包处理
void MultiFramedRTPSource::networkReadHandler1() {
BufferedPacket* bPacket = fPacketReadInProgress;
if (bPacket == NULL) {
// Normal case: Get a free BufferedPacket descriptor to hold the new network packet:
bPacket = fReorderingBuffer->getFreePacket(this);
}
// Read the network packet, and perform sanity checks on the RTP header:
Boolean readSuccess = False;
do {
Boolean packetReadWasIncomplete = fPacketReadInProgress != NULL;
if (!bPacket->fillInData(fRTPInterface, packetReadWasIncomplete)) break;
if (packetReadWasIncomplete) {
// We need additional read(s) before we can process the incoming packet:
fPacketReadInProgress = bPacket;
return;
} else {
fPacketReadInProgress = NULL;
}
#ifdef TEST_LOSS
setPacketReorderingThresholdTime(0);
// don't wait for 'lost' packets to arrive out-of-order later
if ((our_random()%10) == 0) break; // simulate 10% packet loss
#endif
// Check for the 12-byte RTP header:
if (bPacket->dataSize() < 12) break;
unsigned rtpHdr = ntohl(*(u_int32_t*)(bPacket->data())); ADVANCE(4);
Boolean rtpMarkerBit = (rtpHdr&0x00800000) != 0;
unsigned rtpTimestamp = ntohl(*(u_int32_t*)(bPacket->data()));ADVANCE(4);
unsigned rtpSSRC = ntohl(*(u_int32_t*)(bPacket->data())); ADVANCE(4);
// Check the RTP version number (it should be 2):
if ((rtpHdr&0xC0000000) != 0x80000000) break;
// Skip over any CSRC identifiers in the header:
unsigned cc = (rtpHdr>>24)&0xF;
if (bPacket->dataSize() < cc) break;
ADVANCE(cc*4);
// Check for (& ignore) any RTP header extension
if (rtpHdr&0x10000000) {
if (bPacket->dataSize() < 4) break;
unsigned extHdr = ntohl(*(u_int32_t*)(bPacket->data())); ADVANCE(4);
unsigned remExtSize = 4*(extHdr&0xFFFF);
if (bPacket->dataSize() < remExtSize) break;
ADVANCE(remExtSize);
}
// Discard any padding bytes:
if (rtpHdr&0x20000000) {
if (bPacket->dataSize() == 0) break;
unsigned numPaddingBytes
= (unsigned)(bPacket->data())[bPacket->dataSize()-1];
if (bPacket->dataSize() < numPaddingBytes) break;
bPacket->removePadding(numPaddingBytes);
}
// Check the Payload Type.
if ((unsigned char)((rtpHdr&0x007F0000)>>16)
!= rtpPayloadFormat()) {
break;
}
// The rest of the packet is the usable data. Record and save it:
if (rtpSSRC != fLastReceivedSSRC) {
// The SSRC of incoming packets has changed. Unfortunately we don't yet handle streams that contain multiple SSRCs,
// but we can handle a single-SSRC stream where the SSRC changes occasionally:
fLastReceivedSSRC = rtpSSRC;
fReorderingBuffer->resetHaveSeenFirstPacket();
}
unsigned short rtpSeqNo = (unsigned short)(rtpHdr&0xFFFF);
Boolean usableInJitterCalculation
= packetIsUsableInJitterCalculation((bPacket->data()),
bPacket->dataSize());
struct timeval presentationTime; // computed by:
Boolean hasBeenSyncedUsingRTCP; // computed by:
receptionStatsDB()
.noteIncomingPacket(rtpSSRC, rtpSeqNo, rtpTimestamp,
timestampFrequency(),
usableInJitterCalculation, presentationTime,
hasBeenSyncedUsingRTCP, bPacket->dataSize());
// Fill in the rest of the packet descriptor, and store it:
struct timeval timeNow;
gettimeofday(&timeNow, NULL);
bPacket->assignMiscParams(rtpSeqNo, rtpTimestamp, presentationTime,
hasBeenSyncedUsingRTCP, rtpMarkerBit,
timeNow);
if (!fReorderingBuffer->storePacket(bPacket)) break;
readSuccess = True;
} while (0);
if (!readSuccess) fReorderingBuffer->freePacket(bPacket);
doGetNextFrame1();
// If we didn't get proper data this time, we'll get another chance
}
分析玩rtp头等工作后就是doGetNextFrame1