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(¤tInfo, 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
1.5.2