📄 mp4track.cpp
字号:
}}MP4Atom* MP4Track::AddAtom(char* parentName, char* childName){ MP4Atom* pChildAtom = MP4Atom::CreateAtom(childName); MP4Atom* pParentAtom = m_pTrakAtom->FindAtom(parentName); ASSERT(pParentAtom); pParentAtom->AddChildAtom(pChildAtom); pChildAtom->Generate(); return pChildAtom;}u_int64_t MP4Track::GetDuration(){ return m_pMediaDurationProperty->GetValue();}u_int32_t MP4Track::GetTimeScale(){ return m_pTimeScaleProperty->GetValue();}void MP4Track::UpdateDurations(MP4Duration duration){ // update media, track, and movie durations m_pMediaDurationProperty->SetValue( m_pMediaDurationProperty->GetValue() + duration); MP4Duration movieDuration = ToMovieDuration(duration); m_pTrackDurationProperty->SetValue( m_pTrackDurationProperty->GetValue() + movieDuration); m_pFile->UpdateDuration(m_pTrackDurationProperty->GetValue());}MP4Duration MP4Track::ToMovieDuration(MP4Duration trackDuration){ return (trackDuration * m_pFile->GetTimeScale()) / m_pTimeScaleProperty->GetValue();}void MP4Track::UpdateModificationTimes(){ // update media and track modification times MP4Timestamp now = MP4GetAbsTimestamp(); m_pMediaModificationProperty->SetValue(now); m_pTrackModificationProperty->SetValue(now);}u_int32_t MP4Track::GetNumberOfChunks(){ return m_pChunkOffsetProperty->GetCount();}u_int32_t MP4Track::GetChunkStscIndex(MP4ChunkId chunkId){ u_int32_t stscIndex; u_int32_t numStscs = m_pStscCountProperty->GetValue(); ASSERT(chunkId); ASSERT(numStscs > 0); for (stscIndex = 0; stscIndex < numStscs; stscIndex++) { if (chunkId < m_pStscFirstChunkProperty->GetValue(stscIndex)) { ASSERT(stscIndex != 0); break; } } return stscIndex - 1;}MP4Timestamp MP4Track::GetChunkTime(MP4ChunkId chunkId){ u_int32_t stscIndex = GetChunkStscIndex(chunkId); MP4ChunkId firstChunkId = m_pStscFirstChunkProperty->GetValue(stscIndex); MP4SampleId firstSample = m_pStscFirstSampleProperty->GetValue(stscIndex); u_int32_t samplesPerChunk = m_pStscSamplesPerChunkProperty->GetValue(stscIndex); MP4SampleId firstSampleInChunk = firstSample + ((chunkId - firstChunkId) * samplesPerChunk); MP4Timestamp chunkTime; GetSampleTimes(firstSampleInChunk, &chunkTime, NULL); return chunkTime;}u_int32_t MP4Track::GetChunkSize(MP4ChunkId chunkId){ u_int32_t stscIndex = GetChunkStscIndex(chunkId); MP4ChunkId firstChunkId = m_pStscFirstChunkProperty->GetValue(stscIndex); MP4SampleId firstSample = m_pStscFirstSampleProperty->GetValue(stscIndex); u_int32_t samplesPerChunk = m_pStscSamplesPerChunkProperty->GetValue(stscIndex); MP4SampleId firstSampleInChunk = firstSample + ((chunkId - firstChunkId) * samplesPerChunk); // need cumulative sizes of samples in chunk u_int32_t chunkSize = 0; for (u_int32_t i = 0; i < samplesPerChunk; i++) { chunkSize += GetSampleSize(firstSampleInChunk + i); } return chunkSize;}void MP4Track::ReadChunk(MP4ChunkId chunkId, u_int8_t** ppChunk, u_int32_t* pChunkSize){ ASSERT(chunkId); ASSERT(ppChunk); ASSERT(pChunkSize); u_int64_t chunkOffset = m_pChunkOffsetProperty->GetValue(chunkId - 1); *pChunkSize = GetChunkSize(chunkId); *ppChunk = (u_int8_t*)MP4Malloc(*pChunkSize); VERBOSE_READ_SAMPLE(m_pFile->GetVerbosity(), printf("ReadChunk: track %u id %u offset 0x"X64" size %u (0x%x)\n", m_trackId, chunkId, chunkOffset, *pChunkSize, *pChunkSize)); u_int64_t oldPos = m_pFile->GetPosition(); // only used in mode == 'w' try { m_pFile->SetPosition(chunkOffset); m_pFile->ReadBytes(*ppChunk, *pChunkSize); } catch (MP4Error* e) { // let's not leak memory MP4Free(*ppChunk); *ppChunk = NULL; if (m_pFile->GetMode() == 'w') { m_pFile->SetPosition(oldPos); } throw e; } if (m_pFile->GetMode() == 'w') { m_pFile->SetPosition(oldPos); }}void MP4Track::RewriteChunk(MP4ChunkId chunkId, u_int8_t* pChunk, u_int32_t chunkSize){ u_int64_t chunkOffset = m_pFile->GetPosition(); m_pFile->WriteBytes(pChunk, chunkSize); m_pChunkOffsetProperty->SetValue(chunkOffset, chunkId - 1); VERBOSE_WRITE_SAMPLE(m_pFile->GetVerbosity(), printf("RewriteChunk: track %u id %u offset 0x"X64" size %u (0x%x)\n", m_trackId, chunkId, chunkOffset, chunkSize, chunkSize)); }// map track type name aliases to official namesbool MP4Track::InitEditListProperties(){ m_pElstCountProperty = NULL; m_pElstMediaTimeProperty = NULL; m_pElstDurationProperty = NULL; m_pElstRateProperty = NULL; m_pElstReservedProperty = NULL; MP4Atom* pElstAtom = m_pTrakAtom->FindAtom("trak.edts.elst"); if (!pElstAtom) { return false; } (void)pElstAtom->FindProperty( "elst.entryCount", (MP4Property**)&m_pElstCountProperty); (void)pElstAtom->FindProperty( "elst.entries.mediaTime", (MP4Property**)&m_pElstMediaTimeProperty); (void)pElstAtom->FindProperty( "elst.entries.segmentDuration", (MP4Property**)&m_pElstDurationProperty); (void)pElstAtom->FindProperty( "elst.entries.mediaRate", (MP4Property**)&m_pElstRateProperty); (void)pElstAtom->FindProperty( "elst.entries.reserved", (MP4Property**)&m_pElstReservedProperty); return m_pElstCountProperty && m_pElstMediaTimeProperty && m_pElstDurationProperty && m_pElstRateProperty && m_pElstReservedProperty;}MP4EditId MP4Track::AddEdit(MP4EditId editId){ if (!m_pElstCountProperty) { (void)m_pFile->AddDescendantAtoms(m_pTrakAtom, "edts.elst"); if (InitEditListProperties() == false) return MP4_INVALID_EDIT_ID; } if (editId == MP4_INVALID_EDIT_ID) { editId = m_pElstCountProperty->GetValue() + 1; } m_pElstMediaTimeProperty->InsertValue(0, editId - 1); m_pElstDurationProperty->InsertValue(0, editId - 1); m_pElstRateProperty->InsertValue(1, editId - 1); m_pElstReservedProperty->InsertValue(0, editId - 1); m_pElstCountProperty->IncrementValue(); return editId;}void MP4Track::DeleteEdit(MP4EditId editId){ if (editId == MP4_INVALID_EDIT_ID) { throw new MP4Error("edit id can't be zero", "MP4Track::DeleteEdit"); } if (!m_pElstCountProperty || m_pElstCountProperty->GetValue() == 0) { throw new MP4Error("no edits exist", "MP4Track::DeleteEdit"); } m_pElstMediaTimeProperty->DeleteValue(editId - 1); m_pElstDurationProperty->DeleteValue(editId - 1); m_pElstRateProperty->DeleteValue(editId - 1); m_pElstReservedProperty->DeleteValue(editId - 1); m_pElstCountProperty->IncrementValue(-1); // clean up if last edit is deleted if (m_pElstCountProperty->GetValue() == 0) { m_pElstCountProperty = NULL; m_pElstMediaTimeProperty = NULL; m_pElstDurationProperty = NULL; m_pElstRateProperty = NULL; m_pElstReservedProperty = NULL; m_pTrakAtom->DeleteChildAtom( m_pTrakAtom->FindAtom("trak.edts")); }}MP4Timestamp MP4Track::GetEditStart( MP4EditId editId) { if (editId == MP4_INVALID_EDIT_ID) { return MP4_INVALID_TIMESTAMP; } else if (editId == 1) { return 0; } return (MP4Timestamp)GetEditTotalDuration(editId - 1);} MP4Duration MP4Track::GetEditTotalDuration( MP4EditId editId){ u_int32_t numEdits = 0; if (m_pElstCountProperty) { numEdits = m_pElstCountProperty->GetValue(); } if (editId == MP4_INVALID_EDIT_ID) { editId = numEdits; } if (numEdits == 0 || editId > numEdits) { return MP4_INVALID_DURATION; } MP4Duration totalDuration = 0; for (MP4EditId eid = 1; eid <= editId; eid++) { totalDuration += m_pElstDurationProperty->GetValue(eid - 1); } return totalDuration;}MP4SampleId MP4Track::GetSampleIdFromEditTime( MP4Timestamp editWhen, MP4Timestamp* pStartTime, MP4Duration* pDuration){ MP4SampleId sampleId = MP4_INVALID_SAMPLE_ID; u_int32_t numEdits = 0; if (m_pElstCountProperty) { numEdits = m_pElstCountProperty->GetValue(); } if (numEdits) { MP4Duration editElapsedDuration = 0; for (MP4EditId editId = 1; editId <= numEdits; editId++) { // remember edit segment's start time (in edit timeline) MP4Timestamp editStartTime = (MP4Timestamp)editElapsedDuration; // accumulate edit segment's duration editElapsedDuration += m_pElstDurationProperty->GetValue(editId - 1); // calculate difference between the specified edit time // and the end of this edit segment if (editElapsedDuration - editWhen <= 0) { // the specified time has not yet been reached continue; } // 'editWhen' is within this edit segment // calculate the specified edit time // relative to just this edit segment MP4Duration editOffset = editWhen - editStartTime; // calculate the media (track) time that corresponds // to the specified edit time based on the edit list MP4Timestamp mediaWhen = m_pElstMediaTimeProperty->GetValue(editId - 1) + editOffset; // lookup the sample id for the media time sampleId = GetSampleIdFromTime(mediaWhen, false); // lookup the sample's media start time and duration MP4Timestamp sampleStartTime; MP4Duration sampleDuration; GetSampleTimes(sampleId, &sampleStartTime, &sampleDuration); // calculate the difference if any between when the sample // would naturally start and when it starts in the edit timeline MP4Duration sampleStartOffset = mediaWhen - sampleStartTime; // calculate the start time for the sample in the edit time line MP4Timestamp editSampleStartTime = editWhen - MIN(editOffset, sampleStartOffset); MP4Duration editSampleDuration = 0; // calculate how long this sample lasts in the edit list timeline if (m_pElstRateProperty->GetValue(editId - 1) == 0) { // edit segment is a "dwell" // so sample duration is that of the edit segment editSampleDuration = m_pElstDurationProperty->GetValue(editId - 1); } else { // begin with the natural sample duration editSampleDuration = sampleDuration; // now shorten that if the edit segment starts // after the sample would naturally start if (editOffset < sampleStartOffset) { editSampleDuration -= sampleStartOffset - editOffset; } // now shorten that if the edit segment ends // before the sample would naturally end if (editElapsedDuration < editSampleStartTime + sampleDuration) { editSampleDuration -= (editSampleStartTime + sampleDuration) - editElapsedDuration; } } if (pStartTime) { *pStartTime = editSampleStartTime; } if (pDuration) { *pDuration = editSampleDuration; } VERBOSE_EDIT(m_pFile->GetVerbosity(), printf("GetSampleIdFromEditTime: when "U64" " "sampleId %u start "U64" duration "D64"\n", editWhen, sampleId, editSampleStartTime, editSampleDuration)); return sampleId; } throw new MP4Error("time out of range", "MP4Track::GetSampleIdFromEditTime"); } else { // no edit list sampleId = GetSampleIdFromTime(editWhen, false); if (pStartTime || pDuration) { GetSampleTimes(sampleId, pStartTime, pDuration); } } return sampleId;}void MP4Track::CalculateBytesPerSample (){ MP4Atom *pMedia = m_pTrakAtom->FindAtom("trak.mdia.minf.stbl.stsd"); MP4Atom *pMediaData; const char *media_data_name; if (pMedia == NULL) return; if (pMedia->GetNumberOfChildAtoms() != 1) return; pMediaData = pMedia->GetChildAtom(0); media_data_name = pMediaData->GetType(); if ((ATOMID(media_data_name) == ATOMID("twos")) || (ATOMID(media_data_name) == ATOMID("sowt"))) { MP4IntegerProperty *chan, *sampleSize; chan = (MP4IntegerProperty *)pMediaData->GetProperty(4); sampleSize = (MP4IntegerProperty *)pMediaData->GetProperty(5); m_bytesPerSample = chan->GetValue() * (sampleSize->GetValue() / 8); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -