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-2008 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) {
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 }
00043 
00044 FileSink::~FileSink() {
00045   delete[] fPerFrameFileNameBuffer;
00046   delete[] fPerFrameFileNamePrefix;
00047   delete[] fBuffer;
00048   if (fOutFid != NULL) fclose(fOutFid);
00049 }
00050 
00051 FileSink* FileSink::createNew(UsageEnvironment& env, char const* fileName,
00052                               unsigned bufferSize, Boolean oneFilePerFrame) {
00053   do {
00054     FILE* fid;
00055     char const* perFrameFileNamePrefix;
00056     if (oneFilePerFrame) {
00057       // Create the fid for each frame
00058       fid = NULL;
00059       perFrameFileNamePrefix = fileName;
00060     } else {
00061       // Normal case: create the fid once
00062       fid = OpenOutputFile(env, fileName);
00063       if (fid == NULL) break;
00064       perFrameFileNamePrefix = NULL;
00065     }
00066 
00067     return new FileSink(env, fid, bufferSize, perFrameFileNamePrefix);
00068   } while (0);
00069 
00070   return NULL;
00071 }
00072 
00073 Boolean FileSink::continuePlaying() {
00074   if (fSource == NULL) return False;
00075 
00076   fSource->getNextFrame(fBuffer, fBufferSize,
00077                         afterGettingFrame, this,
00078                         onSourceClosure, this);
00079 
00080   return True;
00081 }
00082 
00083 void FileSink::afterGettingFrame(void* clientData, unsigned frameSize,
00084                                  unsigned /*numTruncatedBytes*/,
00085                                  struct timeval presentationTime,
00086                                  unsigned /*durationInMicroseconds*/) {
00087   FileSink* sink = (FileSink*)clientData;
00088   sink->afterGettingFrame1(frameSize, presentationTime);
00089 }
00090 
00091 void FileSink::addData(unsigned char* data, unsigned dataSize,
00092                        struct timeval presentationTime) {
00093   if (fPerFrameFileNameBuffer != NULL) {
00094     // Special case: Open a new file on-the-fly for this frame
00095     sprintf(fPerFrameFileNameBuffer, "%s-%lu.%06lu", fPerFrameFileNamePrefix,
00096             presentationTime.tv_sec, presentationTime.tv_usec);
00097     fOutFid = OpenOutputFile(envir(), fPerFrameFileNameBuffer);
00098   }
00099 
00100   // Write to our file:
00101 #ifdef TEST_LOSS
00102   static unsigned const framesPerPacket = 10;
00103   static unsigned const frameCount = 0;
00104   static Boolean const packetIsLost;
00105   if ((frameCount++)%framesPerPacket == 0) {
00106     packetIsLost = (our_random()%10 == 0); // simulate 10% packet loss #####
00107   }
00108 
00109   if (!packetIsLost)
00110 #endif
00111   if (fOutFid != NULL && data != NULL) {
00112     fwrite(data, 1, dataSize, fOutFid);
00113   }
00114 }
00115 
00116 void FileSink::afterGettingFrame1(unsigned frameSize,
00117                                   struct timeval presentationTime) {
00118   addData(fBuffer, frameSize, presentationTime);
00119 
00120   if (fOutFid == NULL || fflush(fOutFid) == EOF) {
00121     // The output file has closed.  Handle this the same way as if the
00122     // input source had closed:
00123     onSourceClosure(this);
00124 
00125     stopPlaying();
00126     return;
00127   }
00128 
00129   if (fPerFrameFileNameBuffer != NULL) {
00130     if (fOutFid != NULL) { fclose(fOutFid); fOutFid = NULL; }
00131   }
00132 
00133   // Then try getting the next frame:
00134   continuePlaying();
00135 }

Generated on Tue Oct 7 15:38:08 2008 for live by  doxygen 1.5.2