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

📄 mp4file.cpp

📁 网络MPEG4IP流媒体开发源代码
💻 CPP
📖 第 1 页 / 共 4 页
字号:
/* * 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. 2001.  All Rights Reserved. *  * Contributor(s):  *		Dave Mackie		dmackie@cisco.com */#include "mp4common.h"MP4File::MP4File(u_int32_t verbosity){	m_fileName = NULL;	m_pFile = NULL;	m_orgFileSize = 0;	m_fileSize = 0;	m_pRootAtom = NULL;	m_odTrackId = MP4_INVALID_TRACK_ID;	m_verbosity = verbosity;	m_mode = 0;	m_use64bits = false;	m_useIsma = false;	m_pModificationProperty = NULL;	m_pTimeScaleProperty = NULL;	m_pDurationProperty = NULL;	m_memoryBuffer = NULL;	m_memoryBufferSize = 0;	m_memoryBufferPosition = 0;	m_numReadBits = 0;	m_bufReadBits = 0;	m_numWriteBits = 0;	m_bufWriteBits = 0;}MP4File::~MP4File(){	MP4Free(m_fileName);	delete m_pRootAtom;	for (u_int32_t i = 0; i < m_pTracks.Size(); i++) {		delete m_pTracks[i];	}	MP4Free(m_memoryBuffer);	// just in case}void MP4File::Read(const char* fileName){	m_fileName = MP4Stralloc(fileName);	m_mode = 'r';	Open("rb");	ReadFromFile();	CacheProperties();}void MP4File::Create(const char* fileName, bool use64bits){	m_fileName = MP4Stralloc(fileName);	m_mode = 'w';	m_use64bits = use64bits;	Open("wb+");	// generate a skeletal atom tree	m_pRootAtom = MP4Atom::CreateAtom(NULL);	m_pRootAtom->SetFile(this);	m_pRootAtom->Generate();	CacheProperties();	// create mdat, and insert it after ftyp, and before moov	InsertChildAtom(m_pRootAtom, "mdat", 1);	// start writing	m_pRootAtom->BeginWrite();}void MP4File::Modify(const char* fileName){	m_fileName = MP4Stralloc(fileName);	m_mode = 'r';	Open("rb+");	ReadFromFile();	m_mode = 'w';	// find the moov atom	MP4Atom* pMoovAtom = m_pRootAtom->FindAtom("moov");	u_int32_t numAtoms;	if (pMoovAtom == NULL) {		// there isn't one, odd but we can still proceed		pMoovAtom = AddChildAtom(m_pRootAtom, "moov");	} else {		numAtoms = m_pRootAtom->GetNumberOfChildAtoms();		// work backwards thru the top level atoms		int32_t i;		bool lastAtomIsMoov = true;		MP4Atom* pLastAtom = NULL;		for (i = numAtoms - 1; i >= 0; i--) {			MP4Atom* pAtom = m_pRootAtom->GetChildAtom(i);			const char* type = pAtom->GetType();						// get rid of any trailing free or skips			if (!strcmp(type, "free") || !strcmp(type, "skip")) {				m_pRootAtom->DeleteChildAtom(pAtom);				continue;			}			if (strcmp(type, "moov")) {				if (pLastAtom == NULL) {					pLastAtom = pAtom;					lastAtomIsMoov = false;				}				continue;			}			// now at moov atom			// multiple moov atoms?!?			if (pAtom != pMoovAtom) {				throw new MP4Error(					"Badly formed mp4 file, multiple moov atoms", 					"MP4Modify");			}			if (lastAtomIsMoov) {				// position to start of moov atom,				// effectively truncating file 				// prior to adding new mdat				SetPosition(pMoovAtom->GetStart());			} else { // last atom isn't moov				// need to place a free atom 				MP4Atom* pFreeAtom = MP4Atom::CreateAtom("free");				// in existing position of the moov atom				m_pRootAtom->InsertChildAtom(pFreeAtom, i);				m_pRootAtom->DeleteChildAtom(pMoovAtom);				m_pRootAtom->AddChildAtom(pMoovAtom);				// write free atom to disk				SetPosition(pMoovAtom->GetStart());				pFreeAtom->SetSize(pMoovAtom->GetSize());				pFreeAtom->Write();				// finally set our file position to the end of the last atom				SetPosition(pLastAtom->GetEnd());			}			break;		}		ASSERT(i != -1);	}	CacheProperties();	// of moov atom	numAtoms = m_pRootAtom->GetNumberOfChildAtoms();	// insert another mdat prior to moov atom (the last atom)	MP4Atom* pMdatAtom = InsertChildAtom(m_pRootAtom, "mdat", numAtoms - 1);	// start writing new mdat	pMdatAtom->BeginWrite();}void MP4File::Optimize(const char* orgFileName, const char* newFileName){	m_fileName = MP4Stralloc(orgFileName);	m_mode = 'r';	// first load meta-info into memory	Open("rb");	ReadFromFile();	CacheProperties();	// of moov atom	// now switch over to writing the new file	MP4Free(m_fileName);	// create a temporary file if necessary	if (newFileName == NULL) {		m_fileName = MP4Stralloc(TempFileName());	} else {		m_fileName = MP4Stralloc(newFileName);	}	FILE* pReadFile = m_pFile;	m_pFile = NULL;	m_mode = 'w';	Open("wb");	SetIntegerProperty("moov.mvhd.modificationTime", 		MP4GetAbsTimestamp());	// writing meta info in the optimal order	((MP4RootAtom*)m_pRootAtom)->BeginOptimalWrite();	// write data in optimal order	RewriteMdat(pReadFile, m_pFile);	// finish writing	((MP4RootAtom*)m_pRootAtom)->FinishOptimalWrite();	// cleanup	fclose(m_pFile);	m_pFile = NULL;	fclose(pReadFile);	// move temporary file into place	if (newFileName == NULL) {		Rename(m_fileName, orgFileName);	}}void MP4File::RewriteMdat(FILE* pReadFile, FILE* pWriteFile){	u_int32_t numTracks = m_pTracks.Size();	MP4ChunkId* chunkIds = new MP4ChunkId[numTracks];	MP4ChunkId* maxChunkIds = new MP4ChunkId[numTracks];	MP4Timestamp* nextChunkTimes = new MP4Timestamp[numTracks];	for (u_int32_t i = 0; i < numTracks; i++) {		chunkIds[i] = 1;		maxChunkIds[i] = m_pTracks[i]->GetNumberOfChunks();		nextChunkTimes[i] = MP4_INVALID_TIMESTAMP;	}	while (true) {		u_int32_t nextTrackIndex = (u_int32_t)-1;		MP4Timestamp nextTime = MP4_INVALID_TIMESTAMP;		for (u_int32_t i = 0; i < numTracks; i++) {			if (chunkIds[i] > maxChunkIds[i]) {				continue;			}			if (nextChunkTimes[i] == MP4_INVALID_TIMESTAMP) {				MP4Timestamp chunkTime =					m_pTracks[i]->GetChunkTime(chunkIds[i]);				nextChunkTimes[i] = MP4ConvertTime(chunkTime,					m_pTracks[i]->GetTimeScale(), GetTimeScale());			}			// time is not earliest so far			if (nextChunkTimes[i] > nextTime) {				continue;			}			// prefer hint tracks to media tracks if times are equal			if (nextChunkTimes[i] == nextTime 			  && strcmp(m_pTracks[i]->GetType(), MP4_HINT_TRACK_TYPE)) {				continue;			}			// this is our current choice of tracks			nextTime = nextChunkTimes[i];			nextTrackIndex = i;		}		if (nextTrackIndex == (u_int32_t)-1) {			break;		}		// point into original mp4 file for read chunk call		m_pFile = pReadFile;		m_mode = 'r';		u_int8_t* pChunk;		u_int32_t chunkSize;		m_pTracks[nextTrackIndex]->			ReadChunk(chunkIds[nextTrackIndex], &pChunk, &chunkSize);		// point back at the new mp4 file for write chunk		m_pFile = pWriteFile;		m_mode = 'w';		m_pTracks[nextTrackIndex]->			RewriteChunk(chunkIds[nextTrackIndex], pChunk, chunkSize);		MP4Free(pChunk);		chunkIds[nextTrackIndex]++;		nextChunkTimes[nextTrackIndex] = MP4_INVALID_TIMESTAMP;	}	delete [] chunkIds;	delete [] maxChunkIds;	delete [] nextChunkTimes;}void MP4File::Open(const char* fmode){	ASSERT(m_pFile == NULL);#ifdef O_LARGEFILE	// UGH! fopen doesn't open a file in 64-bit mode, period.	// So we need to use open() and then fdopen()	int fd;	int flags = O_LARGEFILE;	if (strchr(fmode, '+')) {		flags |= O_CREAT | O_RDWR;		if (fmode[0] == 'w') {			flags |= O_TRUNC;		}	} else {		if (fmode[0] == 'w') {			flags |= O_CREAT | O_TRUNC | O_WRONLY;		} else {			flags |= O_RDONLY;		}	}	fd = open(m_fileName, flags, 0666); 	if (fd >= 0) {		m_pFile = fdopen(fd, fmode);	}#else	m_pFile = fopen(m_fileName, fmode);#endif	if (m_pFile == NULL) {		throw new MP4Error(errno, "failed", "MP4Open");	}	if (m_mode == 'r') {		struct stat s;		if (fstat(fileno(m_pFile), &s) < 0) {			throw new MP4Error(errno, "stat failed", "MP4Open");		}		m_orgFileSize = m_fileSize = s.st_size;	} else {		m_orgFileSize = m_fileSize = 0;	}}void MP4File::ReadFromFile(){	// ensure we start at beginning of file	SetPosition(0);	// create a new root atom	ASSERT(m_pRootAtom == NULL);	m_pRootAtom = MP4Atom::CreateAtom(NULL);	u_int64_t fileSize = GetSize();	m_pRootAtom->SetFile(this);	m_pRootAtom->SetStart(0);	m_pRootAtom->SetSize(fileSize);	m_pRootAtom->SetEnd(fileSize);	m_pRootAtom->Read();	// create MP4Track's for any tracks in the file	GenerateTracks();}void MP4File::GenerateTracks(){	u_int32_t trackIndex = 0;	while (true) {		char trackName[32];		snprintf(trackName, sizeof(trackName), "moov.trak[%u]", trackIndex);		// find next trak atom		MP4Atom* pTrakAtom = m_pRootAtom->FindAtom(trackName);		// done, no more trak atoms		if (pTrakAtom == NULL) {			break;		}		// find track id property		MP4Integer32Property* pTrackIdProperty = NULL;		pTrakAtom->FindProperty(			"trak.tkhd.trackId",			(MP4Property**)&pTrackIdProperty);		// find track type property		MP4StringProperty* pTypeProperty = NULL;		pTrakAtom->FindProperty(			"trak.mdia.hdlr.handlerType",			(MP4Property**)&pTypeProperty);		// ensure we have the basics properties		if (pTrackIdProperty && pTypeProperty) {			m_trakIds.Add(pTrackIdProperty->GetValue());			MP4Track* pTrack = NULL;			try {				if (!strcmp(pTypeProperty->GetValue(), MP4_HINT_TRACK_TYPE)) {					pTrack = new MP4RtpHintTrack(this, pTrakAtom);				} else {					pTrack = new MP4Track(this, pTrakAtom);				}				m_pTracks.Add(pTrack);			}			catch (MP4Error* e) {				VERBOSE_ERROR(m_verbosity, e->Print());				delete e;			}			// remember when we encounter the OD track			if (pTrack && !strcmp(pTrack->GetType(), MP4_OD_TRACK_TYPE)) {				if (m_odTrackId == MP4_INVALID_TRACK_ID) {					m_odTrackId = pTrackIdProperty->GetValue();				} else {					VERBOSE_READ(GetVerbosity(),						printf("Warning: multiple OD tracks present\n"));				}			}		} else {			m_trakIds.Add(0);		}		trackIndex++;	}}void MP4File::CacheProperties(){	FindIntegerProperty("moov.mvhd.modificationTime", 		(MP4Property**)&m_pModificationProperty);	FindIntegerProperty("moov.mvhd.timeScale", 		(MP4Property**)&m_pTimeScaleProperty);	FindIntegerProperty("moov.mvhd.duration", 		(MP4Property**)&m_pDurationProperty);}void MP4File::BeginWrite(){	m_pRootAtom->BeginWrite();}void MP4File::FinishWrite(){	// for all tracks, flush chunking buffers	for (u_int32_t i = 0; i < m_pTracks.Size(); i++) {		ASSERT(m_pTracks[i]);		m_pTracks[i]->FinishWrite();	}	// ask root atom to write	m_pRootAtom->FinishWrite();	// check if file shrunk, e.g. we deleted a track	if (GetSize() < m_orgFileSize) {		// just use a free atom to mark unused space		// MP4Optimize() should be used to clean up this space		MP4Atom* pFreeAtom = MP4Atom::CreateAtom("free");		ASSERT(pFreeAtom);		pFreeAtom->SetFile(this);		pFreeAtom->SetSize(MAX(m_orgFileSize - (m_fileSize + 8), 0));		pFreeAtom->Write();		delete pFreeAtom;	}}MP4Duration MP4File::UpdateDuration(MP4Duration duration){	MP4Duration currentDuration = GetDuration();	if (duration > currentDuration) {		SetDuration(duration);		return duration;	}	return currentDuration;}void MP4File::Dump(FILE* pDumpFile, bool dumpImplicits){	if (pDumpFile == NULL) {		pDumpFile = stdout;	}	fprintf(pDumpFile, "Dumping %s meta-information...\n", m_fileName);	m_pRootAtom->Dump(pDumpFile, 0, dumpImplicits);}void MP4File::Close(){	if (m_mode == 'w') {		SetIntegerProperty("moov.mvhd.modificationTime", 			MP4GetAbsTimestamp());		FinishWrite();	}	fclose(m_pFile);	m_pFile = NULL;}const char* MP4File::TempFileName(){	// there are so many attempts in libc to get this right	// that for portablity reasons, it's best just to roll our own#ifndef _WIN32	static char tempFileName[64];	u_int32_t i;	for (i = getpid(); i < 0xFFFFFFFF; i++) {		sprintf(tempFileName, "./tmp%u.mp4", i);		if (access(tempFileName, F_OK) != 0) {			break;		}	}	if (i == 0xFFFFFFFF) {		throw new MP4Error("can't create temporary file", "TempFileName");	}#else	static char tempFileName[MAX_PATH + 3];	GetTempFileName(".", // dir. for temp. files 					"mp4",                // temp. filename prefix 					0,                    // create unique name 					tempFileName);        // buffer for name #endif	return tempFileName;}void MP4File::Rename(const char* oldFileName, const char* newFileName){	int rc;#ifdef _WIN32	rc = remove(newFileName);	if (rc == 0) {		rc = rename(oldFileName, newFileName);	}#else	rc = rename(oldFileName, newFileName);#endif	if (rc != 0) {		throw new MP4Error(errno, "can't overwrite existing file", "Rename");	}}void MP4File::ProtectWriteOperation(char* where){	if (m_mode == 'r') {		throw new MP4Error("operation not permitted in read mode", where);	}

⌨️ 快捷键说明

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