⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mp4v.cpp

📁 网络MPEG4IP流媒体开发源代码
💻 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 + -