liveMedia/H263plusVideoStreamParser.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 // Author Bernhard Feiten
00019 // A filter that breaks up an H.263plus video stream into frames.
00020 // Based on MPEG4IP/mp4creator/h263.c
00021 
00022 #include "H263plusVideoStreamParser.hh"
00023 #include "H263plusVideoStreamFramer.hh"
00024 //#include <string.h>
00025 //#include "GroupsockHelper.hh"
00026 
00027 
00028 H263plusVideoStreamParser::H263plusVideoStreamParser(
00029                               H263plusVideoStreamFramer* usingSource,
00030                               FramedSource* inputSource)
00031                               : StreamParser(inputSource,
00032                                    FramedSource::handleClosure,
00033                                    usingSource,
00034                                    &H263plusVideoStreamFramer::continueReadProcessing,
00035                                    usingSource),
00036                                 fUsingSource(usingSource),
00037                                 fnextTR(0),
00038                                 fcurrentPT(0)
00039 {
00040    memset(fStates, 0, sizeof(fStates));
00041    memset(&fNextInfo, 0, sizeof(fNextInfo));
00042    memset(&fCurrentInfo, 0, sizeof(fCurrentInfo));
00043    memset(&fMaxBitrateCtx, 0, sizeof(fMaxBitrateCtx));
00044    memset(fNextHeader,0, H263_REQUIRE_HEADER_SIZE_BYTES);
00045 }
00046 
00048 H263plusVideoStreamParser::~H263plusVideoStreamParser()
00049 {
00050 }
00051 
00053 void H263plusVideoStreamParser::restoreSavedParserState()
00054 {
00055    StreamParser::restoreSavedParserState();
00056    fTo = fSavedTo;
00057    fNumTruncatedBytes = fSavedNumTruncatedBytes;
00058 }
00059 
00061 void H263plusVideoStreamParser::setParseState()
00062 {
00063    fSavedTo = fTo;
00064    fSavedNumTruncatedBytes = fNumTruncatedBytes;
00065    saveParserState();  // Needed for the parsing process in StreamParser
00066 }
00067 
00068 
00070 void H263plusVideoStreamParser::registerReadInterest(
00071                                    unsigned char* to,
00072                                    unsigned maxSize)
00073 {
00074    fStartOfFrame = fTo = fSavedTo = to;
00075    fLimit = to + maxSize;
00076    fMaxSize = maxSize;
00077    fNumTruncatedBytes = fSavedNumTruncatedBytes = 0;
00078 }
00079 
00081 // parse() ,  derived from H263Creator of MPEG4IP, h263.c
00082 unsigned H263plusVideoStreamParser::parse(u_int64_t & currentDuration)
00083 {
00084 
00085 //   u_int8_t       frameBuffer[H263_BUFFER_SIZE]; // The input buffer
00086                  // Pointer which tells LoadNextH263Object where to read data to
00087 //   u_int8_t*      pFrameBuffer = fTo + H263_REQUIRE_HEADER_SIZE_BYTES;
00088    u_int32_t      frameSize;        // The current frame size
00089                                 // Pointer to receive address of the header data
00090 //   u_int8_t*      pCurrentHeader;// = pFrameBuffer;
00091 //   u_int64_t      currentDuration;  // The current frame's duration
00092    u_int8_t       trDifference;     // The current TR difference
00093                                    // The previous TR difference
00094 //   u_int8_t       prevTrDifference = H263_BASIC_FRAME_RATE;
00095 //   u_int64_t      totalDuration = 0;// Duration accumulator
00096 //   u_int64_t      avgBitrate;       // Average bitrate
00097 //   u_int64_t      totalBytes = 0;   // Size accumulator
00098 
00099 
00100    try    // The get data routines of the class FramedFilter returns an error when
00101    {      // the buffer is empty. This occurs at the beginning and at the end of the file.
00102       fCurrentInfo = fNextInfo;
00103 
00104       // Parse 1 frame
00105       // For the first time, only the first frame's header is returned.
00106       // The second time the full first frame is returned
00107       frameSize = parseH263Frame();
00108 
00109       currentDuration = 0;
00110       if ((frameSize > 0)){
00111          // We were able to acquire a frame from the input.
00112 
00113          // Parse the returned frame header (if any)
00114          if (!ParseShortHeader(fTo, &fNextInfo)) {
00115 #ifdef DEBUG
00116            fprintf(stderr,"H263plusVideoStreamParser: Fatal error\n");
00117 #endif
00118          }
00119 
00120          trDifference = GetTRDifference(fNextInfo.tr, fCurrentInfo.tr);
00121 
00122          // calculate the current frame duration
00123          currentDuration = CalculateDuration(trDifference);
00124 
00125          // Accumulate the frame's size and duration for avgBitrate calculation
00126          //totalDuration += currentDuration;
00127          //totalBytes += frameSize;
00128          //  If needed, recalculate bitrate information
00129          //    if (h263Bitrates)
00130          //GetMaxBitrate(&fMaxBitrateCtx, frameSize, prevTrDifference);
00131          //prevTrDifference = trDifference;
00132 
00133          setParseState(); // Needed for the parsing process in StreamParser
00134       }
00135    } catch (int /*e*/) {
00136 #ifdef DEBUG
00137       fprintf(stderr, "H263plusVideoStreamParser::parse() EXCEPTION (This is normal behavior - *not* an error)\n");
00138 #endif
00139       frameSize=0;
00140    }
00141 
00142    return frameSize;
00143 }
00144 
00145 
00147 // parseH263Frame derived from LoadNextH263Object of MPEG4IP
00148 // - service routine that reads a single frame from the input file.
00149 // It shall fill the input buffer with data up until - and including - the
00150 // next start code and shall report back both the number of bytes read and a
00151 // pointer to the next start code. The first call to this function shall only
00152 // yield a pointer with 0 data bytes and the last call to this function shall
00153 // only yield data bytes with a NULL pointer as the next header.
00154 //
00155 // TODO: This function only supports valid bit streams. Upon error, it fails
00156 // without the possibility to recover. A Better idea would be to skip frames
00157 // until a parsable frame is read from the file.
00158 //
00159 // Parameters:
00160 //      ppNextHeader - output parameter that upon return points to the location
00161 //                     of the next frame's head in the buffer.
00162 //                     This pointer shall be NULL for the last frame read.
00163 // Returns the total number of bytes read.
00164 // Uses FrameFileSource intantiated by constructor.
00166 int H263plusVideoStreamParser::parseH263Frame( )
00167 {
00168    char     row = 0;
00169    u_int8_t * bufferIndex = fTo;
00170    // The buffer end which will allow the loop to leave place for
00171    // the additionalBytesNeeded
00172    u_int8_t * bufferEnd = fTo + fMaxSize - ADDITIONAL_BYTES_NEEDED - 1;
00173 
00174    memcpy(fTo, fNextHeader, H263_REQUIRE_HEADER_SIZE_BYTES);
00175    bufferIndex += H263_REQUIRE_HEADER_SIZE_BYTES;
00176 
00177 
00178    // The state table and the following loop implements a state machine enabling
00179    // us to read bytes from the file until (and inclusing) the requested
00180    // start code (00 00 8X) is found
00181 
00182    // Initialize the states array, if it hasn't been initialized yet...
00183    if (!fStates[0][0]) {
00184       // One 00 was read
00185       fStates[0][0] = 1;
00186       // Two sequential 0x00 ware read
00187       fStates[1][0] = fStates[2][0] = 2;
00188       // A full start code was read
00189       fStates[2][128] = fStates[2][129] = fStates[2][130] = fStates[2][131] = -1;
00190    }
00191 
00192    // Read data from file into the output buffer until either a start code
00193    // is found, or the end of file has been reached.
00194    do {
00195       *bufferIndex = get1Byte();
00196    } while ((bufferIndex < bufferEnd) &&                    // We have place in the buffer
00197             ((row = fStates[(unsigned char)row][*(bufferIndex++)]) != -1)); // Start code was not found
00198 
00199    if (row != -1) {
00200       fprintf(stderr, "%s: Buffer too small (%u)\n",
00201          "h263reader:", bufferEnd - fTo + ADDITIONAL_BYTES_NEEDED);
00202       return 0;
00203    }
00204 
00205    // Cool ... now we have a start code
00206    // Now we just have to read the additionalBytesNeeded
00207    getBytes(bufferIndex, ADDITIONAL_BYTES_NEEDED);
00208    memcpy(fNextHeader, bufferIndex - H263_STARTCODE_SIZE_BYTES, H263_REQUIRE_HEADER_SIZE_BYTES);
00209 
00210         int sz = bufferIndex - fTo - H263_STARTCODE_SIZE_BYTES;
00211 
00212    if (sz == 5) // first frame
00213       memcpy(fTo, fTo+H263_REQUIRE_HEADER_SIZE_BYTES, H263_REQUIRE_HEADER_SIZE_BYTES);
00214 
00215    return sz;
00216 }
00217 
00218 
00220 // ParseShortHeader - service routine that accepts a buffer containing a frame
00221 // header and extracts relevant codec information from it.
00222 //
00223 // NOTE: the first bit in the following commnets is 0 (zero).
00224 //
00225 //       0                   1                   2                   3
00226 //       0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
00227 //      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
00228 //      |      PSC (Picture Start Code=22 bits)     |  (TR=8 bits)  |   >
00229 //      |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0|               |1 0>
00230 //      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
00231 //      <   (PTYPE=13 bits)   |
00232 //      <. . .|(FMT)|Z|. . . .|
00233 //      +-+-+-+-+-+-+-+-+-+-+-+
00234 //      -> PTYPE.FMT contains a width/height identification
00235 //      -> PTYPE.Z   is 1 for P-Frames, 0 for I-Frames
00236 //      Note: When FMT is 111, there is an extended PTYPE...
00237 //
00238 // Inputs:
00239 //      headerBuffer - pointer to the current header buffer
00240 //      outputInfoStruct - pointer to the structure receiving the data
00241 // Outputs:
00242 //      This function returns a structure of important codec-specific
00243 //      information (The Temporal Reference bits, width & height of the current
00244 //      frame and the sync - or "frame type" - bit. It reports success or
00245 //      failure to the calling function.
00247 bool H263plusVideoStreamParser::ParseShortHeader(
00248                                    u_int8_t *headerBuffer,
00249                                    H263INFO *outputInfoStruct)
00250 {
00251    u_int8_t fmt = 0;
00252    // Extract temporal reference (TR) from the buffer (bits 22-29 inclusive)
00253    outputInfoStruct->tr  = (headerBuffer[2] << 6) & 0xC0; // 2 LS bits out of the 3rd byte
00254    outputInfoStruct->tr |= (headerBuffer[3] >> 2) & 0x3F; // 6 MS bits out of the 4th byte
00255    // Extract the FMT part of PTYPE from the buffer (bits 35-37 inclusive)
00256    fmt = (headerBuffer[4] >> 2) & 0x07; // bits 3-5 ouf of the 5th byte
00257    // If PTYPE is not supported, return a failure notice to the calling function
00258    // FIXME: PLUSPTYPE is not supported
00259    if (fmt == 0x07) {
00260       return false;
00261    }
00262    // If PTYPE is supported, calculate the current width and height according to
00263    // a predefined table
00264    if (!GetWidthAndHeight(fmt, &(outputInfoStruct->width),
00265                                &(outputInfoStruct->height))) {
00266       return false;
00267    }
00268    // Extract the frame-type bit, which is the 9th bit of PTYPE (bit 38)
00269    outputInfoStruct->isSyncFrame = !(headerBuffer[4] & 0x02);
00270 
00271   return true;
00272 }
00273 
00275 // GetMaxBitrate- service routine that accepts frame information and
00276 // derives bitrate information from it. This function uses a sliding window
00277 // technique to calculate the maximum bitrates in any window of 1 second
00278 // inside the file.
00279 // The sliding window is implemented with a table of bitrates for the last
00280 // second (30 entries - one entry per TR unit).
00281 //
00282 // Inputs:
00283 //      ctx - context for this function
00284 //      frameSize - the size of the current frame in bytes
00285 //      frameTRDiff - the "duration" of the frame in TR units
00286 // Outputs:
00287 //      This function returns the up-to-date maximum bitrate
00289 void H263plusVideoStreamParser::GetMaxBitrate( MaxBitrate_CTX *ctx,
00290                                                u_int32_t      frameSize,
00291                                                u_int8_t       frameTRDiff)
00292 {
00293    if (frameTRDiff == 0)
00294       return;
00295 
00296    // Calculate the current frame's bitrate as bits per TR unit (round the result
00297    // upwards)
00298    u_int32_t frameBitrate = frameSize * 8 / frameTRDiff + 1;
00299 
00300    // for each TRdiff received,
00301    while (frameTRDiff--) {
00302       // Subtract the oldest bitrate entry from the current bitrate
00303       ctx->windowBitrate -= ctx->bitrateTable[ctx->tableIndex];
00304       // Update the oldest bitrate entry with the current frame's bitrate
00305       ctx->bitrateTable[ctx->tableIndex] = frameBitrate;
00306       // Add the current frame's bitrate to the current bitrate
00307       ctx->windowBitrate += frameBitrate;
00308       // Check if we have a new maximum bitrate
00309       if (ctx->windowBitrate > ctx->maxBitrate) {
00310          ctx->maxBitrate = ctx->windowBitrate;
00311           }
00312       // Advance the table index
00313       // Wrapping around the bitrateTable size
00314       ctx->tableIndex = (ctx->tableIndex + 1) %
00315         ( sizeof(ctx->bitrateTable) / sizeof(ctx->bitrateTable[0]) );
00316    }
00317 }
00318 
00320 // CalculateDuration - service routine that calculates the current frame's
00321 // duration in milli-seconds using it's duration in TR units.
00322 //  - In order not to accumulate the calculation error, we are using the TR
00323 // duration to calculate the current and the next frame's presentation time in
00324 // milli-seconds.
00325 //
00326 // Inputs: trDiff - The current frame's duration in TR units
00327 // Return: The current frame's duration in milli-seconds
00329 u_int64_t H263plusVideoStreamParser::CalculateDuration(u_int8_t trDiff)
00330 {
00331   u_int64_t        nextPT;          // The next frame's presentation time in milli-seconds
00332   u_int64_t        duration;        // The current frame's duration in milli-seconds
00333 
00334   fnextTR += trDiff;
00335   // Calculate the next frame's presentation time, in milli-seconds
00336   nextPT = (fnextTR * 1001) / H263_BASIC_FRAME_RATE;
00337   // The frame's duration is the difference between the next presentation
00338   // time and the current presentation time.
00339   duration = nextPT - fcurrentPT;
00340   // "Remember" the next presentation time for the next time this function is called
00341   fcurrentPT = nextPT;
00342 
00343   return duration;
00344 }
00345 
00347 bool H263plusVideoStreamParser::GetWidthAndHeight( u_int8_t  fmt,
00348                                                    u_int16_t *width,
00349                                                    u_int16_t *height)
00350 {
00351    // The 'fmt' corresponds to bits 5-7 of the PTYPE
00352   static struct {
00353       u_int16_t width;
00354       u_int16_t height;
00355    } const dimensionsTable[8] = {
00356            { 0,    0 },      // 000 - 0 - forbidden, generates an error
00357            { 128,  96 },     // 001 - 1 - Sub QCIF
00358            { 176,  144 },    // 010 - 2 - QCIF
00359            { 352,  288 },    // 011 - 3 - CIF
00360            { 704,  576 },    // 100 - 4 - 4CIF
00361            { 1409, 1152 },   // 101 - 5 - 16CIF
00362            { 0,    0 },      // 110 - 6 - reserved, generates an error
00363            { 0,    0 }       // 111 - 7 - extended, not supported by profile 0
00364    };
00365 
00366    if (fmt > 7)
00367       return false;
00368 
00369    *width  = dimensionsTable[fmt].width;
00370    *height = dimensionsTable[fmt].height;
00371 
00372    if (*width  == 0)
00373      return false;
00374 
00375    return true;
00376 }
00377 
00379 u_int8_t H263plusVideoStreamParser::GetTRDifference(
00380                                               u_int8_t nextTR,
00381                                               u_int8_t currentTR)
00382 {
00383    if (currentTR > nextTR) {
00384       // Wrap around 255...
00385       return nextTR + (256 - currentTR);
00386    } else {
00387       return nextTR - currentTR;
00388    }
00389 }
00390 
00391 
00392 
00393 
00394 
00395 
00396 
00400 // this is the h263.c file of MPEG4IP mp4creator
00401 /*
00402 #include "mp4creator.h"
00403 
00404 // Default timescale for H.263 (1000ms)
00405 #define H263_TIMESCALE 1000
00406 // Default H263 frame rate (30fps)
00407 #define H263_BASIC_FRAME_RATE 30
00408 
00409 // Minimum number of bytes needed to parse an H263 header
00410 #define H263_REQUIRE_HEADER_SIZE_BYTES 5
00411 // Number of bytes the start code requries
00412 #define H263_STARTCODE_SIZE_BYTES 3
00413 // This is the input buffer's size. It should contain
00414 // 1 frame with the following start code
00415 #define H263_BUFFER_SIZE 256 * 1024
00416 // The default max different (in %) betwqeen max and average bitrates
00417 #define H263_DEFAULT_CBR_TOLERANCE  10
00418 
00419 // The following structure holds information extracted from each frame's header:
00420 typedef struct _H263INFO {
00421   u_int8_t  tr;                 // Temporal Reference, used in duration calculation
00422   u_int16_t width;              // Width of the picture
00423   u_int16_t height;             // Height of the picture
00424   bool      isSyncFrame;        // Frame type (true = I frame = "sync" frame)
00425 } H263INFO;
00426 
00427 // Context for the GetMaxBitrate function
00428 typedef struct _MaxBitrate_CTX {
00429   u_int32_t  bitrateTable[H263_BASIC_FRAME_RATE];// Window of 1 second
00430   u_int32_t  windowBitrate;              // The bitrate of the current window
00431   u_int32_t  maxBitrate;                 // The up-to-date maximum bitrate
00432   u_int32_t  tableIndex;                 // The next TR unit to update
00433 } MaxBitrate_CTX;
00434 
00435 // Forward declarations:
00436 static int LoadNextH263Object(  FILE           *inputFileHandle,
00437                                 u_int8_t       *frameBuffer,
00438                                 u_int32_t      *frameBufferSize,
00439                                 u_int32_t       additionalBytesNeeded,
00440                                 u_int8_t      **ppNextHeader);
00441 
00442 static bool ParseShortHeader(   u_int8_t       *headerBuffer,
00443                                 H263INFO       *outputInfoStruct);
00444 
00445 static u_int8_t GetTRDifference(u_int8_t        nextTR,
00446                                 u_int8_t        currentTR);
00447 
00448 static void GetMaxBitrate(      MaxBitrate_CTX *ctx,
00449                                 u_int32_t       frameSize,
00450                                 u_int8_t        frameTRDiff);
00451 
00452 static MP4Duration CalculateDuration(u_int8_t   trDiff);
00453 
00454 static bool GetWidthAndHeight(  u_int8_t        fmt,
00455                                 u_int16_t      *width,
00456                                 u_int16_t      *height);
00457 
00458 static char   states[3][256];
00459 / *
00460  * H263Creator - Main function
00461  * Inputs:
00462  *      outputFileHandle - The handle of the output file
00463  *      inputFileHandle - The handle of the input file
00464  *      Codec-specific parameters:
00465  *              H263Level - H.263 Level used for this track
00466  *              H263Profile - H.263 Profile used for this track
00467  *              H263Bitrates - A Parameter indicating whether the function
00468  *                             should calculate H263 bitrates or not.
00469  *              cbrTolerance - CBR tolerance indicates when to set the
00470  *                             average bitrate.
00471  * Outputs:
00472  *      This function returns either the track ID of the newly added track upon
00473  *      success or a predefined value representing an erroneous state.
00474  * /
00475 MP4TrackId H263Creator(MP4FileHandle outputFileHandle,
00476                        FILE*         inputFileHandle,
00477                        u_int8_t      h263Profile,
00478                        u_int8_t      h263Level,
00479                        bool          h263Bitrates,
00480                        u_int8_t      cbrTolerance)
00481 {
00482   H263INFO       nextInfo;   // Holds information about the next frame
00483   H263INFO       currentInfo;// Holds information about the current frame
00484   MaxBitrate_CTX maxBitrateCtx;// Context for the GetMaxBitrate function
00485   memset(&nextInfo, 0, sizeof(nextInfo));
00486   memset(&currentInfo, 0, sizeof(currentInfo));
00487   memset(&maxBitrateCtx, 0, sizeof(maxBitrateCtx));
00488   memset(states, 0, sizeof(states));
00489   u_int8_t       frameBuffer[H263_BUFFER_SIZE]; // The input buffer
00490                  // Pointer which tells LoadNextH263Object where to read data to
00491   u_int8_t*      pFrameBuffer = frameBuffer + H263_REQUIRE_HEADER_SIZE_BYTES;
00492   u_int32_t      frameSize;        // The current frame size
00493                                 // Pointer to receive address of the header data
00494   u_int8_t*      pCurrentHeader = pFrameBuffer;
00495   MP4Duration    currentDuration;  // The current frame's duration
00496   u_int8_t       trDifference;     // The current TR difference
00497                                    // The previous TR difference
00498   u_int8_t       prevTrDifference = H263_BASIC_FRAME_RATE;
00499   MP4Duration    totalDuration = 0;// Duration accumulator
00500   MP4Duration    avgBitrate;       // Average bitrate
00501   u_int64_t      totalBytes = 0;   // Size accumulator
00502   MP4TrackId     trackId = MP4_INVALID_TRACK_ID; // Our MP4 track
00503   bool           stay = true;      // loop flag
00504 
00505   while (stay) {
00506     currentInfo = nextInfo;
00507     memmove(frameBuffer, pCurrentHeader, H263_REQUIRE_HEADER_SIZE_BYTES);
00508     frameSize = H263_BUFFER_SIZE - H263_REQUIRE_HEADER_SIZE_BYTES;
00509     // Read 1 frame and the next frame's header from the file.
00510     // For the first frame, only the first frame's header is returned.
00511     // For the last frame, only the last frame's data is returned.
00512     if (! LoadNextH263Object(inputFileHandle, pFrameBuffer, &frameSize,
00513           H263_REQUIRE_HEADER_SIZE_BYTES - H263_STARTCODE_SIZE_BYTES,
00514           &pCurrentHeader))
00515       break; // Fatal error ...
00516 
00517     if (pCurrentHeader) {
00518       // Parse the returned frame header (if any)
00519       if (!ParseShortHeader(pCurrentHeader, &nextInfo))
00520         break; // Fatal error
00521       trDifference = GetTRDifference(nextInfo.tr, currentInfo.tr);
00522     } else {
00523       // This is the last frame ... we have to fake the trDifference ...
00524       trDifference = 1;
00525       // No header data has been read at this iteration, so we have to manually
00526       // add the frame's header we read at the previous iteration.
00527       // Note that LoadNextH263Object returns the number of bytes read, which
00528       // are the current frame's data and the next frame's header
00529       frameSize += H263_REQUIRE_HEADER_SIZE_BYTES;
00530       // There is no need for the next iteration ...
00531       stay = false;
00532     }
00533 
00534     // If this is the first iteration ...
00535     if (currentInfo.width == 0) {
00536       // If we have more data than just the header
00537       if ((frameSize > H263_REQUIRE_HEADER_SIZE_BYTES) ||
00538           !pCurrentHeader)  // Or no header at all
00539         break;     // Fatal error
00540       else
00541         continue;  // We have only the first frame's header ...
00542     }
00543 
00544     if (trackId == MP4_INVALID_TRACK_ID) {
00545       //  If a track has not been added yet, add the track to the file.
00546       trackId = MP4AddH263VideoTrack(outputFileHandle, H263_TIMESCALE,
00547           0, currentInfo.width, currentInfo.height,
00548           h263Level, h263Profile, 0, 0);
00549       if (trackId == MP4_INVALID_TRACK_ID)
00550         break; // Fatal error
00551     }
00552 
00553     // calculate the current frame duration
00554     currentDuration = CalculateDuration(trDifference);
00555     // Write the current frame to the file.
00556     if (!MP4WriteSample(outputFileHandle, trackId, frameBuffer, frameSize,
00557           currentDuration, 0, currentInfo.isSyncFrame))
00558       break; // Fatal error
00559 
00560     // Accumulate the frame's size and duration for avgBitrate calculation
00561     totalDuration += currentDuration;
00562     totalBytes += frameSize;
00563     //  If needed, recalculate bitrate information
00564     if (h263Bitrates)
00565       GetMaxBitrate(&maxBitrateCtx, frameSize, prevTrDifference);
00566     prevTrDifference = trDifference;
00567   } // while (stay)
00568 
00569   // If this is the last frame,
00570   if (!stay) {
00571     // If needed and possible, update bitrate information in the file
00572     if (h263Bitrates && totalDuration) {
00573       avgBitrate = (totalBytes * 8 * H263_TIMESCALE) / totalDuration;
00574       if (cbrTolerance == 0)
00575         cbrTolerance = H263_DEFAULT_CBR_TOLERANCE;
00576       // Same as: if (maxBitrate / avgBitrate > (cbrTolerance + 100) / 100.0)
00577       if (maxBitrateCtx.maxBitrate * 100 > (cbrTolerance + 100) * avgBitrate)
00578         avgBitrate = 0;
00579       MP4SetH263Bitrates(outputFileHandle, trackId,
00580           avgBitrate, maxBitrateCtx.maxBitrate);
00581     }
00582     // Return the newly added track ID
00583     return trackId;
00584   }
00585 
00586   // If we got to here... something went wrong ...
00587   fprintf(stderr,
00588     "%s: Could not parse input file, invalid video stream?\n", ProgName);
00589   // Upon failure, delete the newly added track if it has been added
00590   if (trackId != MP4_INVALID_TRACK_ID) {
00591     MP4DeleteTrack(outputFileHandle, trackId);
00592   }
00593   return MP4_INVALID_TRACK_ID;
00594 }
00595 
00596 / *
00597  * LoadNextH263Object - service routine that reads a single frame from the input
00598  * file. It shall fill the input buffer with data up until - and including - the
00599  * next start code and shall report back both the number of bytes read and a
00600  * pointer to the next start code. The first call to this function shall only
00601  * yield a pointer with 0 data bytes and the last call to this function shall
00602  * only yield data bytes with a NULL pointer as the next header.
00603  *
00604  * TODO: This function only supports valid bit streams. Upon error, it fails
00605  * without the possibility to recover. A Better idea would be to skip frames
00606  * until a parsable frame is read from the file.
00607  *
00608  * Parameters:
00609  *      inputFileHandle - The handle of the input file
00610  *      frameBuffer - buffer where to place read data
00611  *      frameBufferSize - in/out parameter indicating the size of the buffer on
00612  *                          entry and the number of bytes copied to the buffer upon
00613  *                          return
00614  *      additionalBytesNeeded - indicates how many additional bytes are to be read
00615  *                          from the next frame's header (over the 3 bytes that
00616  *                          are already read).
00617  *                          NOTE: This number MUST be > 0
00618  *      ppNextHeader - output parameter that upon return points to the location
00619  *                     of the next frame's head in the buffer
00620  * Outputs:
00621  *      This function returns two pieces of information:
00622  *      1. The total number of bytes read.
00623  *      2. A Pointer to the header of the next frame. This pointer shall be NULL
00624  *      for the last frame read.
00625  * /
00626 static int LoadNextH263Object(  FILE           *inputFileHandle,
00627                                 u_int8_t       *frameBuffer,
00628                                 u_int32_t      *frameBufferSize,
00629                                 u_int32_t       additionalBytesNeeded,
00630                                 u_int8_t      **ppNextHeader)
00631 {
00632   // This table and the following loop implements a state machine enabling
00633   // us to read bytes from the file untill (and inclusing) the requested
00634   // start code (00 00 8X) is found
00635   int8_t        row = 0;
00636   u_int8_t     *bufferStart = frameBuffer;
00637   // The buffer end which will allow the loop to leave place for
00638   // the additionalBytesNeeded
00639   u_int8_t     *bufferEnd = frameBuffer + *frameBufferSize -
00640                                               additionalBytesNeeded - 1;
00641 
00642   // Initialize the states array, if it hasn't been initialized yet...
00643   if (!states[0][0]) {
00644     // One 00 was read
00645     states[0][0] = 1;
00646     // Two sequential 0x00 ware read
00647     states[1][0] = states[2][0] = 2;
00648     // A full start code was read
00649     states[2][128] = states[2][129] = states[2][130] = states[2][131] = -1;
00650   }
00651 
00652   // Read data from file into the output buffer until either a start code
00653   // is found, or the end of file has been reached.
00654   do {
00655     if (fread(frameBuffer, 1, 1, inputFileHandle) != 1){
00656       // EOF or other error before we got a start code
00657       *ppNextHeader = NULL;
00658       *frameBufferSize = frameBuffer - bufferStart;
00659       return 1;
00660     }
00661   } while ((frameBuffer < bufferEnd) &&                    // We have place in the buffer
00662            ((row = states[row][*(frameBuffer++)]) != -1)); // Start code was not found
00663   if (row != -1) {
00664     fprintf(stderr, "%s: Buffer too small (%u)\n",
00665             ProgName, bufferEnd - bufferStart + additionalBytesNeeded);
00666     return 0;
00667   }
00668 
00669   // Cool ... now we have a start code
00670   *ppNextHeader = frameBuffer - H263_STARTCODE_SIZE_BYTES;
00671   *frameBufferSize = frameBuffer - bufferStart + additionalBytesNeeded;
00672 
00673   // Now we just have to read the additionalBytesNeeded
00674   if(fread(frameBuffer, additionalBytesNeeded, 1, inputFileHandle) != 1) {
00676     fprintf(stderr, "%s: Invalid H263 bitstream\n", ProgName);
00677     return 0;
00678   }
00679 
00680   return 1;
00681 }
00682 
00683 
00684 / *
00685  * ParseShortHeader - service routine that accepts a buffer containing a frame
00686  * header and extracts relevant codec information from it.
00687  *
00688  * NOTE: the first bit in the following commnets is 0 (zero).
00689  *
00690  *
00691  *       0                   1                   2                   3
00692  *       0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
00693  *      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
00694  *      |      PSC (Picture Start Code=22 bits)     |  (TR=8 bits)  |   >
00695  *      |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0|               |1 0>
00696  *      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
00697  *      <   (PTYPE=13 bits)   |
00698  *      <. . .|(FMT)|Z|. . . .|
00699  *      +-+-+-+-+-+-+-+-+-+-+-+
00700  *      -> PTYPE.FMT contains a width/height identification
00701  *      -> PTYPE.Z   is 1 for P-Frames, 0 for I-Frames
00702  *      Note: When FMT is 111, there is an extended PTYPE...
00703  *
00704  * Inputs:
00705  *      headerBuffer - pointer to the current header buffer
00706  *      outputInfoStruct - pointer to the structure receiving the data
00707  * Outputs:
00708  *      This function returns a structure of important codec-specific
00709  *      information (The Temporal Reference bits, width & height of the current
00710  *      frame and the sync - or "frame type" - bit. It reports success or
00711  *      failure to the calling function.
00712  * /
00713 static bool ParseShortHeader(   u_int8_t       *headerBuffer,
00714                                 H263INFO       *outputInfoStruct)
00715 {
00716   u_int8_t fmt = 0;
00717   // Extract temporal reference (TR) from the buffer (bits 22-29 inclusive)
00718   outputInfoStruct->tr  = (headerBuffer[2] << 6) & 0xC0; // 2 LS bits out of the 3rd byte
00719   outputInfoStruct->tr |= (headerBuffer[3] >> 2) & 0x3F; // 6 MS bits out of the 4th byte
00720   // Extract the FMT part of PTYPE from the buffer (bits 35-37 inclusive)
00721   fmt = (headerBuffer[4] >> 2) & 0x07; // bits 3-5 ouf of the 5th byte
00722   // If PTYPE is not supported, return a failure notice to the calling function
00723   // FIXME: PLUSPTYPE is not supported
00724    if (fmt == 0x07) {
00725     return false;
00726   }
00727   // If PTYPE is supported, calculate the current width and height according to
00728   // a predefined table
00729   if (!GetWidthAndHeight(fmt, &(outputInfoStruct->width),
00730                               &(outputInfoStruct->height))) {
00731     return false;
00732   }
00733   // Extract the frame-type bit, which is the 9th bit of PTYPE (bit 38)
00734   outputInfoStruct->isSyncFrame = !(headerBuffer[4] & 0x02);
00735 
00736   return true;
00737 }
00738 
00739 / *
00740  * GetMaxBitrate- service routine that accepts frame information and
00741  * derives bitrate information from it. This function uses a sliding window
00742  * technique to calculate the maximum bitrates in any window of 1 second
00743  * inside the file.
00744  * The sliding window is implemented with a table of bitrates for the last
00745  * second (30 entries - one entry per TR unit).
00746  *
00747  * Inputs:
00748  *      ctx - context for this function
00749  *      frameSize - the size of the current frame in bytes
00750  *      frameTRDiff - the "duration" of the frame in TR units
00751  * Outputs:
00752  *      This function returns the up-to-date maximum bitrate
00753  * /
00754 static void GetMaxBitrate(      MaxBitrate_CTX *ctx,
00755                                 u_int32_t       frameSize,
00756                                 u_int8_t        frameTRDiff)
00757 {
00758   if (frameTRDiff == 0)
00759     return;
00760 
00761   // Calculate the current frame's bitrate as bits per TR unit (round the result
00762   // upwards)
00763   u_int32_t frameBitrate = frameSize * 8 / frameTRDiff + 1;
00764 
00765   // for each TRdiff received,
00766   while (frameTRDiff--) {
00767     // Subtract the oldest bitrate entry from the current bitrate
00768     ctx->windowBitrate -= ctx->bitrateTable[ctx->tableIndex];
00769      // Update the oldest bitrate entry with the current frame's bitrate
00770     ctx->bitrateTable[ctx->tableIndex] = frameBitrate;
00771     // Add the current frame's bitrate to the current bitrate
00772     ctx->windowBitrate += frameBitrate;
00773     // Check if we have a new maximum bitrate
00774     if (ctx->windowBitrate > ctx->maxBitrate) {
00775       ctx->maxBitrate = ctx->windowBitrate;
00776     }
00777     // Advance the table index
00778     ctx->tableIndex = (ctx->tableIndex + 1) %
00779         // Wrapping around the bitrateTable size
00780         ( sizeof(ctx->bitrateTable) / sizeof(ctx->bitrateTable[0]) );
00781   }
00782 }
00783 
00784 / *
00785  * CalculateDuration - service routine that calculates the current frame's
00786  * duration in milli-seconds using it's duration in TR units.
00787  *  - In order not to accumulate the calculation error, we are using the TR
00788  * duration to calculate the current and the next frame's presentation time in
00789  * milli-seconds.
00790  *
00791  * Inputs:
00792  *      trDiff - The current frame's duration in TR units
00793  * Outputs:
00794  *      The current frame's duration in milli-seconds
00795  * /
00796 static MP4Duration CalculateDuration(u_int8_t   trDiff)
00797 {
00798   static u_int32_t const    nextTR    = 0;   // The next frame's presentation time in TR units
00799   static MP4Duration const  currentPT = 0;   // The current frame's presentation time in milli-seconds
00800   MP4Duration         nextPT;          // The next frame's presentation time in milli-seconds
00801   MP4Duration         duration;        // The current frame's duration in milli-seconds
00802 
00803   nextTR += trDiff;
00804   // Calculate the next frame's presentation time, in milli-seconds
00805   nextPT = (nextTR * 1001) / H263_BASIC_FRAME_RATE;
00806   // The frame's duration is the difference between the next presentation
00807   // time and the current presentation time.
00808   duration = nextPT - currentPT;
00809   // "Remember" the next presentation time for the next time this function is
00810   // called
00811   currentPT = nextPT;
00812 
00813   return duration;
00814 }
00815 
00816 static bool GetWidthAndHeight(  u_int8_t        fmt,
00817                                 u_int16_t      *width,
00818                                 u_int16_t      *height)
00819 {
00820   // The 'fmt' corresponds to bits 5-7 of the PTYPE
00821   static struct {
00822     u_int16_t width;
00823     u_int16_t height;
00824   } const dimensionsTable[8] = {
00825     { 0,    0 },      // 000 - 0 - forbidden, generates an error
00826     { 128,  96 },     // 001 - 1 - Sub QCIF
00827     { 176,  144 },    // 010 - 2 - QCIF
00828     { 352,  288 },    // 011 - 3 - CIF
00829     { 704,  576 },    // 100 - 4 - 4CIF
00830     { 1409, 1152 },   // 101 - 5 - 16CIF
00831     { 0,    0 },      // 110 - 6 - reserved, generates an error
00832     { 0,    0 }       // 111 - 7 - extended, not supported by profile 0
00833   };
00834 
00835   if (fmt > 7)
00836     return false;
00837 
00838   *width  = dimensionsTable[fmt].width;
00839   *height = dimensionsTable[fmt].height;
00840 
00841   if (*width  == 0)
00842     return false;
00843 
00844   return true;
00845 }
00846 
00847 static u_int8_t GetTRDifference(u_int8_t        nextTR,
00848                                 u_int8_t        currentTR)
00849 {
00850   if (currentTR > nextTR) {
00851     // Wrap around 255...
00852     return nextTR + (256 - currentTR);
00853   } else {
00854     return nextTR - currentTR;
00855   }
00856 }
00857 
00858 */
00859 

Generated on Thu May 10 20:25:11 2012 for live by  doxygen 1.5.2