SubsessionIOState Class Reference

Collaboration diagram for SubsessionIOState:

Collaboration graph
[legend]

Public Types

typedef unsigned(QuickTimeFileSink::*) atomCreationFunc ()

Public Member Functions

 SubsessionIOState (QuickTimeFileSink &sink, MediaSubsession &subsession)
virtual ~SubsessionIOState ()
Boolean setQTstate ()
void setFinalQTstate ()
void afterGettingFrame (unsigned packetDataSize, struct timeval presentationTime)
void onSourceClosure ()
Boolean syncOK (struct timeval presentationTime)
Boolean isHintTrack () const
Boolean hasHintTrack () const
UsageEnvironmentenvir () const

Static Public Member Functions

static void setHintTrack (SubsessionIOState *hintedTrack, SubsessionIOState *hintTrack)

Data Fields

unsigned fTrackID
SubsessionIOStatefHintTrackForUs
SubsessionIOStatefTrackHintedByUs
SubsessionBufferfBuffer
SubsessionBufferfPrevBuffer
QuickTimeFileSinkfOurSink
MediaSubsessionfOurSubsession
unsigned short fLastPacketRTPSeqNum
Boolean fOurSourceIsActive
Boolean fHaveBeenSynced
timeval fSyncTime
Boolean fQTEnableTrack
unsigned fQTcomponentSubtype
char const * fQTcomponentName
atomCreationFunc fQTMediaInformationAtomCreator
atomCreationFunc fQTMediaDataAtomCreator
char const * fQTAudioDataType
unsigned short fQTSoundSampleVersion
unsigned fQTTimeScale
unsigned fQTTimeUnitsPerSample
unsigned fQTBytesPerFrame
unsigned fQTSamplesPerFrame
unsigned fQTTotNumSamples
unsigned fQTDurationM
unsigned fQTDurationT
unsigned fTKHD_durationPosn
unsigned fQTInitialOffsetDuration
ChunkDescriptorfHeadChunk
ChunkDescriptorfTailChunk
unsigned fNumChunks
SubsessionIOState::hinf fHINF
unsigned frameSize
timeval presentationTime
unsigned destFileOffset
unsigned startSampleNumber
unsigned short seqNum
unsigned rtpHeader
unsigned char numSpecialHeaders
unsigned specialHeaderBytesLength
unsigned char specialHeaderBytes [SPECIAL_HEADER_BUFFER_SIZE]
unsigned packetSizes [256]

Static Public Attributes

static unsigned fCurrentTrackNumber = 0

Private Member Functions

void useFrame (SubsessionBuffer &buffer)
void useFrameForHinting (unsigned frameSize, struct timeval presentationTime, unsigned startSampleNumber)
unsigned useFrame1 (unsigned sourceDataSize, struct timeval presentationTime, unsigned frameDuration, unsigned destFileOffset)

Private Attributes

struct {
   unsigned   frameSize
   timeval   presentationTime
   unsigned   destFileOffset
   unsigned   startSampleNumber
   unsigned short   seqNum
   unsigned   rtpHeader
   unsigned char   numSpecialHeaders
   unsigned   specialHeaderBytesLength
   unsigned char   specialHeaderBytes [SPECIAL_HEADER_BUFFER_SIZE]
   unsigned   packetSizes [256]
fPrevFrameState

Data Structures

struct  hinf

Detailed Description

Definition at line 97 of file QuickTimeFileSink.cpp.


Member Typedef Documentation

typedef unsigned(QuickTimeFileSink::*) SubsessionIOState::atomCreationFunc()

Definition at line 137 of file QuickTimeFileSink.cpp.


Constructor & Destructor Documentation

SubsessionIOState::SubsessionIOState ( QuickTimeFileSink sink,
MediaSubsession subsession 
)

Definition at line 507 of file QuickTimeFileSink.cpp.

References fBuffer, QuickTimeFileSink::fBufferSize, fCurrentTrackNumber, fOurSink, fOurSourceIsActive, QuickTimeFileSink::fPacketLossCompensate, fPrevBuffer, fPrevFrameState, fTrackID, NULL, MediaSubsession::readSource(), and subsession.

00509   : fHintTrackForUs(NULL), fTrackHintedByUs(NULL),
00510     fOurSink(sink), fOurSubsession(subsession),
00511     fLastPacketRTPSeqNum(0), fHaveBeenSynced(False), fQTTotNumSamples(0),
00512     fHeadChunk(NULL), fTailChunk(NULL), fNumChunks(0) {
00513   fTrackID = ++fCurrentTrackNumber;
00514 
00515   fBuffer = new SubsessionBuffer(fOurSink.fBufferSize);
00516   fPrevBuffer = sink.fPacketLossCompensate
00517     ? new SubsessionBuffer(fOurSink.fBufferSize) : NULL;
00518 
00519   FramedSource* subsessionSource = subsession.readSource();
00520   fOurSourceIsActive = subsessionSource != NULL;
00521 
00522   fPrevFrameState.presentationTime.tv_sec = 0;
00523   fPrevFrameState.presentationTime.tv_usec = 0;
00524   fPrevFrameState.seqNum = 0;
00525 }

SubsessionIOState::~SubsessionIOState (  )  [virtual]

Definition at line 527 of file QuickTimeFileSink.cpp.

References fBuffer, fHeadChunk, and fPrevBuffer.

00527                                       {
00528   delete fBuffer; delete fPrevBuffer;
00529   delete fHeadChunk;
00530 }


Member Function Documentation

Boolean SubsessionIOState::setQTstate (  ) 

Definition at line 532 of file QuickTimeFileSink.cpp.

References QuickTimeFileSink::addAtom_dummy(), QuickTimeFileSink::addAtom_genericMedia(), QuickTimeFileSink::addAtom_soundMediaGeneral(), MediaSubsession::codecName(), envir(), False, QuickTimeFileSink::fMovieFPS, MediaSubsession::fmtp_config(), fourChar, fOurSink, fOurSubsession, fQTAudioDataType, fQTBytesPerFrame, fQTcomponentName, fQTcomponentSubtype, fQTEnableTrack, fQTMediaDataAtomCreator, fQTMediaInformationAtomCreator, fQTSamplesPerFrame, fQTSoundSampleVersion, fQTTimeScale, fQTTimeUnitsPerSample, isHintTrack(), MediaSubsession::mediumName(), MediaSubsession::rtpTimestampFrequency(), samplingFrequencyFromAudioSpecificConfig(), and True.

Referenced by QuickTimeFileSink::QuickTimeFileSink().

00532                                       {
00533   char const* noCodecWarning1 = "Warning: We don't implement a QuickTime ";
00534   char const* noCodecWarning2 = " Media Data Type for the \"";
00535   char const* noCodecWarning3 = "\" track, so we'll insert a dummy \"????\" Media Data Atom instead.  A separate, codec-specific editing pass will be needed before this track can be played.\n";
00536 
00537   do {
00538     fQTEnableTrack = True; // enable this track in the movie by default
00539     fQTTimeScale = fOurSubsession.rtpTimestampFrequency(); // by default
00540     fQTTimeUnitsPerSample = 1; // by default
00541     fQTBytesPerFrame = 0;
00542         // by default - indicates that the whole packet data is a frame
00543     fQTSamplesPerFrame = 1; // by default
00544 
00545     // Make sure our subsession's medium is one that we know how to
00546     // represent in a QuickTime file:
00547     if (isHintTrack()) {
00548       // Hint tracks are treated specially
00549       fQTEnableTrack = False; // hint tracks are marked as inactive
00550       fQTcomponentSubtype = fourChar('h','i','n','t');
00551       fQTcomponentName = "hint media handler";
00552       fQTMediaInformationAtomCreator = &QuickTimeFileSink::addAtom_gmhd;
00553       fQTMediaDataAtomCreator = &QuickTimeFileSink::addAtom_rtp;
00554     } else if (strcmp(fOurSubsession.mediumName(), "audio") == 0) {
00555       fQTcomponentSubtype = fourChar('s','o','u','n');
00556       fQTcomponentName = "Apple Sound Media Handler";
00557       fQTMediaInformationAtomCreator = &QuickTimeFileSink::addAtom_smhd;
00558       fQTMediaDataAtomCreator
00559         = &QuickTimeFileSink::addAtom_soundMediaGeneral; // by default
00560       fQTSoundSampleVersion = 0; // by default
00561 
00562       // Make sure that our subsession's codec is one that we can handle:
00563       if (strcmp(fOurSubsession.codecName(), "X-QT") == 0 ||
00564           strcmp(fOurSubsession.codecName(), "X-QUICKTIME") == 0) {
00565         fQTMediaDataAtomCreator = &QuickTimeFileSink::addAtom_genericMedia;
00566       } else if (strcmp(fOurSubsession.codecName(), "PCMU") == 0) {
00567         fQTAudioDataType = "ulaw";
00568         fQTBytesPerFrame = 1;
00569       } else if (strcmp(fOurSubsession.codecName(), "GSM") == 0) {
00570         fQTAudioDataType = "agsm";
00571         fQTBytesPerFrame = 33;
00572         fQTSamplesPerFrame = 160;
00573       } else if (strcmp(fOurSubsession.codecName(), "PCMA") == 0) {
00574         fQTAudioDataType = "alaw";
00575         fQTBytesPerFrame = 1;
00576       } else if (strcmp(fOurSubsession.codecName(), "QCELP") == 0) {
00577         fQTMediaDataAtomCreator = &QuickTimeFileSink::addAtom_Qclp;
00578         fQTSamplesPerFrame = 160;
00579       } else if (strcmp(fOurSubsession.codecName(), "MPEG4-GENERIC") == 0 ||
00580                  strcmp(fOurSubsession.codecName(), "MP4A-LATM") == 0) {
00581         fQTMediaDataAtomCreator = &QuickTimeFileSink::addAtom_mp4a;
00582         fQTTimeUnitsPerSample = 1024; // QT considers each frame to be a 'sample'
00583         // The time scale (frequency) comes from the 'config' information.
00584         // It might be different from the RTP timestamp frequency (e.g., aacPlus).
00585         unsigned frequencyFromConfig
00586           = samplingFrequencyFromAudioSpecificConfig(fOurSubsession.fmtp_config());
00587         if (frequencyFromConfig != 0) fQTTimeScale = frequencyFromConfig;
00588       } else {
00589         envir() << noCodecWarning1 << "Audio" << noCodecWarning2
00590                 << fOurSubsession.codecName() << noCodecWarning3;
00591         fQTMediaDataAtomCreator = &QuickTimeFileSink::addAtom_dummy;
00592         fQTEnableTrack = False; // disable this track in the movie
00593       }
00594     } else if (strcmp(fOurSubsession.mediumName(), "video") == 0) {
00595       fQTcomponentSubtype = fourChar('v','i','d','e');
00596       fQTcomponentName = "Apple Video Media Handler";
00597       fQTMediaInformationAtomCreator = &QuickTimeFileSink::addAtom_vmhd;
00598 
00599       // Make sure that our subsession's codec is one that we can handle:
00600       if (strcmp(fOurSubsession.codecName(), "X-QT") == 0 ||
00601           strcmp(fOurSubsession.codecName(), "X-QUICKTIME") == 0) {
00602         fQTMediaDataAtomCreator = &QuickTimeFileSink::addAtom_genericMedia;
00603       } else if (strcmp(fOurSubsession.codecName(), "H263-1998") == 0 ||
00604                  strcmp(fOurSubsession.codecName(), "H263-2000") == 0) {
00605         fQTMediaDataAtomCreator = &QuickTimeFileSink::addAtom_h263;
00606         fQTTimeScale = 600;
00607         fQTTimeUnitsPerSample = fQTTimeScale/fOurSink.fMovieFPS;
00608       } else if (strcmp(fOurSubsession.codecName(), "H264") == 0) {
00609         fQTMediaDataAtomCreator = &QuickTimeFileSink::addAtom_avc1;
00610         fQTTimeScale = 600;
00611         fQTTimeUnitsPerSample = fQTTimeScale/fOurSink.fMovieFPS;
00612       } else if (strcmp(fOurSubsession.codecName(), "MP4V-ES") == 0) {
00613         fQTMediaDataAtomCreator = &QuickTimeFileSink::addAtom_mp4v;
00614         fQTTimeScale = 600;
00615         fQTTimeUnitsPerSample = fQTTimeScale/fOurSink.fMovieFPS;
00616       } else {
00617         envir() << noCodecWarning1 << "Video" << noCodecWarning2
00618                 << fOurSubsession.codecName() << noCodecWarning3;
00619         fQTMediaDataAtomCreator = &QuickTimeFileSink::addAtom_dummy;
00620         fQTEnableTrack = False; // disable this track in the movie
00621       }
00622     } else {
00623       envir() << "Warning: We don't implement a QuickTime Media Handler for media type \""
00624               << fOurSubsession.mediumName() << "\"";
00625       break;
00626     }
00627 
00628 #ifdef QT_SUPPORT_PARTIALLY_ONLY
00629     envir() << "Warning: We don't have sufficient codec-specific information (e.g., sample sizes) to fully generate the \""
00630             << fOurSubsession.mediumName() << "/" << fOurSubsession.codecName()
00631             << "\" track, so we'll disable this track in the movie.  A separate, codec-specific editing pass will be needed before this track can be played\n";
00632     fQTEnableTrack = False; // disable this track in the movie
00633 #endif
00634 
00635     return True;
00636   } while (0);
00637 
00638   envir() << ", so a track for the \"" << fOurSubsession.mediumName()
00639           << "/" << fOurSubsession.codecName()
00640           << "\" subsession will not be included in the output QuickTime file\n";
00641   return False;
00642 }

void SubsessionIOState::setFinalQTstate (  ) 

Definition at line 644 of file QuickTimeFileSink.cpp.

References chunk, ChunkDescriptor::fFrameDuration, fHeadChunk, QuickTimeFileSink::fMaxTrackDurationM, ChunkDescriptor::fNextChunk, ChunkDescriptor::fNumFrames, fOurSink, fQTDurationM, fQTDurationT, fQTTimeScale, QuickTimeFileSink::movieTimeScale(), and NULL.

Referenced by QuickTimeFileSink::completeOutputFile().

00644                                         {
00645   // Compute derived parameters, by running through the list of chunks:
00646   fQTDurationT = 0;
00647 
00648   ChunkDescriptor* chunk = fHeadChunk;
00649   while (chunk != NULL) {
00650     unsigned const numFrames = chunk->fNumFrames;
00651     unsigned const dur = numFrames*chunk->fFrameDuration;
00652     fQTDurationT += dur;
00653 
00654     chunk = chunk->fNextChunk;
00655   }
00656 
00657   // Convert this duration from track to movie time scale:
00658   double scaleFactor = fOurSink.movieTimeScale()/(double)fQTTimeScale;
00659   fQTDurationM = (unsigned)(fQTDurationT*scaleFactor);
00660 
00661   if (fQTDurationM > fOurSink.fMaxTrackDurationM) {
00662     fOurSink.fMaxTrackDurationM = fQTDurationM;
00663   }
00664 }

void SubsessionIOState::afterGettingFrame ( unsigned  packetDataSize,
struct timeval  presentationTime 
)

Definition at line 666 of file QuickTimeFileSink.cpp.

References QuickTimeFileSink::addAtom_genericMedia(), SubsessionBuffer::addBytes(), SubsessionBuffer::bytesInUse(), QuickTimeFileSink::continuePlaying(), RTPSource::curPacketRTPSeqNum(), fBuffer, fLastPacketRTPSeqNum, QuickTimeFileSink::fMovieFPS, QuickTimeFileSink::fMovieHeight, QuickTimeFileSink::fMovieWidth, fourChar, fOurSink, fOurSubsession, QuickTimeFileSink::fPacketLossCompensate, fPrevBuffer, fQTBytesPerFrame, fQTMediaDataAtomCreator, fQTSamplesPerFrame, fQTTimeScale, fQTTimeUnitsPerSample, QuickTimeGenericRTPSource::QTState::height, QuickTimeGenericRTPSource::qtState, SubsessionBuffer::reset(), MediaSubsession::rtpSource(), QuickTimeGenericRTPSource::QTState::sdAtom, QuickTimeGenericRTPSource::QTState::sdAtomSize, SubsessionBuffer::setPresentationTime(), QuickTimeGenericRTPSource::QTState::timescale, useFrame(), and QuickTimeGenericRTPSource::QTState::width.

Referenced by QuickTimeFileSink::afterGettingFrame().

00667                                                                            {
00668   // Begin by checking whether there was a gap in the RTP stream.
00669   // If so, try to compensate for this (if desired):
00670   unsigned short rtpSeqNum
00671     = fOurSubsession.rtpSource()->curPacketRTPSeqNum();
00672   if (fOurSink.fPacketLossCompensate && fPrevBuffer->bytesInUse() > 0) {
00673     short seqNumGap = rtpSeqNum - fLastPacketRTPSeqNum;
00674     for (short i = 1; i < seqNumGap; ++i) {
00675       // Insert a copy of the previous frame, to compensate for the loss:
00676       useFrame(*fPrevBuffer);
00677     }
00678   }
00679   fLastPacketRTPSeqNum = rtpSeqNum;
00680 
00681   // Now, continue working with the frame that we just got
00682   if (fBuffer->bytesInUse() == 0) {
00683     fBuffer->setPresentationTime(presentationTime);
00684   }
00685   fBuffer->addBytes(packetDataSize);
00686 
00687   // If our RTP source is a "QuickTimeGenericRTPSource", then
00688   // use its 'qtState' to set some parameters that we need:
00689   if (fQTMediaDataAtomCreator == &QuickTimeFileSink::addAtom_genericMedia){
00690     QuickTimeGenericRTPSource* rtpSource
00691       = (QuickTimeGenericRTPSource*)fOurSubsession.rtpSource();
00692     QuickTimeGenericRTPSource::QTState& qtState = rtpSource->qtState;
00693     fQTTimeScale = qtState.timescale;
00694     if (qtState.width != 0) {
00695       fOurSink.fMovieWidth = qtState.width;
00696     }
00697     if (qtState.height != 0) {
00698       fOurSink.fMovieHeight = qtState.height;
00699     }
00700 
00701     // Also, if the media type in the "sdAtom" is one that we recognize
00702     // to have a special parameters, then fix this here:
00703     if (qtState.sdAtomSize >= 8) {
00704       char const* atom = qtState.sdAtom;
00705       unsigned mediaType = fourChar(atom[4],atom[5],atom[6],atom[7]);
00706       switch (mediaType) {
00707       case fourChar('a','g','s','m'): {
00708         fQTBytesPerFrame = 33;
00709         fQTSamplesPerFrame = 160;
00710         break;
00711       }
00712       case fourChar('Q','c','l','p'): {
00713         fQTBytesPerFrame = 35;
00714         fQTSamplesPerFrame = 160;
00715         break;
00716       }
00717       case fourChar('H','c','l','p'): {
00718         fQTBytesPerFrame = 17;
00719         fQTSamplesPerFrame = 160;
00720         break;
00721       }
00722       case fourChar('h','2','6','3'): {
00723         fQTTimeUnitsPerSample = fQTTimeScale/fOurSink.fMovieFPS;
00724         break;
00725       }
00726       }
00727     }
00728   } else if (fQTMediaDataAtomCreator == &QuickTimeFileSink::addAtom_Qclp) {
00729     // For QCELP data, make a note of the frame size (even though it's the
00730     // same as the packet data size), because it varies depending on the
00731     // 'rate' of the stream, and this size gets used later when setting up
00732     // the 'Qclp' QuickTime atom:
00733     fQTBytesPerFrame = packetDataSize;
00734   }
00735 
00736   useFrame(*fBuffer);
00737   if (fOurSink.fPacketLossCompensate) {
00738     // Save this frame, in case we need it for recovery:
00739     SubsessionBuffer* tmp = fPrevBuffer; // assert: != NULL
00740     fPrevBuffer = fBuffer;
00741     fBuffer = tmp;
00742   }
00743   fBuffer->reset(); // for the next input
00744 
00745   // Now, try getting more frames:
00746   fOurSink.continuePlaying();
00747 }

void SubsessionIOState::onSourceClosure (  ) 

Definition at line 1042 of file QuickTimeFileSink.cpp.

References False, fOurSink, fOurSourceIsActive, and QuickTimeFileSink::onSourceClosure1().

Referenced by QuickTimeFileSink::onRTCPBye(), and QuickTimeFileSink::onSourceClosure().

01042                                         {
01043   fOurSourceIsActive = False;
01044   fOurSink.onSourceClosure1();
01045 }

Boolean SubsessionIOState::syncOK ( struct timeval  presentationTime  ) 

Definition at line 1047 of file QuickTimeFileSink.cpp.

References False, fHaveBeenSynced, QuickTimeFileSink::fNumSubsessions, QuickTimeFileSink::fNumSyncedSubsessions, fOurSink, fOurSubsession, QuickTimeFileSink::fSyncStreams, fSyncTime, RTPSource::hasBeenSynchronizedUsingRTCP(), MediaSubsession::rtpSource(), timevalGE(), and True.

Referenced by QuickTimeFileSink::afterGettingFrame().

01047                                                                  {
01048   QuickTimeFileSink& s = fOurSink; // abbreviation
01049   if (!s.fSyncStreams) return True; // we don't care
01050 
01051   if (s.fNumSyncedSubsessions < s.fNumSubsessions) {
01052     // Not all subsessions have yet been synced.  Check whether ours was
01053     // one of the unsynced ones, and, if so, whether it is now synced:
01054     if (!fHaveBeenSynced) {
01055       // We weren't synchronized before
01056       if (fOurSubsession.rtpSource()->hasBeenSynchronizedUsingRTCP()) {
01057         // But now we are
01058         fHaveBeenSynced = True;
01059         fSyncTime = presentationTime;
01060         ++s.fNumSyncedSubsessions;
01061 
01062         if (timevalGE(fSyncTime, s.fNewestSyncTime)) {
01063           s.fNewestSyncTime = fSyncTime;
01064         }
01065       }
01066     }
01067   }
01068 
01069   // Check again whether all subsessions have been synced:
01070   if (s.fNumSyncedSubsessions < s.fNumSubsessions) return False;
01071 
01072   // Allow this data if it is more recent than the newest sync time:
01073   return timevalGE(presentationTime, s.fNewestSyncTime);
01074 }

void SubsessionIOState::setHintTrack ( SubsessionIOState hintedTrack,
SubsessionIOState hintTrack 
) [static]

Definition at line 1076 of file QuickTimeFileSink.cpp.

References fHintTrackForUs, fTrackHintedByUs, hintedTrack, and NULL.

Referenced by QuickTimeFileSink::QuickTimeFileSink().

01077                                                                    {
01078   if (hintedTrack != NULL) hintedTrack->fHintTrackForUs = hintTrack;
01079   if (hintTrack != NULL) hintTrack->fTrackHintedByUs = hintedTrack;
01080 }

Boolean SubsessionIOState::isHintTrack (  )  const [inline]

Definition at line 114 of file QuickTimeFileSink.cpp.

References fTrackHintedByUs, and NULL.

Referenced by QuickTimeFileSink::addAtom_hdlr2(), and setQTstate().

00114 { return fTrackHintedByUs != NULL; }

Boolean SubsessionIOState::hasHintTrack (  )  const [inline]

Definition at line 115 of file QuickTimeFileSink.cpp.

References fHintTrackForUs, and NULL.

Referenced by QuickTimeFileSink::completeOutputFile(), useFrame(), and while().

00115 { return fHintTrackForUs != NULL; }

UsageEnvironment& SubsessionIOState::envir (  )  const [inline]

Definition at line 117 of file QuickTimeFileSink.cpp.

References Medium::envir(), and fOurSink.

Referenced by QuickTimeFileSink::onRTCPBye(), setQTstate(), and useFrameForHinting().

00117 { return fOurSink.envir(); }

void SubsessionIOState::useFrame ( SubsessionBuffer buffer  )  [private]

Definition at line 749 of file QuickTimeFileSink.cpp.

References QuickTimeFileSink::addWord(), SubsessionBuffer::bytesInUse(), SubsessionBuffer::dataStart(), destFileOffset, duration, fHaveBeenSynced, fHintTrackForUs, fourChar, fOurSink, fOurSubsession, QuickTimeFileSink::fOutFid, fPrevFrameState, fQTcomponentSubtype, fQTMediaDataAtomCreator, fQTSamplesPerFrame, fQTTimeScale, fQTTimeUnitsPerSample, fQTTotNumSamples, frameSize, QuickTimeFileSink::fSyncStreams, RTPSource::hasBeenSynchronizedUsingRTCP(), hasHintTrack(), SubsessionBuffer::presentationTime(), presentationTime, MediaSubsession::rtpSource(), useFrame1(), and useFrameForHinting().

Referenced by afterGettingFrame().

00749                                                          {
00750   unsigned char* const frameSource = buffer.dataStart();
00751   unsigned const frameSize = buffer.bytesInUse();
00752   struct timeval const& presentationTime = buffer.presentationTime();
00753   unsigned const destFileOffset = ftell(fOurSink.fOutFid);
00754   unsigned sampleNumberOfFrameStart = fQTTotNumSamples + 1;
00755   Boolean avcHack = fQTMediaDataAtomCreator == &QuickTimeFileSink::addAtom_avc1;
00756 
00757   // If we're not syncing streams, or this subsession is not video, then
00758   // just give this frame a fixed duration:
00759   if (!fOurSink.fSyncStreams
00760       || fQTcomponentSubtype != fourChar('v','i','d','e')) {
00761     unsigned const frameDuration = fQTTimeUnitsPerSample*fQTSamplesPerFrame;
00762     unsigned frameSizeToUse = frameSize;
00763     if (avcHack) frameSizeToUse += 4; // H.264/AVC gets the frame size prefix
00764 
00765     fQTTotNumSamples += useFrame1(frameSizeToUse, presentationTime, frameDuration, destFileOffset);
00766   } else {
00767     // For synced video streams, we use the difference between successive
00768     // frames' presentation times as the 'frame duration'.  So, record
00769     // information about the *previous* frame:
00770     struct timeval const& ppt = fPrevFrameState.presentationTime; //abbrev
00771     if (ppt.tv_sec != 0 || ppt.tv_usec != 0) {
00772       // There has been a previous frame.
00773       double duration = (presentationTime.tv_sec - ppt.tv_sec)
00774         + (presentationTime.tv_usec - ppt.tv_usec)/1000000.0;
00775       if (duration < 0.0) duration = 0.0;
00776       unsigned frameDuration
00777         = (unsigned)((2*duration*fQTTimeScale+1)/2); // round
00778       unsigned frameSizeToUse = fPrevFrameState.frameSize;
00779       if (avcHack) frameSizeToUse += 4; // H.264/AVC gets the frame size prefix
00780 
00781       unsigned numSamples
00782         = useFrame1(frameSizeToUse, ppt, frameDuration, fPrevFrameState.destFileOffset);
00783       fQTTotNumSamples += numSamples;
00784       sampleNumberOfFrameStart = fQTTotNumSamples + 1;
00785     }
00786 
00787     // Remember the current frame for next time:
00788     fPrevFrameState.frameSize = frameSize;
00789     fPrevFrameState.presentationTime = presentationTime;
00790     fPrevFrameState.destFileOffset = destFileOffset;
00791   }
00792 
00793   if (avcHack) fOurSink.addWord(frameSize);
00794 
00795   // Write the data into the file:
00796   fwrite(frameSource, 1, frameSize, fOurSink.fOutFid);
00797 
00798   // If we have a hint track, then write to it also:
00799   if (hasHintTrack()) {
00800     // Because presentation times are used for RTP packet timestamps,
00801     // we don't starting writing to the hint track until we've been synced:
00802     if (!fHaveBeenSynced) {
00803       fHaveBeenSynced
00804         = fOurSubsession.rtpSource()->hasBeenSynchronizedUsingRTCP();
00805     }
00806     if (fHaveBeenSynced) {
00807       fHintTrackForUs->useFrameForHinting(frameSize, presentationTime,
00808                                           sampleNumberOfFrameStart);
00809     }
00810   }
00811 }

void SubsessionIOState::useFrameForHinting ( unsigned  frameSize,
struct timeval  presentationTime,
unsigned  startSampleNumber 
) [private]

Definition at line 813 of file QuickTimeFileSink.cpp.

References QuickTimeFileSink::addByte(), QuickTimeFileSink::addHalfWord(), QuickTimeFileSink::addWord(), MediaSubsession::codecName(), RTPSource::curPacketMarkerBit(), SubsessionIOState::hinf::dimm, SubsessionIOState::hinf::dmax, SubsessionIOState::hinf::dmed, duration, envir(), fHINF, MediaSubsession::fmtp_indexlength(), MediaSubsession::fmtp_sizelength(), H263plusVideoRTPSource::fNumSpecialHeaders, fOurSink, fOurSubsession, QuickTimeFileSink::fOutFid, H263plusVideoRTPSource::fPacketSizes, fPrevFrameState, fQTBytesPerFrame, fQTSamplesPerFrame, fQTTimeScale, fQTTimeUnitsPerSample, fQTTotNumSamples, H263plusVideoRTPSource::fSpecialHeaderBytes, H263plusVideoRTPSource::fSpecialHeaderBytesLength, fTrackHintedByUs, if(), maxPacketSize, MediaSubsession::mediumName(), NULL, SubsessionIOState::hinf::nump, SubsessionIOState::hinf::pmax, rtpHeader, RTPSource::rtpPayloadFormat(), MediaSubsession::rtpSource(), MediaSubsession::rtpTimestampFrequency(), seqNum, SubsessionIOState::hinf::tpyl, SubsessionIOState::hinf::trpy, and useFrame1().

Referenced by useFrame().

00815                                                                        {
00816   // At this point, we have a single, combined frame - not individual packets.
00817   // For the hint track, we need to split the frame back up into separate packets.
00818   // However, for some RTP sources, then we also need to reuse the special
00819   // header bytes that were at the start of each of the RTP packets.
00820   Boolean hack263 = strcmp(fOurSubsession.codecName(), "H263-1998") == 0;
00821   Boolean hackm4a_generic = strcmp(fOurSubsession.mediumName(), "audio") == 0
00822     && strcmp(fOurSubsession.codecName(), "MPEG4-GENERIC") == 0;
00823   Boolean hackm4a_latm = strcmp(fOurSubsession.mediumName(), "audio") == 0
00824     && strcmp(fOurSubsession.codecName(), "MP4A-LATM") == 0;
00825   Boolean hackm4a = hackm4a_generic || hackm4a_latm;
00826   Boolean haveSpecialHeaders = (hack263 || hackm4a_generic);
00827 
00828   // If there has been a previous frame, then output a 'hint sample' for it.
00829   // (We use the current frame's presentation time to compute the previous
00830   // hint sample's duration.)
00831   RTPSource* const rs = fOurSubsession.rtpSource(); // abbrev
00832   struct timeval const& ppt = fPrevFrameState.presentationTime; //abbrev
00833   if (ppt.tv_sec != 0 || ppt.tv_usec != 0) {
00834     double duration = (