liveMedia/FileSink.cpp

Go to the documentation of this file.
00001 /**********
00002 This library is free software; you can redistribute it and/or modify it under
00003 the terms of the GNU Lesser General Public License as published by the
00004 Free Software Foundation; either version 2.1 of the License, or (at your
00005 option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.)
00006 
00007 This library is distributed in the hope that it will be useful, but WITHOUT
00008 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00009 FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
00010 more details.
00011 
00012 You should have received a copy of the GNU Lesser General Public License
00013 along with this library; if not, write to the Free Software Foundation, Inc.,
00014 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
00015 **********/
00016 // "liveMedia"
00017 // Copyright (c) 1996-2014 Live Networks, Inc.  All rights reserved.
00018 // File sinks
00019 // Implementation
00020 
00021 #if (defined(__WIN32__) || defined(_WIN32)) && !defined(_WIN32_WCE)
00022 #include <io.h>
00023 #include <fcntl.h>
00024 #endif
00025 #include "FileSink.hh"
00026 #include "GroupsockHelper.hh"
00027 #include "OutputFile.hh"
00028 
00030 
00031 FileSink::FileSink(UsageEnvironment& env, FILE* fid, unsigned bufferSize,
00032                    char const* perFrameFileNamePrefix)
00033   : MediaSink(env), fOutFid(fid), fBufferSize(bufferSize), fSamePresentationTimeCounter(0) {
00034   fBuffer = new unsigned char[bufferSize];
00035   if (perFrameFileNamePrefix != NULL) {
00036     fPerFrameFileNamePrefix = strDup(perFrameFileNamePrefix);
00037     fPerFrameFileNameBuffer = new char[strlen(perFrameFileNamePrefix) + 100];
00038   } else {
00039     fPerFrameFileNamePrefix = NULL;
00040     fPerFrameFileNameBuffer = NULL;
00041   }
00042   fPrevPresentationTime.tv_sec = ~0; fPrevPresentationTime.tv_usec = 0;
00043 }
00044 
00045 FileSink::~FileSink() {
00046   delete[] fPerFrameFileNameBuffer;
00047   delete[] fPerFrameFileNamePrefix;
00048   delete[] fBuffer;
00049   if (fOutFid != NULL) fclose(fOutFid);
00050 }
00051 
00052 FileSink* FileSink::createNew(UsageEnvironment& env, char const* fileName,
00053                               unsigned bufferSize, Boolean oneFilePerFrame) {
00054   do {
00055     FILE* fid;
00056     char const* perFrameFileNamePrefix;
00057     if (oneFilePerFrame) {
00058       // Create the fid for each frame
00059       fid = NULL;
00060       perFrameFileNamePrefix = fileName;
00061     } else {
00062       // Normal case: create the fid once
00063       fid = OpenOutputFile(env, fileName);
00064       if (fid == NULL) break;
00065       perFrameFileNamePrefix = NULL;
00066     }
00067 
00068     return new FileSink(env, fid, bufferSize, perFrameFileNamePrefix);
00069   } while (0);
00070 
00071   return NULL;
00072 }
00073 
00074 Boolean FileSink::continuePlaying() {
00075   if (fSource == NULL) return False;
00076 
00077   fSource->getNextFrame(fBuffer, fBufferSize,
00078                         afterGettingFrame, this,
00079                         onSourceClosure, this);
00080 
00081   return True;
00082 }
00083 
00084 void FileSink::afterGettingFrame(void* clientData, unsigned frameSize,
00085                                  unsigned numTruncatedBytes,
00086                                  struct timeval presentationTime,
00087                                  unsigned /*durationInMicroseconds*/) {
00088   FileSink* sink = (FileSink*)clientData;
00089   sink->afterGettingFrame(frameSize, numTruncatedBytes, presentationTime);
00090 }
00091 
00092 void FileSink::addData(unsigned char const* data, unsigned dataSize,
00093                        struct timeval presentationTime) {
00094   if (fPerFrameFileNameBuffer != NULL && fOutFid == NULL) {
00095     // Special case: Open a new file on-the-fly for this frame
00096     if (presentationTime.tv_usec == fPrevPresentationTime.tv_usec &&
00097         presentationTime.tv_sec == fPrevPresentationTime.tv_sec) {
00098       // The presentation time is unchanged from the previous frame, so we add a 'counter'
00099       // suffix to the file name, to distinguish them:
00100       sprintf(fPerFrameFileNameBuffer, "%s-%lu.%06lu-%u", fPerFrameFileNamePrefix,
00101               presentationTime.tv_sec, presentationTime.tv_usec, ++fSamePresentationTimeCounter);
00102     } else {
00103       sprintf(fPerFrameFileNameBuffer, "%s-%lu.%06lu", fPerFrameFileNamePrefix,
00104               presentationTime.tv_sec, presentationTime.tv_usec);
00105       fPrevPresentationTime = presentationTime; // for next time
00106       fSamePresentationTimeCounter = 0; // for next time
00107     }
00108     fOutFid = OpenOutputFile(envir(), fPerFrameFileNameBuffer);
00109   }
00110 
00111   // Write to our file:
00112 #ifdef TEST_LOSS
00113   static unsigned const framesPerPacket = 10;
00114   static unsigned const frameCount = 0;
00115   static Boolean const packetIsLost;
00116   if ((frameCount++)%framesPerPacket == 0) {
00117     packetIsLost = (our_random()%10 == 0); // simulate 10% packet loss #####
00118   }
00119 
00120   if (!packetIsLost)
00121 #endif
00122   if (fOutFid != NULL && data != NULL) {
00123     fwrite(data, 1, dataSize, fOutFid);
00124   }
00125 }
00126 
00127 void FileSink::afterGettingFrame(unsigned frameSize,
00128                                  unsigned numTruncatedBytes,
00129                                  struct timeval presentationTime) {
00130   if (numTruncatedBytes > 0) {
00131     envir() << "FileSink::afterGettingFrame(): The input frame data was too large for our buffer size ("
00132             << fBufferSize << ").  "
00133             << numTruncatedBytes << " bytes of trailing data was dropped!  Correct this by increasing the \"bufferSize\" parameter in the \"createNew()\" call to at least "
00134             << fBufferSize + numTruncatedBytes << "\n";
00135   }
00136   addData(fBuffer, frameSize, presentationTime);
00137 
00138   if (fOutFid == NULL || fflush(fOutFid) == EOF) {
00139     // The output file has closed.  Handle this the same way as if the input source had closed:
00140     if (fSource != NULL) fSource->stopGettingFrames();
00141     onSourceClosure();
00142     return;
00143   }
00144 
00145   if (fPerFrameFileNameBuffer != NULL) {
00146     if (fOutFid != NULL) { fclose(fOutFid); fOutFid = NULL; }
00147   }
00148 
00149   // Then try getting the next frame:
00150   continuePlaying();
00151 }

Generated on Tue Mar 25 14:35:34 2014 for live by  doxygen 1.5.2