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

📄 quicktimefilesink.cpp

📁 流媒体传输协议的实现代码,非常有用.可以支持rtsp mms等流媒体传输协议
💻 CPP
📖 第 1 页 / 共 5 页
字号:
    // We can extend this existing chunk, provided that the frame size    // and frame duration have not changed:    if (newFrameSize == fFrameSize && newFrameDuration == fFrameDuration) {      fNumFrames += newSize/fFrameSize;      return this;    }  }  // We'll allocate a new ChunkDescriptor, and link it to the end of us:  ChunkDescriptor* newDescriptor    = new ChunkDescriptor(newOffsetInFile, newSize,			  newFrameSize, newFrameDuration,			  newPresentationTime);  fNextChunk = newDescriptor;  return newDescriptor;}////////// QuickTime-specific implementation //////////unsigned QuickTimeFileSink::addWord(unsigned word) {  addByte(word>>24); addByte(word>>16);  addByte(word>>8); addByte(word);  return 4;}unsigned QuickTimeFileSink::addHalfWord(unsigned short halfWord) {  addByte((unsigned char)(halfWord>>8)); addByte((unsigned char)halfWord);  return 2;}unsigned QuickTimeFileSink::addZeroWords(unsigned numWords) {  for (unsigned i = 0; i < numWords; ++i) {    addWord(0);  }  return numWords*4;}unsigned QuickTimeFileSink::add4ByteString(char const* str) {  addByte(str[0]); addByte(str[1]); addByte(str[2]); addByte(str[3]);  return 4;}unsigned QuickTimeFileSink::addArbitraryString(char const* str,					       Boolean oneByteLength) {  unsigned size = 0;  if (oneByteLength) {    // Begin with a byte containing the string length:    unsigned strLength = strlen(str);    if (strLength >= 256) {      envir() << "QuickTimeFileSink::addArbitraryString(\""	      << str << "\") saw string longer than we know how to handle ("	      << strLength << "\n";    }    size += addByte((unsigned char)strLength);  }  while (*str != '\0') {    size += addByte(*str++);  }  return size;}unsigned QuickTimeFileSink::addAtomHeader(char const* atomName) {  // Output a placeholder for the 4-byte size:  addWord(0);  // Output the 4-byte atom name:  add4ByteString(atomName);  return 8;}void QuickTimeFileSink::setWord(unsigned filePosn, unsigned size) {  do {    if (fseek(fOutFid, filePosn, SEEK_SET) < 0) break;    addWord(size);    if (fseek(fOutFid, 0, SEEK_END) < 0) break; // go back to where we were    return;  } while (0);  // One of the fseek()s failed, probable because we're not a seekable file  envir() << "QuickTimeFileSink::setWord(): fseek failed (err "	  << envir().getErrno() << ")\n";}// Methods for writing particular atoms.  Note the following macros:#define addAtom(name) \    unsigned QuickTimeFileSink::addAtom_##name() { \    unsigned initFilePosn = ftell(fOutFid); \    unsigned size = addAtomHeader("" #name "")#define addAtomEnd \  setWord(initFilePosn, size); \  return size; \}addAtom(ftyp);  size += add4ByteString("mp42");  size += addWord(0x00000000);  size += add4ByteString("mp42");  size += add4ByteString("isom");addAtomEnd;addAtom(moov);  size += addAtom_mvhd();  if (fGenerateMP4Format) {    size += addAtom_iods();  }  // Add a 'trak' atom for each subsession:  // (For some unknown reason, QuickTime Player (5.0 at least)  //  doesn't display the movie correctly unless the audio track  //  (if present) appears before the video track.  So ensure this here.)  MediaSubsessionIterator iter(fInputSession);  MediaSubsession* subsession;  while ((subsession = iter.next()) != NULL) {    fCurrentIOState = (SubsessionIOState*)(subsession->miscPtr);     if (fCurrentIOState == NULL) continue;    if (strcmp(subsession->mediumName(), "audio") != 0) continue;    size += addAtom_trak();    if (fCurrentIOState->hasHintTrack()) {      // This track has a hint track; output it also:      fCurrentIOState = fCurrentIOState->fHintTrackForUs;      size += addAtom_trak();    }  }  iter.reset();  while ((subsession = iter.next()) != NULL) {    fCurrentIOState = (SubsessionIOState*)(subsession->miscPtr);     if (fCurrentIOState == NULL) continue;    if (strcmp(subsession->mediumName(), "audio") == 0) continue;    size += addAtom_trak();    if (fCurrentIOState->hasHintTrack()) {      // This track has a hint track; output it also:      fCurrentIOState = fCurrentIOState->fHintTrackForUs;      size += addAtom_trak();    }  }addAtomEnd;addAtom(mvhd);  size += addWord(0x00000000); // Version + Flags  size += addWord(fAppleCreationTime); // Creation time  size += addWord(fAppleCreationTime); // Modification time  // For the "Time scale" field, use the largest RTP timestamp frequency  // that we saw in any of the subsessions.  size += addWord(movieTimeScale()); // Time scale  unsigned const duration = fMaxTrackDurationM;  fMVHD_durationPosn = ftell(fOutFid);  size += addWord(duration); // Duration  size += addWord(0x00010000); // Preferred rate  size += addWord(0x01000000); // Preferred volume + Reserved[0]  size += addZeroWords(2); // Reserved[1-2]  size += addWord(0x00010000); // matrix top left corner  size += addZeroWords(3); // matrix  size += addWord(0x00010000); // matrix center  size += addZeroWords(3); // matrix  size += addWord(0x40000000); // matrix bottom right corner  size += addZeroWords(6); // various time fields  size += addWord(SubsessionIOState::fCurrentTrackNumber+1);// Next track IDaddAtomEnd;addAtom(iods);  size += addWord(0x00000000); // Version + Flags  size += addWord(0x10808080);  size += addWord(0x07004FFF);  size += addWord(0xFF0FFFFF);addAtomEnd;addAtom(trak);  size += addAtom_tkhd();  // If we're synchronizing the media streams (or are a hint track),  // add an edit list that helps do this:  if (fCurrentIOState->fHeadChunk != NULL      && (fSyncStreams || fCurrentIOState->isHintTrack())) {    size += addAtom_edts();  }  // If we're generating a hint track, add a 'tref' atom:  if (fCurrentIOState->isHintTrack()) size += addAtom_tref();  size += addAtom_mdia();  // If we're generating a hint track, add a 'udta' atom:  if (fCurrentIOState->isHintTrack()) size += addAtom_udta();addAtomEnd;addAtom(tkhd);  if (fCurrentIOState->fQTEnableTrack) {    size += addWord(0x0000000F); // Version +  Flags  } else {    // Disable this track in the movie:    size += addWord(0x00000000); // Version +  Flags  }  size += addWord(fAppleCreationTime); // Creation time  size += addWord(fAppleCreationTime); // Modification time  size += addWord(fCurrentIOState->fTrackID); // Track ID  size += addWord(0x00000000); // Reserved  unsigned const duration = fCurrentIOState->fQTDurationM; // movie units  fCurrentIOState->fTKHD_durationPosn = ftell(fOutFid);  size += addWord(duration); // Duration  size += addZeroWords(3); // Reserved+Layer+Alternate grp  size += addWord(0x01000000); // Volume + Reserved  size += addWord(0x00010000); // matrix top left corner  size += addZeroWords(3); // matrix  size += addWord(0x00010000); // matrix center  size += addZeroWords(3); // matrix  size += addWord(0x40000000); // matrix bottom right corner  if (strcmp(fCurrentIOState->fOurSubsession.mediumName(), "video") == 0) {    size += addWord(fMovieWidth<<16); // Track width    size += addWord(fMovieHeight<<16); // Track height  } else {    size += addZeroWords(2); // not video: leave width and height fields zero  }addAtomEnd;addAtom(edts);  size += addAtom_elst();addAtomEnd;#define addEdit1(duration,trackPosition) do { \      unsigned trackDuration \        = (unsigned) ((2*(duration)*movieTimeScale()+1)/2); \            /* in movie time units */ \      size += addWord(trackDuration); /* Track duration */ \      totalDurationOfEdits += trackDuration; \      size += addWord(trackPosition); /* Media time */ \      size += addWord(0x00010000); /* Media rate (1x) */ \      ++numEdits; \} while (0)#define addEdit(duration) addEdit1((duration),editTrackPosition)#define addEmptyEdit(duration) addEdit1((duration),(~0))addAtom(elst);  size += addWord(0x00000000); // Version + Flags  // Add a dummy "Number of entries" field  // (and remember its position).  We'll fill this field in later:  unsigned numEntriesPosition = ftell(fOutFid);  size += addWord(0); // dummy for "Number of entries"  unsigned numEdits = 0;  unsigned totalDurationOfEdits = 0; // in movie time units  // Run through our chunks, looking at their presentation times.  // From these, figure out the edits that need to be made to keep  // the track media data in sync with the presentation times.    double const syncThreshold = 0.1; // 100 ms    // don't allow the track to get out of sync by more than this  struct timeval editStartTime = fFirstDataTime;  unsigned editTrackPosition = 0;  unsigned currentTrackPosition = 0;  double trackDurationOfEdit = 0.0;  unsigned chunkDuration = 0;  ChunkDescriptor* chunk = fCurrentIOState->fHeadChunk;  while (chunk != NULL) {    struct timeval const& chunkStartTime = chunk->fPresentationTime;    double movieDurationOfEdit      = (chunkStartTime.tv_sec - editStartTime.tv_sec)      + (chunkStartTime.tv_usec - editStartTime.tv_usec)/1000000.0;    trackDurationOfEdit = (currentTrackPosition-editTrackPosition)      / (double)(fCurrentIOState->fQTTimeScale);          double outOfSync = movieDurationOfEdit - trackDurationOfEdit;    if (outOfSync > syncThreshold) {      // The track's data is too short, so end this edit, add a new      // 'empty' edit after it, and start a new edit      // (at the current track posn.):      if (trackDurationOfEdit > 0.0) addEdit(trackDurationOfEdit);      addEmptyEdit(outOfSync);      editStartTime = chunkStartTime;      editTrackPosition = currentTrackPosition;    } else if (outOfSync < -syncThreshold) {      // The track's data is too long, so end this edit, and start      // a new edit (pointing at the current track posn.):      if (movieDurationOfEdit > 0.0) addEdit(movieDurationOfEdit);      editStartTime = chunkStartTime;      editTrackPosition = currentTrackPosition;    }    // Note the duration of this chunk:    unsigned numChannels = fCurrentIOState->fOurSubsession.numChannels();    chunkDuration = chunk->fNumFrames*chunk->fFrameDuration/numChannels;    currentTrackPosition += chunkDuration;    chunk = chunk->fNextChunk;  }  // Write out the final edit  trackDurationOfEdit      += (double)chunkDuration/fCurrentIOState->fQTTimeScale;  if (trackDurationOfEdit > 0.0) addEdit(trackDurationOfEdit);  // Now go back and fill in the "Number of entries" field:  setWord(numEntriesPosition, numEdits);  // Also, if the sum of all of the edit durations exceeds the  // track duration that we already computed (from sample durations),  // then reset the track duration to this new value:  if (totalDurationOfEdits > fCurrentIOState->fQTDurationM) {    fCurrentIOState->fQTDurationM = totalDurationOfEdits;    setWord(fCurrentIOState->fTKHD_durationPosn, totalDurationOfEdits);    // Also, check whether the overall movie duration needs to change:    if (totalDurationOfEdits > fMaxTrackDurationM) {      fMaxTrackDurationM = totalDurationOfEdits;      setWord(fMVHD_durationPosn, totalDurationOfEdits);    }    // Also, convert to track time scale:    double scaleFactor      = fCurrentIOState->fQTTimeScale/(double)movieTimeScale();    fCurrentIOState->fQTDurationT      = (unsigned)(totalDurationOfEdits*scaleFactor);  }addAtomEnd;addAtom(tref);  size += addAtom_hint();addAtomEnd;addAtom(hint);  SubsessionIOState* hintedTrack = fCurrentIOState->fTrackHintedByUs;    // Assert: hintedTrack != NULL  size += addWord(hintedTrack->fTrackID);addAtomEnd;addAtom(mdia);  size += addAtom_mdhd();  size += addAtom_hdlr();  size += addAtom_minf();addAtomEnd;addAtom(mdhd);  size += addWord(0x00000000); // Version + Flags  size += addWord(fAppleCreationTime); // Creation time  size += addWord(fAppleCreationTime); // Modification time  unsigned const timeScale = fCurrentIOState->fQTTimeScale;  size += addWord(timeScale); // Time scale  unsigned const duration = fCurrentIOState->fQTDurationT; // track units

⌨️ 快捷键说明

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