mp4file.cpp
资源名称:NETVIDEO.rar [点击查看]
上传用户:sun1608
上传日期:2007-02-02
资源大小:6116k
文件大小:58k
源码类别:
流媒体/Mpeg4/MP4
开发平台:
Visual C++
- /*
- * 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 presentn"));
- }
- }
- } 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);
- }
- }
- MP4Track* MP4File::GetTrack(MP4TrackId trackId)
- {
- return m_pTracks[FindTrackIndex(trackId)];
- }
- MP4Atom* MP4File::FindAtom(const char* name)
- {
- MP4Atom* pAtom = NULL;
- if (!name || !strcmp(name, "")) {
- pAtom = m_pRootAtom;
- } else {
- pAtom = m_pRootAtom->FindAtom(name);
- }
- return pAtom;
- }
- MP4Atom* MP4File::AddChildAtom(
- const char* parentName,
- const char* childName)
- {
- return AddChildAtom(FindAtom(parentName), childName);
- }
- MP4Atom* MP4File::AddChildAtom(
- MP4Atom* pParentAtom,
- const char* childName)
- {
- return InsertChildAtom(pParentAtom, childName,
- pParentAtom->GetNumberOfChildAtoms());
- }
- MP4Atom* MP4File::InsertChildAtom(
- const char* parentName,
- const char* childName,
- u_int32_t index)
- {
- return InsertChildAtom(FindAtom(parentName), childName, index);
- }
- MP4Atom* MP4File::InsertChildAtom(
- MP4Atom* pParentAtom,
- const char* childName,
- u_int32_t index)
- {
- MP4Atom* pChildAtom = MP4Atom::CreateAtom(childName);
- ASSERT(pParentAtom);
- pParentAtom->InsertChildAtom(pChildAtom, index);
- pChildAtom->Generate();
- return pChildAtom;
- }
- MP4Atom* MP4File::AddDescendantAtoms(
- const char* ancestorName,
- const char* descendantNames)
- {
- return AddDescendantAtoms(FindAtom(ancestorName), descendantNames);
- }
- MP4Atom* MP4File::AddDescendantAtoms(
- MP4Atom* pAncestorAtom, const char* descendantNames)
- {
- ASSERT(pAncestorAtom);
- MP4Atom* pParentAtom = pAncestorAtom;
- MP4Atom* pChildAtom = NULL;
- while (true) {
- char* childName = MP4NameFirst(descendantNames);
- if (childName == NULL) {
- break;
- }
- descendantNames = MP4NameAfterFirst(descendantNames);
- pChildAtom = pParentAtom->FindChildAtom(childName);
- if (pChildAtom == NULL) {
- pChildAtom = AddChildAtom(pParentAtom, childName);
- }
- pParentAtom = pChildAtom;
- MP4Free(childName);
- }
- return pChildAtom;
- }
- bool MP4File::FindProperty(const char* name,
- MP4Property** ppProperty, u_int32_t* pIndex)
- {
- if (pIndex) {
- *pIndex = 0; // set the default answer for index
- }
- return m_pRootAtom->FindProperty(name, ppProperty, pIndex);
- }
- void MP4File::FindIntegerProperty(const char* name,
- MP4Property** ppProperty, u_int32_t* pIndex)
- {
- if (!FindProperty(name, ppProperty, pIndex)) {
- throw new MP4Error("no such property - %s", "MP4File::FindIntegerProperty", name);
- }
- switch ((*ppProperty)->GetType()) {
- case Integer8Property:
- case Integer16Property:
- case Integer24Property:
- case Integer32Property:
- case Integer64Property:
- break;
- default:
- throw new MP4Error("type mismatch - property %s type %d", "MP4File::FindIntegerProperty", name, (*ppProperty)->GetType());
- }
- }
- u_int64_t MP4File::GetIntegerProperty(const char* name)
- {
- MP4Property* pProperty;
- u_int32_t index;
- FindIntegerProperty(name, &pProperty, &index);
- return ((MP4IntegerProperty*)pProperty)->GetValue(index);
- }
- void MP4File::SetIntegerProperty(const char* name, u_int64_t value)
- {
- ProtectWriteOperation("SetIntegerProperty");
- MP4Property* pProperty = NULL;
- u_int32_t index = 0;
- FindIntegerProperty(name, &pProperty, &index);
- ((MP4IntegerProperty*)pProperty)->SetValue(value, index);
- }
- void MP4File::FindFloatProperty(const char* name,
- MP4Property** ppProperty, u_int32_t* pIndex)
- {
- if (!FindProperty(name, ppProperty, pIndex)) {
- throw new MP4Error("no such property - %s", "MP4File::FindFloatProperty", name);
- }
- if ((*ppProperty)->GetType() != Float32Property) {
- throw new MP4Error("type mismatch - property %s type %d",
- "MP4File::FindFloatProperty",
- name,
- (*ppProperty)->GetType());
- }
- }
- float MP4File::GetFloatProperty(const char* name)
- {
- MP4Property* pProperty;
- u_int32_t index;
- FindFloatProperty(name, &pProperty, &index);
- return ((MP4Float32Property*)pProperty)->GetValue(index);
- }
- void MP4File::SetFloatProperty(const char* name, float value)
- {
- ProtectWriteOperation("SetFloatProperty");
- MP4Property* pProperty;
- u_int32_t index;
- FindFloatProperty(name, &pProperty, &index);
- ((MP4Float32Property*)pProperty)->SetValue(value, index);
- }
- void MP4File::FindStringProperty(const char* name,
- MP4Property** ppProperty, u_int32_t* pIndex)
- {
- if (!FindProperty(name, ppProperty, pIndex)) {
- throw new MP4Error("no such property - %s", "MP4File::FindStringProperty", name);
- }
- if ((*ppProperty)->GetType() != StringProperty) {
- throw new MP4Error("type mismatch - property %s type %d", "MP4File::FindStringProperty",
- name, (*ppProperty)->GetType());
- }
- }
- const char* MP4File::GetStringProperty(const char* name)
- {
- MP4Property* pProperty;
- u_int32_t index;
- FindStringProperty(name, &pProperty, &index);
- return ((MP4StringProperty*)pProperty)->GetValue(index);
- }
- void MP4File::SetStringProperty(const char* name, const char* value)
- {
- ProtectWriteOperation("SetStringProperty");
- MP4Property* pProperty;
- u_int32_t index;
- FindStringProperty(name, &pProperty, &index);
- ((MP4StringProperty*)pProperty)->SetValue(value, index);
- }
- void MP4File::FindBytesProperty(const char* name,
- MP4Property** ppProperty, u_int32_t* pIndex)
- {
- if (!FindProperty(name, ppProperty, pIndex)) {
- throw new MP4Error("no such property %s", "MP4File::FindBytesProperty", name);
- }
- if ((*ppProperty)->GetType() != BytesProperty) {
- throw new MP4Error("type mismatch - property %s - type %d", "MP4File::FindBytesProperty", name, (*ppProperty)->GetType());
- }
- }
- void MP4File::GetBytesProperty(const char* name,
- u_int8_t** ppValue, u_int32_t* pValueSize)
- {
- MP4Property* pProperty;
- u_int32_t index;
- FindBytesProperty(name, &pProperty, &index);
- ((MP4BytesProperty*)pProperty)->GetValue(ppValue, pValueSize, index);
- }
- void MP4File::SetBytesProperty(const char* name,
- const u_int8_t* pValue, u_int32_t valueSize)
- {
- ProtectWriteOperation("SetBytesProperty");
- MP4Property* pProperty;
- u_int32_t index;
- FindBytesProperty(name, &pProperty, &index);
- ((MP4BytesProperty*)pProperty)->SetValue(pValue, valueSize, index);
- }
- // track functions
- MP4TrackId MP4File::AddTrack(const char* type, u_int32_t timeScale)
- {
- ProtectWriteOperation("AddTrack");
- // create and add new trak atom
- MP4Atom* pTrakAtom = AddChildAtom("moov", "trak");
- // allocate a new track id
- MP4TrackId trackId = AllocTrackId();
- m_trakIds.Add(trackId);
- // set track id
- MP4Integer32Property* pInteger32Property = NULL;
- pTrakAtom->FindProperty(
- "trak.tkhd.trackId", (MP4Property**)&pInteger32Property);
- ASSERT(pInteger32Property);
- pInteger32Property->SetValue(trackId);
- // set track type
- const char* normType = MP4Track::NormalizeTrackType(type);
- // sanity check for user defined types
- if (strlen(normType) > 4) {
- VERBOSE_WARNING(m_verbosity,
- printf("AddTrack: type truncated to four charactersn"));
- // StringProperty::SetValue() will do the actual truncation
- }
- MP4StringProperty* pStringProperty = NULL;
- pTrakAtom->FindProperty(
- "trak.mdia.hdlr.handlerType", (MP4Property**)&pStringProperty);
- ASSERT(pStringProperty);
- pStringProperty->SetValue(normType);
- // set track time scale
- pInteger32Property = NULL;
- pTrakAtom->FindProperty(
- "trak.mdia.mdhd.timeScale", (MP4Property**)&pInteger32Property);
- ASSERT(pInteger32Property);
- pInteger32Property->SetValue(timeScale ? timeScale : 1000);
- // now have enough to create MP4Track object
- MP4Track* pTrack = NULL;
- if (!strcmp(normType, MP4_HINT_TRACK_TYPE)) {
- pTrack = new MP4RtpHintTrack(this, pTrakAtom);
- } else {
- pTrack = new MP4Track(this, pTrakAtom);
- }
- m_pTracks.Add(pTrack);
- // mark non-hint tracks as enabled
- if (strcmp(normType, MP4_HINT_TRACK_TYPE)) {
- SetTrackIntegerProperty(trackId, "tkhd.flags", 1);
- }
- // mark track as contained in this file
- // LATER will provide option for external data references
- AddDataReference(trackId, NULL);
- return trackId;
- }
- void MP4File::AddTrackToIod(MP4TrackId trackId)
- {
- MP4DescriptorProperty* pDescriptorProperty = NULL;
- m_pRootAtom->FindProperty("moov.iods.esIds",
- (MP4Property**)&pDescriptorProperty);
- ASSERT(pDescriptorProperty);
- MP4Descriptor* pDescriptor =
- pDescriptorProperty->AddDescriptor(MP4ESIDIncDescrTag);
- ASSERT(pDescriptor);
- MP4Integer32Property* pIdProperty = NULL;
- pDescriptor->FindProperty("id",
- (MP4Property**)&pIdProperty);
- ASSERT(pIdProperty);
- pIdProperty->SetValue(trackId);
- }
- void MP4File::RemoveTrackFromIod(MP4TrackId trackId)
- {
- MP4DescriptorProperty* pDescriptorProperty = NULL;
- m_pRootAtom->FindProperty("moov.iods.esIds",
- (MP4Property**)&pDescriptorProperty);
- ASSERT(pDescriptorProperty);
- for (u_int32_t i = 0; i < pDescriptorProperty->GetCount(); i++) {
- static char name[32];
- snprintf(name, sizeof(name), "esIds[%u].id", i);
- MP4Integer32Property* pIdProperty = NULL;
- pDescriptorProperty->FindProperty(name,
- (MP4Property**)&pIdProperty);
- ASSERT(pIdProperty);
- if (pIdProperty->GetValue() == trackId) {
- pDescriptorProperty->DeleteDescriptor(i);
- break;
- }
- }
- }
- void MP4File::AddTrackToOd(MP4TrackId trackId)
- {
- if (!m_odTrackId) {
- return;
- }
- AddTrackReference(MakeTrackName(m_odTrackId, "tref.mpod"), trackId);
- }
- void MP4File::RemoveTrackFromOd(MP4TrackId trackId)
- {
- if (!m_odTrackId) {
- return;
- }
- RemoveTrackReference(MakeTrackName(m_odTrackId, "tref.mpod"), trackId);
- }
- void MP4File::GetTrackReferenceProperties(const char* trefName,
- MP4Property** ppCountProperty, MP4Property** ppTrackIdProperty)
- {
- char propName[1024];
- snprintf(propName, sizeof(propName), "%s.%s", trefName, "entryCount");
- m_pRootAtom->FindProperty(propName, ppCountProperty);
- ASSERT(*ppCountProperty);
- snprintf(propName, sizeof(propName), "%s.%s", trefName, "entries.trackId");
- m_pRootAtom->FindProperty(propName, ppTrackIdProperty);
- ASSERT(*ppTrackIdProperty);
- }
- void MP4File::AddTrackReference(const char* trefName, MP4TrackId refTrackId)
- {
- MP4Integer32Property* pCountProperty = NULL;
- MP4Integer32Property* pTrackIdProperty = NULL;
- GetTrackReferenceProperties(trefName,
- (MP4Property**)&pCountProperty,
- (MP4Property**)&pTrackIdProperty);
- pTrackIdProperty->AddValue(refTrackId);
- pCountProperty->IncrementValue();
- }
- u_int32_t MP4File::FindTrackReference(const char* trefName,
- MP4TrackId refTrackId)
- {
- MP4Integer32Property* pCountProperty = NULL;
- MP4Integer32Property* pTrackIdProperty = NULL;
- GetTrackReferenceProperties(trefName,
- (MP4Property**)&pCountProperty,
- (MP4Property**)&pTrackIdProperty);
- for (u_int32_t i = 0; i < pCountProperty->GetValue(); i++) {
- if (refTrackId == pTrackIdProperty->GetValue(i)) {
- return i + 1; // N.B. 1 not 0 based index
- }
- }
- return 0;
- }
- void MP4File::RemoveTrackReference(const char* trefName, MP4TrackId refTrackId)
- {
- MP4Integer32Property* pCountProperty = NULL;
- MP4Integer32Property* pTrackIdProperty = NULL;
- GetTrackReferenceProperties(trefName,
- (MP4Property**)&pCountProperty,
- (MP4Property**)&pTrackIdProperty);
- for (u_int32_t i = 0; i < pCountProperty->GetValue(); i++) {
- if (refTrackId == pTrackIdProperty->GetValue(i)) {
- pTrackIdProperty->DeleteValue(i);
- pCountProperty->IncrementValue(-1);
- }
- }
- }
- void MP4File::AddDataReference(MP4TrackId trackId, const char* url)
- {
- MP4Atom* pDrefAtom =
- FindAtom(MakeTrackName(trackId, "mdia.minf.dinf.dref"));
- ASSERT(pDrefAtom);
- MP4Integer32Property* pCountProperty = NULL;
- pDrefAtom->FindProperty("dref.entryCount",
- (MP4Property**)&pCountProperty);
- ASSERT(pCountProperty);
- pCountProperty->IncrementValue();
- MP4Atom* pUrlAtom = AddChildAtom(pDrefAtom, "url ");
- if (url && url[0] != ' ') {
- pUrlAtom->SetFlags(pUrlAtom->GetFlags() & 0xFFFFFE);
- MP4StringProperty* pUrlProperty = NULL;
- pUrlAtom->FindProperty("url .location",
- (MP4Property**)&pUrlProperty);
- ASSERT(pUrlProperty);
- pUrlProperty->SetValue(url);
- } else {
- pUrlAtom->SetFlags(pUrlAtom->GetFlags() | 1);
- }
- }
- MP4TrackId MP4File::AddSystemsTrack(const char* type)
- {
- const char* normType = MP4Track::NormalizeTrackType(type);
- // TBD if user type, fix name to four chars, and warn
- MP4TrackId trackId = AddTrack(type, MP4_MSECS_TIME_SCALE);
- InsertChildAtom(MakeTrackName(trackId, "mdia.minf"), "nmhd", 0);
- AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd"), "mp4s");
- // stsd is a unique beast in that it has a count of the number
- // of child atoms that needs to be incremented after we add the mp4s atom
- MP4Integer32Property* pStsdCountProperty;
- FindIntegerProperty(
- MakeTrackName(trackId, "mdia.minf.stbl.stsd.entryCount"),
- (MP4Property**)&pStsdCountProperty);
- pStsdCountProperty->IncrementValue();
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.mp4s.esds.ESID", trackId);
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.mp4s.esds.decConfigDescr.objectTypeId",
- MP4SystemsV1ObjectType);
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.mp4s.esds.decConfigDescr.streamType",
- ConvertTrackTypeToStreamType(normType));
- return trackId;
- }
- MP4TrackId MP4File::AddODTrack()
- {
- // until a demonstrated need emerges
- // we limit ourselves to one object description track
- if (m_odTrackId != MP4_INVALID_TRACK_ID) {
- throw new MP4Error("object description track already exists",
- "AddObjectDescriptionTrack");
- }
- m_odTrackId = AddSystemsTrack(MP4_OD_TRACK_TYPE);
- AddTrackToIod(m_odTrackId);
- AddDescendantAtoms(MakeTrackName(m_odTrackId, NULL), "tref.mpod");
- return m_odTrackId;
- }
- MP4TrackId MP4File::AddSceneTrack()
- {
- MP4TrackId trackId = AddSystemsTrack(MP4_SCENE_TRACK_TYPE);
- AddTrackToIod(trackId);
- AddTrackToOd(trackId);
- return trackId;
- }
- MP4TrackId MP4File::AddAudioTrack(
- u_int32_t timeScale,
- MP4Duration sampleDuration,
- u_int8_t audioType)
- {
- MP4TrackId trackId = AddTrack(MP4_AUDIO_TRACK_TYPE, timeScale);
- AddTrackToOd(trackId);
- SetTrackFloatProperty(trackId, "tkhd.volume", 1.0);
- InsertChildAtom(MakeTrackName(trackId, "mdia.minf"), "smhd", 0);
- AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd"), "mp4a");
- // stsd is a unique beast in that it has a count of the number
- // of child atoms that needs to be incremented after we add the mp4a atom
- MP4Integer32Property* pStsdCountProperty;
- FindIntegerProperty(
- MakeTrackName(trackId, "mdia.minf.stbl.stsd.entryCount"),
- (MP4Property**)&pStsdCountProperty);
- pStsdCountProperty->IncrementValue();
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.mp4a.timeScale", timeScale);
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.mp4a.esds.ESID", trackId);
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.mp4a.esds.decConfigDescr.objectTypeId",
- audioType);
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.mp4a.esds.decConfigDescr.streamType",
- MP4AudioStreamType);
- m_pTracks[FindTrackIndex(trackId)]->
- SetFixedSampleDuration(sampleDuration);
- return trackId;
- }
- MP4TrackId MP4File::AddVideoTrack(
- u_int32_t timeScale,
- MP4Duration sampleDuration,
- u_int16_t width,
- u_int16_t height,
- u_int8_t videoType)
- {
- MP4TrackId trackId = AddTrack(MP4_VIDEO_TRACK_TYPE, timeScale);
- AddTrackToOd(trackId);
- SetTrackFloatProperty(trackId, "tkhd.width", width);
- SetTrackFloatProperty(trackId, "tkhd.height", height);
- InsertChildAtom(MakeTrackName(trackId, "mdia.minf"), "vmhd", 0);
- AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd"), "mp4v");
- // stsd is a unique beast in that it has a count of the number
- // of child atoms that needs to be incremented after we add the mp4v atom
- MP4Integer32Property* pStsdCountProperty;
- FindIntegerProperty(
- MakeTrackName(trackId, "mdia.minf.stbl.stsd.entryCount"),
- (MP4Property**)&pStsdCountProperty);
- pStsdCountProperty->IncrementValue();
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.mp4v.width", width);
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.mp4v.height", height);
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.mp4v.esds.ESID", trackId);
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.mp4v.esds.decConfigDescr.objectTypeId",
- videoType);
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.mp4v.esds.decConfigDescr.streamType",
- MP4VisualStreamType);
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsz.sampleSize", sampleDuration);
- m_pTracks[FindTrackIndex(trackId)]->
- SetFixedSampleDuration(sampleDuration);
- return trackId;
- }
- MP4TrackId MP4File::AddHintTrack(MP4TrackId refTrackId)
- {
- // validate reference track id
- FindTrackIndex(refTrackId);
- MP4TrackId trackId =
- AddTrack(MP4_HINT_TRACK_TYPE, GetTrackTimeScale(refTrackId));
- InsertChildAtom(MakeTrackName(trackId, "mdia.minf"), "hmhd", 0);
- AddChildAtom(MakeTrackName(trackId, "mdia.minf.stbl.stsd"), "rtp ");
- // stsd is a unique beast in that it has a count of the number
- // of child atoms that needs to be incremented after we add the rtp atom
- MP4Integer32Property* pStsdCountProperty;
- FindIntegerProperty(
- MakeTrackName(trackId, "mdia.minf.stbl.stsd.entryCount"),
- (MP4Property**)&pStsdCountProperty);
- pStsdCountProperty->IncrementValue();
- SetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.rtp .tims.timeScale",
- GetTrackTimeScale(trackId));
- AddDescendantAtoms(MakeTrackName(trackId, NULL), "tref.hint");
- AddTrackReference(MakeTrackName(trackId, "tref.hint"), refTrackId);
- AddDescendantAtoms(MakeTrackName(trackId, NULL), "udta.hnti.sdp ");
- AddDescendantAtoms(MakeTrackName(trackId, NULL), "udta.hinf");
- return trackId;
- }
- void MP4File::DeleteTrack(MP4TrackId trackId)
- {
- ProtectWriteOperation("MP4DeleteTrack");
- u_int32_t trakIndex = FindTrakAtomIndex(trackId);
- u_int16_t trackIndex = FindTrackIndex(trackId);
- MP4Track* pTrack = m_pTracks[trackIndex];
- MP4Atom* pTrakAtom = pTrack->GetTrakAtom();
- ASSERT(pTrakAtom);
- MP4Atom* pMoovAtom = FindAtom("moov");
- ASSERT(pMoovAtom);
- RemoveTrackFromIod(trackId);
- RemoveTrackFromOd(trackId);
- if (trackId == m_odTrackId) {
- m_odTrackId = 0;
- }
- pMoovAtom->DeleteChildAtom(pTrakAtom);
- m_trakIds.Delete(trakIndex);
- m_pTracks.Delete(trackIndex);
- delete pTrack;
- delete pTrakAtom;
- }
- u_int32_t MP4File::GetNumberOfTracks(const char* type, u_int8_t subType)
- {
- if (type == NULL) {
- return m_pTracks.Size();
- }
- u_int16_t typeSeen = 0;
- const char* normType = MP4Track::NormalizeTrackType(type);
- for (u_int16_t i = 0; i < m_pTracks.Size(); i++) {
- if (!strcmp(normType, m_pTracks[i]->GetType())) {
- if (subType) {
- if (normType == MP4_AUDIO_TRACK_TYPE) {
- if (subType != GetTrackAudioType(m_pTracks[i]->GetId())) {
- continue;
- }
- } else if (normType == MP4_VIDEO_TRACK_TYPE) {
- if (subType != GetTrackVideoType(m_pTracks[i]->GetId())) {
- continue;
- }
- }
- // else unknown subtype, ignore it
- }
- typeSeen++;
- }
- }
- return typeSeen;
- }
- MP4TrackId MP4File::AllocTrackId()
- {
- MP4TrackId trackId =
- GetIntegerProperty("moov.mvhd.nextTrackId");
- if (trackId <= 0xFFFF) {
- // check that nextTrackid is correct
- try {
- FindTrackIndex(trackId);
- // ERROR, this trackId is in use
- }
- catch (MP4Error* e) {
- // OK, this trackId is not in use, proceed
- delete e;
- SetIntegerProperty("moov.mvhd.nextTrackId", trackId + 1);
- return trackId;
- }
- }
- // we need to search for a track id
- for (trackId = 1; trackId <= 0xFFFF; trackId++) {
- try {
- FindTrackIndex(trackId);
- // KEEP LOOKING, this trackId is in use
- }
- catch (MP4Error* e) {
- // OK, this trackId is not in use, proceed
- delete e;
- return trackId;
- }
- }
- // extreme case where mp4 file has 2^16 tracks in it
- throw new MP4Error("too many exising tracks", "AddTrack");
- return MP4_INVALID_TRACK_ID; // to keep MSVC happy
- }
- MP4TrackId MP4File::FindTrackId(
- u_int16_t trackIndex, const char* type, u_int8_t subType)
- {
- if (type == NULL) {
- return m_pTracks[trackIndex]->GetId();
- }
- u_int16_t typeSeen = 0;
- const char* normType = MP4Track::NormalizeTrackType(type);
- for (u_int16_t i = 0; i < m_pTracks.Size(); i++) {
- if (!strcmp(normType, m_pTracks[i]->GetType())) {
- if (subType) {
- if (normType == MP4_AUDIO_TRACK_TYPE) {
- if (subType != GetTrackAudioType(m_pTracks[i]->GetId())) {
- continue;
- }
- } else if (normType == MP4_VIDEO_TRACK_TYPE) {
- if (subType != GetTrackVideoType(m_pTracks[i]->GetId())) {
- continue;
- }
- }
- // else unknown subtype, ignore it
- }
- if (trackIndex == typeSeen) {
- return m_pTracks[i]->GetId();
- }
- typeSeen++;
- }
- }
- throw new MP4Error("Track index doesn't exist - track %d type %s",
- "FindTrackId",
- trackIndex, type);
- return MP4_INVALID_TRACK_ID; // satisfy MS compiler
- }
- u_int16_t MP4File::FindTrackIndex(MP4TrackId trackId)
- {
- for (u_int16_t i = 0; i < m_pTracks.Size(); i++) {
- if (m_pTracks[i]->GetId() == trackId) {
- return i;
- }
- }
- throw new MP4Error("Track id %d doesn't exist", "FindTrackIndex", trackId);
- return (u_int16_t)-1; // satisfy MS compiler
- }
- u_int16_t MP4File::FindTrakAtomIndex(MP4TrackId trackId)
- {
- if (trackId) {
- for (u_int32_t i = 0; i < m_trakIds.Size(); i++) {
- if (m_trakIds[i] == trackId) {
- return i;
- }
- }
- }
- throw new MP4Error("Track id %d doesn't exist", "FindTrakAtomIndex",
- trackId);
- return (u_int16_t)-1; // satisfy MS compiler
- }
- u_int32_t MP4File::GetSampleSize(MP4TrackId trackId, MP4SampleId sampleId)
- {
- return m_pTracks[FindTrackIndex(trackId)]->GetSampleSize(sampleId);
- }
- u_int32_t MP4File::GetTrackMaxSampleSize(MP4TrackId trackId)
- {
- return m_pTracks[FindTrackIndex(trackId)]->GetMaxSampleSize();
- }
- MP4SampleId MP4File::GetSampleIdFromTime(MP4TrackId trackId,
- MP4Timestamp when, bool wantSyncSample)
- {
- return m_pTracks[FindTrackIndex(trackId)]->
- GetSampleIdFromTime(when, wantSyncSample);
- }
- MP4Timestamp MP4File::GetSampleTime(
- MP4TrackId trackId, MP4SampleId sampleId)
- {
- MP4Timestamp timestamp;
- m_pTracks[FindTrackIndex(trackId)]->
- GetSampleTimes(sampleId, ×tamp, NULL);
- return timestamp;
- }
- MP4Duration MP4File::GetSampleDuration(
- MP4TrackId trackId, MP4SampleId sampleId)
- {
- MP4Duration duration;
- m_pTracks[FindTrackIndex(trackId)]->
- GetSampleTimes(sampleId, NULL, &duration);
- return duration;
- }
- MP4Duration MP4File::GetSampleRenderingOffset(
- MP4TrackId trackId, MP4SampleId sampleId)
- {
- return m_pTracks[FindTrackIndex(trackId)]->
- GetSampleRenderingOffset(sampleId);
- }
- bool MP4File::GetSampleSync(MP4TrackId trackId, MP4SampleId sampleId)
- {
- return m_pTracks[FindTrackIndex(trackId)]->IsSyncSample(sampleId);
- }
- void MP4File::ReadSample(MP4TrackId trackId, MP4SampleId sampleId,
- u_int8_t** ppBytes, u_int32_t* pNumBytes,
- MP4Timestamp* pStartTime, MP4Duration* pDuration,
- MP4Duration* pRenderingOffset, bool* pIsSyncSample)
- {
- m_pTracks[FindTrackIndex(trackId)]->
- ReadSample(sampleId, ppBytes, pNumBytes,
- pStartTime, pDuration, pRenderingOffset, pIsSyncSample);
- }
- void MP4File::WriteSample(MP4TrackId trackId,
- u_int8_t* pBytes, u_int32_t numBytes,
- MP4Duration duration, MP4Duration renderingOffset, bool isSyncSample)
- {
- ProtectWriteOperation("MP4WriteSample");
- m_pTracks[FindTrackIndex(trackId)]->
- WriteSample(pBytes, numBytes, duration, renderingOffset, isSyncSample);
- m_pModificationProperty->SetValue(MP4GetAbsTimestamp());
- }
- void MP4File::SetSampleRenderingOffset(MP4TrackId trackId,
- MP4SampleId sampleId, MP4Duration renderingOffset)
- {
- ProtectWriteOperation("MP4SetSampleRenderingOffset");
- m_pTracks[FindTrackIndex(trackId)]->
- SetSampleRenderingOffset(sampleId, renderingOffset);
- m_pModificationProperty->SetValue(MP4GetAbsTimestamp());
- }
- char* MP4File::MakeTrackName(MP4TrackId trackId, const char* name)
- {
- u_int16_t trakIndex = FindTrakAtomIndex(trackId);
- static char trakName[1024];
- if (name == NULL || name[0] == ' ') {
- snprintf(trakName, sizeof(trakName),
- "moov.trak[%u]", trakIndex);
- } else {
- snprintf(trakName, sizeof(trakName),
- "moov.trak[%u].%s", trakIndex, name);
- }
- return trakName;
- }
- u_int64_t MP4File::GetTrackIntegerProperty(MP4TrackId trackId, const char* name)
- {
- return GetIntegerProperty(MakeTrackName(trackId, name));
- }
- void MP4File::SetTrackIntegerProperty(MP4TrackId trackId, const char* name,
- int64_t value)
- {
- SetIntegerProperty(MakeTrackName(trackId, name), value);
- }
- float MP4File::GetTrackFloatProperty(MP4TrackId trackId, const char* name)
- {
- return GetFloatProperty(MakeTrackName(trackId, name));
- }
- void MP4File::SetTrackFloatProperty(MP4TrackId trackId, const char* name,
- float value)
- {
- SetFloatProperty(MakeTrackName(trackId, name), value);
- }
- const char* MP4File::GetTrackStringProperty(MP4TrackId trackId, const char* name)
- {
- return GetStringProperty(MakeTrackName(trackId, name));
- }
- void MP4File::SetTrackStringProperty(MP4TrackId trackId, const char* name,
- const char* value)
- {
- SetStringProperty(MakeTrackName(trackId, name), value);
- }
- void MP4File::GetTrackBytesProperty(MP4TrackId trackId, const char* name,
- u_int8_t** ppValue, u_int32_t* pValueSize)
- {
- GetBytesProperty(MakeTrackName(trackId, name), ppValue, pValueSize);
- }
- void MP4File::SetTrackBytesProperty(MP4TrackId trackId, const char* name,
- const u_int8_t* pValue, u_int32_t valueSize)
- {
- SetBytesProperty(MakeTrackName(trackId, name), pValue, valueSize);
- }
- // file level convenience functions
- MP4Duration MP4File::GetDuration()
- {
- return m_pDurationProperty->GetValue();
- }
- void MP4File::SetDuration(MP4Duration value)
- {
- m_pDurationProperty->SetValue(value);
- }
- u_int32_t MP4File::GetTimeScale()
- {
- return m_pTimeScaleProperty->GetValue();
- }
- void MP4File::SetTimeScale(u_int32_t value)
- {
- if (value == 0) {
- throw new MP4Error("invalid value", "SetTimeScale");
- }
- m_pTimeScaleProperty->SetValue(value);
- }
- u_int8_t MP4File::GetODProfileLevel()
- {
- return GetIntegerProperty("moov.iods.ODProfileLevelId");
- }
- void MP4File::SetODProfileLevel(u_int8_t value)
- {
- SetIntegerProperty("moov.iods.ODProfileLevelId", value);
- }
- u_int8_t MP4File::GetSceneProfileLevel()
- {
- return GetIntegerProperty("moov.iods.sceneProfileLevelId");
- }
- void MP4File::SetSceneProfileLevel(u_int8_t value)
- {
- SetIntegerProperty("moov.iods.sceneProfileLevelId", value);
- }
- u_int8_t MP4File::GetVideoProfileLevel()
- {
- return GetIntegerProperty("moov.iods.visualProfileLevelId");
- }
- void MP4File::SetVideoProfileLevel(u_int8_t value)
- {
- SetIntegerProperty("moov.iods.visualProfileLevelId", value);
- }
- u_int8_t MP4File::GetAudioProfileLevel()
- {
- return GetIntegerProperty("moov.iods.audioProfileLevelId");
- }
- void MP4File::SetAudioProfileLevel(u_int8_t value)
- {
- SetIntegerProperty("moov.iods.audioProfileLevelId", value);
- }
- u_int8_t MP4File::GetGraphicsProfileLevel()
- {
- return GetIntegerProperty("moov.iods.graphicsProfileLevelId");
- }
- void MP4File::SetGraphicsProfileLevel(u_int8_t value)
- {
- SetIntegerProperty("moov.iods.graphicsProfileLevelId", value);
- }
- const char* MP4File::GetSessionSdp()
- {
- return GetStringProperty("moov.udta.hnti.rtp .sdpText");
- }
- void MP4File::SetSessionSdp(const char* sdpString)
- {
- AddDescendantAtoms("moov", "udta.hnti.rtp ");
- SetStringProperty("moov.udta.hnti.rtp .sdpText", sdpString);
- }
- void MP4File::AppendSessionSdp(const char* sdpFragment)
- {
- const char* oldSdpString = NULL;
- try {
- oldSdpString = GetSessionSdp();
- }
- catch (MP4Error* e) {
- delete e;
- SetSessionSdp(sdpFragment);
- return;
- }
- char* newSdpString =
- (char*)MP4Malloc(strlen(oldSdpString) + strlen(sdpFragment) + 1);
- strcpy(newSdpString, oldSdpString);
- strcat(newSdpString, sdpFragment);
- SetSessionSdp(newSdpString);
- MP4Free(newSdpString);
- }
- // track level convenience functions
- MP4SampleId MP4File::GetTrackNumberOfSamples(MP4TrackId trackId)
- {
- return m_pTracks[FindTrackIndex(trackId)]->GetNumberOfSamples();
- }
- const char* MP4File::GetTrackType(MP4TrackId trackId)
- {
- return m_pTracks[FindTrackIndex(trackId)]->GetType();
- }
- u_int32_t MP4File::GetTrackTimeScale(MP4TrackId trackId)
- {
- return m_pTracks[FindTrackIndex(trackId)]->GetTimeScale();
- }
- void MP4File::SetTrackTimeScale(MP4TrackId trackId, u_int32_t value)
- {
- if (value == 0) {
- throw new MP4Error("invalid value", "SetTrackTimeScale");
- }
- SetTrackIntegerProperty(trackId, "mdia.mdhd.timeScale", value);
- }
- MP4Duration MP4File::GetTrackDuration(MP4TrackId trackId)
- {
- return GetTrackIntegerProperty(trackId, "mdia.mdhd.duration");
- }
- u_int8_t MP4File::GetTrackAudioType(MP4TrackId trackId)
- {
- return GetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.mp4a.esds.decConfigDescr.objectTypeId");
- }
- u_int8_t MP4File::GetTrackAudioMpeg4Type(MP4TrackId trackId)
- {
- // verify that track is an MPEG-4 audio track
- if (GetTrackAudioType(trackId) != MP4_MPEG4_AUDIO_TYPE) {
- return MP4_MPEG4_INVALID_AUDIO_TYPE;
- }
- u_int8_t* pEsConfig = NULL;
- u_int32_t esConfigSize;
- // The Mpeg4 audio type (AAC, CELP, HXVC, ...)
- // is the first 5 bits of the ES configuration
- GetTrackESConfiguration(trackId, &pEsConfig, &esConfigSize);
- if (esConfigSize < 1) {
- return MP4_MPEG4_INVALID_AUDIO_TYPE;
- }
- u_int8_t mpeg4Type = (pEsConfig[0] >> 3);
- free(pEsConfig);
- return mpeg4Type;
- }
- u_int8_t MP4File::GetTrackVideoType(MP4TrackId trackId)
- {
- return GetTrackIntegerProperty(trackId,
- "mdia.minf.stbl.stsd.mp4v.esds.decConfigDescr.objectTypeId");
- }
- MP4Duration MP4File::GetTrackFixedSampleDuration(MP4TrackId trackId)
- {
- return m_pTracks[FindTrackIndex(trackId)]->GetFixedSampleDuration();
- }
- float MP4File::GetTrackVideoFrameRate(MP4TrackId trackId)
- {
- MP4SampleId numSamples =
- GetTrackNumberOfSamples(trackId);
- #ifdef _WIN32
- int64_t
- #else
- u_int64_t
- #endif
- msDuration =
- ConvertFromTrackDuration(trackId,
- GetTrackDuration(trackId), MP4_MSECS_TIME_SCALE);
- if (msDuration == 0) {
- return 0.0;
- }
- return ((double)numSamples / (double)msDuration) * MP4_MSECS_TIME_SCALE;
- }
- void MP4File::GetTrackESConfiguration(MP4TrackId trackId,
- u_int8_t** ppConfig, u_int32_t* pConfigSize)
- {
- GetTrackBytesProperty(trackId,
- "mdia.minf.stbl.stsd.*[0].esds.decConfigDescr.decSpecificInfo[0].info",
- ppConfig, pConfigSize);
- }
- void MP4File::SetTrackESConfiguration(MP4TrackId trackId,
- const u_int8_t* pConfig, u_int32_t configSize)
- {
- // get a handle on the track decoder config descriptor
- MP4DescriptorProperty* pConfigDescrProperty = NULL;
- FindProperty(MakeTrackName(trackId,
- "mdia.minf.stbl.stsd.*[0].esds.decConfigDescr.decSpecificInfo"),
- (MP4Property**)&pConfigDescrProperty);
- if (pConfigDescrProperty == NULL) {
- // probably trackId refers to a hint track
- throw new MP4Error("no such property", "MP4SetTrackESConfiguration");
- }
- // lookup the property to store the configuration
- MP4BytesProperty* pInfoProperty = NULL;
- pConfigDescrProperty->FindProperty("decSpecificInfo[0].info",
- (MP4Property**)&pInfoProperty);
- // configuration being set for the first time
- if (pInfoProperty == NULL) {
- // need to create a new descriptor to hold it
- MP4Descriptor* pConfigDescr =
- pConfigDescrProperty->AddDescriptor(MP4DecSpecificDescrTag);
- pConfigDescr->Generate();
- pConfigDescrProperty->FindProperty(
- "decSpecificInfo[0].info",
- (MP4Property**)&pInfoProperty);
- ASSERT(pInfoProperty);
- }
- // set the value
- pInfoProperty->SetValue(pConfig, configSize);
- }
- const char* MP4File::GetHintTrackSdp(MP4TrackId hintTrackId)
- {
- return GetTrackStringProperty(hintTrackId, "udta.hnti.sdp .sdpText");
- }
- void MP4File::SetHintTrackSdp(MP4TrackId hintTrackId, const char* sdpString)
- {
- MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)];
- if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) {
- throw new MP4Error("track is not a hint track",
- "MP4SetHintTrackSdp");
- }
- AddDescendantAtoms(
- MakeTrackName(hintTrackId, NULL), "udta.hnti.sdp ");
- SetTrackStringProperty(hintTrackId, "udta.hnti.sdp .sdpText", sdpString);
- }
- void MP4File::AppendHintTrackSdp(MP4TrackId hintTrackId,
- const char* sdpFragment)
- {
- const char* oldSdpString = NULL;
- try {
- oldSdpString = GetHintTrackSdp(hintTrackId);
- }
- catch (MP4Error* e) {
- delete e;
- SetHintTrackSdp(hintTrackId, sdpFragment);
- return;
- }
- char* newSdpString =
- (char*)MP4Malloc(strlen(oldSdpString) + strlen(sdpFragment) + 1);
- strcpy(newSdpString, oldSdpString);
- strcat(newSdpString, sdpFragment);
- SetHintTrackSdp(hintTrackId, newSdpString);
- MP4Free(newSdpString);
- }
- void MP4File::GetHintTrackRtpPayload(
- MP4TrackId hintTrackId,
- char** ppPayloadName,
- u_int8_t* pPayloadNumber,
- u_int16_t* pMaxPayloadSize)
- {
- MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)];
- if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) {
- throw new MP4Error("track is not a hint track",
- "MP4GetHintTrackRtpPayload");
- }
- ((MP4RtpHintTrack*)pTrack)->GetPayload(
- ppPayloadName, pPayloadNumber, pMaxPayloadSize);
- }
- void MP4File::SetHintTrackRtpPayload(MP4TrackId hintTrackId,
- const char* payloadName, u_int8_t* pPayloadNumber, u_int16_t maxPayloadSize)
- {
- MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)];
- if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) {
- throw new MP4Error("track is not a hint track",
- "MP4SetHintTrackRtpPayload");
- }
- u_int8_t payloadNumber;
- if (pPayloadNumber && *pPayloadNumber != 0) {
- payloadNumber = *pPayloadNumber;
- } else {
- payloadNumber = AllocRtpPayloadNumber();
- if (pPayloadNumber) {
- *pPayloadNumber = payloadNumber;
- }
- }
- ((MP4RtpHintTrack*)pTrack)->SetPayload(
- payloadName, payloadNumber, maxPayloadSize);
- }
- u_int8_t MP4File::AllocRtpPayloadNumber()
- {
- MP4Integer32Array usedPayloads;
- u_int32_t i;
- // collect rtp payload numbers in use by existing tracks
- for (i = 0; i < m_pTracks.Size(); i++) {
- MP4Atom* pTrakAtom = m_pTracks[i]->GetTrakAtom();
- MP4Integer32Property* pPayloadProperty = NULL;
- pTrakAtom->FindProperty("trak.udta.hinf.payt.payloadNumber",
- (MP4Property**)&pPayloadProperty);
- if (pPayloadProperty) {
- usedPayloads.Add(pPayloadProperty->GetValue());
- }
- }
- // search dynamic payload range for an available slot
- u_int8_t payload;
- for (payload = 96; payload < 128; payload++) {
- for (i = 0; i < usedPayloads.Size(); i++) {
- if (payload == usedPayloads[i]) {
- break;
- }
- }
- if (i == usedPayloads.Size()) {
- break;
- }
- }
- if (payload >= 128) {
- throw new MP4Error("no more available rtp payload numbers",
- "AllocRtpPayloadNumber");
- }
- return payload;
- }
- MP4TrackId MP4File::GetHintTrackReferenceTrackId(
- MP4TrackId hintTrackId)
- {
- MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)];
- if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) {
- throw new MP4Error("track is not a hint track",
- "MP4GetHintTrackReferenceTrackId");
- }
- MP4Track* pRefTrack = ((MP4RtpHintTrack*)pTrack)->GetRefTrack();
- if (pRefTrack == NULL) {
- return MP4_INVALID_TRACK_ID;
- }
- return pRefTrack->GetId();
- }
- void MP4File::ReadRtpHint(
- MP4TrackId hintTrackId,
- MP4SampleId hintSampleId,
- u_int16_t* pNumPackets)
- {
- MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)];
- if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) {
- throw new MP4Error("track is not a hint track", "MP4ReadRtpHint");
- }
- ((MP4RtpHintTrack*)pTrack)->
- ReadHint(hintSampleId, pNumPackets);
- }
- u_int16_t MP4File::GetRtpHintNumberOfPackets(
- MP4TrackId hintTrackId)
- {
- MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)];
- if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) {
- throw new MP4Error("track is not a hint track",
- "MP4GetRtpHintNumberOfPackets");
- }
- return ((MP4RtpHintTrack*)pTrack)->GetHintNumberOfPackets();
- }
- int8_t MP4File::GetRtpPacketBFrame(
- MP4TrackId hintTrackId,
- u_int16_t packetIndex)
- {
- MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)];
- if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) {
- throw new MP4Error("track is not a hint track",
- "MP4GetRtpHintBFrame");
- }
- return ((MP4RtpHintTrack*)pTrack)->GetPacketBFrame(packetIndex);
- }
- int32_t MP4File::GetRtpPacketTransmitOffset(
- MP4TrackId hintTrackId,
- u_int16_t packetIndex)
- {
- MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)];
- if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) {
- throw new MP4Error("track is not a hint track",
- "MP4GetRtpPacketTransmitOffset");
- }
- return ((MP4RtpHintTrack*)pTrack)->GetPacketTransmitOffset(packetIndex);
- }
- void MP4File::ReadRtpPacket(
- MP4TrackId hintTrackId,
- u_int16_t packetIndex,
- u_int8_t** ppBytes,
- u_int32_t* pNumBytes,
- u_int32_t ssrc,
- bool includeHeader,
- bool includePayload)
- {
- MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)];
- if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) {
- throw new MP4Error("track is not a hint track", "MP4ReadPacket");
- }
- ((MP4RtpHintTrack*)pTrack)->ReadPacket(
- packetIndex, ppBytes, pNumBytes,
- ssrc, includeHeader, includePayload);
- }
- MP4Timestamp MP4File::GetRtpTimestampStart(
- MP4TrackId hintTrackId)
- {
- MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)];
- if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) {
- throw new MP4Error("track is not a hint track",
- "MP4GetRtpTimestampStart");
- }
- return ((MP4RtpHintTrack*)pTrack)->GetRtpTimestampStart();
- }
- void MP4File::SetRtpTimestampStart(
- MP4TrackId hintTrackId,
- MP4Timestamp rtpStart)
- {
- MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)];
- if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) {
- throw new MP4Error("track is not a hint track",
- "MP4SetRtpTimestampStart");
- }
- ((MP4RtpHintTrack*)pTrack)->SetRtpTimestampStart(rtpStart);
- }
- void MP4File::AddRtpHint(MP4TrackId hintTrackId,
- bool isBframe, u_int32_t timestampOffset)
- {
- ProtectWriteOperation("MP4AddRtpHint");
- MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)];
- if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) {
- throw new MP4Error("track is not a hint track", "MP4AddRtpHint");
- }
- ((MP4RtpHintTrack*)pTrack)->AddHint(isBframe, timestampOffset);
- }
- void MP4File::AddRtpPacket(
- MP4TrackId hintTrackId, bool setMbit, int32_t transmitOffset)
- {
- ProtectWriteOperation("MP4AddRtpPacket");
- MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)];
- if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) {
- throw new MP4Error("track is not a hint track", "MP4AddRtpPacket");
- }
- ((MP4RtpHintTrack*)pTrack)->AddPacket(setMbit, transmitOffset);
- }
- void MP4File::AddRtpImmediateData(MP4TrackId hintTrackId,
- const u_int8_t* pBytes, u_int32_t numBytes)
- {
- ProtectWriteOperation("MP4AddRtpImmediateData");
- MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)];
- if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) {
- throw new MP4Error("track is not a hint track",
- "MP4AddRtpImmediateData");
- }
- ((MP4RtpHintTrack*)pTrack)->AddImmediateData(pBytes, numBytes);
- }
- void MP4File::AddRtpSampleData(MP4TrackId hintTrackId,
- MP4SampleId sampleId, u_int32_t dataOffset, u_int32_t dataLength)
- {
- ProtectWriteOperation("MP4AddRtpSampleData");
- MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)];
- if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) {
- throw new MP4Error("track is not a hint track",
- "MP4AddRtpSampleData");
- }
- ((MP4RtpHintTrack*)pTrack)->AddSampleData(
- sampleId, dataOffset, dataLength);
- }
- void MP4File::AddRtpESConfigurationPacket(MP4TrackId hintTrackId)
- {
- ProtectWriteOperation("MP4AddRtpESConfigurationPacket");
- MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)];
- if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) {
- throw new MP4Error("track is not a hint track",
- "MP4AddRtpESConfigurationPacket");
- }
- ((MP4RtpHintTrack*)pTrack)->AddESConfigurationPacket();
- }
- void MP4File::WriteRtpHint(MP4TrackId hintTrackId,
- MP4Duration duration, bool isSyncSample)
- {
- ProtectWriteOperation("MP4WriteRtpHint");
- MP4Track* pTrack = m_pTracks[FindTrackIndex(hintTrackId)];
- if (strcmp(pTrack->GetType(), MP4_HINT_TRACK_TYPE)) {
- throw new MP4Error("track is not a hint track",
- "MP4WriteRtpHint");
- }
- ((MP4RtpHintTrack*)pTrack)->WriteHint(duration, isSyncSample);
- }
- u_int64_t MP4File::ConvertFromMovieDuration(
- MP4Duration duration,
- u_int32_t timeScale)
- {
- return MP4ConvertTime((u_int64_t)duration,
- GetTimeScale(), timeScale);
- }
- u_int64_t MP4File::ConvertFromTrackTimestamp(
- MP4TrackId trackId,
- MP4Timestamp timeStamp,
- u_int32_t timeScale)
- {
- return MP4ConvertTime((u_int64_t)timeStamp,
- GetTrackTimeScale(trackId), timeScale);
- }
- MP4Timestamp MP4File::ConvertToTrackTimestamp(
- MP4TrackId trackId,
- u_int64_t timeStamp,
- u_int32_t timeScale)
- {
- return (MP4Timestamp)MP4ConvertTime(timeStamp,
- timeScale, GetTrackTimeScale(trackId));
- }
- u_int64_t MP4File::ConvertFromTrackDuration(
- MP4TrackId trackId,
- MP4Duration duration,
- u_int32_t timeScale)
- {
- return MP4ConvertTime((u_int64_t)duration,
- GetTrackTimeScale(trackId), timeScale);
- }
- MP4Duration MP4File::ConvertToTrackDuration(
- MP4TrackId trackId,
- u_int64_t duration,
- u_int32_t timeScale)
- {
- return (MP4Duration)MP4ConvertTime(duration,
- timeScale, GetTrackTimeScale(trackId));
- }
- u_int8_t MP4File::ConvertTrackTypeToStreamType(const char* trackType)
- {
- u_int8_t streamType;
- if (!strcmp(trackType, MP4_OD_TRACK_TYPE)) {
- streamType = MP4ObjectDescriptionStreamType;
- } else if (!strcmp(trackType, MP4_SCENE_TRACK_TYPE)) {
- streamType = MP4SceneDescriptionStreamType;
- } else if (!strcmp(trackType, MP4_CLOCK_TRACK_TYPE)) {
- streamType = MP4ClockReferenceStreamType;
- } else if (!strcmp(trackType, MP4_MPEG7_TRACK_TYPE)) {
- streamType = MP4Mpeg7StreamType;
- } else if (!strcmp(trackType, MP4_OCI_TRACK_TYPE)) {
- streamType = MP4OCIStreamType;
- } else if (!strcmp(trackType, MP4_IPMP_TRACK_TYPE)) {
- streamType = MP4IPMPStreamType;
- } else if (!strcmp(trackType, MP4_MPEGJ_TRACK_TYPE)) {
- streamType = MP4MPEGJStreamType;
- } else {
- streamType = MP4UserPrivateStreamType;
- }
- return streamType;
- }
- // edit list
- char* MP4File::MakeTrackEditName(
- MP4TrackId trackId,
- MP4EditId editId,
- const char* name)
- {
- char* trakName = MakeTrackName(trackId, NULL);
- static char editName[1024];
- snprintf(editName, sizeof(editName),
- "%s.edts.elst.entries[%u].%s",
- trakName, editId - 1, name);
- return editName;
- }
- MP4EditId MP4File::AddTrackEdit(
- MP4TrackId trackId,
- MP4EditId editId)
- {
- ProtectWriteOperation("AddTrackEdit");
- return m_pTracks[FindTrackIndex(trackId)]->AddEdit(editId);
- }
- void MP4File::DeleteTrackEdit(
- MP4TrackId trackId,
- MP4EditId editId)
- {
- ProtectWriteOperation("DeleteTrackEdit");
- m_pTracks[FindTrackIndex(trackId)]->DeleteEdit(editId);
- }
- u_int32_t MP4File::GetTrackNumberOfEdits(
- MP4TrackId trackId)
- {
- return GetTrackIntegerProperty(trackId, "edts.elst.entryCount");
- }
- MP4Duration MP4File::GetTrackEditTotalDuration(
- MP4TrackId trackId,
- MP4EditId editId)
- {
- return m_pTracks[FindTrackIndex(trackId)]->GetEditTotalDuration(editId);
- }
- MP4Timestamp MP4File::GetTrackEditStart(
- MP4TrackId trackId,
- MP4EditId editId)
- {
- return m_pTracks[FindTrackIndex(trackId)]->GetEditStart(editId);
- }
- MP4Timestamp MP4File::GetTrackEditMediaStart(
- MP4TrackId trackId,
- MP4EditId editId)
- {
- return GetIntegerProperty(
- MakeTrackEditName(trackId, editId, "mediaTime"));
- }
- void MP4File::SetTrackEditMediaStart(
- MP4TrackId trackId,
- MP4EditId editId,
- MP4Timestamp startTime)
- {
- SetIntegerProperty(
- MakeTrackEditName(trackId, editId, "mediaTime"),
- startTime);
- }
- MP4Duration MP4File::GetTrackEditDuration(
- MP4TrackId trackId,
- MP4EditId editId)
- {
- return GetIntegerProperty(
- MakeTrackEditName(trackId, editId, "segmentDuration"));
- }
- void MP4File::SetTrackEditDuration(
- MP4TrackId trackId,
- MP4EditId editId,
- MP4Duration duration)
- {
- SetIntegerProperty(
- MakeTrackEditName(trackId, editId, "segmentDuration"),
- duration);
- }
- bool MP4File::GetTrackEditDwell(
- MP4TrackId trackId,
- MP4EditId editId)
- {
- return (GetIntegerProperty(
- MakeTrackEditName(trackId, editId, "mediaRate")) == 0);
- }
- void MP4File::SetTrackEditDwell(
- MP4TrackId trackId,
- MP4EditId editId,
- bool dwell)
- {
- SetIntegerProperty(
- MakeTrackEditName(trackId, editId, "mediaRate"),
- (dwell ? 0 : 1));
- }
- MP4SampleId MP4File::GetSampleIdFromEditTime(
- MP4TrackId trackId,
- MP4Timestamp when,
- MP4Timestamp* pStartTime,
- MP4Duration* pDuration)
- {
- return m_pTracks[FindTrackIndex(trackId)]->GetSampleIdFromEditTime(
- when, pStartTime, pDuration);
- }