liveMedia/MP3FileSource.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 // MP3 File Sources
00019 // Implementation
00020 
00021 #include "MP3FileSource.hh"
00022 #include "MP3StreamState.hh"
00023 #include "InputFile.hh"
00024 
00026 
00027 MP3FileSource::MP3FileSource(UsageEnvironment& env, FILE* fid)
00028   : FramedFileSource(env, fid),
00029     fStreamState(new MP3StreamState(env)) {
00030 }
00031 
00032 MP3FileSource::~MP3FileSource() {
00033   delete fStreamState;
00034 }
00035 
00036 char const* MP3FileSource::MIMEtype() const {
00037   return "audio/MPEG";
00038 }
00039 
00040 MP3FileSource* MP3FileSource::createNew(UsageEnvironment& env, char const* fileName) {
00041   MP3FileSource* newSource = NULL;
00042 
00043   do {
00044     FILE* fid;
00045 
00046     fid = OpenInputFile(env, fileName);
00047     if (fid == NULL) break;
00048 
00049     newSource = new MP3FileSource(env, fid);
00050     if (newSource == NULL) break;
00051 
00052     unsigned fileSize = (unsigned)GetFileSize(fileName, fid);
00053     newSource->assignStream(fid, fileSize);
00054     if (!newSource->initializeStream()) break;
00055 
00056     return newSource;
00057   } while (0);
00058 
00059   Medium::close(newSource);
00060   return NULL;
00061 }
00062 
00063 float MP3FileSource::filePlayTime() const {
00064   return fStreamState->filePlayTime();
00065 }
00066 
00067 unsigned MP3FileSource::fileSize() const {
00068   return fStreamState->fileSize();
00069 }
00070 
00071 void MP3FileSource::setPresentationTimeScale(unsigned scale) {
00072   fStreamState->setPresentationTimeScale(scale);
00073 }
00074 
00075 void MP3FileSource::seekWithinFile(double seekNPT, double streamDuration) {
00076   float fileDuration = filePlayTime();
00077 
00078   // First, make sure that 0.0 <= seekNPT <= seekNPT + streamDuration <= fileDuration
00079   if (seekNPT < 0.0) {
00080     seekNPT = 0.0;
00081   } else if (seekNPT > fileDuration) {
00082     seekNPT = fileDuration;
00083   }
00084   if (streamDuration < 0.0) {
00085     streamDuration = 0.0;
00086   } else if (seekNPT + streamDuration > fileDuration) {
00087     streamDuration = fileDuration - seekNPT; 
00088   }
00089 
00090   float seekFraction = (float)seekNPT/fileDuration;
00091   unsigned seekByteNumber = fStreamState->getByteNumberFromPositionFraction(seekFraction);
00092   fStreamState->seekWithinFile(seekByteNumber);
00093 
00094   fLimitNumBytesToStream = False; // by default
00095   if (streamDuration > 0.0) {
00096     float endFraction = (float)(seekNPT + streamDuration)/fileDuration;
00097     unsigned endByteNumber = fStreamState->getByteNumberFromPositionFraction(endFraction);
00098     if (endByteNumber > seekByteNumber) { // sanity check
00099       fNumBytesToStream = endByteNumber - seekByteNumber;
00100       fLimitNumBytesToStream = True;
00101     }
00102   } else {
00103   }
00104 }
00105 
00106 void MP3FileSource::getAttributes() const {
00107   char buffer[200];
00108   fStreamState->getAttributes(buffer, sizeof buffer);
00109   envir().setResultMsg(buffer);
00110 }
00111 
00112 void MP3FileSource::doGetNextFrame() {
00113   if (!doGetNextFrame1()) {
00114     handleClosure(this);
00115     return;
00116   }
00117 
00118   // Switch to another task:
00119 #if defined(__WIN32__) || defined(_WIN32)
00120   // HACK: liveCaster/lc uses an implementation of scheduleDelayedTask()
00121   // that performs very badly (chewing up lots of CPU time, apparently polling)
00122   // on Windows.  Until this is fixed, we just call our "afterGetting()"
00123   // function directly.  This avoids infinite recursion, as long as our sink
00124   // is discontinuous, which is the case for the RTP sink that liveCaster/lc
00125   // uses. #####
00126   afterGetting(this);
00127 #else
00128   nextTask() = envir().taskScheduler().scheduleDelayedTask(0,
00129                                 (TaskFunc*)afterGetting, this);
00130 #endif
00131 }
00132 
00133 Boolean MP3FileSource::doGetNextFrame1() {
00134   if (fLimitNumBytesToStream && fNumBytesToStream == 0) return False; // we've already streamed as much as we were asked for
00135 
00136   if (!fHaveJustInitialized) {
00137     if (fStreamState->findNextHeader(fPresentationTime) == 0) return False;
00138   } else {
00139     fPresentationTime = fFirstFramePresentationTime;
00140     fHaveJustInitialized = False;
00141   }
00142 
00143   if (!fStreamState->readFrame(fTo, fMaxSize, fFrameSize, fDurationInMicroseconds)) {
00144     char tmp[200];
00145     sprintf(tmp,
00146             "Insufficient buffer size %d for reading MPEG audio frame (needed %d)\n",
00147             fMaxSize, fFrameSize);
00148     envir().setResultMsg(tmp);
00149     fFrameSize = fMaxSize;
00150     return False;
00151   }
00152   if (fNumBytesToStream > fFrameSize) fNumBytesToStream -= fFrameSize; else fNumBytesToStream = 0;
00153 
00154   return True;
00155 }
00156 
00157 void MP3FileSource::assignStream(FILE* fid, unsigned fileSize) {
00158   fStreamState->assignStream(fid, fileSize);
00159 }
00160 
00161 
00162 Boolean MP3FileSource::initializeStream() {
00163   // Make sure the file has an appropriate header near the start:
00164   if (fStreamState->findNextHeader(fFirstFramePresentationTime) == 0) {
00165       envir().setResultMsg("not an MPEG audio file");
00166       return False;
00167   }
00168 
00169   fStreamState->checkForXingHeader(); // in case this is a VBR file
00170 
00171   fHaveJustInitialized = True;
00172   fLimitNumBytesToStream = False;
00173   fNumBytesToStream = 0;
00174 
00175   // Hack: It's possible that our environment's 'result message' has been
00176   // reset within this function, so set it again to our name now:
00177   envir().setResultMsg(name());
00178   return True;
00179 }

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