liveMedia/ByteStreamFileSource.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-2012 Live Networks, Inc.  All rights reserved.
00018 // A file source that is a plain byte stream (rather than frames)
00019 // Implementation
00020 
00021 #include "ByteStreamFileSource.hh"
00022 #include "InputFile.hh"
00023 #include "GroupsockHelper.hh"
00024 
00026 
00027 ByteStreamFileSource*
00028 ByteStreamFileSource::createNew(UsageEnvironment& env, char const* fileName,
00029                                 unsigned preferredFrameSize,
00030                                 unsigned playTimePerFrame) {
00031   FILE* fid = OpenInputFile(env, fileName);
00032   if (fid == NULL) return NULL;
00033 
00034   ByteStreamFileSource* newSource
00035     = new ByteStreamFileSource(env, fid, preferredFrameSize, playTimePerFrame);
00036   newSource->fFileSize = GetFileSize(fileName, fid);
00037 
00038   return newSource;
00039 }
00040 
00041 ByteStreamFileSource*
00042 ByteStreamFileSource::createNew(UsageEnvironment& env, FILE* fid,
00043                                 unsigned preferredFrameSize,
00044                                 unsigned playTimePerFrame) {
00045   if (fid == NULL) return NULL;
00046 
00047   ByteStreamFileSource* newSource = new ByteStreamFileSource(env, fid, preferredFrameSize, playTimePerFrame);
00048   newSource->fFileSize = GetFileSize(NULL, fid);
00049 
00050   return newSource;
00051 }
00052 
00053 void ByteStreamFileSource::seekToByteAbsolute(u_int64_t byteNumber, u_int64_t numBytesToStream) {
00054   SeekFile64(fFid, (int64_t)byteNumber, SEEK_SET);
00055 
00056   fNumBytesToStream = numBytesToStream;
00057   fLimitNumBytesToStream = fNumBytesToStream > 0;
00058 }
00059 
00060 void ByteStreamFileSource::seekToByteRelative(int64_t offset) {
00061   SeekFile64(fFid, offset, SEEK_CUR);
00062 }
00063 
00064 void ByteStreamFileSource::seekToEnd() {
00065   SeekFile64(fFid, 0, SEEK_END);
00066 }
00067 
00068 ByteStreamFileSource::ByteStreamFileSource(UsageEnvironment& env, FILE* fid,
00069                                            unsigned preferredFrameSize,
00070                                            unsigned playTimePerFrame)
00071   : FramedFileSource(env, fid), fFileSize(0), fPreferredFrameSize(preferredFrameSize),
00072     fPlayTimePerFrame(playTimePerFrame), fLastPlayTime(0),
00073     fHaveStartedReading(False), fLimitNumBytesToStream(False), fNumBytesToStream(0) {
00074 #ifndef READ_FROM_FILES_SYNCHRONOUSLY
00075   makeSocketNonBlocking(fileno(fFid));
00076 #endif
00077 
00078   // Test whether the file is seekable
00079   fFidIsSeekable = FileIsSeekable(fFid);
00080 }
00081 
00082 ByteStreamFileSource::~ByteStreamFileSource() {
00083   if (fFid == NULL) return;
00084 
00085 #ifndef READ_FROM_FILES_SYNCHRONOUSLY
00086   envir().taskScheduler().turnOffBackgroundReadHandling(fileno(fFid));
00087 #endif
00088 
00089   CloseInputFile(fFid);
00090 }
00091 
00092 void ByteStreamFileSource::doGetNextFrame() {
00093   if (feof(fFid) || ferror(fFid) || (fLimitNumBytesToStream && fNumBytesToStream == 0)) {
00094     handleClosure(this);
00095     return;
00096   }
00097 
00098 #ifdef READ_FROM_FILES_SYNCHRONOUSLY
00099   doReadFromFile();
00100 #else
00101   if (!fHaveStartedReading) {
00102     // Await readable data from the file:
00103     envir().taskScheduler().turnOnBackgroundReadHandling(fileno(fFid),
00104                (TaskScheduler::BackgroundHandlerProc*)&fileReadableHandler, this);
00105     fHaveStartedReading = True;
00106   }
00107 #endif
00108 }
00109 
00110 void ByteStreamFileSource::doStopGettingFrames() {
00111 #ifndef READ_FROM_FILES_SYNCHRONOUSLY
00112   envir().taskScheduler().turnOffBackgroundReadHandling(fileno(fFid));
00113   fHaveStartedReading = False;
00114 #endif
00115 }
00116 
00117 void ByteStreamFileSource::fileReadableHandler(ByteStreamFileSource* source, int /*mask*/) {
00118   if (!source->isCurrentlyAwaitingData()) {
00119     source->doStopGettingFrames(); // we're not ready for the data yet
00120     return;
00121   }
00122   source->doReadFromFile();
00123 }
00124 
00125 static Boolean const readFromFilesSynchronously
00126 #ifdef READ_FROM_FILES_SYNCHRONOUSLY
00127 = True;
00128 #else
00129 = False;
00130 #endif
00131 
00132 void ByteStreamFileSource::doReadFromFile() {
00133   // Try to read as many bytes as will fit in the buffer provided (or "fPreferredFrameSize" if less)
00134   if (fLimitNumBytesToStream && fNumBytesToStream < (u_int64_t)fMaxSize) {
00135     fMaxSize = (unsigned)fNumBytesToStream;
00136   }
00137   if (fPreferredFrameSize > 0 && fPreferredFrameSize < fMaxSize) {
00138     fMaxSize = fPreferredFrameSize;
00139   }
00140   if (readFromFilesSynchronously || fFidIsSeekable) {
00141     fFrameSize = fread(fTo, 1, fMaxSize, fFid);
00142   } else {
00143     // For non-seekable files (e.g., pipes), call "read()" rather than "fread()", to ensure that the read doesn't block:
00144     fFrameSize = read(fileno(fFid), fTo, fMaxSize);
00145   }
00146   if (fFrameSize == 0) {
00147     handleClosure(this);
00148     return;
00149   }
00150   fNumBytesToStream -= fFrameSize;
00151 
00152   // Set the 'presentation time':
00153   if (fPlayTimePerFrame > 0 && fPreferredFrameSize > 0) {
00154     if (fPresentationTime.tv_sec == 0 && fPresentationTime.tv_usec == 0) {
00155       // This is the first frame, so use the current time:
00156       gettimeofday(&fPresentationTime, NULL);
00157     } else {
00158       // Increment by the play time of the previous data:
00159       unsigned uSeconds = fPresentationTime.tv_usec + fLastPlayTime;
00160       fPresentationTime.tv_sec += uSeconds/1000000;
00161       fPresentationTime.tv_usec = uSeconds%1000000;
00162     }
00163 
00164     // Remember the play time of this data:
00165     fLastPlayTime = (fPlayTimePerFrame*fFrameSize)/fPreferredFrameSize;
00166     fDurationInMicroseconds = fLastPlayTime;
00167   } else {
00168     // We don't know a specific play time duration for this data,
00169     // so just record the current time as being the 'presentation time':
00170     gettimeofday(&fPresentationTime, NULL);
00171   }
00172 
00173   // Inform the reader that he has data:
00174 #ifdef READ_FROM_FILES_SYNCHRONOUSLY
00175   // To avoid possible infinite recursion, we need to return to the event loop to do this:
00176   nextTask() = envir().taskScheduler().scheduleDelayedTask(0,
00177                                 (TaskFunc*)FramedSource::afterGetting, this);
00178 #else
00179   // Because the file read was done from the event loop, we can call the
00180   // 'after getting' function directly, without risk of infinite recursion:
00181   FramedSource::afterGetting(this);
00182 #endif
00183 }

Generated on Thu May 17 07:11:45 2012 for live by  doxygen 1.5.2