📄 mp4track.cpp
字号:
// add size value for this sample m_pStszSampleSizeProperty->AddValue(numBytes); } } m_pStszSampleCountProperty->IncrementValue();}u_int32_t MP4Track::GetAvgBitrate(){ if (GetDuration() == 0) { return 0; } u_int64_t durationSecs = MP4ConvertTime(GetDuration(), GetTimeScale(), MP4_SECS_TIME_SCALE); if (GetDuration() % GetTimeScale() != 0) { durationSecs++; } return (GetTotalOfSampleSizes() * 8) / durationSecs;}u_int32_t MP4Track::GetMaxBitrate(){ u_int32_t timeScale = GetTimeScale(); MP4SampleId numSamples = GetNumberOfSamples(); u_int32_t maxBytesPerSec = 0; u_int32_t bytesThisSec = 0; MP4Timestamp thisSec = 0; for (MP4SampleId sid = 1; sid <= numSamples; sid++) { u_int32_t sampleSize; MP4Timestamp sampleTime; sampleSize = GetSampleSize(sid); GetSampleTimes(sid, &sampleTime, NULL); // sample counts for current second if (sampleTime < thisSec + timeScale) { bytesThisSec += sampleSize; } else { // sample is in a future second if (bytesThisSec > maxBytesPerSec) { maxBytesPerSec = bytesThisSec; } thisSec = sampleTime - (sampleTime % timeScale); bytesThisSec = sampleSize; } } // last second (or partial second) if (bytesThisSec > maxBytesPerSec) { maxBytesPerSec = bytesThisSec; } return maxBytesPerSec * 8;}u_int32_t MP4Track::GetSampleStscIndex(MP4SampleId sampleId){ u_int32_t stscIndex; u_int32_t numStscs = m_pStscCountProperty->GetValue(); if (numStscs == 0) { throw new MP4Error("No data chunks exist", "GetSampleStscIndex"); } for (stscIndex = 0; stscIndex < numStscs; stscIndex++) { if (sampleId < m_pStscFirstSampleProperty->GetValue(stscIndex)) { ASSERT(stscIndex != 0); stscIndex -= 1; break; } } if (stscIndex == numStscs) { ASSERT(stscIndex != 0); stscIndex -= 1; } return stscIndex;}FILE* MP4Track::GetSampleFile(MP4SampleId sampleId){ u_int32_t stscIndex = GetSampleStscIndex(sampleId); u_int32_t stsdIndex = m_pStscSampleDescrIndexProperty->GetValue(stscIndex); // check if the answer will be the same as last time if (m_lastStsdIndex && stsdIndex == m_lastStsdIndex) { return m_lastSampleFile; } MP4Atom* pStsdAtom = m_pTrakAtom->FindAtom("trak.mdia.minf.stbl.stsd"); ASSERT(pStsdAtom); MP4Atom* pStsdEntryAtom = pStsdAtom->GetChildAtom(stsdIndex - 1); ASSERT(pStsdEntryAtom); MP4Integer16Property* pDrefIndexProperty = NULL; pStsdEntryAtom->FindProperty( "*.dataReferenceIndex", (MP4Property**)&pDrefIndexProperty); if (pDrefIndexProperty == NULL) { throw new MP4Error("invalid stsd entry", "GetSampleFile"); } u_int32_t drefIndex = pDrefIndexProperty->GetValue(); MP4Atom* pDrefAtom = m_pTrakAtom->FindAtom("trak.mdia.minf.dinf.dref"); ASSERT(pDrefAtom); MP4Atom* pUrlAtom = pDrefAtom->GetChildAtom(drefIndex - 1); ASSERT(pUrlAtom); FILE* pFile; if (pUrlAtom->GetFlags() & 1) { pFile = NULL; // self-contained } else { MP4StringProperty* pLocationProperty = NULL; pUrlAtom->FindProperty( "*.location", (MP4Property**)&pLocationProperty); ASSERT(pLocationProperty); const char* url = pLocationProperty->GetValue(); VERBOSE_READ_SAMPLE(m_pFile->GetVerbosity(), printf("dref url = %s\n", url)); pFile = (FILE*)-1; // attempt to open url if it's a file url // currently this is the only thing we understand if (!strncmp(url, "file:", 5)) { const char* fileName = url + 5; if (!strncmp(fileName, "//", 2)) { fileName = strchr(fileName + 2, '/'); } if (fileName) { pFile = fopen(fileName, "rb"); if (!pFile) { pFile = (FILE*)-1; } } } } if (m_lastSampleFile) { fclose(m_lastSampleFile); } // cache the answer m_lastStsdIndex = stsdIndex; m_lastSampleFile = pFile; return pFile;}u_int64_t MP4Track::GetSampleFileOffset(MP4SampleId sampleId){ u_int32_t stscIndex = GetSampleStscIndex(sampleId); u_int32_t firstChunk = m_pStscFirstChunkProperty->GetValue(stscIndex); MP4SampleId firstSample = m_pStscFirstSampleProperty->GetValue(stscIndex); u_int32_t samplesPerChunk = m_pStscSamplesPerChunkProperty->GetValue(stscIndex); MP4ChunkId chunkId = firstChunk + ((sampleId - firstSample) / samplesPerChunk); u_int64_t chunkOffset = m_pChunkOffsetProperty->GetValue(chunkId - 1); 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);}bool 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 false; } m_fixedSampleDuration = duration; return true;}void MP4Track::GetSampleTimes(MP4SampleId sampleId, MP4Timestamp* pStartTime, MP4Duration* pDuration){ 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 (sampleId <= sid + sampleCount - 1) { if (pStartTime) { *pStartTime = elapsed + ((sampleId - sid) * sampleDelta); } if (pDuration) { *pDuration = sampleDelta; } 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 pCttsAtom->FindProperty( "ctts.entryCount", (MP4Property**)&m_pCttsCountProperty); pCttsAtom->FindProperty( "ctts.entries.sampleCount", (MP4Property**)&m_pCttsSampleCountProperty); 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); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -