QuickTimeFileSink Class Reference

#include <QuickTimeFileSink.hh>

Inheritance diagram for QuickTimeFileSink:

Inheritance graph
[legend]
Collaboration diagram for QuickTimeFileSink:

Collaboration graph
[legend]

Public Types

typedef void( afterPlayingFunc )(void *clientData)

Public Member Functions

Boolean startPlaying (afterPlayingFunc *afterFunc, void *afterClientData)
unsigned numActiveSubsessions () const
UsageEnvironmentenvir () const
char const * name () const
virtual Boolean isSource () const
virtual Boolean isSink () const
virtual Boolean isRTCPInstance () const
virtual Boolean isRTSPClient () const
virtual Boolean isRTSPServer () const
virtual Boolean isMediaSession () const
virtual Boolean isServerMediaSession () const
virtual Boolean isDarwinInjector () const

Static Public Member Functions

static QuickTimeFileSinkcreateNew (UsageEnvironment &env, MediaSession &inputSession, char const *outputFileName, unsigned bufferSize=20000, unsigned short movieWidth=240, unsigned short movieHeight=180, unsigned movieFPS=15, Boolean packetLossCompensate=False, Boolean syncStreams=False, Boolean generateHintTracks=False, Boolean generateMP4Format=False)
static Boolean lookupByName (UsageEnvironment &env, char const *mediumName, Medium *&resultMedium)
static void close (UsageEnvironment &env, char const *mediumName)
static void close (Medium *medium)

Protected Member Functions

TaskTokennextTask ()

Private Member Functions

 QuickTimeFileSink (UsageEnvironment &env, MediaSession &inputSession, FILE *outFid, unsigned bufferSize, unsigned short movieWidth, unsigned short movieHeight, unsigned movieFPS, Boolean packetLossCompensate, Boolean syncStreams, Boolean generateHintTracks, Boolean generateMP4Format)
virtual ~QuickTimeFileSink ()
Boolean continuePlaying ()
void onSourceClosure1 ()
void completeOutputFile ()
unsigned addWord (unsigned word)
unsigned addHalfWord (unsigned short halfWord)
unsigned addByte (unsigned char byte)
unsigned addZeroWords (unsigned numWords)
unsigned add4ByteString (char const *str)
unsigned addArbitraryString (char const *str, Boolean oneByteLength=True)
unsigned addAtomHeader (char const *atomName)
void setWord (unsigned filePosn, unsigned size)
unsigned movieTimeScale () const
 _atom (ftyp)
 _atom (moov)
 _atom (mvhd)
 _atom (iods)
 _atom (trak)
 _atom (tkhd)
 _atom (edts)
 _atom (elst)
 _atom (tref)
 _atom (hint)
 _atom (mdia)
 _atom (mdhd)
 _atom (hdlr)
 _atom (minf)
 _atom (smhd)
 _atom (vmhd)
 _atom (gmhd)
 _atom (gmin)
unsigned addAtom_hdlr2 ()
 _atom (dinf)
 _atom (dref)
 _atom (alis)
 _atom (stbl)
 _atom (stsd)
unsigned addAtom_genericMedia ()
unsigned addAtom_soundMediaGeneral ()
 _atom (ulaw)
 _atom (alaw)
 _atom (Qclp)
 _atom (wave)
 _atom (frma)
 _atom (Fclp)
 _atom (Hclp)
 _atom (mp4a)
 _atom (esds)
 _atom (srcq)
 _atom (h263)
 _atom (avc1)
 _atom (avcC)
 _atom (mp4v)
 _atom (rtp)
 _atom (tims)
 _atom (stts)
 _atom (stsc)
 _atom (stsz)
 _atom (stco)
 _atom (udta)
 _atom (name)
 _atom (hnti)
 _atom (sdp)
 _atom (hinf)
 _atom (totl)
 _atom (npck)
 _atom (tpay)
 _atom (trpy)
 _atom (nump)
 _atom (tpyl)
 _atom (dmed)
 _atom (dimm)
 _atom (drep)
 _atom (tmin)
 _atom (tmax)
 _atom (pmax)
 _atom (dmax)
 _atom (payt)
unsigned addAtom_dummy ()

Static Private Member Functions

static void afterGettingFrame (void *clientData, unsigned frameSize, unsigned numTruncatedBytes, struct timeval presentationTime, unsigned durationInMicroseconds)
static void onSourceClosure (void *clientData)
static void onRTCPBye (void *clientData)

Private Attributes

MediaSessionfInputSession
FILE * fOutFid
unsigned fBufferSize
Boolean fPacketLossCompensate
Boolean fSyncStreams
Boolean fGenerateMP4Format
timeval fNewestSyncTime fFirstDataTime
Boolean fAreCurrentlyBeingPlayed
afterPlayingFuncfAfterFunc
void * fAfterClientData
unsigned fAppleCreationTime
unsigned fLargestRTPtimestampFrequency
unsigned fNumSubsessions
unsigned fNumSyncedSubsessions
timeval fStartTime
Boolean fHaveCompletedOutputFile
unsigned short fMovieWidth
unsigned short fMovieHeight
unsigned fMovieFPS
unsigned fMDATposition
unsigned fMVHD_durationPosn
unsigned fMaxTrackDurationM
SubsessionIOStatefCurrentIOState

Friends

class SubsessionIOState

Detailed Description

Definition at line 28 of file QuickTimeFileSink.hh.


Member Typedef Documentation

typedef void( QuickTimeFileSink::afterPlayingFunc)(void *clientData)

Definition at line 42 of file QuickTimeFileSink.hh.


Constructor & Destructor Documentation

QuickTimeFileSink::QuickTimeFileSink ( UsageEnvironment env,
MediaSession inputSession,
FILE *  outFid,
unsigned  bufferSize,
unsigned short  movieWidth,
unsigned short  movieHeight,
unsigned  movieFPS,
Boolean  packetLossCompensate,
Boolean  syncStreams,
Boolean  generateHintTracks,
Boolean  generateMP4Format 
) [private]

Definition at line 206 of file QuickTimeFileSink.cpp.

References addAtomHeader(), fAppleCreationTime, fFirstDataTime, fInputSession, fLargestRTPtimestampFrequency, fMDATposition, fMovieFPS, fMovieHeight, fMovieWidth, fNumSubsessions, fOutFid, fStartTime, iter, MediaSubsession::miscPtr, MediaSubsessionIterator::next(), NULL, onRTCPBye(), MediaSubsession::readSource(), MediaSubsession::rtcpInstance(), MediaSubsession::rtpTimestampFrequency(), RTCPInstance::setByeHandler(), SubsessionIOState::setHintTrack(), SubsessionIOState::setQTstate(), subsession, SubsessionIOState, MediaSubsession::videoFPS(), MediaSubsession::videoHeight(), and MediaSubsession::videoWidth().

Referenced by createNew().

00217   : Medium(env), fInputSession(inputSession), fOutFid(outFid),
00218     fBufferSize(bufferSize), fPacketLossCompensate(packetLossCompensate),
00219     fSyncStreams(syncStreams), fGenerateMP4Format(generateMP4Format),
00220     fAreCurrentlyBeingPlayed(False),
00221     fLargestRTPtimestampFrequency(0),
00222     fNumSubsessions(0), fNumSyncedSubsessions(0),
00223     fHaveCompletedOutputFile(False),
00224     fMovieWidth(movieWidth), fMovieHeight(movieHeight),
00225     fMovieFPS(movieFPS), fMaxTrackDurationM(0) {
00226   fNewestSyncTime.tv_sec = fNewestSyncTime.tv_usec = 0;
00227   fFirstDataTime.tv_sec = fFirstDataTime.tv_usec = (unsigned)(~0);
00228 
00229   // Set up I/O state for each input subsession:
00230   MediaSubsessionIterator iter(fInputSession);
00231   MediaSubsession* subsession;
00232   while ((subsession = iter.next()) != NULL) {
00233     // Ignore subsessions without a data source:
00234     FramedSource* subsessionSource = subsession->readSource();
00235     if (subsessionSource == NULL) continue;
00236 
00237     // If "subsession's" SDP description specified screen dimension
00238     // or frame rate parameters, then use these.  (Note that this must
00239     // be done before the call to "setQTState()" below.)
00240     if (subsession->videoWidth() != 0) {
00241       fMovieWidth = subsession->videoWidth();
00242     }
00243     if (subsession->videoHeight() != 0) {
00244       fMovieHeight = subsession->videoHeight();
00245     }
00246     if (subsession->videoFPS() != 0) {
00247       fMovieFPS = subsession->videoFPS();
00248     }
00249 
00250     SubsessionIOState* ioState
00251       = new SubsessionIOState(*this, *subsession);
00252     if (ioState == NULL || !ioState->setQTstate()) {
00253       // We're not able to output a QuickTime track for this subsession
00254       delete ioState; ioState = NULL;
00255       continue;
00256     }
00257     subsession->miscPtr = (void*)ioState;
00258 
00259     if (generateHintTracks) {
00260       // Also create a hint track for this track:
00261       SubsessionIOState* hintTrack
00262         = new SubsessionIOState(*this, *subsession);
00263       SubsessionIOState::setHintTrack(ioState, hintTrack);
00264       if (!hintTrack->setQTstate()) {
00265         delete hintTrack;
00266         SubsessionIOState::setHintTrack(ioState, NULL);
00267       }
00268     }
00269 
00270     // Also set a 'BYE' handler for this subsession's RTCP instance:
00271     if (subsession->rtcpInstance() != NULL) {
00272       subsession->rtcpInstance()->setByeHandler(onRTCPBye, ioState);
00273     }
00274 
00275     unsigned rtpTimestampFrequency = subsession->rtpTimestampFrequency();
00276     if (rtpTimestampFrequency > fLargestRTPtimestampFrequency) {
00277       fLargestRTPtimestampFrequency = rtpTimestampFrequency;
00278     }
00279 
00280     ++fNumSubsessions;
00281   }
00282 
00283   // Use the current time as the file's creation and modification
00284   // time.  Use Apple's time format: seconds since January 1, 1904
00285 
00286   gettimeofday(&fStartTime, NULL);
00287   fAppleCreationTime = fStartTime.tv_sec - 0x83dac000;
00288 
00289   // Begin by writing a "mdat" atom at the start of the file.
00290   // (Later, when we've finished copying data to the file, we'll come
00291   // back and fill in its size.)
00292   fMDATposition = ftell(fOutFid);
00293   addAtomHeader("mdat");
00294 }

QuickTimeFileSink::~QuickTimeFileSink (  )  [private, virtual]

Definition at line 296 of file QuickTimeFileSink.cpp.

References completeOutputFile(), SubsessionIOState::fHintTrackForUs, fInputSession, iter, MediaSubsession::miscPtr, MediaSubsessionIterator::next(), NULL, and subsession.

00296                                       {
00297   completeOutputFile();
00298 
00299   // Then, delete each active "SubsessionIOState":
00300   MediaSubsessionIterator iter(fInputSession);
00301   MediaSubsession* subsession;
00302   while ((subsession = iter.next()) != NULL) {
00303     SubsessionIOState* ioState
00304       = (SubsessionIOState*)(subsession->miscPtr); 
00305     if (ioState == NULL) continue;
00306 
00307     delete ioState->fHintTrackForUs; // if any
00308     delete ioState;
00309   }
00310 }


Member Function Documentation

QuickTimeFileSink * QuickTimeFileSink::createNew ( UsageEnvironment env,
MediaSession inputSession,
char const *  outputFileName,
unsigned  bufferSize = 20000,
unsigned short  movieWidth = 240,
unsigned short  movieHeight = 180,
unsigned  movieFPS = 15,
Boolean  packetLossCompensate = False,
Boolean  syncStreams = False,
Boolean  generateHintTracks = False,
Boolean  generateMP4Format = False 
) [static]

Definition at line 313 of file QuickTimeFileSink.cpp.

References env, NULL, OpenOutputFile(), and QuickTimeFileSink().

Referenced by main().

00323                                                         {
00324   do {
00325     FILE* fid = OpenOutputFile(env, outputFileName);
00326     if (fid == NULL) break;
00327 
00328     return new QuickTimeFileSink(env, inputSession, fid, bufferSize,
00329                                  movieWidth, movieHeight, movieFPS,
00330                                  packetLossCompensate, syncStreams,
00331                                  generateHintTracks, generateMP4Format);
00332   } while (0);
00333 
00334   return NULL;
00335 }

Boolean QuickTimeFileSink::startPlaying ( afterPlayingFunc afterFunc,
void *  afterClientData 
)

Definition at line 337 of file QuickTimeFileSink.cpp.

References continuePlaying(), Medium::envir(), fAfterClientData, fAfterFunc, False, fAreCurrentlyBeingPlayed, UsageEnvironment::setResultMsg(), and True.

Referenced by main().

00338                                                                {
00339   // Make sure we're not already being played:
00340   if (fAreCurrentlyBeingPlayed) {
00341     envir().setResultMsg("This sink has already been played");
00342     return False;
00343   }
00344 
00345   fAreCurrentlyBeingPlayed = True;
00346   fAfterFunc = afterFunc;
00347   fAfterClientData = afterClientData;
00348 
00349   return continuePlaying();
00350 }

unsigned QuickTimeFileSink::numActiveSubsessions (  )  const [inline]

Definition at line 46 of file QuickTimeFileSink.hh.

References fNumSubsessions.

Referenced by checkForPacketArrival().

00046 { return fNumSubsessions; }

Boolean QuickTimeFileSink::continuePlaying (  )  [private]

Definition at line 352 of file QuickTimeFileSink.cpp.

References afterGettingFrame(), SubsessionBuffer::bytesAvailable(), SubsessionBuffer::dataEnd(), Medium::envir(), False, SubsessionIOState::fBuffer, fInputSession, FramedSource::getNextFrame(), FramedSource::isCurrentlyAwaitingData(), iter, MediaSubsession::miscPtr, MediaSubsessionIterator::next(), NULL, onSourceClosure(), MediaSubsession::readSource(), UsageEnvironment::setResultMsg(), subsession, and True.

Referenced by SubsessionIOState::afterGettingFrame(), afterGettingFrame(), and startPlaying().

00352                                            {
00353   // Run through each of our input session's 'subsessions',
00354   // asking for a frame from each one:
00355   Boolean haveActiveSubsessions = False; 
00356   MediaSubsessionIterator iter(fInputSession);
00357   MediaSubsession* subsession;
00358   while ((subsession = iter.next()) != NULL) {
00359     FramedSource* subsessionSource = subsession->readSource();
00360     if (subsessionSource == NULL) continue;
00361 
00362     if (subsessionSource->isCurrentlyAwaitingData()) continue;
00363 
00364     SubsessionIOState* ioState
00365       = (SubsessionIOState*)(subsession->miscPtr); 
00366     if (ioState == NULL) continue;
00367 
00368     haveActiveSubsessions = True;
00369     unsigned char* toPtr = ioState->fBuffer->dataEnd();
00370     unsigned toSize = ioState->fBuffer->bytesAvailable();
00371     subsessionSource->getNextFrame(toPtr, toSize,
00372                                    afterGettingFrame, ioState,
00373                                    onSourceClosure, ioState);
00374   }
00375   if (!haveActiveSubsessions) {
00376     envir().setResultMsg("No subsessions are currently active");
00377     return False;
00378   }
00379 
00380   return True;
00381 }

void QuickTimeFileSink::afterGettingFrame ( void *  clientData,
unsigned  frameSize,
unsigned  numTruncatedBytes,
struct timeval  presentationTime,
unsigned  durationInMicroseconds 
) [static, private]

Definition at line 384 of file QuickTimeFileSink.cpp.

References SubsessionIOState::afterGettingFrame(), continuePlaying(), SubsessionIOState::fOurSink, and SubsessionIOState::syncOK().

Referenced by continuePlaying().

00387                                                          {
00388   SubsessionIOState* ioState = (SubsessionIOState*)clientData;
00389   if (!ioState->syncOK(presentationTime)) {
00390     // Ignore this data:
00391     ioState->fOurSink.continuePlaying();
00392     return;
00393   }
00394   ioState->afterGettingFrame(packetDataSize, presentationTime);
00395 }

void QuickTimeFileSink::onSourceClosure ( void *  clientData  )  [static, private]

Definition at line 397 of file QuickTimeFileSink.cpp.

References SubsessionIOState::onSourceClosure().

Referenced by continuePlaying().

00397                                                         {
00398   SubsessionIOState* ioState = (SubsessionIOState*)clientData;
00399   ioState->onSourceClosure();
00400 }

void QuickTimeFileSink::onSourceClosure1 (  )  [private]

Definition at line 402 of file QuickTimeFileSink.cpp.

References completeOutputFile(), fAfterClientData, fAfterFunc, fInputSession, SubsessionIOState::fOurSourceIsActive, iter, MediaSubsession::miscPtr, MediaSubsessionIterator::next(), NULL, and subsession.

Referenced by SubsessionIOState::onSourceClosure().

00402                                          {
00403   // Check whether *all* of the subsession sources have closed.
00404   // If not, do nothing for now:
00405   MediaSubsessionIterator iter(fInputSession);
00406   MediaSubsession* subsession;
00407   while ((subsession = iter.next()) != NULL) {
00408     SubsessionIOState* ioState
00409       = (SubsessionIOState*)(subsession->miscPtr); 
00410     if (ioState == NULL) continue;
00411 
00412     if (ioState->fOurSourceIsActive) return; // this source hasn't closed
00413   }
00414 
00415   completeOutputFile();
00416 
00417   // Call our specified 'after' function:
00418   if (fAfterFunc != NULL) {
00419     (*fAfterFunc)(fAfterClientData);
00420   }
00421 }

void QuickTimeFileSink::onRTCPBye ( void *  clientData  )  [static, private]

Definition at line 423 of file QuickTimeFileSink.cpp.

References MediaSubsession::codecName(), SubsessionIOState::envir(), SubsessionIOState::fOurSink, SubsessionIOState::fOurSubsession, fStartTime, MediaSubsession::mediumName(), NULL, SubsessionIOState::onSourceClosure(), and subsession.

Referenced by QuickTimeFileSink().

00423                                                   {
00424   SubsessionIOState* ioState = (SubsessionIOState*)clientData;
00425 
00426   struct timeval timeNow;
00427   gettimeofday(&timeNow, NULL);
00428   unsigned secsDiff
00429     = timeNow.tv_sec - ioState->fOurSink.fStartTime.tv_sec;
00430 
00431   MediaSubsession& subsession = ioState->fOurSubsession;
00432   ioState->envir() << "Received RTCP \"BYE\" on \""
00433                    << subsession.mediumName()
00434                    << "/" << subsession.codecName()
00435                    << "\" subsession (after "
00436                    << secsDiff << " seconds)\n";
00437 
00438   // Handle the reception of a RTCP "BYE" as if the source had closed:
00439   ioState->onSourceClosure();
00440 }

void QuickTimeFileSink::completeOutputFile (  )  [private]

Definition at line 449 of file QuickTimeFileSink.cpp.

References fFirstDataTime, fGenerateMP4Format, fHaveCompletedOutputFile, SubsessionIOState::fHeadChunk, SubsessionIOState::fHintTrackForUs, fInputSession, fMDATposition, fOutFid, ChunkDescriptor::fPresentationTime, SubsessionIOState::hasHintTrack(), iter, MediaSubsession::miscPtr, MediaSubsessionIterator::next(), NULL, MediaSubsessionIterator::reset(), SubsessionIOState::setFinalQTstate(), setWord(), subsession, timevalGE(), and True.

Referenced by onSourceClosure1(), and ~QuickTimeFileSink().

00449                                            {
00450   if (fHaveCompletedOutputFile || fOutFid == NULL) return;
00451 
00452   // Begin by filling in the initial "mdat" atom with the current
00453   // file size:
00454   unsigned curFileSize = ftell(fOutFid);
00455   setWord(fMDATposition, curFileSize);
00456 
00457   // Then, note the time of the first received data:
00458   MediaSubsessionIterator iter(fInputSession);
00459   MediaSubsession* subsession;
00460   while ((subsession = iter.next()) != NULL) {
00461     SubsessionIOState* ioState
00462       = (SubsessionIOState*)(subsession->miscPtr); 
00463     if (ioState == NULL) continue;
00464 
00465     ChunkDescriptor* const headChunk = ioState->fHeadChunk;
00466     if (headChunk != NULL
00467         && timevalGE(fFirstDataTime, headChunk->fPresentationTime)) {
00468       fFirstDataTime = headChunk->fPresentationTime;
00469     }
00470   }
00471 
00472   // Then, update the QuickTime-specific state for each active track:
00473   iter.reset();
00474   while ((subsession = iter.next()) != NULL) {
00475     SubsessionIOState* ioState
00476       = (SubsessionIOState*)(subsession->miscPtr); 
00477     if (ioState == NULL) continue;
00478 
00479     ioState->setFinalQTstate();
00480     // Do the same for a hint track (if any):
00481     if (ioState->hasHintTrack()) {
00482       ioState->fHintTrackForUs->setFinalQTstate();
00483     }
00484   }
00485 
00486   if (fGenerateMP4Format) {
00487     // Begin with a "ftyp" atom:
00488     addAtom_ftyp();
00489   }
00490 
00491   // Then, add a "moov" atom for the file metadata:
00492   addAtom_moov();
00493 
00494   // We're done:
00495   fHaveCompletedOutputFile = True;
00496 }

unsigned QuickTimeFileSink::addWord ( unsigned  word  )  [private]

Definition at line 1129 of file QuickTimeFileSink.cpp.

References addByte().

Referenced by addAtom_hdlr2(), addAtomHeader(), addZeroWords(), if(), setWord(), SubsessionIOState::useFrame(), and SubsessionIOState::useFrameForHinting().

01129                                                  {
01130   addByte(word>>24); addByte(word>>16);
01131   addByte(word>>8); addByte(word);
01132 
01133   return 4;
01134 }

unsigned QuickTimeFileSink::addHalfWord ( unsigned short  halfWord  )  [private]

Definition at line 1136 of file QuickTimeFileSink.cpp.

References addByte().

Referenced by addAtom_hdlr2(), and SubsessionIOState::useFrameForHinting().

01136                                                                {
01137   addByte((unsigned char)(halfWord>>8)); addByte((unsigned char)halfWord);
01138 
01139   return 2;
01140 }

unsigned QuickTimeFileSink::addByte ( unsigned char  byte  )  [inline, private]

Definition at line 90 of file QuickTimeFileSink.hh.

References fOutFid.

Referenced by add4ByteString(), addArbitraryString(), addAtom_hdlr2(), addHalfWord(), addWord(), and SubsessionIOState::useFrameForHinting().

00090                                        {
00091     putc(byte, fOutFid);
00092     return 1;
00093   }

unsigned QuickTimeFileSink::addZeroWords ( unsigned  numWords  )  [private]

Definition at line 1142 of file QuickTimeFileSink.cpp.

References addWord().

Referenced by addAtom_hdlr2().

01142                                                           {
01143   for (unsigned i = 0; i < numWords; ++i) {
01144     addWord(0);
01145   }
01146 
01147   return numWords*4;
01148 }

unsigned QuickTimeFileSink::add4ByteString ( char const *  str  )  [private]

Definition at line 1150 of file QuickTimeFileSink.cpp.

References addByte().

Referenced by addAtom_hdlr2(), and addAtomHeader().

01150                                                           {
01151   addByte(str[0]); addByte(str[1]); addByte(str[2]); addByte(str[3]);
01152 
01153   return 4;
01154 }

unsigned QuickTimeFileSink::addArbitraryString ( char const *  str,
Boolean  oneByteLength = True 
) [private]

Definition at line 1156 of file QuickTimeFileSink.cpp.

References addByte(), Medium::envir(), and size.

Referenced by addAtom_hdlr2().

01157                                                                       {
01158   unsigned size = 0;
01159   if (oneByteLength) {
01160     // Begin with a byte containing the string length:
01161     unsigned strLength = strlen(str);
01162     if (strLength >= 256) {
01163       envir() << "QuickTimeFileSink::addArbitraryString(\""
01164               << str << "\") saw string longer than we know how to handle ("
01165               << strLength << "\n";
01166     }
01167     size += addByte((unsigned char)strLength);
01168