⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 quicktimefilesink.cpp

📁 流媒体传输协议的实现代码,非常有用.可以支持rtsp mms等流媒体传输协议
💻 CPP
📖 第 1 页 / 共 5 页
字号:
    SubsessionBuffer* tmp = fPrevBuffer; // assert: != NULL    fPrevBuffer = fBuffer;    fBuffer = tmp;  }  fBuffer->reset(); // for the next input  // Now, try getting more frames:  fOurSink.continuePlaying();}void SubsessionIOState::useFrame(SubsessionBuffer& buffer) {  unsigned char* const frameSource = buffer.dataStart();  unsigned const frameSize = buffer.bytesInUse();  struct timeval const& presentationTime = buffer.presentationTime();  unsigned const destFileOffset = ftell(fOurSink.fOutFid);  unsigned sampleNumberOfFrameStart = fQTTotNumSamples + 1;  // If we're not syncing streams, or this subsession is not video, then  // just give this frame a fixed duration:  if (!fOurSink.fSyncStreams      || fQTcomponentSubtype != fourChar('v','i','d','e')) {    unsigned const frameDuration = fQTTimeUnitsPerSample*fQTSamplesPerFrame;    fQTTotNumSamples += useFrame1(frameSize, presentationTime,				  frameDuration, destFileOffset);  } else {    // For synced video streams, we use the difference between successive    // frames' presentation times as the 'frame duration'.  So, record    // information about the *previous* frame:    struct timeval const& ppt = fPrevFrameState.presentationTime; //abbrev    if (ppt.tv_sec != 0 || ppt.tv_usec != 0) {      // There has been a previous frame.      double duration = (presentationTime.tv_sec - ppt.tv_sec)	+ (presentationTime.tv_usec - ppt.tv_usec)/1000000.0;      if (duration < 0.0) duration = 0.0;      unsigned frameDuration	= (unsigned)((2*duration*fQTTimeScale+1)/2); // round      unsigned numSamples	= useFrame1(fPrevFrameState.frameSize, ppt,		    frameDuration, fPrevFrameState.destFileOffset);      fQTTotNumSamples += numSamples;      sampleNumberOfFrameStart = fQTTotNumSamples + 1;    }    // Remember the current frame for next time:    fPrevFrameState.frameSize = frameSize;    fPrevFrameState.presentationTime = presentationTime;    fPrevFrameState.destFileOffset = destFileOffset;  }  // Write the data into the file:  fwrite(frameSource, 1, frameSize, fOurSink.fOutFid);  // If we have a hint track, then write to it also:  if (hasHintTrack()) {    // Because presentation times are used for RTP packet timestamps,    // we don't starting writing to the hint track until we've been synced:    if (!fHaveBeenSynced) {      fHaveBeenSynced	= fOurSubsession.rtpSource()->hasBeenSynchronizedUsingRTCP();    }    if (fHaveBeenSynced) {      fHintTrackForUs->useFrameForHinting(frameSize, presentationTime,					  sampleNumberOfFrameStart);    }  }}void SubsessionIOState::useFrameForHinting(unsigned frameSize,					   struct timeval presentationTime,					   unsigned startSampleNumber) {  // At this point, we have a single, combined frame - not individual packets.  // For the hint track, we need to split the frame back up into separate packets.  // However, for some RTP sources, then we also need to reuse the special  // header bytes that were at the start of each of the RTP packets.  Boolean hack263 = strcmp(fOurSubsession.codecName(), "H263-1998") == 0;  Boolean hackm4a_generic = strcmp(fOurSubsession.mediumName(), "audio") == 0    && strcmp(fOurSubsession.codecName(), "MPEG4-GENERIC") == 0;  Boolean hackm4a_latm = strcmp(fOurSubsession.mediumName(), "audio") == 0    && strcmp(fOurSubsession.codecName(), "MP4A-LATM") == 0;  Boolean hackm4a = hackm4a_generic || hackm4a_latm;  Boolean haveSpecialHeaders = (hack263 || hackm4a_generic);  // If there has been a previous frame, then output a 'hint sample' for it.  // (We use the current frame's presentation time to compute the previous  // hint sample's duration.)  RTPSource* const rs = fOurSubsession.rtpSource(); // abbrev   struct timeval const& ppt = fPrevFrameState.presentationTime; //abbrev  if (ppt.tv_sec != 0 || ppt.tv_usec != 0) {    double duration = (presentationTime.tv_sec - ppt.tv_sec)      + (presentationTime.tv_usec - ppt.tv_usec)/1000000.0;    if (duration < 0.0) duration = 0.0;    unsigned msDuration = (unsigned)(duration*1000); // milliseconds    if (msDuration > fHINF.dmax) fHINF.dmax = msDuration;    unsigned hintSampleDuration      = (unsigned)((2*duration*fQTTimeScale+1)/2); // round    if (hackm4a) {      // Because multiple AAC frames can appear in a RTP packet, the presentation      // times of the second and subsequent frames will not be accurate.      // So, use the known "hintSampleDuration" instead:      hintSampleDuration = fTrackHintedByUs->fQTTimeUnitsPerSample;      // Also, if the 'time scale' was different from the RTP timestamp frequency,      // (as can happen with aacPlus), then we need to scale "hintSampleDuration"      // accordingly:      if (fTrackHintedByUs->fQTTimeScale != fOurSubsession.rtpTimestampFrequency()) {	unsigned const scalingFactor	  = fOurSubsession.rtpTimestampFrequency()/fTrackHintedByUs->fQTTimeScale ;	hintSampleDuration *= scalingFactor;      }    }    unsigned const hintSampleDestFileOffset = ftell(fOurSink.fOutFid);    unsigned const maxPacketSize = 1450;    unsigned short numPTEntries      = (fPrevFrameState.frameSize + (maxPacketSize-1))/maxPacketSize; // normal case    unsigned char* immediateDataPtr = NULL;    unsigned immediateDataBytesRemaining = 0;    if (haveSpecialHeaders) { // special case      numPTEntries = fPrevFrameState.numSpecialHeaders;      immediateDataPtr = fPrevFrameState.specialHeaderBytes;      immediateDataBytesRemaining	= fPrevFrameState.specialHeaderBytesLength;    }    unsigned hintSampleSize      = fOurSink.addHalfWord(numPTEntries);// Entry count    hintSampleSize += fOurSink.addHalfWord(0x0000); // Reserved    unsigned offsetWithinSample = 0;    for (unsigned i = 0; i < numPTEntries; ++i) {      // Output a Packet Table entry (representing a single RTP packet):      unsigned short numDTEntries = 1;      unsigned short seqNum = fPrevFrameState.seqNum++;          // Note: This assumes that the input stream had no packets lost #####      unsigned rtpHeader = fPrevFrameState.rtpHeader;      if (i+1 < numPTEntries) {	// This is not the last RTP packet, so clear the marker bit:	rtpHeader &=~ (1<<23);      }      unsigned dataFrameSize = (i+1 < numPTEntries)	? maxPacketSize : fPrevFrameState.frameSize - i*maxPacketSize; // normal case      unsigned sampleNumber = fPrevFrameState.startSampleNumber;      unsigned char immediateDataLen = 0;      if (haveSpecialHeaders) { // special case	++numDTEntries; // to include a Data Table entry for the special hdr	if (immediateDataBytesRemaining > 0) {	  if (hack263) {	    immediateDataLen = *immediateDataPtr++;	    --immediateDataBytesRemaining;	    if (immediateDataLen > immediateDataBytesRemaining) {	      // shouldn't happen (length byte was bad)	      immediateDataLen = immediateDataBytesRemaining;	    }	  } else {	    immediateDataLen = fPrevFrameState.specialHeaderBytesLength;	  }	}	dataFrameSize = fPrevFrameState.packetSizes[i] - immediateDataLen;	if (hack263) {	  Boolean PbitSet	    = immediateDataLen >= 1 && (immediateDataPtr[0]&0x4) != 0;	  if (PbitSet) {	    offsetWithinSample += 2; // to omit the two leading 0 bytes	  }	}      }      // Output the Packet Table:      hintSampleSize += fOurSink.addWord(0); // Relative transmission time      hintSampleSize += fOurSink.addWord(rtpHeader|seqNum);          // RTP header info + RTP sequence number      hintSampleSize += fOurSink.addHalfWord(0x0000); // Flags      hintSampleSize += fOurSink.addHalfWord(numDTEntries); // Entry count      unsigned totalPacketSize = 0;      // Output the Data Table:      if (haveSpecialHeaders) {	//   use the "Immediate Data" format (1):	hintSampleSize += fOurSink.addByte(1); // Source	unsigned char len = immediateDataLen > 14 ? 14 : immediateDataLen;	hintSampleSize += fOurSink.addByte(len); // Length	totalPacketSize += len; fHINF.dimm += len;	unsigned char j;	for (j = 0; j < len; ++j) {	  hintSampleSize += fOurSink.addByte(immediateDataPtr[j]); // Data	}	for (j = len; j < 14; ++j) {	  hintSampleSize += fOurSink.addByte(0); // Data (padding)	}	immediateDataPtr += immediateDataLen;	immediateDataBytesRemaining -= immediateDataLen;      }      //   use the "Sample Data" format (2):      hintSampleSize += fOurSink.addByte(2); // Source      hintSampleSize += fOurSink.addByte(0); // Track ref index      hintSampleSize += fOurSink.addHalfWord(dataFrameSize); // Length      totalPacketSize += dataFrameSize; fHINF.dmed += dataFrameSize;      hintSampleSize += fOurSink.addWord(sampleNumber); // Sample number      hintSampleSize += fOurSink.addWord(offsetWithinSample); // Offset      // Get "bytes|samples per compression block" from the hinted track:      unsigned short const bytesPerCompressionBlock	= fTrackHintedByUs->fQTBytesPerFrame;      unsigned short const samplesPerCompressionBlock	= fTrackHintedByUs->fQTSamplesPerFrame;      hintSampleSize += fOurSink.addHalfWord(bytesPerCompressionBlock);      hintSampleSize += fOurSink.addHalfWord(samplesPerCompressionBlock);      offsetWithinSample += dataFrameSize;// for the next iteration (if any)      // Tally statistics for this packet:      fHINF.nump += 1;      fHINF.tpyl += totalPacketSize;      totalPacketSize += 12; // add in the size of the RTP header      fHINF.trpy += totalPacketSize;      if (totalPacketSize > fHINF.pmax) fHINF.pmax = totalPacketSize;    }    // Make note of this completed hint sample frame:    fQTTotNumSamples += useFrame1(hintSampleSize, ppt, hintSampleDuration,				  hintSampleDestFileOffset);  }    // Remember this frame for next time:  fPrevFrameState.frameSize = frameSize;  fPrevFrameState.presentationTime = presentationTime;  fPrevFrameState.startSampleNumber = startSampleNumber;  fPrevFrameState.rtpHeader    = rs->curPacketMarkerBit()<<23    | (rs->rtpPayloadFormat()&0x7F)<<16;  if (hack263) {    H263plusVideoRTPSource* rs_263 = (H263plusVideoRTPSource*)rs;    fPrevFrameState.numSpecialHeaders = rs_263->fNumSpecialHeaders;    fPrevFrameState.specialHeaderBytesLength = rs_263->fSpecialHeaderBytesLength;    unsigned i;    for (i = 0; i < rs_263->fSpecialHeaderBytesLength; ++i) {      fPrevFrameState.specialHeaderBytes[i] = rs_263->fSpecialHeaderBytes[i];    }    for (i = 0; i < rs_263->fNumSpecialHeaders; ++i) {      fPrevFrameState.packetSizes[i] = rs_263->fPacketSizes[i];    }  } else if (hackm4a_generic) {    // Synthesize a special header, so that this frame can be in its own RTP packet.    unsigned const sizeLength = fOurSubsession.fmtp_sizelength();    unsigned const indexLength = fOurSubsession.fmtp_indexlength();    if (sizeLength + indexLength != 16) {      envir() << "Warning: unexpected 'sizeLength' " << sizeLength	      << " and 'indexLength' " << indexLength	      << "seen when creating hint track\n";    }    fPrevFrameState.numSpecialHeaders = 1;    fPrevFrameState.specialHeaderBytesLength = 4;    fPrevFrameState.specialHeaderBytes[0] = 0; // AU_headers_length (high byte)    fPrevFrameState.specialHeaderBytes[1] = 16; // AU_headers_length (low byte)    fPrevFrameState.specialHeaderBytes[2] = ((frameSize<<indexLength)&0xFF00)>>8;    fPrevFrameState.specialHeaderBytes[3] = (frameSize<<indexLength);    fPrevFrameState.packetSizes[0]      = fPrevFrameState.specialHeaderBytesLength + frameSize;  }}unsigned SubsessionIOState::useFrame1(unsigned sourceDataSize,				      struct timeval presentationTime,				      unsigned frameDuration,				      unsigned destFileOffset) {  // Figure out the actual frame size for this data:  unsigned frameSize = fQTBytesPerFrame;  if (frameSize == 0) {    // The entire packet data is assumed to be a frame:    frameSize = sourceDataSize;  }  unsigned const numFrames = sourceDataSize/frameSize;  unsigned const numSamples = numFrames*fQTSamplesPerFrame;  // Record the information about which 'chunk' this data belongs to:  ChunkDescriptor* newTailChunk;  if (fTailChunk == NULL) {    newTailChunk = fHeadChunk      = new ChunkDescriptor(destFileOffset, sourceDataSize,			    frameSize, frameDuration, presentationTime);  } else {    newTailChunk = fTailChunk->extendChunk(destFileOffset, sourceDataSize,					   frameSize, frameDuration,					   presentationTime);  }  if (newTailChunk != fTailChunk) {   // This data created a new chunk, rather than extending the old one    ++fNumChunks;    fTailChunk = newTailChunk;  }  return numSamples;}  void SubsessionIOState::onSourceClosure() {  fOurSourceIsActive = False;  fOurSink.onSourceClosure1();}Boolean SubsessionIOState::syncOK(struct timeval presentationTime) {  QuickTimeFileSink& s = fOurSink; // abbreviation  if (!s.fSyncStreams) return True; // we don't care  if (s.fNumSyncedSubsessions < s.fNumSubsessions) {    // Not all subsessions have yet been synced.  Check whether ours was    // one of the unsynced ones, and, if so, whether it is now synced:    if (!fHaveBeenSynced) {      // We weren't synchronized before      if (fOurSubsession.rtpSource()->hasBeenSynchronizedUsingRTCP()) {	// But now we are	fHaveBeenSynced = True;	fSyncTime = presentationTime;	++s.fNumSyncedSubsessions;	if (timevalGE(fSyncTime, s.fNewestSyncTime)) {	  s.fNewestSyncTime = fSyncTime;	}      }    }  }      // Check again whether all subsessions have been synced:  if (s.fNumSyncedSubsessions < s.fNumSubsessions) return False;  // Allow this data if it is more recent than the newest sync time:  return timevalGE(presentationTime, s.fNewestSyncTime);}void SubsessionIOState::setHintTrack(SubsessionIOState* hintedTrack,				     SubsessionIOState* hintTrack) {  if (hintedTrack != NULL) hintedTrack->fHintTrackForUs = hintTrack;  if (hintTrack != NULL) hintTrack->fTrackHintedByUs = hintedTrack;}void Count64::operator+=(unsigned arg) {  unsigned newLo = lo + arg;  if (newLo < lo) { // lo has overflowed    ++hi;  }  lo = newLo;}ChunkDescriptor::ChunkDescriptor(unsigned offsetInFile, unsigned size,		  unsigned frameSize, unsigned frameDuration,		  struct timeval presentationTime)  : fNextChunk(NULL), fOffsetInFile(offsetInFile),    fNumFrames(size/frameSize),    fFrameSize(frameSize), fFrameDuration(frameDuration),    fPresentationTime(presentationTime) {}ChunkDescriptor::~ChunkDescriptor() {  delete fNextChunk;}ChunkDescriptor* ChunkDescriptor::extendChunk(unsigned newOffsetInFile, unsigned newSize,	      unsigned newFrameSize, unsigned newFrameDuration,	      struct timeval newPresentationTime) {  // First, check whether the new space is just at the end of this  // existing chunk:  if (newOffsetInFile == fOffsetInFile + fNumFrames*fFrameSize) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -