liveMedia/MPEGVideoStreamFramer.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 filter that breaks up an MPEG video elementary stream into
00019 //   headers and frames
00020 // Implementation
00021 
00022 #include "MPEGVideoStreamParser.hh"
00023 #include <GroupsockHelper.hh>
00024 
00026 
00027 TimeCode::TimeCode()
00028   : days(0), hours(0), minutes(0), seconds(0), pictures(0) {
00029 }
00030 
00031 TimeCode::~TimeCode() {
00032 }
00033 
00034 int TimeCode::operator==(TimeCode const& arg2) {
00035   return pictures == arg2.pictures && seconds == arg2.seconds
00036     && minutes == arg2.minutes && hours == arg2.hours && days == arg2.days;
00037 }
00038 
00040 
00041 MPEGVideoStreamFramer::MPEGVideoStreamFramer(UsageEnvironment& env,
00042                                              FramedSource* inputSource)
00043   : FramedFilter(env, inputSource),
00044     fFrameRate(0.0) /* until we learn otherwise */,
00045     fParser(NULL) {
00046   reset();
00047 }
00048 
00049 MPEGVideoStreamFramer::~MPEGVideoStreamFramer() {
00050   delete fParser;
00051 }
00052 
00053 void MPEGVideoStreamFramer::flushInput() {
00054   reset();
00055   if (fParser != NULL) fParser->flushInput();
00056 }
00057 
00058 void MPEGVideoStreamFramer::reset() {
00059   fPictureCount = 0;
00060   fPictureEndMarker = False;
00061   fPicturesAdjustment = 0;
00062   fPictureTimeBase = 0.0;
00063   fTcSecsBase = 0;
00064   fHaveSeenFirstTimeCode = False;
00065 
00066   // Use the current wallclock time as the base 'presentation time':
00067   gettimeofday(&fPresentationTimeBase, NULL);
00068 }
00069 
00070 #ifdef DEBUG
00071 static struct timeval firstPT;
00072 #endif
00073 void MPEGVideoStreamFramer
00074 ::computePresentationTime(unsigned numAdditionalPictures) {
00075   // Computes "fPresentationTime" from the most recent GOP's
00076   // time_code, along with the "numAdditionalPictures" parameter:
00077   TimeCode& tc = fCurGOPTimeCode;
00078 
00079   unsigned tcSecs
00080     = (((tc.days*24)+tc.hours)*60+tc.minutes)*60+tc.seconds - fTcSecsBase;
00081   double pictureTime = fFrameRate == 0.0 ? 0.0
00082     : (tc.pictures + fPicturesAdjustment + numAdditionalPictures)/fFrameRate;
00083   while (pictureTime < fPictureTimeBase) { // "if" should be enough, but just in case
00084     if (tcSecs > 0) tcSecs -= 1;
00085     pictureTime += 1.0;
00086   }
00087   pictureTime -= fPictureTimeBase;
00088   if (pictureTime < 0.0) pictureTime = 0.0; // sanity check
00089   unsigned pictureSeconds = (unsigned)pictureTime;
00090   double pictureFractionOfSecond = pictureTime - (double)pictureSeconds;
00091 
00092   fPresentationTime = fPresentationTimeBase;
00093   fPresentationTime.tv_sec += tcSecs + pictureSeconds;
00094   fPresentationTime.tv_usec += (long)(pictureFractionOfSecond*1000000.0);
00095   if (fPresentationTime.tv_usec >= 1000000) {
00096     fPresentationTime.tv_usec -= 1000000;
00097     ++fPresentationTime.tv_sec;
00098   }
00099 #ifdef DEBUG
00100   if (firstPT.tv_sec == 0 && firstPT.tv_usec == 0) firstPT = fPresentationTime;
00101   struct timeval diffPT;
00102   diffPT.tv_sec = fPresentationTime.tv_sec - firstPT.tv_sec;
00103   diffPT.tv_usec = fPresentationTime.tv_usec - firstPT.tv_usec;
00104   if (fPresentationTime.tv_usec < firstPT.tv_usec) {
00105     --diffPT.tv_sec;
00106     diffPT.tv_usec += 1000000;
00107   }
00108   fprintf(stderr, "MPEGVideoStreamFramer::computePresentationTime(%d) -> %lu.%06ld [%lu.%06ld]\n", numAdditionalPictures, fPresentationTime.tv_sec, fPresentationTime.tv_usec, diffPT.tv_sec, diffPT.tv_usec);
00109 #endif
00110 }
00111 
00112 void MPEGVideoStreamFramer
00113 ::setTimeCode(unsigned hours, unsigned minutes, unsigned seconds,
00114               unsigned pictures, unsigned picturesSinceLastGOP) {
00115   TimeCode& tc = fCurGOPTimeCode; // abbrev
00116   unsigned days = tc.days;
00117   if (hours < tc.hours) {
00118     // Assume that the 'day' has wrapped around:
00119     ++days;
00120   }
00121   tc.days = days;
00122   tc.hours = hours;
00123   tc.minutes = minutes;
00124   tc.seconds = seconds;
00125   tc.pictures = pictures;
00126   if (!fHaveSeenFirstTimeCode) {
00127     fPictureTimeBase = fFrameRate == 0.0 ? 0.0 : tc.pictures/fFrameRate;
00128     fTcSecsBase = (((tc.days*24)+tc.hours)*60+tc.minutes)*60+tc.seconds;
00129     fHaveSeenFirstTimeCode = True;
00130   } else if (fCurGOPTimeCode == fPrevGOPTimeCode) {
00131     // The time code has not changed since last time.  Adjust for this:
00132     fPicturesAdjustment += picturesSinceLastGOP;
00133   } else {
00134     // Normal case: The time code changed since last time.
00135     fPrevGOPTimeCode = tc;
00136     fPicturesAdjustment = 0;
00137   }
00138 }
00139 
00140 void MPEGVideoStreamFramer::doGetNextFrame() {
00141   fParser->registerReadInterest(fTo, fMaxSize);
00142   continueReadProcessing();
00143 }
00144 
00145 void MPEGVideoStreamFramer
00146 ::continueReadProcessing(void* clientData,
00147                          unsigned char* /*ptr*/, unsigned /*size*/,
00148                          struct timeval /*presentationTime*/) {
00149   MPEGVideoStreamFramer* framer = (MPEGVideoStreamFramer*)clientData;
00150   framer->continueReadProcessing();
00151 }
00152 
00153 void MPEGVideoStreamFramer::continueReadProcessing() {
00154   unsigned acquiredFrameSize = fParser->parse();
00155   if (acquiredFrameSize > 0) {
00156     // We were able to acquire a frame from the input.
00157     // It has already been copied to the reader's space.
00158     fFrameSize = acquiredFrameSize;
00159     fNumTruncatedBytes = fParser->numTruncatedBytes();
00160 
00161     // "fPresentationTime" should have already been computed.
00162 
00163     // Compute "fDurationInMicroseconds" now:
00164     fDurationInMicroseconds
00165       = (fFrameRate == 0.0 || ((int)fPictureCount) < 0) ? 0
00166       : (unsigned)((fPictureCount*1000000)/fFrameRate);
00167 #ifdef DEBUG
00168     fprintf(stderr, "%d bytes @%u.%06d, fDurationInMicroseconds: %d ((%d*1000000)/%f)\n", acquiredFrameSize, fPresentationTime.tv_sec, fPresentationTime.tv_usec, fDurationInMicroseconds, fPictureCount, fFrameRate);
00169 #endif
00170     fPictureCount = 0;
00171 
00172     // Call our own 'after getting' function.  Because we're not a 'leaf'
00173     // source, we can call this directly, without risking infinite recursion.
00174     afterGetting(this);
00175   } else {
00176     // We were unable to parse a complete frame from the input, because:
00177     // - we had to read more data from the source stream, or
00178     // - the source stream has ended.
00179   }
00180 }

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