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

📄 avi.cpp

📁 MPEG-4编解码的实现(包括MPEG4视音频编解码)
💻 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-2002.  All Rights Reserved.
 * 
 * Contributor(s): 
 *		Dave Mackie		dmackie@cisco.com
 */

/* 
 * Notes:
 *  - file formatted with tabstops == 4 spaces 
 */

#include <mp4creator.h>
#include <avilib.h>

static MP4TrackId VideoCreator(MP4FileHandle mp4File, avi_t* aviFile)
{
	char* videoType = AVI_video_compressor(aviFile);

	if (strcasecmp(videoType, "divx")
	  && strcasecmp(videoType, "dx50")
	  && strcasecmp(videoType, "xvid")) {
		fprintf(stderr,	
			"%s: video compressor %s not recognized\n",
			 ProgName, videoType);
		exit(EXIT_AVI_CREATOR);
	}

	double frameRate = AVI_video_frame_rate(aviFile);

	if (frameRate == 0) {
		fprintf(stderr,	
			"%s: no video frame rate in avi file\n", ProgName);
		exit(EXIT_AVI_CREATOR);
	}

#ifdef _WIN32
	MP4Duration mp4FrameDuration;
	mp4FrameDuration = 
		(MP4Duration)((double)Mp4TimeScale / frameRate);
#else
	MP4Duration mp4FrameDuration = 
		(MP4Duration)(Mp4TimeScale / frameRate);
#endif

	MP4TrackId trackId = MP4AddVideoTrack(mp4File,
		Mp4TimeScale, mp4FrameDuration, 
		AVI_video_width(aviFile), AVI_video_height(aviFile), 
		MP4_MPEG4_VIDEO_TYPE);

	if (trackId == MP4_INVALID_TRACK_ID) {
		fprintf(stderr,	
			"%s: can't create video track\n", ProgName);
		exit(EXIT_AVI_CREATOR);
	}

	int32_t i;
	int32_t numFrames = AVI_video_frames(aviFile);
	int32_t frameSize;
	int32_t maxFrameSize = 0;

	// determine maximum video frame size
	AVI_seek_start(aviFile);

	for (i = 0; i < numFrames; i++) {
		frameSize = AVI_frame_size(aviFile, i);
		if (frameSize > maxFrameSize) {
			maxFrameSize = frameSize;
		}
	}

	// allocate a large enough frame buffer
	u_int8_t* pFrameBuffer = (u_int8_t*)malloc(maxFrameSize);

	if (pFrameBuffer == NULL) {
		fprintf(stderr,	
			"%s: can't allocate memory\n", ProgName);
		exit(EXIT_AVI_CREATOR);
	}

	AVI_seek_start(aviFile);

	// read first frame, should contain VO/VOL and I-VOP
	frameSize = AVI_read_frame(aviFile, (char*)pFrameBuffer);

	if (frameSize < 0) {
		fprintf(stderr,	
			"%s: can't read video frame 1: %s\n",
			ProgName, AVI_strerror());
		exit(EXIT_AVI_CREATOR);
	}

	// find VOP start code in first sample
	static u_int8_t vopStartCode[4] = { 
		0x00, 0x00, 0x01, MP4AV_MPEG4_VOP_START 
	};

	for (i = 0; i < frameSize - 4; i++) {
		if (!memcmp(&pFrameBuffer[i], vopStartCode, 4)) {
			// everything before the VOP
			// should be configuration info
			MP4SetTrackESConfiguration(mp4File, trackId,
				pFrameBuffer, i);
		}
	}

	if (MP4GetNumberOfTracks(mp4File, MP4_VIDEO_TRACK_TYPE) == 1) {
		MP4SetVideoProfileLevel(mp4File, 0x01);
	}

	// write out the first frame, including the initial configuration info
	MP4WriteSample(mp4File, trackId, 
		pFrameBuffer, frameSize, mp4FrameDuration, 0, true);

	// process the rest of the frames
	for (i = 1; i < numFrames; i++) {
		// read the frame from the AVI file
		frameSize = AVI_read_frame(aviFile, (char*)pFrameBuffer);

		if (frameSize < 0) {
			fprintf(stderr,	
				"%s: can't read video frame %i: %s\n",
				ProgName, i + 1, AVI_strerror());
			exit(EXIT_AVI_CREATOR);
		}

		// we mark random access points in MP4 files
		bool isIFrame = 
			(MP4AV_Mpeg4GetVopType(pFrameBuffer, frameSize) == 'I');

		// write the frame to the MP4 file
		MP4WriteSample(mp4File, trackId, 
			pFrameBuffer, frameSize, mp4FrameDuration, 0, isIFrame);
	}

	return trackId;
}

static inline u_int32_t BytesToInt32(u_int8_t* pBytes) 
{
	return (pBytes[0] << 24) | (pBytes[1] << 16) 
		| (pBytes[2] << 8) | pBytes[3];
}

static MP4TrackId AudioCreator(MP4FileHandle mp4File, avi_t* aviFile)
{
	int32_t audioType = AVI_audio_format(aviFile);

	// Check for MP3 audio type
	if (audioType != 0x55) {
		fprintf(stderr,	
			"%s: audio compressor 0x%x not recognized\n",
			 ProgName, audioType);
		exit(EXIT_AVI_CREATOR);
	}

	u_int8_t temp[4];
	u_int32_t mp3header;

	AVI_seek_start(aviFile);

	if (AVI_read_audio(aviFile, (char*)&temp, 4) != 4) {
		fprintf(stderr,	
			"%s: can't read audio frame 0: %s\n",
			ProgName, AVI_strerror());
		exit(EXIT_AVI_CREATOR);
	}
	mp3header = BytesToInt32(temp);

	// check mp3header sanity
	if ((mp3header & 0xFFE00000) != 0xFFE00000) {
		fprintf(stderr,	
			"%s: data in file doesn't appear to be valid mp3 audio\n",
			ProgName);
		exit(EXIT_AVI_CREATOR);
	}

	u_int16_t samplesPerSecond = 
		MP4AV_Mp3GetHdrSamplingRate(mp3header);
	u_int16_t samplesPerFrame = 
		MP4AV_Mp3GetHdrSamplingWindow(mp3header);
	u_int8_t mp4AudioType = 
		MP4AV_Mp3ToMp4AudioType(MP4AV_Mp3GetHdrVersion(mp3header));

	if (audioType == MP4_INVALID_AUDIO_TYPE
	  || samplesPerSecond == 0) {
		fprintf(stderr,	
			"%s: data in file doesn't appear to be valid mp3 audio\n",
			 ProgName);
		exit(EXIT_AVI_CREATOR);
	}

	MP4TrackId trackId = MP4AddAudioTrack(mp4File, 
		samplesPerSecond, samplesPerFrame, mp4AudioType);

	if (trackId == MP4_INVALID_TRACK_ID) {
		fprintf(stderr,	
			"%s: can't create audio track\n", ProgName);
		exit(EXIT_AVI_CREATOR);
	}

	if (MP4GetNumberOfTracks(mp4File, MP4_AUDIO_TRACK_TYPE) == 1) {
		MP4SetAudioProfileLevel(mp4File, 0xFE);
	}

	int32_t i;
	int32_t aviFrameSize;
	int32_t maxAviFrameSize = 0;

	// determine maximum avi audio chunk size
	// should be at least as large as maximum mp3 frame size
	AVI_seek_start(aviFile);

	i = 0;
	while (AVI_set_audio_frame(aviFile, i, (long*)&aviFrameSize) == 0) {
		if (aviFrameSize > maxAviFrameSize) {
			maxAviFrameSize = aviFrameSize;
		}
		i++;
	}

	// allocate a large enough frame buffer
	u_int8_t* pFrameBuffer = (u_int8_t*)malloc(maxAviFrameSize);

	if (pFrameBuffer == NULL) {
		fprintf(stderr,	
			"%s: can't allocate memory\n", ProgName);
		exit(EXIT_AVI_CREATOR);
	}

	AVI_seek_start(aviFile);

	u_int32_t mp3FrameNumber = 1;
	while (true) {
		if (AVI_read_audio(aviFile, (char*)pFrameBuffer, 4) != 4) {
			// EOF presumably
			break;
		}

		mp3header = BytesToInt32(&pFrameBuffer[0]);

		u_int16_t mp3FrameSize = MP4AV_Mp3GetFrameSize(mp3header);

		if (AVI_read_audio(aviFile, (char*)&pFrameBuffer[4], mp3FrameSize - 4)
		  != mp3FrameSize - 4) {
			fprintf(stderr,	
				"%s: can't read audio frame %u: %s\n",
				ProgName, mp3FrameNumber, AVI_strerror());
			exit(EXIT_AVI_CREATOR);
		}

		if (!MP4WriteSample(mp4File, trackId, 
		  &pFrameBuffer[0], mp3FrameSize)) {
			fprintf(stderr,	
				"%s: can't write audio frame %u\n", ProgName, mp3FrameNumber);
			exit(EXIT_AVI_CREATOR);
		}
	
		mp3FrameNumber++;
	}

	return trackId;
}

MP4TrackId* AviCreator(MP4FileHandle mp4File, const char* aviFileName)
{
	static MP4TrackId trackIds[3];
	u_int8_t numTracks = 0;

	avi_t* aviFile = AVI_open_input_file(aviFileName, true);
	if (aviFile == NULL) {
		fprintf(stderr,	
			"%s: can't open %s: %s\n",
			ProgName, aviFileName, AVI_strerror());
		exit(EXIT_AVI_CREATOR);
	}

	if (AVI_video_frames(aviFile) > 0) {
		trackIds[numTracks++] = VideoCreator(mp4File, aviFile);
	}

	if (AVI_audio_bytes(aviFile) > 0) {
		trackIds[numTracks++] = AudioCreator(mp4File, aviFile);
	}

	trackIds[numTracks] = MP4_INVALID_TRACK_ID;

	AVI_close(aviFile);

	return trackIds;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -