📄 mp4file.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. 2001 - 2005. All Rights Reserved. * * 3GPP features implementation is based on 3GPP's TS26.234-v5.60, * and was contributed by Ximpo Group Ltd. * * Portions created by Ximpo Group Ltd. are * Copyright (C) Ximpo Group Ltd. 2003, 2004. All Rights Reserved. * * Contributor(s): * Dave Mackie dmackie@cisco.com * Alix Marchandise-Franquet alix@cisco.com * Ximpo Group Ltd. mp4v2@ximpo.com * Bill May wmay@cisco.com */#include "mp4common.h"#ifdef SIMON_CHANGEDstatic void char2wchar_t(const char *str_char, wchar_t *str_wchar){ int i, j; int leng; char c; leng = strlen(str_char); for (i=j=0; i<leng; i++, j++) { c = str_char[i]; if (c == 0) { str_wchar[j] = '\0'; break; } else if (c > 0) { str_wchar[j] = (wchar_t)str_char[i]; } else { // Currently the non-alphanumeric characters are not supported. i++; } } str_wchar[j] = 0;}static void wchar_t2char(const wchar_t *str_wchar, char *str_char){ int i, j; int leng; wchar_t c; leng = wcslen(str_wchar); for (i=j=0; i<leng; i++, j++) { c = str_wchar[i]; if (c == 0) { str_char[j] = '\0'; break; } else if (c < 0x80) { str_char[j] = (char)str_wchar[i]; } else { // Currently the non-alphanumeric characters are not supported. i++; } } str_char[j] = '\0';}#endifMP4File::MP4File(u_int32_t verbosity){ m_fileName = NULL; #ifdef _WIN32 m_fileName_w = NULL; #endif m_pFile = NULL; m_orgFileSize = 0; m_fileSize = 0; m_pRootAtom = NULL; m_odTrackId = MP4_INVALID_TRACK_ID; m_verbosity = verbosity;// = MP4_DETAILS_READ; m_mode = 0; m_createFlags = 0; 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; m_editName = NULL;}MP4File::~MP4File(){ MP4Free(m_fileName); #ifdef _WIN32 MP4Free(m_fileName_w); #endif if (m_pFile != NULL) { // not closed ? fclose(m_pFile); m_pFile = NULL; } delete m_pRootAtom; for (u_int32_t i = 0; i < m_pTracks.Size(); i++) { delete m_pTracks[i]; } MP4Free(m_memoryBuffer); // just in case CHECK_AND_FREE(m_editName); }void MP4File::Read(const char* fileName){ m_fileName = MP4Stralloc(fileName); m_mode = 'r'; Open("rb"); ReadFromFile(); CacheProperties();}#ifdef _WIN32void MP4File::Read(const wchar_t* fileName){ m_fileName_w = MP4Stralloc(fileName); m_mode = 'r'; Open(L"rb"); ReadFromFile(); CacheProperties();}#endifvoid MP4File::Create(const char* fileName, u_int32_t flags, int add_ftyp, int add_iods, char* majorBrand, u_int32_t minorVersion, char** supportedBrands, u_int32_t supportedBrandsCount){ m_fileName = MP4Stralloc(fileName); m_mode = 'w'; m_createFlags = flags; Open("wb+"); // generate a skeletal atom tree m_pRootAtom = MP4Atom::CreateAtom(NULL); m_pRootAtom->SetFile(this); m_pRootAtom->Generate(); if (add_ftyp != 0) { MakeFtypAtom(majorBrand, minorVersion, supportedBrands, supportedBrandsCount); } CacheProperties(); // create mdat, and insert it after ftyp, and before moov InsertChildAtom(m_pRootAtom, "mdat", add_ftyp != 0 ? 1 : 0); // start writing m_pRootAtom->BeginWrite(); if (add_iods != 0) { AddChildAtom("moov", "iods"); }}bool MP4File::Use64Bits (const char *atomName){ uint32_t atomid = ATOMID(atomName); if (atomid == ATOMID("mdat") || atomid == ATOMID("stbl")) { return (m_createFlags & MP4_CREATE_64BIT_DATA) == MP4_CREATE_64BIT_DATA; } if (atomid == ATOMID("mvhd") || atomid == ATOMID("tkhd") || atomid == ATOMID("mdhd")) { return (m_createFlags & MP4_CREATE_64BIT_TIME) == MP4_CREATE_64BIT_TIME; } return false;}void MP4File::Check64BitStatus (const char *atomName){ uint32_t atomid = ATOMID(atomName); if (atomid == ATOMID("mdat") || atomid == ATOMID("stbl")) { m_createFlags |= MP4_CREATE_64BIT_DATA; } else if (atomid == ATOMID("mvhd") || atomid == ATOMID("tkhd") || atomid == ATOMID("mdhd")) { m_createFlags |= MP4_CREATE_64BIT_TIME; }} 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) {#ifdef SIMON_CHANGED printf("\n[%s] %s", "MP4Modify", "Badly formed mp4 file, multiple moov atoms"); RaiseException(1, 0, 0, NULL);#else// throw new MP4Error(// "Badly formed mp4 file, multiple moov atoms", // "MP4Modify");#endif } 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); #ifdef _WIN32 MP4Free(m_fileName_w); #endif // 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -