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-2013 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   envir().taskScheduler().unscheduleDelayedTask(nextTask());
00112 #ifndef READ_FROM_FILES_SYNCHRONOUSLY
00113   envir().taskScheduler().turnOffBackgroundReadHandling(fileno(fFid));
00114   fHaveStartedReading = False;
00115 #endif
00116 }
00117 
00118 void ByteStreamFileSource::fileReadableHandler(ByteStreamFileSource* source, int /*mask*/) {
00119   if (!source->isCurrentlyAwaitingData()) {
00120     source->doStopGettingFrames(); // we're not ready for the data yet
00121     return;
00122   }
00123   source->doReadFromFile();
00124 }
00125 
00126 void ByteStreamFileSource::doReadFromFile() {
00127   // Try to read as many bytes as will fit in the buffer provided (or "fPreferredFrameSize" if less)
00128   if (fLimitNumBytesToStream && fNumBytesToStream < (u_int64_t)fMaxSize) {
00129     fMaxSize = (unsigned)fNumBytesToStream;
00130   }
00131   if (fPreferredFrameSize > 0 && fPreferredFrameSize < fMaxSize) {
00132     fMaxSize = fPreferredFrameSize;
00133   }
00134 #ifdef READ_FROM_FILES_SYNCHRONOUSLY
00135   fFrameSize = fread(fTo, 1, fMaxSize, fFid);
00136 #else
00137   if (fFidIsSeekable) {
00138     fFrameSize = fread(fTo, 1, fMaxSize, fFid);
00139   } else {
00140     // For non-seekable files (e.g., pipes), call "read()" rather than "fread()", to ensure that the read doesn't block:
00141     fFrameSize = read(fileno(fFid), fTo, fMaxSize);
00142   }
00143 #endif
00144   if (fFrameSize == 0) {
00145     handleClosure(this);
00146     return;
00147   }
00148   fNumBytesToStream -= fFrameSize;
00149 
00150   // Set the 'presentation time':
00151   if (fPlayTimePerFrame > 0 && fPreferredFrameSize > 0) {
00152     if (fPresentationTime.tv_sec == 0 && fPresentationTime.tv_usec == 0) {
00153       // This is the first frame, so use the current time:
00154       gettimeofday(&fPresentationTime, NULL);
00155     } else {
00156       // Increment by the play time of the previous data:
00157       unsigned uSeconds = fPresentationTime.tv_usec + fLastPlayTime;
00158       fPresentationTime.tv_sec += uSeconds/1000000;
00159       fPresentationTime.tv_usec = uSeconds%1000000;
00160     }
00161 
00162     // Remember the play time of this data:
00163     fLastPlayTime = (fPlayTimePerFrame*fFrameSize)/fPreferredFrameSize;
00164     fDurationInMicroseconds = fLastPlayTime;
00165   } else {
00166     // We don't know a specific play time duration for this data,
00167     // so just record the current time as being the 'presentation time':
00168     gettimeofday(&fPresentationTime, NULL);
00169   }
00170 
00171   // Inform the reader that he has data:
00172 #ifdef READ_FROM_FILES_SYNCHRONOUSLY
00173   // To avoid possible infinite recursion, we need to return to the event loop to do this:
00174   nextTask() = envir().taskScheduler().scheduleDelayedTask(0,
00175                                 (TaskFunc*)FramedSource::afterGetting, this);
00176 #else
00177   // Because the file read was done from the event loop, we can call the
00178   // 'after getting' function directly, without risk of infinite recursion:
00179   FramedSource::afterGetting(this);
00180 #endif
00181 }

Generated on Mon Apr 29 13:28:01 2013 for live by  doxygen 1.5.2