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