📄 h263.cpp
字号:
/* * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is MPEG4IP. * * The Initial Developer of the Original Code is Cisco Systems Inc. * Portions created by Cisco Systems Inc. are * Copyright (C) Cisco Systems Inc. 2000, 2001. All Rights Reserved. * * Portions created by Ximpo Group Ltd. are * Copyright (C) Ximpo Group Ltd. 2003, 2004. All Rights Reserved. * * Contributor(s): * Ximpo Group Ltd. mp4v2@ximpo.com * Bill May wmay@cisco.com */#include "mp4creator.h"// Default timescale for H.263 (1000ms)#define H263_TIMESCALE 1000// Default H263 frame rate (30fps)#define H263_BASIC_FRAME_RATE 30// Minimum number of bytes needed to parse an H263 header#define H263_REQUIRE_HEADER_SIZE_BYTES 5// Number of bytes the start code requries#define H263_STARTCODE_SIZE_BYTES 3// This is the input buffer's size. It should contain// 1 frame with the following start code#define H263_BUFFER_SIZE 256 * 1024// The default max different (in %) betwqeen max and average bitrates#define H263_DEFAULT_CBR_TOLERANCE 10// The following structure holds information extracted from each frame's header:typedef struct _H263INFO { u_int8_t tr; // Temporal Reference, used in duration calculation u_int16_t width; // Width of the picture u_int16_t height; // Height of the picture bool isSyncFrame; // Frame type (true = I frame = "sync" frame)} H263INFO;// Context for the GetMaxBitrate functiontypedef struct _MaxBitrate_CTX { u_int32_t bitrateTable[H263_BASIC_FRAME_RATE];// Window of 1 second u_int32_t windowBitrate; // The bitrate of the current window u_int32_t maxBitrate; // The up-to-date maximum bitrate u_int32_t tableIndex; // The next TR unit to update} MaxBitrate_CTX;// Forward declarations:static int LoadNextH263Object( FILE *inputFileHandle, u_int8_t *frameBuffer, u_int32_t *frameBufferSize, u_int32_t additionalBytesNeeded, u_int8_t **ppNextHeader);static bool ParseShortHeader( u_int8_t *headerBuffer, H263INFO *outputInfoStruct);static u_int8_t GetTRDifference(u_int8_t nextTR, u_int8_t currentTR);static void GetMaxBitrate( MaxBitrate_CTX *ctx, u_int32_t frameSize, u_int8_t frameTRDiff);static MP4Duration CalculateDuration(u_int8_t trDiff);static bool GetWidthAndHeight( u_int8_t fmt, u_int16_t *width, u_int16_t *height);/* * H263Creator - Main function * Inputs: * outputFileHandle - The handle of the output file * inputFileHandle - The handle of the input file * Codec-specific parameters: * H263Level - H.263 Level used for this track * H263Profile - H.263 Profile used for this track * H263Bitrates - A Parameter indicating whether the function * should calculate H263 bitrates or not. * cbrTolerance - CBR tolerance indicates when to set the * average bitrate. * Outputs: * This function returns either the track ID of the newly added track upon * success or a predefined value representing an erroneous state. */MP4TrackId H263Creator(MP4FileHandle outputFileHandle, FILE* inputFileHandle, u_int8_t h263Profile, u_int8_t h263Level, bool h263Bitrates, u_int8_t cbrTolerance){ H263INFO nextInfo; // Holds information about the next frame H263INFO currentInfo;// Holds information about the current frame MaxBitrate_CTX maxBitrateCtx;// Context for the GetMaxBitrate function memset(&nextInfo, 0, sizeof(nextInfo)); memset(¤tInfo, 0, sizeof(currentInfo)); memset(&maxBitrateCtx, 0, sizeof(maxBitrateCtx)); u_int8_t frameBuffer[H263_BUFFER_SIZE]; // The input buffer // Pointer which tells LoadNextH263Object where to read data to u_int8_t* pFrameBuffer = frameBuffer + H263_REQUIRE_HEADER_SIZE_BYTES; u_int32_t frameSize; // The current frame size // Pointer to receive address of the header data u_int8_t* pCurrentHeader = pFrameBuffer; MP4Duration currentDuration; // The current frame's duration u_int8_t trDifference; // The current TR difference // The previous TR difference u_int8_t prevTrDifference = H263_BASIC_FRAME_RATE; MP4Duration totalDuration = 0;// Duration accumulator MP4Duration avgBitrate; // Average bitrate u_int64_t totalBytes = 0; // Size accumulator MP4TrackId trackId = MP4_INVALID_TRACK_ID; // Our MP4 track bool stay = true; // loop flag while (stay) { currentInfo = nextInfo; memmove(frameBuffer, pCurrentHeader, H263_REQUIRE_HEADER_SIZE_BYTES); frameSize = H263_BUFFER_SIZE - H263_REQUIRE_HEADER_SIZE_BYTES; // Read 1 frame and the next frame's header from the file. // For the first frame, only the first frame's header is returned. // For the last frame, only the last frame's data is returned. if (! LoadNextH263Object(inputFileHandle, pFrameBuffer, &frameSize, H263_REQUIRE_HEADER_SIZE_BYTES - H263_STARTCODE_SIZE_BYTES, &pCurrentHeader)) break; // Fatal error ... if (pCurrentHeader) { // Parse the returned frame header (if any) if (!ParseShortHeader(pCurrentHeader, &nextInfo)) break; // Fatal error trDifference = GetTRDifference(nextInfo.tr, currentInfo.tr); } else { // This is the last frame ... we have to fake the trDifference ... trDifference = 1; // No header data has been read at this iteration, so we have to manually // add the frame's header we read at the previous iteration. // Note that LoadNextH263Object returns the number of bytes read, which // are the current frame's data and the next frame's header frameSize += H263_REQUIRE_HEADER_SIZE_BYTES; // There is no need for the next iteration ... stay = false; } // If this is the first iteration ... if (currentInfo.width == 0) { // If we have more data than just the header if ((frameSize > H263_REQUIRE_HEADER_SIZE_BYTES) || !pCurrentHeader) // Or no header at all break; // Fatal error else continue; // We have only the first frame's header ... } if (trackId == MP4_INVALID_TRACK_ID) { // If a track has not been added yet, add the track to the file. trackId = MP4AddH263VideoTrack(outputFileHandle, H263_TIMESCALE, 0, currentInfo.width, currentInfo.height, h263Level, h263Profile, 0, 0); if (trackId == MP4_INVALID_TRACK_ID) break; // Fatal error } // calculate the current frame duration currentDuration = CalculateDuration(trDifference); // Write the current frame to the file. if (!MP4WriteSample(outputFileHandle, trackId, frameBuffer, frameSize, currentDuration, 0, currentInfo.isSyncFrame)) break; // Fatal error // Accumulate the frame's size and duration for avgBitrate calculation totalDuration += currentDuration; totalBytes += frameSize; // If needed, recalculate bitrate information if (h263Bitrates) GetMaxBitrate(&maxBitrateCtx, frameSize, prevTrDifference); prevTrDifference = trDifference; } // while (stay) // If this is the last frame, if (!stay) { // If needed and possible, update bitrate information in the file if (h263Bitrates && totalDuration) { avgBitrate = (totalBytes * 8 * H263_TIMESCALE) / totalDuration; if (cbrTolerance == 0) cbrTolerance = H263_DEFAULT_CBR_TOLERANCE; // Same as: if (maxBitrate / avgBitrate > (cbrTolerance + 100) / 100.0) if (maxBitrateCtx.maxBitrate * 100 > (cbrTolerance + 100) * avgBitrate) avgBitrate = 0; MP4SetH263Bitrates(outputFileHandle, trackId, avgBitrate, maxBitrateCtx.maxBitrate); } // Return the newly added track ID return trackId; } // If we got to here... something went wrong ... fprintf(stderr, "%s: Could not parse input file, invalid video stream?\n", ProgName); // Upon failure, delete the newly added track if it has been added if (trackId != MP4_INVALID_TRACK_ID) { MP4DeleteTrack(outputFileHandle, trackId); } return MP4_INVALID_TRACK_ID;}/* * LoadNextH263Object - service routine that reads a single frame from the input * file. It shall fill the input buffer with data up until - and including - the * next start code and shall report back both the number of bytes read and a * pointer to the next start code. The first call to this function shall only * yield a pointer with 0 data bytes and the last call to this function shall * only yield data bytes with a NULL pointer as the next header. * * TODO: This function only supports valid bit streams. Upon error, it fails * without the possibility to recover. A Better idea would be to skip frames * until a parsable frame is read from the file. * * Parameters: * inputFileHandle - The handle of the input file * frameBuffer - buffer where to place read data * frameBufferSize - in/out parameter indicating the size of the buffer on * entry and the number of bytes copied to the buffer upon * return * additionalBytesNeeded - indicates how many additional bytes are to be read * from the next frame's header (over the 3 bytes that * are already read).
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -