liveMedia/MPEG4VideoStreamDiscreteFramer.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 simplified version of "MPEG4VideoStreamFramer" that takes only complete,
00019 // discrete frames (rather than an arbitrary byte stream) as input.
00020 // This avoids the parsing and data copying overhead of the full
00021 // "MPEG4VideoStreamFramer".
00022 // Implementation
00023 
00024 #include "MPEG4VideoStreamDiscreteFramer.hh"
00025 
00026 MPEG4VideoStreamDiscreteFramer*
00027 MPEG4VideoStreamDiscreteFramer::createNew(UsageEnvironment& env,
00028                                   FramedSource* inputSource) {
00029   // Need to add source type checking here???  #####
00030   return new MPEG4VideoStreamDiscreteFramer(env, inputSource);
00031 }
00032 
00033 MPEG4VideoStreamDiscreteFramer
00034 ::MPEG4VideoStreamDiscreteFramer(UsageEnvironment& env,
00035                                  FramedSource* inputSource)
00036   : MPEG4VideoStreamFramer(env, inputSource, False/*don't create a parser*/),
00037     vop_time_increment_resolution(0), fNumVTIRBits(0),
00038     fLastNonBFrameVop_time_increment(0) {
00039   fLastNonBFramePresentationTime.tv_sec = 0;
00040   fLastNonBFramePresentationTime.tv_usec = 0;
00041 }
00042 
00043 MPEG4VideoStreamDiscreteFramer::~MPEG4VideoStreamDiscreteFramer() {
00044 }
00045 
00046 void MPEG4VideoStreamDiscreteFramer::doGetNextFrame() {
00047   // Arrange to read data (which should be a complete MPEG-4 video frame)
00048   // from our data source, directly into the client's input buffer.
00049   // After reading this, we'll do some parsing on the frame.
00050   fInputSource->getNextFrame(fTo, fMaxSize,
00051                              afterGettingFrame, this,
00052                              FramedSource::handleClosure, this);
00053 }
00054 
00055 void MPEG4VideoStreamDiscreteFramer
00056 ::afterGettingFrame(void* clientData, unsigned frameSize,
00057                     unsigned numTruncatedBytes,
00058                     struct timeval presentationTime,
00059                     unsigned durationInMicroseconds) {
00060   MPEG4VideoStreamDiscreteFramer* source = (MPEG4VideoStreamDiscreteFramer*)clientData;
00061   source->afterGettingFrame1(frameSize, numTruncatedBytes,
00062                              presentationTime, durationInMicroseconds);
00063 }
00064 
00065 void MPEG4VideoStreamDiscreteFramer
00066 ::afterGettingFrame1(unsigned frameSize, unsigned numTruncatedBytes,
00067                      struct timeval presentationTime,
00068                      unsigned durationInMicroseconds) {
00069   // Check that the first 4 bytes are a system code:
00070   if (frameSize >= 4 && fTo[0] == 0 && fTo[1] == 0 && fTo[2] == 1) {
00071     fPictureEndMarker = True; // Assume that we have a complete 'picture' here
00072     unsigned i = 3;
00073     if (fTo[i] == 0xB0) { // VISUAL_OBJECT_SEQUENCE_START_CODE
00074       // The next byte is the "profile_and_level_indication":
00075       if (frameSize >= 5) fProfileAndLevelIndication = fTo[4];
00076 
00077       // The start of this frame - up to the first GROUP_VOP_START_CODE
00078       // or VOP_START_CODE - is stream configuration information.  Save this:
00079       for (i = 7; i < frameSize; ++i) {
00080         if ((fTo[i] == 0xB3 /*GROUP_VOP_START_CODE*/ ||
00081              fTo[i] == 0xB6 /*VOP_START_CODE*/)
00082             && fTo[i-1] == 1 && fTo[i-2] == 0 && fTo[i-3] == 0) {
00083           break; // The configuration information ends here
00084         }
00085       }
00086       fNumConfigBytes = i < frameSize ? i-3 : frameSize;
00087       delete[] fConfigBytes; fConfigBytes = new unsigned char[fNumConfigBytes];
00088       for (unsigned j = 0; j < fNumConfigBytes; ++j) fConfigBytes[j] = fTo[j];
00089 
00090       // This information (should) also contain a VOL header, which we need
00091       // to analyze, to get "vop_time_increment_resolution" (which we need
00092       // - along with "vop_time_increment" - in order to generate accurate
00093       // presentation times for "B" frames).
00094       analyzeVOLHeader();
00095     }
00096 
00097     if (i < frameSize) {
00098       u_int8_t nextCode = fTo[i];
00099 
00100       if (nextCode == 0xB3 /*GROUP_VOP_START_CODE*/) {
00101         // Skip to the following VOP_START_CODE (if any):
00102         for (i += 4; i < frameSize; ++i) {
00103           if (fTo[i] == 0xB6 /*VOP_START_CODE*/
00104               && fTo[i-1] == 1 && fTo[i-2] == 0 && fTo[i-3] == 0) {
00105             nextCode = fTo[i];
00106             break;
00107           }
00108         }
00109       }
00110 
00111       if (nextCode == 0xB6 /*VOP_START_CODE*/ && i+5 < frameSize) {
00112         ++i;
00113 
00114         // Get the "vop_coding_type" from the next byte:
00115         u_int8_t nextByte = fTo[i++];
00116         u_int8_t vop_coding_type = nextByte>>6;
00117 
00118         // Next, get the "modulo_time_base" by counting the '1' bits that
00119         // follow.  We look at the next 32-bits only.
00120         // This should be enough in most cases.
00121         u_int32_t next4Bytes
00122           = (fTo[i]<<24)|(fTo[i+1]<<16)|(fTo[i+2]<<8)|fTo[i+3];
00123         i += 4;
00124         u_int32_t timeInfo = (nextByte<<(32-6))|(next4Bytes>>6);
00125         unsigned modulo_time_base = 0;
00126         u_int32_t mask = 0x80000000;
00127         while ((timeInfo&mask) != 0) {
00128           ++modulo_time_base;
00129           mask >>= 1;
00130         }
00131         mask >>= 2;
00132 
00133         // Then, get the "vop_time_increment".
00134         unsigned vop_time_increment = 0;
00135         // First, make sure we have enough bits left for this:
00136         if ((mask>>(fNumVTIRBits-1)) != 0) {
00137           for (unsigned i = 0; i < fNumVTIRBits; ++i) {
00138             vop_time_increment |= timeInfo&mask;
00139             mask >>= 1;
00140           }
00141           while (mask != 0) {
00142             vop_time_increment >>= 1;
00143             mask >>= 1;
00144           }
00145         }
00146 
00147         // If this is a "B" frame, then we have to tweak "presentationTime":
00148         if (vop_coding_type == 2/*B*/
00149             && (fLastNonBFramePresentationTime.tv_usec > 0 ||
00150                 fLastNonBFramePresentationTime.tv_sec > 0)) {
00151           int timeIncrement
00152             = fLastNonBFrameVop_time_increment - vop_time_increment;
00153           if (timeIncrement<0) timeIncrement += vop_time_increment_resolution;
00154           unsigned const MILLION = 1000000;
00155           double usIncrement = vop_time_increment_resolution == 0 ? 0.0
00156             : ((double)timeIncrement*MILLION)/vop_time_increment_resolution;
00157           unsigned secondsToSubtract = (unsigned)(usIncrement/MILLION);
00158           unsigned uSecondsToSubtract = ((unsigned)usIncrement)%MILLION;
00159 
00160           presentationTime = fLastNonBFramePresentationTime;
00161           if ((unsigned)presentationTime.tv_usec < uSecondsToSubtract) {
00162             presentationTime.tv_usec += MILLION;
00163             if (presentationTime.tv_sec > 0) --presentationTime.tv_sec;
00164           }
00165           presentationTime.tv_usec -= uSecondsToSubtract;
00166           if ((unsigned)presentationTime.tv_sec > secondsToSubtract) {
00167             presentationTime.tv_sec -= secondsToSubtract;
00168           } else {
00169             presentationTime.tv_sec = presentationTime.tv_usec = 0;
00170           }
00171         } else {
00172           fLastNonBFramePresentationTime = presentationTime;
00173           fLastNonBFrameVop_time_increment = vop_time_increment;
00174         }
00175       }
00176     }
00177   }
00178 
00179   // Complete delivery to the client:
00180   fFrameSize = frameSize;
00181   fNumTruncatedBytes = numTruncatedBytes;
00182   fPresentationTime = presentationTime;
00183   fDurationInMicroseconds = durationInMicroseconds;
00184   afterGetting(this);
00185 }
00186 
00187 Boolean MPEG4VideoStreamDiscreteFramer::getNextFrameBit(u_int8_t& result) {
00188   if (fNumBitsSeenSoFar/8 >= fNumConfigBytes) return False;
00189 
00190   u_int8_t nextByte = fConfigBytes[fNumBitsSeenSoFar/8];
00191   result = (nextByte>>(7-fNumBitsSeenSoFar%8))&1;
00192   ++fNumBitsSeenSoFar;
00193   return True;
00194 }
00195 
00196 Boolean MPEG4VideoStreamDiscreteFramer::getNextFrameBits(unsigned numBits,
00197                                                          u_int32_t& result) {
00198   result = 0;
00199   for (unsigned i = 0; i < numBits; ++i) {
00200     u_int8_t nextBit;
00201     if (!getNextFrameBit(nextBit)) return False;
00202     result = (result<<1)|nextBit;
00203   }
00204   return True;
00205 }
00206 
00207 void MPEG4VideoStreamDiscreteFramer::analyzeVOLHeader() {
00208   // Begin by moving to the VOL header:
00209   unsigned i;
00210   for (i = 3; i < fNumConfigBytes; ++i) {
00211     if (fConfigBytes[i] >= 0x20 && fConfigBytes[i] <= 0x2F
00212         && fConfigBytes[i-1] == 1
00213         && fConfigBytes[i-2] == 0 && fConfigBytes[i-3] == 0) {
00214       ++i;
00215       break;
00216     }
00217   }
00218 
00219   fNumBitsSeenSoFar = 8*i + 9;
00220   do {
00221     u_int8_t is_object_layer_identifier;
00222     if (!getNextFrameBit(is_object_layer_identifier)) break;
00223     if (is_object_layer_identifier) fNumBitsSeenSoFar += 7;
00224 
00225     u_int32_t aspect_ratio_info;
00226     if (!getNextFrameBits(4, aspect_ratio_info)) break;
00227     if (aspect_ratio_info == 15 /*extended_PAR*/) fNumBitsSeenSoFar += 16;
00228 
00229     u_int8_t vol_control_parameters;
00230     if (!getNextFrameBit(vol_control_parameters)) break;
00231     if (vol_control_parameters) {
00232       fNumBitsSeenSoFar += 3; // chroma_format; low_delay
00233       u_int8_t vbw_parameters;
00234       if (!getNextFrameBit(vbw_parameters)) break;
00235       if (vbw_parameters) fNumBitsSeenSoFar += 79;
00236     }
00237 
00238     fNumBitsSeenSoFar += 2; // video_object_layer_shape
00239     u_int8_t marker_bit;
00240     if (!getNextFrameBit(marker_bit)) break;
00241     if (marker_bit != 1) break; // sanity check
00242 
00243     if (!getNextFrameBits(16, vop_time_increment_resolution)) break;
00244     if (vop_time_increment_resolution == 0) break; // shouldn't happen
00245 
00246     // Compute how many bits are necessary to represent this:
00247     fNumVTIRBits = 0;
00248     for (unsigned test = vop_time_increment_resolution; test>0; test /= 2) {
00249       ++fNumVTIRBits;
00250     }
00251   } while (0);
00252 }

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