1/**********
2This library is free software; you can redistribute it and/or modify it under
3the terms of the GNU Lesser General Public License as published by the
4Free Software Foundation; either version 3 of the License, or (at your
5option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.)
6
7This library is distributed in the hope that it will be useful, but WITHOUT
8ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
9FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
10more details.
11
12You should have received a copy of the GNU Lesser General Public License
13along with this library; if not, write to the Free Software Foundation, Inc.,
1451 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
15**********/
16// "liveMedia"
17// Copyright (c) 1996-2020 Live Networks, Inc. All rights reserved.
18// Author Bernhard Feiten
19// A filter that breaks up an H.263plus video stream into frames.
20// Based on MPEG4IP/mp4creator/h263.c
21
22#include "H263plusVideoStreamParser.hh"
23#include "H263plusVideoStreamFramer.hh"
24//#include <string.h>
25//#include "GroupsockHelper.hh"
26
27
28H263plusVideoStreamParser::H263plusVideoStreamParser(
29 H263plusVideoStreamFramer* usingSource,
30 FramedSource* inputSource)
31 : StreamParser(inputSource,
32 FramedSource::handleClosure,
33 usingSource,
34 &H263plusVideoStreamFramer::continueReadProcessing,
35 usingSource),
36 fUsingSource(usingSource),
37 fnextTR(0),
38 fcurrentPT(0)
39{
40 memset(fStates, 0, sizeof(fStates));
41 memset(&fNextInfo, 0, sizeof(fNextInfo));
42 memset(&fCurrentInfo, 0, sizeof(fCurrentInfo));
43 memset(&fMaxBitrateCtx, 0, sizeof(fMaxBitrateCtx));
44 memset(fNextHeader,0, H263_REQUIRE_HEADER_SIZE_BYTES);
45}
46
47///////////////////////////////////////////////////////////////////////////////
48H263plusVideoStreamParser::~H263plusVideoStreamParser()
49{
50}
51
52///////////////////////////////////////////////////////////////////////////////
53void H263plusVideoStreamParser::restoreSavedParserState()
54{
55 StreamParser::restoreSavedParserState();
56 fTo = fSavedTo;
57 fNumTruncatedBytes = fSavedNumTruncatedBytes;
58}
59
60///////////////////////////////////////////////////////////////////////////////
61void H263plusVideoStreamParser::setParseState()
62{
63 fSavedTo = fTo;
64 fSavedNumTruncatedBytes = fNumTruncatedBytes;
65 saveParserState(); // Needed for the parsing process in StreamParser
66}
67
68
69///////////////////////////////////////////////////////////////////////////////
70void H263plusVideoStreamParser::registerReadInterest(
71 unsigned char* to,
72 unsigned maxSize)
73{
74 fStartOfFrame = fTo = fSavedTo = to;
75 fLimit = to + maxSize;
76 fMaxSize = maxSize;
77 fNumTruncatedBytes = fSavedNumTruncatedBytes = 0;
78}
79
80///////////////////////////////////////////////////////////////////////////////
81// parse() , derived from H263Creator of MPEG4IP, h263.c
82unsigned H263plusVideoStreamParser::parse(u_int64_t & currentDuration)
83{
84
85// u_int8_t frameBuffer[H263_BUFFER_SIZE]; // The input buffer
86 // Pointer which tells LoadNextH263Object where to read data to
87// u_int8_t* pFrameBuffer = fTo + H263_REQUIRE_HEADER_SIZE_BYTES;
88 u_int32_t frameSize; // The current frame size
89 // Pointer to receive address of the header data
90// u_int8_t* pCurrentHeader;// = pFrameBuffer;
91// u_int64_t currentDuration; // The current frame's duration
92 u_int8_t trDifference; // The current TR difference
93 // The previous TR difference
94// u_int8_t prevTrDifference = H263_BASIC_FRAME_RATE;
95// u_int64_t totalDuration = 0;// Duration accumulator
96// u_int64_t avgBitrate; // Average bitrate
97// u_int64_t totalBytes = 0; // Size accumulator
98
99
100 try // The get data routines of the class FramedFilter returns an error when
101 { // the buffer is empty. This occurs at the beginning and at the end of the file.
102 fCurrentInfo = fNextInfo;
103
104 // Parse 1 frame
105 // For the first time, only the first frame's header is returned.
106 // The second time the full first frame is returned
107 frameSize = parseH263Frame();
108
109 currentDuration = 0;
110 if ((frameSize > 0)){
111 // We were able to acquire a frame from the input.
112
113 // Parse the returned frame header (if any)
114 if (!ParseShortHeader(fTo, &fNextInfo)) {
115#ifdef DEBUG
116 fprintf(stderr,"H263plusVideoStreamParser: Fatal error\n");
117#endif
118 }
119
120 trDifference = GetTRDifference(fNextInfo.tr, fCurrentInfo.tr);
121
122 // calculate the current frame duration
123 currentDuration = CalculateDuration(trDifference);
124
125 // Accumulate the frame's size and duration for avgBitrate calculation
126 //totalDuration += currentDuration;
127 //totalBytes += frameSize;
128 // If needed, recalculate bitrate information
129 // if (h263Bitrates)
130 //GetMaxBitrate(&fMaxBitrateCtx, frameSize, prevTrDifference);
131 //prevTrDifference = trDifference;
132
133 setParseState(); // Needed for the parsing process in StreamParser
134 }
135 } catch (int /*e*/) {
136#ifdef DEBUG
137 fprintf(stderr, "H263plusVideoStreamParser::parse() EXCEPTION (This is normal behavior - *not* an error)\n");
138#endif
139 frameSize=0;
140 }
141
142 return frameSize;
143}
144
145
146///////////////////////////////////////////////////////////////////////////////
147// parseH263Frame derived from LoadNextH263Object of MPEG4IP
148// - service routine that reads a single frame from the input file.
149// It shall fill the input buffer with data up until - and including - the
150// next start code and shall report back both the number of bytes read and a
151// pointer to the next start code. The first call to this function shall only
152// yield a pointer with 0 data bytes and the last call to this function shall
153// only yield data bytes with a NULL pointer as the next header.
154//
155// TODO: This function only supports valid bit streams. Upon error, it fails
156// without the possibility to recover. A Better idea would be to skip frames
157// until a parsable frame is read from the file.
158//
159// Parameters:
160// ppNextHeader - output parameter that upon return points to the location
161// of the next frame's head in the buffer.
162// This pointer shall be NULL for the last frame read.
163// Returns the total number of bytes read.
164// Uses FrameFileSource intantiated by constructor.
165///////////////////////////////////////////////////////////////////////////////
166int H263plusVideoStreamParser::parseH263Frame( )
167{
168 char row = 0;
169 u_int8_t * bufferIndex = fTo;
170 // The buffer end which will allow the loop to leave place for
171 // the additionalBytesNeeded
172 u_int8_t * bufferEnd = fTo + fMaxSize - ADDITIONAL_BYTES_NEEDED - 1;
173
174 memcpy(fTo, fNextHeader, H263_REQUIRE_HEADER_SIZE_BYTES);
175 bufferIndex += H263_REQUIRE_HEADER_SIZE_BYTES;
176
177
178 // The state table and the following loop implements a state machine enabling
179 // us to read bytes from the file until (and inclusing) the requested
180 // start code (00 00 8X) is found
181
182 // Initialize the states array, if it hasn't been initialized yet...
183 if (!fStates[0][0]) {
184 // One 00 was read
185 fStates[0][0] = 1;
186 // Two sequential 0x00 ware read
187 fStates[1][0] = fStates[2][0] = 2;
188 // A full start code was read
189 fStates[2][128] = fStates[2][129] = fStates[2][130] = fStates[2][131] = -1;
190 }
191
192 // Read data from file into the output buffer until either a start code
193 // is found, or the end of file has been reached.
194 do {
195 *bufferIndex = get1Byte();
196 } while ((bufferIndex < bufferEnd) && // We have place in the buffer
197 ((row = fStates[(unsigned char)row][*(bufferIndex++)]) != -1)); // Start code was not found
198
199 if (row != -1) {
200 fprintf(stderr, "%s: Buffer too small (%u)\n",
201 "h263reader:", bufferEnd - fTo + ADDITIONAL_BYTES_NEEDED);
202 return 0;
203 }
204
205 // Cool ... now we have a start code
206 // Now we just have to read the additionalBytesNeeded
207 getBytes(bufferIndex, ADDITIONAL_BYTES_NEEDED);
208 memcpy(fNextHeader, bufferIndex - H263_STARTCODE_SIZE_BYTES, H263_REQUIRE_HEADER_SIZE_BYTES);
209
210 int sz = bufferIndex - fTo - H263_STARTCODE_SIZE_BYTES;
211
212 if (sz == 5) // first frame
213 memcpy(fTo, fTo+H263_REQUIRE_HEADER_SIZE_BYTES, H263_REQUIRE_HEADER_SIZE_BYTES);
214
215 return sz;
216}
217
218
219////////////////////////////////////////////////////////////////////////////////
220// ParseShortHeader - service routine that accepts a buffer containing a frame
221// header and extracts relevant codec information from it.
222//
223// NOTE: the first bit in the following commnets is 0 (zero).
224//
225// 0 1 2 3
226// 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
227// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
228// | PSC (Picture Start Code=22 bits) | (TR=8 bits) | >
229// |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0| |1 0>
230// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
231// < (PTYPE=13 bits) |
232// <. . .|(FMT)|Z|. . . .|
233// +-+-+-+-+-+-+-+-+-+-+-+
234// -> PTYPE.FMT contains a width/height identification
235// -> PTYPE.Z is 1 for P-Frames, 0 for I-Frames
236// Note: When FMT is 111, there is an extended PTYPE...
237//
238// Inputs:
239// headerBuffer - pointer to the current header buffer
240// outputInfoStruct - pointer to the structure receiving the data
241// Outputs:
242// This function returns a structure of important codec-specific
243// information (The Temporal Reference bits, width & height of the current
244// frame and the sync - or "frame type" - bit. It reports success or
245// failure to the calling function.
246////////////////////////////////////////////////////////////////////////////////
247bool H263plusVideoStreamParser::ParseShortHeader(
248 u_int8_t *headerBuffer,
249 H263INFO *outputInfoStruct)
250{
251 u_int8_t fmt = 0;
252 // Extract temporal reference (TR) from the buffer (bits 22-29 inclusive)
253 outputInfoStruct->tr = (headerBuffer[2] << 6) & 0xC0; // 2 LS bits out of the 3rd byte
254 outputInfoStruct->tr |= (headerBuffer[3] >> 2) & 0x3F; // 6 MS bits out of the 4th byte
255 // Extract the FMT part of PTYPE from the buffer (bits 35-37 inclusive)
256 fmt = (headerBuffer[4] >> 2) & 0x07; // bits 3-5 ouf of the 5th byte
257 // If PTYPE is not supported, return a failure notice to the calling function
258 // FIXME: PLUSPTYPE is not supported
259 if (fmt == 0x07) {
260 return false;
261 }
262 // If PTYPE is supported, calculate the current width and height according to
263 // a predefined table
264 if (!GetWidthAndHeight(fmt, &(outputInfoStruct->width),
265 &(outputInfoStruct->height))) {
266 return false;
267 }
268 // Extract the frame-type bit, which is the 9th bit of PTYPE (bit 38)
269 outputInfoStruct->isSyncFrame = !(headerBuffer[4] & 0x02);
270
271 return true;
272}
273
274////////////////////////////////////////////////////////////////////////////////
275// GetMaxBitrate- service routine that accepts frame information and
276// derives bitrate information from it. This function uses a sliding window
277// technique to calculate the maximum bitrates in any window of 1 second
278// inside the file.
279// The sliding window is implemented with a table of bitrates for the last
280// second (30 entries - one entry per TR unit).
281//
282// Inputs:
283// ctx - context for this function
284// frameSize - the size of the current frame in bytes
285// frameTRDiff - the "duration" of the frame in TR units
286// Outputs:
287// This function returns the up-to-date maximum bitrate
288////////////////////////////////////////////////////////////////////////////////
289void H263plusVideoStreamParser::GetMaxBitrate( MaxBitrate_CTX *ctx,
290 u_int32_t frameSize,
291 u_int8_t frameTRDiff)
292{
293 if (frameTRDiff == 0)
294 return;
295
296 // Calculate the current frame's bitrate as bits per TR unit (round the result
297 // upwards)
298 u_int32_t frameBitrate = frameSize * 8 / frameTRDiff + 1;
299
300 // for each TRdiff received,
301 while (frameTRDiff--) {
302 // Subtract the oldest bitrate entry from the current bitrate
303 ctx->windowBitrate -= ctx->bitrateTable[ctx->tableIndex];
304 // Update the oldest bitrate entry with the current frame's bitrate
305 ctx->bitrateTable[ctx->tableIndex] = frameBitrate;
306 // Add the current frame's bitrate to the current bitrate
307 ctx->windowBitrate += frameBitrate;
308 // Check if we have a new maximum bitrate
309 if (ctx->windowBitrate > ctx->maxBitrate) {
310 ctx->maxBitrate = ctx->windowBitrate;
311 }
312 // Advance the table index
313 // Wrapping around the bitrateTable size
314 ctx->tableIndex = (ctx->tableIndex + 1) %
315 ( sizeof(ctx->bitrateTable) / sizeof(ctx->bitrateTable[0]) );
316 }
317}
318
319////////////////////////////////////////////////////////////////////////////////
320// CalculateDuration - service routine that calculates the current frame's
321// duration in milli-seconds using it's duration in TR units.
322// - In order not to accumulate the calculation error, we are using the TR
323// duration to calculate the current and the next frame's presentation time in
324// milli-seconds.
325//
326// Inputs: trDiff - The current frame's duration in TR units
327// Return: The current frame's duration in milli-seconds
328////////////////////////////////////////////////////////////////////////////////
329u_int64_t H263plusVideoStreamParser::CalculateDuration(u_int8_t trDiff)
330{
331 u_int64_t nextPT; // The next frame's presentation time in milli-seconds
332 u_int64_t duration; // The current frame's duration in milli-seconds
333
334 fnextTR += trDiff;
335 // Calculate the next frame's presentation time, in milli-seconds
336 nextPT = (fnextTR * 1001) / H263_BASIC_FRAME_RATE;
337 // The frame's duration is the difference between the next presentation
338 // time and the current presentation time.
339 duration = nextPT - fcurrentPT;
340 // "Remember" the next presentation time for the next time this function is called
341 fcurrentPT = nextPT;
342
343 return duration;
344}
345
346////////////////////////////////////////////////////////////////////////////////
347bool H263plusVideoStreamParser::GetWidthAndHeight( u_int8_t fmt,
348 u_int16_t *width,
349 u_int16_t *height)
350{
351 // The 'fmt' corresponds to bits 5-7 of the PTYPE
352 static struct {
353 u_int16_t width;
354 u_int16_t height;
355 } const dimensionsTable[8] = {
356 { 0, 0 }, // 000 - 0 - forbidden, generates an error
357 { 128, 96 }, // 001 - 1 - Sub QCIF
358 { 176, 144 }, // 010 - 2 - QCIF
359 { 352, 288 }, // 011 - 3 - CIF
360 { 704, 576 }, // 100 - 4 - 4CIF
361 { 1409, 1152 }, // 101 - 5 - 16CIF
362 { 0, 0 }, // 110 - 6 - reserved, generates an error
363 { 0, 0 } // 111 - 7 - extended, not supported by profile 0
364 };
365
366 if (fmt > 7)
367 return false;
368
369 *width = dimensionsTable[fmt].width;
370 *height = dimensionsTable[fmt].height;
371
372 if (*width == 0)
373 return false;
374
375 return true;
376}
377
378////////////////////////////////////////////////////////////////////////////////
379u_int8_t H263plusVideoStreamParser::GetTRDifference(
380 u_int8_t nextTR,
381 u_int8_t currentTR)
382{
383 if (currentTR > nextTR) {
384 // Wrap around 255...
385 return nextTR + (256 - currentTR);
386 } else {
387 return nextTR - currentTR;
388 }
389}
390
391
392
393
394
395
396
397////////////////////////////////////////////////////////////////////////////////
398////////////////////////////////////////////////////////////////////////////////
399////////////////////////////////////////////////////////////////////////////////
400// this is the h263.c file of MPEG4IP mp4creator
401/*
402#include "mp4creator.h"
403
404// Default timescale for H.263 (1000ms)
405#define H263_TIMESCALE 1000
406// Default H263 frame rate (30fps)
407#define H263_BASIC_FRAME_RATE 30
408
409// Minimum number of bytes needed to parse an H263 header
410#define H263_REQUIRE_HEADER_SIZE_BYTES 5
411// Number of bytes the start code requries
412#define H263_STARTCODE_SIZE_BYTES 3
413// This is the input buffer's size. It should contain
414// 1 frame with the following start code
415#define H263_BUFFER_SIZE 256 * 1024
416// The default max different (in %) betwqeen max and average bitrates
417#define H263_DEFAULT_CBR_TOLERANCE 10
418
419// The following structure holds information extracted from each frame's header:
420typedef struct _H263INFO {
421 u_int8_t tr; // Temporal Reference, used in duration calculation
422 u_int16_t width; // Width of the picture
423 u_int16_t height; // Height of the picture
424 bool isSyncFrame; // Frame type (true = I frame = "sync" frame)
425} H263INFO;
426
427// Context for the GetMaxBitrate function
428typedef struct _MaxBitrate_CTX {
429 u_int32_t bitrateTable[H263_BASIC_FRAME_RATE];// Window of 1 second
430 u_int32_t windowBitrate; // The bitrate of the current window
431 u_int32_t maxBitrate; // The up-to-date maximum bitrate
432 u_int32_t tableIndex; // The next TR unit to update
433} MaxBitrate_CTX;
434
435// Forward declarations:
436static int LoadNextH263Object( FILE *inputFileHandle,
437 u_int8_t *frameBuffer,
438 u_int32_t *frameBufferSize,
439 u_int32_t additionalBytesNeeded,
440 u_int8_t **ppNextHeader);
441
442static bool ParseShortHeader( u_int8_t *headerBuffer,
443 H263INFO *outputInfoStruct);
444
445static u_int8_t GetTRDifference(u_int8_t nextTR,
446 u_int8_t currentTR);
447
448static void GetMaxBitrate( MaxBitrate_CTX *ctx,
449 u_int32_t frameSize,
450 u_int8_t frameTRDiff);
451
452static MP4Duration CalculateDuration(u_int8_t trDiff);
453
454static bool GetWidthAndHeight( u_int8_t fmt,
455 u_int16_t *width,
456 u_int16_t *height);
457
458static char states[3][256];
459/ *
460 * H263Creator - Main function
461 * Inputs:
462 * outputFileHandle - The handle of the output file
463 * inputFileHandle - The handle of the input file
464 * Codec-specific parameters:
465 * H263Level - H.263 Level used for this track
466 * H263Profile - H.263 Profile used for this track
467 * H263Bitrates - A Parameter indicating whether the function
468 * should calculate H263 bitrates or not.
469 * cbrTolerance - CBR tolerance indicates when to set the
470 * average bitrate.
471 * Outputs:
472 * This function returns either the track ID of the newly added track upon
473 * success or a predefined value representing an erroneous state.
474 * /
475MP4TrackId H263Creator(MP4FileHandle outputFileHandle,
476 FILE* inputFileHandle,
477 u_int8_t h263Profile,
478 u_int8_t h263Level,
479 bool h263Bitrates,
480 u_int8_t cbrTolerance)
481{
482 H263INFO nextInfo; // Holds information about the next frame
483 H263INFO currentInfo;// Holds information about the current frame
484 MaxBitrate_CTX maxBitrateCtx;// Context for the GetMaxBitrate function
485 memset(&nextInfo, 0, sizeof(nextInfo));
486 memset(&currentInfo, 0, sizeof(currentInfo));
487 memset(&maxBitrateCtx, 0, sizeof(maxBitrateCtx));
488 memset(states, 0, sizeof(states));
489 u_int8_t frameBuffer[H263_BUFFER_SIZE]; // The input buffer
490 // Pointer which tells LoadNextH263Object where to read data to
491 u_int8_t* pFrameBuffer = frameBuffer + H263_REQUIRE_HEADER_SIZE_BYTES;
492 u_int32_t frameSize; // The current frame size
493 // Pointer to receive address of the header data
494 u_int8_t* pCurrentHeader = pFrameBuffer;
495 MP4Duration currentDuration; // The current frame's duration
496 u_int8_t trDifference; // The current TR difference
497 // The previous TR difference
498 u_int8_t prevTrDifference = H263_BASIC_FRAME_RATE;
499 MP4Duration totalDuration = 0;// Duration accumulator
500 MP4Duration avgBitrate; // Average bitrate
501 u_int64_t totalBytes = 0; // Size accumulator
502 MP4TrackId trackId = MP4_INVALID_TRACK_ID; // Our MP4 track
503 bool stay = true; // loop flag
504
505 while (stay) {
506 currentInfo = nextInfo;
507 memmove(frameBuffer, pCurrentHeader, H263_REQUIRE_HEADER_SIZE_BYTES);
508 frameSize = H263_BUFFER_SIZE - H263_REQUIRE_HEADER_SIZE_BYTES;
509 // Read 1 frame and the next frame's header from the file.
510 // For the first frame, only the first frame's header is returned.
511 // For the last frame, only the last frame's data is returned.
512 if (! LoadNextH263Object(inputFileHandle, pFrameBuffer, &frameSize,
513 H263_REQUIRE_HEADER_SIZE_BYTES - H263_STARTCODE_SIZE_BYTES,
514 &pCurrentHeader))
515 break; // Fatal error ...
516
517 if (pCurrentHeader) {
518 // Parse the returned frame header (if any)
519 if (!ParseShortHeader(pCurrentHeader, &nextInfo))
520 break; // Fatal error
521 trDifference = GetTRDifference(nextInfo.tr, currentInfo.tr);
522 } else {
523 // This is the last frame ... we have to fake the trDifference ...
524 trDifference = 1;
525 // No header data has been read at this iteration, so we have to manually
526 // add the frame's header we read at the previous iteration.
527 // Note that LoadNextH263Object returns the number of bytes read, which
528 // are the current frame's data and the next frame's header
529 frameSize += H263_REQUIRE_HEADER_SIZE_BYTES;
530 // There is no need for the next iteration ...
531 stay = false;
532 }
533
534 // If this is the first iteration ...
535 if (currentInfo.width == 0) {
536 // If we have more data than just the header
537 if ((frameSize > H263_REQUIRE_HEADER_SIZE_BYTES) ||
538 !pCurrentHeader) // Or no header at all
539 break; // Fatal error
540 else
541 continue; // We have only the first frame's header ...
542 }
543
544 if (trackId == MP4_INVALID_TRACK_ID) {
545 // If a track has not been added yet, add the track to the file.
546 trackId = MP4AddH263VideoTrack(outputFileHandle, H263_TIMESCALE,
547 0, currentInfo.width, currentInfo.height,
548 h263Level, h263Profile, 0, 0);
549 if (trackId == MP4_INVALID_TRACK_ID)
550 break; // Fatal error
551 }
552
553 // calculate the current frame duration
554 currentDuration = CalculateDuration(trDifference);
555 // Write the current frame to the file.
556 if (!MP4WriteSample(outputFileHandle, trackId, frameBuffer, frameSize,
557 currentDuration, 0, currentInfo.isSyncFrame))
558 break; // Fatal error
559
560 // Accumulate the frame's size and duration for avgBitrate calculation
561 totalDuration += currentDuration;
562 totalBytes += frameSize;
563 // If needed, recalculate bitrate information
564 if (h263Bitrates)
565 GetMaxBitrate(&maxBitrateCtx, frameSize, prevTrDifference);
566 prevTrDifference = trDifference;
567 } // while (stay)
568
569 // If this is the last frame,
570 if (!stay) {
571 // If needed and possible, update bitrate information in the file
572 if (h263Bitrates && totalDuration) {
573 avgBitrate = (totalBytes * 8 * H263_TIMESCALE) / totalDuration;
574 if (cbrTolerance == 0)
575 cbrTolerance = H263_DEFAULT_CBR_TOLERANCE;
576 // Same as: if (maxBitrate / avgBitrate > (cbrTolerance + 100) / 100.0)
577 if (maxBitrateCtx.maxBitrate * 100 > (cbrTolerance + 100) * avgBitrate)
578 avgBitrate = 0;
579 MP4SetH263Bitrates(outputFileHandle, trackId,
580 avgBitrate, maxBitrateCtx.maxBitrate);
581 }
582 // Return the newly added track ID
583 return trackId;
584 }
585
586 // If we got to here... something went wrong ...
587 fprintf(stderr,
588 "%s: Could not parse input file, invalid video stream?\n", ProgName);
589 // Upon failure, delete the newly added track if it has been added
590 if (trackId != MP4_INVALID_TRACK_ID) {
591 MP4DeleteTrack(outputFileHandle, trackId);
592 }
593 return MP4_INVALID_TRACK_ID;
594}
595
596/ *
597 * LoadNextH263Object - service routine that reads a single frame from the input
598 * file. It shall fill the input buffer with data up until - and including - the
599 * next start code and shall report back both the number of bytes read and a
600 * pointer to the next start code. The first call to this function shall only
601 * yield a pointer with 0 data bytes and the last call to this function shall
602 * only yield data bytes with a NULL pointer as the next header.
603 *
604 * TODO: This function only supports valid bit streams. Upon error, it fails
605 * without the possibility to recover. A Better idea would be to skip frames
606 * until a parsable frame is read from the file.
607 *
608 * Parameters:
609 * inputFileHandle - The handle of the input file
610 * frameBuffer - buffer where to place read data
611 * frameBufferSize - in/out parameter indicating the size of the buffer on
612 * entry and the number of bytes copied to the buffer upon
613 * return
614 * additionalBytesNeeded - indicates how many additional bytes are to be read
615 * from the next frame's header (over the 3 bytes that
616 * are already read).
617 * NOTE: This number MUST be > 0
618 * ppNextHeader - output parameter that upon return points to the location
619 * of the next frame's head in the buffer
620 * Outputs:
621 * This function returns two pieces of information:
622 * 1. The total number of bytes read.
623 * 2. A Pointer to the header of the next frame. This pointer shall be NULL
624 * for the last frame read.
625 * /
626static int LoadNextH263Object( FILE *inputFileHandle,
627 u_int8_t *frameBuffer,
628 u_int32_t *frameBufferSize,
629 u_int32_t additionalBytesNeeded,
630 u_int8_t **ppNextHeader)
631{
632 // This table and the following loop implements a state machine enabling
633 // us to read bytes from the file untill (and inclusing) the requested
634 // start code (00 00 8X) is found
635 char row = 0;
636 u_int8_t *bufferStart = frameBuffer;
637 // The buffer end which will allow the loop to leave place for
638 // the additionalBytesNeeded
639 u_int8_t *bufferEnd = frameBuffer + *frameBufferSize -
640 additionalBytesNeeded - 1;
641
642 // Initialize the states array, if it hasn't been initialized yet...
643 if (!states[0][0]) {
644 // One 00 was read
645 states[0][0] = 1;
646 // Two sequential 0x00 ware read
647 states[1][0] = states[2][0] = 2;
648 // A full start code was read
649 states[2][128] = states[2][129] = states[2][130] = states[2][131] = -1;
650 }
651
652 // Read data from file into the output buffer until either a start code
653 // is found, or the end of file has been reached.
654 do {
655 if (fread(frameBuffer, 1, 1, inputFileHandle) != 1){
656 // EOF or other error before we got a start code
657 *ppNextHeader = NULL;
658 *frameBufferSize = frameBuffer - bufferStart;
659 return 1;
660 }
661 } while ((frameBuffer < bufferEnd) && // We have place in the buffer
662 ((row = states[row][*(frameBuffer++)]) != -1)); // Start code was not found
663 if (row != -1) {
664 fprintf(stderr, "%s: Buffer too small (%u)\n",
665 ProgName, bufferEnd - bufferStart + additionalBytesNeeded);
666 return 0;
667 }
668
669 // Cool ... now we have a start code
670 *ppNextHeader = frameBuffer - H263_STARTCODE_SIZE_BYTES;
671 *frameBufferSize = frameBuffer - bufferStart + additionalBytesNeeded;
672
673 // Now we just have to read the additionalBytesNeeded
674 if(fread(frameBuffer, additionalBytesNeeded, 1, inputFileHandle) != 1) {
675 /// We got a start code but can't read additionalBytesNeeded ... that's a fatal error
676 fprintf(stderr, "%s: Invalid H263 bitstream\n", ProgName);
677 return 0;
678 }
679
680 return 1;
681}
682
683
684/ *
685 * ParseShortHeader - service routine that accepts a buffer containing a frame
686 * header and extracts relevant codec information from it.
687 *
688 * NOTE: the first bit in the following commnets is 0 (zero).
689 *
690 *
691 * 0 1 2 3
692 * 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
693 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
694 * | PSC (Picture Start Code=22 bits) | (TR=8 bits) | >
695 * |0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0| |1 0>
696 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
697 * < (PTYPE=13 bits) |
698 * <. . .|(FMT)|Z|. . . .|
699 * +-+-+-+-+-+-+-+-+-+-+-+
700 * -> PTYPE.FMT contains a width/height identification
701 * -> PTYPE.Z is 1 for P-Frames, 0 for I-Frames
702 * Note: When FMT is 111, there is an extended PTYPE...
703 *
704 * Inputs:
705 * headerBuffer - pointer to the current header buffer
706 * outputInfoStruct - pointer to the structure receiving the data
707 * Outputs:
708 * This function returns a structure of important codec-specific
709 * information (The Temporal Reference bits, width & height of the current
710 * frame and the sync - or "frame type" - bit. It reports success or
711 * failure to the calling function.
712 * /
713static bool ParseShortHeader( u_int8_t *headerBuffer,
714 H263INFO *outputInfoStruct)
715{
716 u_int8_t fmt = 0;
717 // Extract temporal reference (TR) from the buffer (bits 22-29 inclusive)
718 outputInfoStruct->tr = (headerBuffer[2] << 6) & 0xC0; // 2 LS bits out of the 3rd byte
719 outputInfoStruct->tr |= (headerBuffer[3] >> 2) & 0x3F; // 6 MS bits out of the 4th byte
720 // Extract the FMT part of PTYPE from the buffer (bits 35-37 inclusive)
721 fmt = (headerBuffer[4] >> 2) & 0x07; // bits 3-5 ouf of the 5th byte
722 // If PTYPE is not supported, return a failure notice to the calling function
723 // FIXME: PLUSPTYPE is not supported
724 if (fmt == 0x07) {
725 return false;
726 }
727 // If PTYPE is supported, calculate the current width and height according to
728 // a predefined table
729 if (!GetWidthAndHeight(fmt, &(outputInfoStruct->width),
730 &(outputInfoStruct->height))) {
731 return false;
732 }
733 // Extract the frame-type bit, which is the 9th bit of PTYPE (bit 38)
734 outputInfoStruct->isSyncFrame = !(headerBuffer[4] & 0x02);
735
736 return true;
737}
738
739/ *
740 * GetMaxBitrate- service routine that accepts frame information and
741 * derives bitrate information from it. This function uses a sliding window
742 * technique to calculate the maximum bitrates in any window of 1 second
743 * inside the file.
744 * The sliding window is implemented with a table of bitrates for the last
745 * second (30 entries - one entry per TR unit).
746 *
747 * Inputs:
748 * ctx - context for this function
749 * frameSize - the size of the current frame in bytes
750 * frameTRDiff - the "duration" of the frame in TR units
751 * Outputs:
752 * This function returns the up-to-date maximum bitrate
753 * /
754static void GetMaxBitrate( MaxBitrate_CTX *ctx,
755 u_int32_t frameSize,
756 u_int8_t frameTRDiff)
757{
758 if (frameTRDiff == 0)
759 return;
760
761 // Calculate the current frame's bitrate as bits per TR unit (round the result
762 // upwards)
763 u_int32_t frameBitrate = frameSize * 8 / frameTRDiff + 1;
764
765 // for each TRdiff received,
766 while (frameTRDiff--) {
767 // Subtract the oldest bitrate entry from the current bitrate
768 ctx->windowBitrate -= ctx->bitrateTable[ctx->tableIndex];
769 // Update the oldest bitrate entry with the current frame's bitrate
770 ctx->bitrateTable[ctx->tableIndex] = frameBitrate;
771 // Add the current frame's bitrate to the current bitrate
772 ctx->windowBitrate += frameBitrate;
773 // Check if we have a new maximum bitrate
774 if (ctx->windowBitrate > ctx->maxBitrate) {
775 ctx->maxBitrate = ctx->windowBitrate;
776 }
777 // Advance the table index
778 ctx->tableIndex = (ctx->tableIndex + 1) %
779 // Wrapping around the bitrateTable size
780 ( sizeof(ctx->bitrateTable) / sizeof(ctx->bitrateTable[0]) );
781 }
782}
783
784/ *
785 * CalculateDuration - service routine that calculates the current frame's
786 * duration in milli-seconds using it's duration in TR units.
787 * - In order not to accumulate the calculation error, we are using the TR
788 * duration to calculate the current and the next frame's presentation time in
789 * milli-seconds.
790 *
791 * Inputs:
792 * trDiff - The current frame's duration in TR units
793 * Outputs:
794 * The current frame's duration in milli-seconds
795 * /
796static MP4Duration CalculateDuration(u_int8_t trDiff)
797{
798 static u_int32_t const nextTR = 0; // The next frame's presentation time in TR units
799 static MP4Duration const currentPT = 0; // The current frame's presentation time in milli-seconds
800 MP4Duration nextPT; // The next frame's presentation time in milli-seconds
801 MP4Duration duration; // The current frame's duration in milli-seconds
802
803 nextTR += trDiff;
804 // Calculate the next frame's presentation time, in milli-seconds
805 nextPT = (nextTR * 1001) / H263_BASIC_FRAME_RATE;
806 // The frame's duration is the difference between the next presentation
807 // time and the current presentation time.
808 duration = nextPT - currentPT;
809 // "Remember" the next presentation time for the next time this function is
810 // called
811 currentPT = nextPT;
812
813 return duration;
814}
815
816static bool GetWidthAndHeight( u_int8_t fmt,
817 u_int16_t *width,
818 u_int16_t *height)
819{
820 // The 'fmt' corresponds to bits 5-7 of the PTYPE
821 static struct {
822 u_int16_t width;
823 u_int16_t height;
824 } const dimensionsTable[8] = {
825 { 0, 0 }, // 000 - 0 - forbidden, generates an error
826 { 128, 96 }, // 001 - 1 - Sub QCIF
827 { 176, 144 }, // 010 - 2 - QCIF
828 { 352, 288 }, // 011 - 3 - CIF
829 { 704, 576 }, // 100 - 4 - 4CIF
830 { 1409, 1152 }, // 101 - 5 - 16CIF
831 { 0, 0 }, // 110 - 6 - reserved, generates an error
832 { 0, 0 } // 111 - 7 - extended, not supported by profile 0
833 };
834
835 if (fmt > 7)
836 return false;
837
838 *width = dimensionsTable[fmt].width;
839 *height = dimensionsTable[fmt].height;
840
841 if (*width == 0)
842 return false;
843
844 return true;
845}
846
847static u_int8_t GetTRDifference(u_int8_t nextTR,
848 u_int8_t currentTR)
849{
850 if (currentTR > nextTR) {
851 // Wrap around 255...
852 return nextTR + (256 - currentTR);
853 } else {
854 return nextTR - currentTR;
855 }
856}
857
858*/
859
860