📄 mp4v.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. * * Contributor(s): * Dave Mackie dmackie@cisco.com *///#define MP4V_DEBUG 1/* * Notes: * - file formatted with tabstops == 4 spaces */#include <mp4creator.h>/* * Load the next syntatic object from the file * into the supplied buffer, which better be large enough! * * Objects are delineated by 4 byte start codes (0x00 0x00 0x01 0x??) * Objects are padded to byte boundaries, and the encoder assures that * the start code pattern is never generated for encoded data */static int LoadNextObject(FILE* inFile, u_int8_t* pBuf, u_int32_t* pBufSize, u_int8_t* pObjCode){ static u_int8_t state = 0; static u_int8_t nextObjCode = 0; *pBufSize = 0; /* initial state, never read from file before */ if (state == 0) { /* * go looking for first sync word * we discard anything before this */ state = 1; while (state < 5) { /* read a byte */ u_char b; if (fread(&b, 1, 1, inFile) == 0) { // EOF or IO error return 0; } switch (state) { case 1: if (b == 0) { state = 2; } break; case 2: if (b == 0) { state = 3; } break; case 3: if (b == 1) { state = 4; } break; case 4: pBuf[0] = 0; pBuf[1] = 0; pBuf[2] = 1; pBuf[3] = b; (*pObjCode) = (u_int)b; *pBufSize = 4; state = 5; break; } } /* we're primed now */ state = 1; } else if (state == 5) { state = 0; return 0; } else { /* * We have next object code from prevous call * insert start code into buffer */ (*pObjCode) = nextObjCode; pBuf[(*pBufSize)++] = 0; pBuf[(*pBufSize)++] = 0; pBuf[(*pBufSize)++] = 1; pBuf[(*pBufSize)++] = (u_char)(*pObjCode); } /* read bytes, execute state machine */ while (1) { /* read a byte */ u_char b; if (fread(&b, 1, 1, inFile) == 0) { /* handle EOF */ if (feof(inFile)) { switch (state) { case 3: pBuf[(*pBufSize)++] = 0; /* fall thru */ case 2: pBuf[(*pBufSize)++] = 0; break; } state = 5; return 1; } /* else error */ *pBufSize = 0; return 0; } switch (state) { case 1: if (b == 0) { state = 2; } else { pBuf[(*pBufSize)++] = b; } break; case 2: if (b == 0) { state = 3; } else { pBuf[(*pBufSize)++] = 0; pBuf[(*pBufSize)++] = b; state = 1; } break; case 3: if (b == 1) { state = 4; } else if (b == 0) { pBuf[(*pBufSize)++] = 0; // state remains 3 } else { pBuf[(*pBufSize)++] = 0; pBuf[(*pBufSize)++] = 0; pBuf[(*pBufSize)++] = b; state = 1; } break; case 4: nextObjCode = b; state = 1; return 1; default: ASSERT(false); } }}MP4TrackId Mp4vCreator(MP4FileHandle mp4File, FILE* inFile){ bool rc; u_int8_t sampleBuffer[256 * 1024]; u_int8_t* pCurrentSample = sampleBuffer; u_int32_t maxSampleSize = sizeof(sampleBuffer); // the current syntactical object // typically 1:1 with a sample // but not always, i.e. non-VOP's u_int8_t* pObj = pCurrentSample; u_int32_t objSize; u_int8_t objType; // the current sample MP4SampleId sampleId = 1; MP4Timestamp currentSampleTime = 0; // the last reference VOP MP4SampleId refVopId = 1; MP4Timestamp refVopTime = 0; // track configuration info u_int8_t videoProfileLevel = 0x03; u_int8_t timeBits = 15; u_int16_t timeTicks = 30000; u_int16_t frameDuration = 3000; u_int16_t frameWidth = 320; u_int16_t frameHeight = 240; u_int32_t esConfigSize = 0; u_char vopType = 0; bool foundVOSH = false, foundVO = false, foundVOL = false; // start reading objects until we get the first VOP while (LoadNextObject(inFile, pObj, &objSize, &objType)) { // guard against buffer overflow if (pObj + objSize >= pCurrentSample + maxSampleSize) { fprintf(stderr, "%s: buffer overflow, invalid video stream?\n", ProgName); return MP4_INVALID_TRACK_ID; } if (Verbosity & MP4_DETAILS_SAMPLE) { printf("MP4V type %x size %u\n", objType, objSize); } if (objType == MP4AV_MPEG4_VOSH_START) { MP4AV_Mpeg4ParseVosh(pObj, objSize, &videoProfileLevel); foundVOSH = true; } else if (objType == MP4AV_MPEG4_VO_START) { foundVO = true; } else if (objType == MP4AV_MPEG4_VOL_START) { MP4AV_Mpeg4ParseVol(pObj, objSize, &timeBits, &timeTicks, &frameDuration, &frameWidth, &frameHeight); foundVOL = true;#ifdef MP4V_DEBUG printf("ParseVol: timeBits %u timeTicks %u frameDuration %u\n", timeBits, timeTicks, frameDuration);#endif } else if (objType == MP4AV_MPEG4_VOP_START) { esConfigSize = pObj - pCurrentSample; // ready to set up mp4 track break; } pObj += objSize; } if (foundVOSH == false) { fprintf(stderr, "%s: no VOSH header found in MPEG-4 video.\n" "This can cause problems with players other than mp4player included\n" "with this package.\n", ProgName); } else { if (VideoProfileLevelSpecified && videoProfileLevel != VideoProfileLevel) { fprintf(stderr, "%s: You have specified a different video profile level than was detected in the VOSH header\n" "The level you specified was %d and %d was read from the VOSH\n", ProgName, VideoProfileLevel, videoProfileLevel); } } if (foundVO == false) { fprintf(stderr, "%s: No VO header found in mpeg-4 video.\n" "This can cause problems with players other than mp4player\n", ProgName); } if (foundVOL == false) { fprintf(stderr, "%s: fatal: No VOL header found in mpeg-4 video stream\n", ProgName); return MP4_INVALID_TRACK_ID; } // convert frame duration to canonical time scale // note zero value for frame duration signals variable rate video if (timeTicks == 0) { timeTicks = 1; } u_int32_t mp4FrameDuration; if (VideoFrameRate) { mp4FrameDuration = (u_int32_t)(((float)Mp4TimeScale) / VideoFrameRate); } else if (frameDuration) { mp4FrameDuration = (Mp4TimeScale * frameDuration) / timeTicks; } else { // the spec for embedded timing and the implementations that I've // seen all vary dramatically, so until things become clearer // we don't support these types of encoders fprintf(stderr, "%s: variable rate video stream signalled," " please specify average frame rate with -r option\n", ProgName); return MP4_INVALID_TRACK_ID; } // create the new video track MP4TrackId trackId = MP4AddVideoTrack( mp4File, Mp4TimeScale, mp4FrameDuration, frameWidth, frameHeight, MP4_MPEG4_VIDEO_TYPE); if (trackId == MP4_INVALID_TRACK_ID) { fprintf(stderr, "%s: can't create video track\n", ProgName); return MP4_INVALID_TRACK_ID; } if (VideoProfileLevelSpecified) { videoProfileLevel = VideoProfileLevel; } if (MP4GetNumberOfTracks(mp4File, MP4_VIDEO_TRACK_TYPE) == 1) { MP4SetVideoProfileLevel(mp4File, MP4AV_Mpeg4VideoToSystemsProfileLevel(videoProfileLevel)); } if (esConfigSize) { MP4SetTrackESConfiguration(mp4File, trackId, pCurrentSample, esConfigSize); // move past ES config, so it doesn't go into first sample pCurrentSample += esConfigSize; } // now process the rest of the video stream while (true) { if (objType != MP4AV_MPEG4_VOP_START) { // keep it in the buffer until a VOP comes along pObj += objSize; } else { // we have a VOP u_int32_t sampleSize = (pObj + objSize) - pCurrentSample; vopType = MP4AV_Mpeg4GetVopType(pObj, objSize); rc = MP4WriteSample(mp4File, trackId, pCurrentSample, sampleSize, mp4FrameDuration, 0, vopType == 'I'); if (!rc) { fprintf(stderr, "%s: can't write video frame %u\n", ProgName, sampleId); MP4DeleteTrack(mp4File, trackId); return MP4_INVALID_TRACK_ID; } // deal with rendering time offsets // that can occur when B frames are being used // which is the case for all profiles except Simple Profile if (vopType != 'B') { if (videoProfileLevel > 3) {#ifdef MP4V_DEBUG printf("sample %u %c renderingOffset %llu\n", refVopId, vopType, currentSampleTime - refVopTime);#endif // Note - this writes to the previous // I or P frame MP4SetSampleRenderingOffset( mp4File, trackId, refVopId, currentSampleTime - refVopTime); } refVopId = sampleId; refVopTime = currentSampleTime; } sampleId++; currentSampleTime += mp4FrameDuration; // reset pointers pObj = pCurrentSample = sampleBuffer; } // load next object from bitstream if (!LoadNextObject(inFile, pObj, &objSize, &objType)) { break; } // guard against buffer overflow if (pObj + objSize >= pCurrentSample + maxSampleSize) { fprintf(stderr, "%s: buffer overflow, invalid video stream?\n", ProgName); MP4DeleteTrack(mp4File, trackId); return MP4_INVALID_TRACK_ID; } if (Verbosity & MP4_DETAILS_SAMPLE) { printf("MP4V type %x size %u\n", objType, objSize); } } // Left over at end - make sure we set the last P or I frame // with the last time if (videoProfileLevel > 3) {#ifdef MP4V_DEBUG printf("sample %u %c renderingOffset %llu\n", refVopId, vopType, currentSampleTime - refVopTime);#endif MP4SetSampleRenderingOffset(mp4File, trackId, refVopId, currentSampleTime - refVopTime); } return trackId;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -