📄 mp4track.cpp
字号:
MP4SampleId firstSampleInChunk = sampleId - ((sampleId - firstSample) % samplesPerChunk); // need cumulative samples sizes from firstSample to sampleId - 1 u_int32_t sampleOffset = 0; for (MP4SampleId i = firstSampleInChunk; i < sampleId; i++) { sampleOffset += GetSampleSize(i); } return chunkOffset + sampleOffset;}void MP4Track::UpdateSampleToChunk(MP4SampleId sampleId, MP4ChunkId chunkId, u_int32_t samplesPerChunk){ u_int32_t numStsc = m_pStscCountProperty->GetValue(); // if samplesPerChunk == samplesPerChunk of last entry if (numStsc && samplesPerChunk == m_pStscSamplesPerChunkProperty->GetValue(numStsc-1)) { // nothing to do } else { // add stsc entry m_pStscFirstChunkProperty->AddValue(chunkId); m_pStscSamplesPerChunkProperty->AddValue(samplesPerChunk); m_pStscSampleDescrIndexProperty->AddValue(1); m_pStscFirstSampleProperty->AddValue(sampleId - samplesPerChunk + 1); m_pStscCountProperty->IncrementValue(); }}void MP4Track::UpdateChunkOffsets(u_int64_t chunkOffset){ if (m_pChunkOffsetProperty->GetType() == Integer32Property) { ((MP4Integer32Property*)m_pChunkOffsetProperty)->AddValue(chunkOffset); } else { ((MP4Integer64Property*)m_pChunkOffsetProperty)->AddValue(chunkOffset); } m_pChunkCountProperty->IncrementValue();}MP4Duration MP4Track::GetFixedSampleDuration(){ u_int32_t numStts = m_pSttsCountProperty->GetValue(); if (numStts == 0) { return m_fixedSampleDuration; } if (numStts != 1) { return MP4_INVALID_DURATION; // sample duration is not fixed } return m_pSttsSampleDeltaProperty->GetValue(0);}void MP4Track::SetFixedSampleDuration(MP4Duration duration){ u_int32_t numStts = m_pSttsCountProperty->GetValue(); // setting this is only allowed before samples have been written if (numStts != 0) { return; } m_fixedSampleDuration = duration; return;}void MP4Track::GetSampleTimes(MP4SampleId sampleId, MP4Timestamp* pStartTime, MP4Duration* pDuration){ u_int32_t numStts = m_pSttsCountProperty->GetValue(); MP4SampleId sid; MP4Duration elapsed; if (m_cachedSttsSid != MP4_INVALID_SAMPLE_ID && sampleId >= m_cachedSttsSid) { sid = m_cachedSttsSid; elapsed = m_cachedSttsElapsed; } else { m_cachedSttsIndex = 0; sid = 1; elapsed = 0; } for (u_int32_t sttsIndex = m_cachedSttsIndex; sttsIndex < numStts; sttsIndex++) { u_int32_t sampleCount = m_pSttsSampleCountProperty->GetValue(sttsIndex); u_int32_t sampleDelta = m_pSttsSampleDeltaProperty->GetValue(sttsIndex); if (sampleId <= sid + sampleCount - 1) { if (pStartTime) { *pStartTime = (sampleId - sid); *pStartTime *= sampleDelta; *pStartTime += elapsed; } if (pDuration) { *pDuration = sampleDelta; } m_cachedSttsIndex = sttsIndex; m_cachedSttsSid = sid; m_cachedSttsElapsed = elapsed; return; } sid += sampleCount; elapsed += sampleCount * sampleDelta; } throw new MP4Error("sample id out of range", "MP4Track::GetSampleTimes");}MP4SampleId MP4Track::GetSampleIdFromTime( MP4Timestamp when, bool wantSyncSample) { u_int32_t numStts = m_pSttsCountProperty->GetValue(); MP4SampleId sid = 1; MP4Duration elapsed = 0; for (u_int32_t sttsIndex = 0; sttsIndex < numStts; sttsIndex++) { u_int32_t sampleCount = m_pSttsSampleCountProperty->GetValue(sttsIndex); u_int32_t sampleDelta = m_pSttsSampleDeltaProperty->GetValue(sttsIndex); if (sampleDelta == 0 && sttsIndex < numStts - 1) { VERBOSE_READ(m_pFile->GetVerbosity(), printf("Warning: Zero sample duration, stts entry %u\n", sttsIndex)); } MP4Duration d = when - elapsed; if (d <= sampleCount * sampleDelta) { MP4SampleId sampleId = sid; if (sampleDelta) { sampleId += (d / sampleDelta); } if (wantSyncSample) { return GetNextSyncSample(sampleId); } return sampleId; } sid += sampleCount; elapsed += sampleCount * sampleDelta; } throw new MP4Error("time out of range", "MP4Track::GetSampleIdFromTime"); return 0; // satisfy MS compiler}void MP4Track::UpdateSampleTimes(MP4Duration duration){ u_int32_t numStts = m_pSttsCountProperty->GetValue(); // if duration == duration of last entry if (numStts && duration == m_pSttsSampleDeltaProperty->GetValue(numStts-1)) { // increment last entry sampleCount m_pSttsSampleCountProperty->IncrementValue(1, numStts-1); } else { // add stts entry, sampleCount = 1, sampleDuration = duration m_pSttsSampleCountProperty->AddValue(1); m_pSttsSampleDeltaProperty->AddValue(duration); m_pSttsCountProperty->IncrementValue();; }}u_int32_t MP4Track::GetSampleCttsIndex(MP4SampleId sampleId, MP4SampleId* pFirstSampleId){ u_int32_t numCtts = m_pCttsCountProperty->GetValue(); MP4SampleId sid = 1; for (u_int32_t cttsIndex = 0; cttsIndex < numCtts; cttsIndex++) { u_int32_t sampleCount = m_pCttsSampleCountProperty->GetValue(cttsIndex); if (sampleId <= sid + sampleCount - 1) { if (pFirstSampleId) { *pFirstSampleId = sid; } return cttsIndex; } sid += sampleCount; } throw new MP4Error("sample id out of range", "MP4Track::GetSampleCttsIndex"); return 0; // satisfy MS compiler}MP4Duration MP4Track::GetSampleRenderingOffset(MP4SampleId sampleId){ if (m_pCttsCountProperty == NULL) { return 0; } if (m_pCttsCountProperty->GetValue() == 0) { return 0; } u_int32_t cttsIndex = GetSampleCttsIndex(sampleId); return m_pCttsSampleOffsetProperty->GetValue(cttsIndex);}void MP4Track::UpdateRenderingOffsets(MP4SampleId sampleId, MP4Duration renderingOffset){ // if ctts atom doesn't exist if (m_pCttsCountProperty == NULL) { // no rendering offset, so nothing to do if (renderingOffset == 0) { return; } // else create a ctts atom MP4Atom* pCttsAtom = AddAtom("trak.mdia.minf.stbl", "ctts"); // and get handles on the properties ASSERT(pCttsAtom->FindProperty( "ctts.entryCount", (MP4Property**)&m_pCttsCountProperty)); ASSERT(pCttsAtom->FindProperty( "ctts.entries.sampleCount", (MP4Property**)&m_pCttsSampleCountProperty)); ASSERT(pCttsAtom->FindProperty( "ctts.entries.sampleOffset", (MP4Property**)&m_pCttsSampleOffsetProperty)); // if this is not the first sample if (sampleId > 1) { // add a ctts entry for all previous samples // with rendering offset equal to zero m_pCttsSampleCountProperty->AddValue(sampleId - 1); m_pCttsSampleOffsetProperty->AddValue(0); m_pCttsCountProperty->IncrementValue();; } } // ctts atom exists (now) u_int32_t numCtts = m_pCttsCountProperty->GetValue(); // if renderingOffset == renderingOffset of last entry if (numCtts && renderingOffset == m_pCttsSampleOffsetProperty->GetValue(numCtts-1)) { // increment last entry sampleCount m_pCttsSampleCountProperty->IncrementValue(1, numCtts-1); } else { // add ctts entry, sampleCount = 1, sampleOffset = renderingOffset m_pCttsSampleCountProperty->AddValue(1); m_pCttsSampleOffsetProperty->AddValue(renderingOffset); m_pCttsCountProperty->IncrementValue(); }}void MP4Track::SetSampleRenderingOffset(MP4SampleId sampleId, MP4Duration renderingOffset){ // check if any ctts entries exist if (m_pCttsCountProperty == NULL || m_pCttsCountProperty->GetValue() == 0) { // if not then Update routine can be used // to create a ctts entry for samples before this one // and a ctts entry for this sample UpdateRenderingOffsets(sampleId, renderingOffset); // but we also need a ctts entry // for all samples after this one u_int32_t afterSamples = GetNumberOfSamples() - sampleId; if (afterSamples) { m_pCttsSampleCountProperty->AddValue(afterSamples); m_pCttsSampleOffsetProperty->AddValue(0); m_pCttsCountProperty->IncrementValue();; } return; } MP4SampleId firstSampleId; u_int32_t cttsIndex = GetSampleCttsIndex(sampleId, &firstSampleId); // do nothing in the degenerate case if (renderingOffset == m_pCttsSampleOffsetProperty->GetValue(cttsIndex)) { return; } u_int32_t sampleCount = m_pCttsSampleCountProperty->GetValue(cttsIndex); // if this sample has it's own ctts entry if (sampleCount == 1) { // then just set the value, // note we don't attempt to collapse entries m_pCttsSampleOffsetProperty->SetValue(renderingOffset, cttsIndex); return; } MP4SampleId lastSampleId = firstSampleId + sampleCount - 1; // else we share this entry with other samples // we need to insert our own entry if (sampleId == firstSampleId) { // our sample is the first one m_pCttsSampleCountProperty-> InsertValue(1, cttsIndex); m_pCttsSampleOffsetProperty-> InsertValue(renderingOffset, cttsIndex); m_pCttsSampleCountProperty-> SetValue(sampleCount - 1, cttsIndex + 1); m_pCttsCountProperty->IncrementValue(); } else if (sampleId == lastSampleId) { // our sample is the last one m_pCttsSampleCountProperty-> InsertValue(1, cttsIndex + 1); m_pCttsSampleOffsetProperty-> InsertValue(renderingOffset, cttsIndex + 1); m_pCttsSampleCountProperty-> SetValue(sampleCount - 1, cttsIndex); m_pCttsCountProperty->IncrementValue(); } else { // our sample is in the middle, UGH! // insert our new entry m_pCttsSampleCountProperty-> InsertValue(1, cttsIndex + 1); m_pCttsSampleOffsetProperty-> InsertValue(renderingOffset, cttsIndex + 1); // adjust count of previous entry m_pCttsSampleCountProperty-> SetValue(sampleId - firstSampleId, cttsIndex); // insert new entry for those samples beyond our sample m_pCttsSampleCountProperty-> InsertValue(lastSampleId - sampleId, cttsIndex + 2); u_int32_t oldRenderingOffset = m_pCttsSampleOffsetProperty->GetValue(cttsIndex); m_pCttsSampleOffsetProperty-> InsertValue(oldRenderingOffset, cttsIndex + 2); m_pCttsCountProperty->IncrementValue(2); }}bool MP4Track::IsSyncSample(MP4SampleId sampleId){ if (m_pStssCountProperty == NULL) { return true; } u_int32_t numStss = m_pStssCountProperty->GetValue(); u_int32_t stssLIndex = 0; u_int32_t stssRIndex = numStss - 1; while (stssRIndex >= stssLIndex){ u_int32_t stssIndex = (stssRIndex + stssLIndex) >> 1; MP4SampleId syncSampleId = m_pStssSampleProperty->GetValue(stssIndex); if (sampleId == syncSampleId) { return true; } if (sampleId > syncSampleId) { stssLIndex = stssIndex + 1; } else { stssRIndex = stssIndex - 1; } } return false;}// N.B. "next" is inclusive of this sample idMP4SampleId MP4Track::GetNextSyncSample(MP4SampleId sampleId){ if (m_pStssCountProperty == NULL) { return sampleId; } u_int32_t numStss = m_pStssCountProperty->GetValue(); for (u_int32_t stssIndex = 0; stssIndex < numStss; stssIndex++) { MP4SampleId syncSampleId = m_pStssSampleProperty->GetValue(stssIndex); if (sampleId > syncSampleId) { continue; } return syncSampleId; } // LATER check stsh for alternate sample return MP4_INVALID_SAMPLE_ID;}void MP4Track::UpdateSyncSamples(MP4SampleId sampleId, bool isSyncSample){ if (isSyncSample) { // if stss atom exists, add entry if (m_pStssCountProperty) { m_pStssSampleProperty->AddValue(sampleId); m_pStssCountProperty->IncrementValue(); } // else nothing to do (yet) } else { // !isSyncSample // if stss atom doesn't exist, create one if (m_pStssCountProperty == NULL) { MP4Atom* pStssAtom = AddAtom("trak.mdia.minf.stbl", "stss"); ASSERT(pStssAtom->FindProperty( "stss.entryCount", (MP4Property**)&m_pStssCountProperty)); ASSERT(pStssAtom->FindProperty( "stss.entries.sampleNumber", (MP4Property**)&m_pStssSampleProperty)); // set values for all samples that came before this one uint32_t samples = GetNumberOfSamples(); for (MP4SampleId sid = 1; sid < samples; sid++) { m_pStssSampleProperty->AddValue(sid); m_pStssCountProperty->IncrementValue(); } } // else nothing to do
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -