int32 CompositionOffsetAtom::getTimeOffsetForSampleNumber(uint32 num) { if ((_psampleOffsetVec == NULL) || (_psampleCountVec == NULL) || (_entryCount == 0)) { return PV_ERROR; } uint32 sampleCount = 0; int32 offset = 0; // Offset value to return for (uint32 i = 0; i < _entryCount; i++) { if (_parsing_mode == 1) CheckAndParseEntry(i); if (num < (sampleCount + _psampleCountVec[i%_stbl_buff_size])) { // Sample num within current entry int32 count = num - sampleCount; PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "CompositionOffsetAtom::getTimestampForSampleNumber- Time StampOffset = %d", _psampleOffsetVec[i%_stbl_buff_size])); return _psampleOffsetVec[i%_stbl_buff_size]; } else { sampleCount += _psampleCountVec[i%_stbl_buff_size]; } } // Went past end of list - not a valid sample number return PV_ERROR; }
MP4_ERROR_CODE SampleToChunkAtom::getNumChunksInRunofChunks(uint32 chunk, uint32& NumChunks) { if (_pfirstChunkVec == NULL) { return READ_SAMPLE_TO_CHUNK_ATOM_FAILED; } if ((chunk + 1) < _entryCount) { for (uint32 i = 0; i < _entryCount; i++) { if (_parsing_mode == 1) { CheckAndParseEntry(i); } if (_pfirstChunkVec[i%_stbl_buff_size] < chunk) { continue; } else if (_pfirstChunkVec[i%_stbl_buff_size] == chunk) { uint32 chunkNum = _pfirstChunkVec[(int32)(i%_stbl_buff_size)]; if (_parsing_mode == 1) { CheckAndParseEntry(i + 1); } uint32 nextChunkNum = _pfirstChunkVec[(int32)((i+1)%_stbl_buff_size)]; NumChunks = (nextChunkNum - chunkNum); return EVERYTHING_FINE; } else if (_pfirstChunkVec[(i%_stbl_buff_size)] > chunk) { NumChunks = (_pfirstChunkVec[(i%_stbl_buff_size)] - chunk); return EVERYTHING_FINE; } } } else { NumChunks = 1; return EVERYTHING_FINE; } return READ_SAMPLE_TO_CHUNK_ATOM_FAILED; }
MP4_ERROR_CODE CompositionOffsetAtom::GetTimeOffsetFromMT(uint32 aSampleNum, uint32 aCurrEC, uint32 aCurrSampleCount, uint32& aTimeOffset) { MP4_ERROR_CODE retval = DEFAULT_ERROR; if ((_psampleOffsetVec == NULL) || (_psampleCountVec == NULL) || (_entryCount == 0)) { return retval; } if (aSampleNum < aCurrSampleCount) { // Sample num within current entry if (_parsing_mode == 1) CheckAndParseEntry(aCurrEC); PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "CompositionOffsetAtom::getTimestampForaSampleNumber- Time StampOffset = %d", _psampleOffsetVec[aCurrEC%_stbl_buff_size])); aTimeOffset = _psampleOffsetVec[aCurrEC%_stbl_buff_size]; retval = EVERYTHING_FINE; } else { for (uint32 i = aCurrEC + 1; i < _entryCount; i++) { if (_parsing_mode == 1) CheckAndParseEntry(i); if (aSampleNum < (aCurrSampleCount + _psampleCountVec[i%_stbl_buff_size])) { PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "CompositionOffsetAtom::getTimestampForaSampleNumber- Time StampOffset = %d", _psampleOffsetVec[i%_stbl_buff_size])); aTimeOffset = _psampleOffsetVec[i%_stbl_buff_size]; retval = EVERYTHING_FINE; } else { aCurrSampleCount += _psampleCountVec[i%_stbl_buff_size]; } } } // Went past end of list - not a valid sample number return retval; }
uint32 SampleToChunkAtom::getNumChunksInRunofChunks(uint32 chunk) { if (_pfirstChunkVec == NULL) { return (uint32)PV_ERROR; } if ((chunk + 1) < _entryCount) { for (uint32 i = 0; i < _entryCount; i++) { if (_parsing_mode == 1) { CheckAndParseEntry(i); } if (_pfirstChunkVec[i%_stbl_buff_size] < chunk) { continue; } else if (_pfirstChunkVec[i%_stbl_buff_size] == chunk) { uint32 chunkNum = _pfirstChunkVec[(int32)(i%_stbl_buff_size)]; if (_parsing_mode == 1) { CheckAndParseEntry(i + 1); } uint32 nextChunkNum = _pfirstChunkVec[(int32)((i+1)%_stbl_buff_size)]; return(nextChunkNum - chunkNum); } else if (_pfirstChunkVec[(i%_stbl_buff_size)] > chunk) { return(_pfirstChunkVec[(i%_stbl_buff_size)] - chunk); } } } else { return (1); } return (uint32)PV_ERROR; }
MP4_ERROR_CODE TimeToSampleAtom::GetSampleCountAt(uint32 aIndex, uint32& aCount) { MP4_ERROR_CODE retval = READ_FAILED; if ((aIndex < _entryCount) && _psampleCountVec) { if (_parsing_mode == 1) CheckAndParseEntry(aIndex); aCount = _psampleCountVec[aIndex%_stbl_buff_size]; retval = EVERYTHING_FINE; } else { PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>TimeToSampleAtom::getSampleCountAt aIndex = %d", aIndex)); } return retval; }
// Return sample offset at index MP4_ERROR_CODE CompositionOffsetAtom::GetTimeOffsetForSampleNumberPeek(uint32 aSampleNumber, uint32& aTimeOffset) { MP4_ERROR_CODE retval = DEFAULT_ERROR; // It is assumed that sample 0 has a ts of 0 - i.e. the first // entry in the table starts with the delta between sample 1 and sample 0 if ((_psampleOffsetVec == NULL) || (_psampleCountVec == NULL) || (_entryCount == 0)) { return retval; } // note that aSampleNumber is a zero based index while _currGetSampleCount is 1 based index if (aSampleNumber < _currPeekSampleCount) { aTimeOffset = _currPeekTimeOffset; retval = EVERYTHING_FINE; } else { do { _currPeekIndex++; if (_parsing_mode) CheckAndParseEntry(_currPeekIndex); _currPeekSampleCount += _psampleCountVec[_currPeekIndex%_stbl_buff_size]; _currPeekTimeOffset = _psampleOffsetVec[_currPeekIndex%_stbl_buff_size]; } while (_currPeekSampleCount == 0); PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "CompositionOffsetAtom::getTimeOffsetForSampleNumberPeek- _currPeekIndex =%d", _currPeekIndex)); PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "CompositionOffsetAtom::getTimeOffsetForSampleNumberPeek- _currPeekSampleCount =%d", _currPeekSampleCount)); PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "CompositionOffsetAtom::getTimeOffsetForSampleNumberPeek- _currPeekTimeOffset =%d", _currPeekTimeOffset)); if (aSampleNumber < _currPeekSampleCount) { aTimeOffset = _currPeekTimeOffset; retval = EVERYTHING_FINE; } else { PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>CompositionOffsetAtom::getTimeOffsetForaSampleNumberberPeek aSampleNumber = %d", aSampleNumber)); } } return retval; }
// Return the number of samples at index MP4_ERROR_CODE CompositionOffsetAtom::GetSampleCountAt(uint32 aIndex, uint32& aSampleCount) { MP4_ERROR_CODE retval = DEFAULT_ERROR; if ((aIndex < _entryCount) && _psampleCountVec) { if (_parsing_mode == 1) CheckAndParseEntry(aIndex); aSampleCount = _psampleCountVec[aIndex%_stbl_buff_size]; retval = EVERYTHING_FINE; } else { PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>CompositionOffsetAtom::getSampleCountAt aIndex = %d", aIndex)); } return retval; }
int32 CompositionOffsetAtom::getTimeOffsetForSampleNumberPeek(uint32 sampleNum) { // It is assumed that sample 0 has a ts of 0 - i.e. the first // entry in the table starts with the delta between sample 1 and sample 0 if ((_psampleOffsetVec == NULL) || (_psampleCountVec == NULL) || (_entryCount == 0)) { return PV_ERROR; } // note that sampleNum is a zero based index while _currGetSampleCount is 1 based index if (sampleNum < _currPeekSampleCount) { return (_currPeekTimeOffset); } else { do { _currPeekIndex++; if (_parsing_mode) CheckAndParseEntry(_currPeekIndex); _currPeekSampleCount += _psampleCountVec[_currPeekIndex%_stbl_buff_size]; _currPeekTimeOffset = _psampleOffsetVec[_currPeekIndex%_stbl_buff_size]; } while (_currPeekSampleCount == 0); PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "CompositionOffsetAtom::getTimeOffsetForSampleNumberPeek- _currPeekIndex =%d", _currPeekIndex)); PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "CompositionOffsetAtom::getTimeOffsetForSampleNumberPeek- _currPeekSampleCount =%d", _currPeekSampleCount)); PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "CompositionOffsetAtom::getTimeOffsetForSampleNumberPeek- _currPeekTimeOffset =%d", _currPeekTimeOffset)); if (sampleNum < _currPeekSampleCount) { return (_currPeekTimeOffset); } else { PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>CompositionOffsetAtom::getTimeOffsetForSampleNumberPeek sampleNum = %d", sampleNum)); return (PV_ERROR); } } }
// Returns the timestamp delta (ms) for the current sample given by num. This value // is the difference in timestamps between the sample (num) and the previous sample // in the track. It is implicit that sample[0] occurs at timestamp ts=0. MP4_ERROR_CODE TimeToSampleAtom::GetTimeDeltaForSampleNumberGet(uint32 aSampleNumber, uint32& aTimeDelta) { MP4_ERROR_CODE retval = READ_FAILED; // It is assumed that sample 0 has a ts of 0 - i.e. the first // entry in the table starts with the delta between sample 1 and sample 0 if ((NULL == _psampleDeltaVec) || (NULL == _psampleCountVec) || (0 == _entryCount)) { return retval; } // note that sampleNum is a zero based index while _currGetSampleCount is 1 based index if (aSampleNumber < _currGetSampleCount) { aTimeDelta = _currGetTimeDelta; return EVERYTHING_FINE; } do { ++_currGetIndex; if (_parsing_mode) CheckAndParseEntry(_currGetIndex); _currGetSampleCount += _psampleCountVec[_currGetIndex%_stbl_buff_size]; _currGetTimeDelta = _psampleDeltaVec[_currGetIndex%_stbl_buff_size]; } while (0 == _currGetSampleCount); PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "TimeToSampleAtom::getTimeDeltaForSampleNumberGet- _currGetIndex =%d", _currGetIndex)); PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "TimeToSampleAtom::getTimeDeltaForSampleNumberGet- _currGetSampleCount =%d", _currGetSampleCount)); PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "TimeToSampleAtom::getTimeDeltaForSampleNumberGet- _currGetTimeDelta =%d", _currGetTimeDelta)); if (aSampleNumber < _currGetSampleCount) { aTimeDelta = _currGetTimeDelta; retval = EVERYTHING_FINE; } else { PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>TimeToSampleAtom::getTimeDeltaForSampleNumberGet sampleNum = %d", aSampleNumber)); } return retval; }
// This is the most widely used API // Returns the offset (ms) for the sample given by num. This is used when // randomly accessing a frame and the timestamp has not been accumulated. MP4_ERROR_CODE CompositionOffsetAtom::GetTimeOffsetForSampleNumberGet(uint32 aSampleNum, uint32& aTimeOffset) { MP4_ERROR_CODE retval = DEFAULT_ERROR; if ((_psampleOffsetVec == NULL) || (_psampleCountVec == NULL) || (_entryCount == 0)) { return retval; } // note that aSampleNum is a zero based index while _currGetSampleCount is 1 based index if (aSampleNum < _currGetSampleCount) { aTimeOffset = _currGetTimeOffset; retval = EVERYTHING_FINE; } else { do { _currGetIndex++; if (_parsing_mode) CheckAndParseEntry(_currGetIndex); _currGetSampleCount += _psampleCountVec[_currGetIndex%_stbl_buff_size]; _currGetTimeOffset = _psampleOffsetVec[_currGetIndex%_stbl_buff_size]; } while (_currGetSampleCount == 0); PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "CompositionOffsetAtom::getTimeOffsetForaSampleNumberGet- _currGetIndex =%d", _currGetIndex)); PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "CompositionOffsetAtom::getTimeOffsetForaSampleNumberGet- _currGetSampleCount =%d", _currGetSampleCount)); PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "CompositionOffsetAtom::getTimeOffsetForaSampleNumberGet- _currGetTimeOffset =%d", _currGetTimeOffset)); if (aSampleNum < _currGetSampleCount) { aTimeOffset = _currGetTimeOffset; retval = EVERYTHING_FINE; } else { PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>TimeToSampleAtom::getTimeDeltaForaSampleNumberGet aSampleNum = %d", aSampleNum)); } } return retval; }
// Returns the timestamp (ms) for the current sample given by num. This is used when // randomly accessing a frame and the timestamp has not been accumulated. It is implicit // that sample[0] occurs at timestamp ts=0. MP4_ERROR_CODE TimeToSampleAtom::GetTimestampForSampleNumber(uint32 aSampleNumber, uint64& aTimestamp) { MP4_ERROR_CODE retval = READ_FAILED; if ((_psampleDeltaVec == NULL) || (_psampleCountVec == NULL) || (_entryCount == 0)) { return retval; } // It is assumed that sample 0 has a ts of 0 - i.e. the first // entry in the table starts with the delta between sample 1 and sample 0 if (0 == aSampleNumber) { aTimestamp = 0; return EVERYTHING_FINE; } uint32 sampleCount = 0; uint64 ts = 0; // Timestamp value to return for (uint32 i = 0; i < _entryCount; i++) { if (_parsing_mode == 1) CheckAndParseEntry(i); if (aSampleNumber <= (sampleCount + _psampleCountVec[i%_stbl_buff_size])) { // Sample num within current entry int32 count = aSampleNumber - sampleCount; ts += _psampleDeltaVec[i%_stbl_buff_size] * count; aTimestamp = ts; retval = EVERYTHING_FINE; PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "TimeToSampleAtom::getTimestampForSampleNumber- Time Stamp =%d", ts)); break; } else { sampleCount += _psampleCountVec[i%_stbl_buff_size]; ts += (_psampleDeltaVec[i%_stbl_buff_size] * _psampleCountVec[i%_stbl_buff_size]); } } // Went past end of list - not a valid sample number return retval; }
MP4_ERROR_CODE TimeToSampleAtom::ResetStateVariables(uint32 aSampleNum) { _currGetSampleCount = 0; _currGetIndex = -1; _currGetTimeDelta = 0; _currPeekSampleCount = 0; _currPeekIndex = -1; _currPeekTimeDelta = 0; // It is assumed that sample 0 has a ts of 0 - i.e. the first // entry in the table starts with the delta between sample 1 and sample 0 if ((_psampleDeltaVec == NULL) || (_psampleCountVec == NULL) || (_entryCount == 0)) { return DEFAULT_ERROR; } for (uint32 i = 0; i < _entryCount; i++) { if (_parsing_mode) CheckAndParseEntry(i); _currPeekIndex++; _currPeekSampleCount += _psampleCountVec[i%_stbl_buff_size]; _currPeekTimeDelta = _psampleDeltaVec[i%_stbl_buff_size]; _currGetIndex++; _currGetSampleCount += _psampleCountVec[i%_stbl_buff_size]; _currGetTimeDelta = _psampleDeltaVec[i%_stbl_buff_size]; if (aSampleNum <= _currPeekSampleCount) { return (EVERYTHING_FINE); } } // Went past end of list - not a valid sample number return DEFAULT_ERROR; }
// This is the most widely used API // Returns the offset (ms) for the sample given by num. This is used when // randomly accessing a frame and the timestamp has not been accumulated. int32 CompositionOffsetAtom::getTimeOffsetForSampleNumberGet(uint32 sampleNum) { if ((_psampleOffsetVec == NULL) || (_psampleCountVec == NULL) || (_entryCount == 0)) { return PV_ERROR; } // note that sampleNum is a zero based index while _currGetSampleCount is 1 based index if (sampleNum < _currGetSampleCount) { return (_currGetTimeOffset); } else { do { _currGetIndex++; if (_parsing_mode) CheckAndParseEntry(_currGetIndex); _currGetSampleCount += _psampleCountVec[_currGetIndex%_stbl_buff_size]; _currGetTimeOffset = _psampleOffsetVec[_currGetIndex%_stbl_buff_size]; } while (_currGetSampleCount == 0); PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "CompositionOffsetAtom::getTimeOffsetForSampleNumberGet- _currGetIndex =%d", _currGetIndex)); PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "CompositionOffsetAtom::getTimeOffsetForSampleNumberGet- _currGetSampleCount =%d", _currGetSampleCount)); PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "CompositionOffsetAtom::getTimeOffsetForSampleNumberGet- _currGetTimeOffset =%d", _currGetTimeOffset)); if (sampleNum < _currGetSampleCount) { return (_currGetTimeOffset); } else { PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>TimeToSampleAtom::getTimeDeltaForSampleNumberGet sampleNum = %d", sampleNum)); return (PV_ERROR); } } }
// Return sample offset at index int32 CompositionOffsetAtom::getSampleOffsetAt(int32 index) { if (_psampleOffsetVec == NULL) { return PV_ERROR; } if (index < (int32)_entryCount) { if (_parsing_mode == 1) CheckAndParseEntry(index); return (int32)(_psampleOffsetVec[index%_stbl_buff_size]); } else { PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>CompositionOffsetAtom::getSampleOffsetAt index = %d", index)); return PV_ERROR; } }
// Returns the chunk number of the first chunk in run[index] int32 SampleToChunkAtom::getFirstChunkAt(uint32 index) { if (_pfirstChunkVec == NULL) { return PV_ERROR; } if (index < _entryCount) { if (_parsing_mode == 1) { CheckAndParseEntry(index); } return (_pfirstChunkVec[index%_stbl_buff_size]); } else { PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>SampleToChunkAtom::getFirstChunkAt index = %d", index)); return PV_ERROR; } }
// Returns the chunk number of the first chunk in run[index] MP4_ERROR_CODE SampleToChunkAtom::getFirstChunkAt(uint32 index, int32& pos) { if (_pfirstChunkVec == NULL) { return READ_SAMPLE_TO_CHUNK_ATOM_FAILED; } if (index < _entryCount) { if (_parsing_mode == 1) { CheckAndParseEntry(index); } pos = (_pfirstChunkVec[index%_stbl_buff_size]); return EVERYTHING_FINE; } else { PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>SampleToChunkAtom::getFirstChunkAt index = %d", index)); return READ_SAMPLE_TO_CHUNK_ATOM_FAILED; } }
// Returns the timestamp delta (ms) for the current sample given by num. This value // is the difference in timestamps between the sample (num) and the previous sample // in the track. It is implicit that sample[0] occurs at timestamp ts=0. MP4_ERROR_CODE TimeToSampleAtom::GetTimeDeltaForSampleNumber(uint32 aNumber, uint32& aTimeDelta) { MP4_ERROR_CODE retval = READ_FAILED; // It is assumed that sample 0 has a ts of 0 - i.e. the first // entry in the table starts with the delta between sample 1 and sample 0 if ((_psampleDeltaVec == NULL) || (_psampleCountVec == NULL) || (_entryCount == 0)) { return retval; } if (0 == aNumber) { aTimeDelta = 0; return EVERYTHING_FINE; } uint32 sampleCount = 0; for (uint32 i = 0; i < _entryCount; i++) { if (_parsing_mode == 1) CheckAndParseEntry(i); if (aNumber <= (sampleCount + _psampleCountVec[i%_stbl_buff_size])) { // Sample num within current entry aTimeDelta = (_psampleDeltaVec[i%_stbl_buff_size]); retval = EVERYTHING_FINE; break; } else { sampleCount += _psampleCountVec[i%_stbl_buff_size]; } } // Went past end of list - not a valid sample number return retval; }
//Populate the Marker Table with SampleCount and EntryCount values //for every nth sample starting from n-1, where n=MT_SAMPLECOUNT_INCREMENT. uint32 CompositionOffsetAtom::PopulateMarkerTable() { uint32 increment = MT_SAMPLECOUNT_INCREMENT; uint32 numPopulated = 0; for (uint32 i = entrycountTraversed; i < _entryCount; i++) { if (refSample < _iTotalNumSamplesInTrack) { if (i == 0) { if (_parsing_mode == 1) CheckAndParseEntry(i); MT_SampleCount[0] = _psampleCountVec[i%_stbl_buff_size]; prevSampleCount = MT_SampleCount[0]; addSampleCount = MT_SampleCount[0]; } else if (addSampleCount < refSample) { if (_parsing_mode == 1) CheckAndParseEntry(MT_j); prevSampleCount = addSampleCount; addSampleCount += _psampleCountVec[MT_j%_stbl_buff_size]; MT_j++; } else { entrycountTraversed = i - 1; i = i - 1; refSample += increment; MT_SampleCount[MT_Counter] = prevSampleCount; //Incase SampleCounts have same value for consecutive MT entries, //even the same EntryCount should be mentioned in the Marker Table. if (MT_SampleCount[MT_Counter] == MT_SampleCount[MT_Counter-1]) { MT_EntryCount[MT_Counter] = MT_EntryCount[MT_Counter-1]; } else { MT_EntryCount[MT_Counter] = MT_j - 2; } MT_Counter++; numPopulated++; if ((numPopulated == NUMBER_OF_SAMPLE_POPULATES_PER_RUNL) || (MT_Counter >= _iTotalNumSamplesInTrack / MT_SAMPLECOUNT_INCREMENT)) break; } } else { break; } } return numPopulated; }
MP4_ERROR_CODE CompositionOffsetAtom::GetTimeOffsetForSampleNumber(uint32 aSampleNum, uint32& aTimeOffset) { uint32 currSample = 0; uint32 currEC = 0; MP4_ERROR_CODE retval = DEFAULT_ERROR; if (iMarkerTableCreation == true) { uint32 MT_EC = aSampleNum / (MT_SAMPLECOUNT_INCREMENT - 1); //where MT_SAMPLECOUNT_INCREMENT is the granuality of sample separation in Marker Table if (MT_EC > ((_iTotalNumSamplesInTrack / MT_SAMPLECOUNT_INCREMENT) - 1)) { //boundary check, MT_EC valid value will always be between 0 to (_samples_count/MT_SAMPLECOUNT_INCREMENT)-1 MT_EC = (_iTotalNumSamplesInTrack / MT_SAMPLECOUNT_INCREMENT) - 1; } //assign the last marker entry count created till now to look for sample from this location onwards instead of from start if (MT_EC > MT_Counter) MT_EC = MT_Counter; while ((aSampleNum < MT_SampleCount[MT_EC]) && (MT_EC > 0)) { //This check was put keeping in mind that it may happen (due to rounding off error), //that we choose a MT_EC greater than desired. So to avoid such a scenario. MT_EC = MT_EC - 1; currSample = MT_SampleCount[MT_EC]; currEC = MT_EntryCount[MT_EC]; } currSample = MT_SampleCount[MT_EC]; currEC = MT_EntryCount[MT_EC]; GetTimeOffsetFromMT(aSampleNum, currEC, currSample, aTimeOffset); retval = EVERYTHING_FINE; } else { if ((_psampleOffsetVec == NULL) || (_psampleCountVec == NULL) || (_entryCount == 0)) { return retval; } uint32 sampleCount = 0; for (uint32 i = 0; i < _entryCount; i++) { if (_parsing_mode == 1) CheckAndParseEntry(i); if (aSampleNum < (sampleCount + _psampleCountVec[i%_stbl_buff_size])) { // Sample aSampleNum within current entry PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "CompositionOffsetAtom::getTimestampForSampleaSampleNumber- Time StampOffset = %d", _psampleOffsetVec[i%_stbl_buff_size])); aTimeOffset = _psampleOffsetVec[i%_stbl_buff_size]; retval = EVERYTHING_FINE; break; } else { sampleCount += _psampleCountVec[i%_stbl_buff_size]; } } } return retval; }
// Returns the chunk number for the given sample number uint32 SampleToChunkAtom::getChunkNumberForSample(uint32 sampleNum) { if ((_pfirstChunkVec == NULL) || (_psamplesPerChunkVec == NULL)) { return (uint32)PV_ERROR; } uint32 sampleCount = 0; for (uint32 i = 0; i < _entryCount; i++) { uint32 chunkNum = 0; uint32 samplesPerChunkInRun = 0; if (_parsing_mode == 1) { CheckAndParseEntry(i); } chunkNum = _pfirstChunkVec[i%_stbl_buff_size]; samplesPerChunkInRun = _psamplesPerChunkVec[i%_stbl_buff_size]; if ((i + 1) < _entryCount) { if (_parsing_mode == 1) { CheckAndParseEntry(i + 1); } uint32 nextChunkNum = _pfirstChunkVec[(int32)((i+1)%_stbl_buff_size)]; uint32 numChunksInRun = nextChunkNum - chunkNum; uint32 count = sampleCount + samplesPerChunkInRun * numChunksInRun; if (count < sampleNum) { // Haven't found chunk yet - running count still less than sampleNum sampleCount = count; continue; } else { // Found run of chunks in which sample lies - now find actual chunk for (int32 j = 0; j < (int32)numChunksInRun; j++) { sampleCount += samplesPerChunkInRun; // samples for jth chunk if (sampleNum < sampleCount) { // Found specific chunk _Index = i; return chunkNum + j; // Return jth chunk in run } } } } else { // Last run of chunks - simply find specific chunk int k = 0; while (sampleNum >= sampleCount) { // Continue until find chunk number - we do not know how many chunks are in // this final run so keep going til we find a number sampleCount += samplesPerChunkInRun; if (sampleNum < sampleCount) { // Found specific chunk _Index = i; return chunkNum + k; // Return ith chunk in run // Since we do not actually know how many chunk are in this last run, // the chunkNum that is returned may not be a valid chunk! // This is handled in the exception handling in the chunkOffset atom } k++; } } } return (uint32)PV_ERROR; // Should never get here }
// Returns the chunk number for the given sample number uint32 SampleToChunkAtom::getChunkNumberForSampleGet(uint32 sampleNum) { if ((_pfirstChunkVec == NULL) || (_psamplesPerChunkVec == NULL)) { return (uint32)PV_ERROR; } if (_parsing_mode == 1) { CheckAndParseEntry(_majorGetIndex); } if (sampleNum < _currGetSampleCount) { return (_currGetChunk); } else if (_numGetChunksInRun > 1) { _firstGetSampleInCurrChunk = _currGetSampleCount; _currGetSampleCount += _numGetSamplesPerChunk; _currGetChunk++; PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleToChunkAtom::getChunkNumberForSampleGet- _firstGetSampleInCurrChunk =%d", _firstGetSampleInCurrChunk)); PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleToChunkAtom::getChunkNumberForSampleGet- _currGetSampleCount =%d", _currGetSampleCount)); PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleToChunkAtom::getChunkNumberForSampleGet- _currGetChunk =%d", _currGetChunk)); // to handle special case, every sample is a chunk if (_entryCount > 1) { _numGetChunksInRun--; } if (sampleNum < _currGetSampleCount) { return (_currGetChunk); } else { PVMF_MP4FFPARSER_LOGERROR((0, "ERROR=>SampleToChunkAtom::getChunkNumberForSampleGet sampleNum= %d", sampleNum)); return (uint32)PV_ERROR; } } else if (_numGetChunksInRun <= 1) { if (_majorGetIndex < (int32)(_entryCount - 1)) { uint32 prevFirstChunk = _pfirstChunkVec[_majorGetIndex%_stbl_buff_size]; _numGetSamplesPerChunk = _psamplesPerChunkVec[_majorGetIndex%_stbl_buff_size]; _currGetSDI = _psampleDescriptionIndexVec[_majorGetIndex%_stbl_buff_size]; if (_parsing_mode == 1) { CheckAndParseEntry(_majorGetIndex + 1); } uint32 nextFirstChunk = _pfirstChunkVec[(_majorGetIndex+1)%_stbl_buff_size]; _numGetChunksInRun = nextFirstChunk - prevFirstChunk; _numChunksInRun = _numGetChunksInRun; _majorGetIndex++; _firstGetSampleInCurrChunk = _currGetSampleCount; _currGetSampleCount += _numGetSamplesPerChunk; _currGetChunk++; PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleToChunkAtom::getChunkNumberForSampleGet- _numGetChunksInRun =%d", _numGetChunksInRun)); PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleToChunkAtom::getChunkNumberForSampleGet- _numGetSamplesPerChunk =%d", _numGetSamplesPerChunk)); PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleToChunkAtom::getChunkNumberForSampleGet- _currGetSampleCount =%d", _currGetSampleCount)); PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleToChunkAtom::getChunkNumberForSampleGet- _currGetChunk =%d", _currGetChunk)); PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleToChunkAtom::getChunkNumberForSampleGet- _majorGetIndex =%d", _majorGetIndex)); if (sampleNum < _currGetSampleCount) { return (_currGetChunk); } else { PVMF_MP4FFPARSER_LOGERROR((0, "ERROR=>SampleToChunkAtom::getChunkNumberForSampleGet sampleNum= %d", sampleNum)); return (uint32)PV_ERROR; } } else if (_majorGetIndex == (int32)(_entryCount - 1)) { // Last run of chunks _numGetChunksInRun = 1; _numChunksInRun = _numGetChunksInRun; _currGetSDI = _psampleDescriptionIndexVec[_majorGetIndex%_stbl_buff_size]; _numGetSamplesPerChunk = _psamplesPerChunkVec[_majorGetIndex%_stbl_buff_size]; _firstGetSampleInCurrChunk = _currGetSampleCount; _currGetSampleCount += _numGetSamplesPerChunk; _currGetChunk++; PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleToChunkAtom::getChunkNumberForSampleGet- _numGetSamplesPerChunk =%d", _firstGetSampleInCurrChunk)); PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleToChunkAtom::getChunkNumberForSampleGet- _firstGetSampleInCurrChunk =%d", _firstGetSampleInCurrChunk)); PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleToChunkAtom::getChunkNumberForSampleGet- _currGetSampleCount =%d", _currGetSampleCount)); PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleToChunkAtom::getChunkNumberForSampleGet- _currGetChunk =%d", _currGetChunk)); if (sampleNum < _currGetSampleCount) { return (_currGetChunk); } else { PVMF_MP4FFPARSER_LOGERROR((0, "ERROR=>SampleToChunkAtom::getChunkNumberForSampleGet sampleNum= %d", sampleNum)); return (uint32)PV_ERROR; } } else { PVMF_MP4FFPARSER_LOGERROR((0, "ERROR=>SampleToChunkAtom::getChunkNumberForSampleGet _majorGetIndex = %d _entryCount= %d", _majorGetIndex, _entryCount)); return (uint32)PV_ERROR; } } return (uint32)PV_ERROR; // Should never get here }
// Return the samples corresponding to the timestamp ts. If there is not a sample // exactly at ts, the very next sample is used. // This atom maintains timestamp deltas between samples, i.e. delta[i] is the // timestamp difference between sample[i] and sample[i+1]. It is implicit that // sample[0] occurs at timestamp ts=0. MP4_ERROR_CODE TimeToSampleAtom::GetSampleNumberFromTimestamp(uint64 aTimeStamp, uint32& aSampleNumber, bool oAlwaysRetSampleCount) { MP4_ERROR_CODE retval = DEFAULT_ERROR; // It is assumed that sample 0 has a ts of 0 - i.e. the first // entry in the table starts with the delta between sample 1 and sample 0 uint32 sampleCount = 0; uint64 timeCount = 0; if ((_psampleDeltaVec == NULL) || (_psampleCountVec == NULL) || (_entryCount == 0)) { return retval; } for (uint32 i = 0; i < _entryCount; i++) { if (_parsing_mode == 1) CheckAndParseEntry(i); if (aTimeStamp < timeCount) { // found range that the sample is in - need to backtrack if (_parsing_mode == 1) CheckAndParseEntry(i - 1); uint32 samples = _psampleCountVec[(i-1)%_stbl_buff_size]; sampleCount -= samples; timeCount -= _psampleDeltaVec[(i-1)%_stbl_buff_size] * samples; while (timeCount <= aTimeStamp) { timeCount += _psampleDeltaVec[(i-1)%_stbl_buff_size]; sampleCount += 1; } if (timeCount > aTimeStamp) { if (sampleCount > 0) { sampleCount--; } aSampleNumber = sampleCount; return EVERYTHING_FINE; } } else if (aTimeStamp == timeCount) { // Found sample at aTimeStamp aSampleNumber = sampleCount; return EVERYTHING_FINE; } else { // Sample not yet found - advance uint32 samples = _psampleCountVec[i%_stbl_buff_size]; //number of samples at this index sampleCount += samples; timeCount += _psampleDeltaVec[i%_stbl_buff_size] * samples; } } // Timestamp is in last run of samples (or possibly beyond) // - need to backtrack to beginning of last run to find it uint32 samples = _psampleCountVec[(_entryCount-1)%_stbl_buff_size]; uint32 delta = _psampleDeltaVec[(_entryCount-1)%_stbl_buff_size]; sampleCount -= samples; timeCount -= delta * samples; for (uint32 count = 0; count < (samples - 1); count++) { timeCount += delta; sampleCount += 1; if (timeCount > aTimeStamp) { if (sampleCount > 0) { sampleCount--; } aSampleNumber = sampleCount; return EVERYTHING_FINE; } else if (timeCount == aTimeStamp) { aSampleNumber = sampleCount; return EVERYTHING_FINE; } } sampleCount += 1; if (aTimeStamp >= timeCount) { if (oAlwaysRetSampleCount) { aSampleNumber = sampleCount; return EVERYTHING_FINE; } else { if (_mediaType == MEDIA_TYPE_VISUAL) { aSampleNumber = sampleCount; return EVERYTHING_FINE; } } } // Went past last sample in last run of samples - not a valid timestamp return retval; }
MP4_ERROR_CODE SampleToChunkAtom::getChunkNumberForSamplePeek(uint32 sampleNum, uint32& ChunkNumber) { if ((_pfirstChunkVec == NULL) || (_psamplesPerChunkVec == NULL)) { return READ_SAMPLE_TO_CHUNK_ATOM_FAILED; } if (_parsing_mode == 1) { CheckAndParseEntry(_majorPeekIndex); } if (sampleNum < _currPeekSampleCount) { ChunkNumber = _currPeekChunk; return EVERYTHING_FINE; } else if (_numPeekChunksInRun > 1) { _firstPeekSampleInCurrChunk = _currPeekSampleCount; _currPeekSampleCount += _numPeekSamplesPerChunk; _currPeekChunk++; PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleToChunkAtom::getChunkNumberForSamplePeek- _firstPeekSampleInCurrChunk =%d", _firstPeekSampleInCurrChunk)); PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleToChunkAtom::getChunkNumberForSamplePeek- _currPeekSampleCount =%d", _currPeekSampleCount)); PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleToChunkAtom::getChunkNumberForSamplePeek- _numPeekSamplesPerChunk =%d", _numPeekSamplesPerChunk)); PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleToChunkAtom::getChunkNumberForSamplePeek- _currPeekChunk =%d", _currPeekChunk)); // to handle special case, every sample is a chunk if (_entryCount > 1) { _numPeekChunksInRun--; } if (sampleNum < _currPeekSampleCount) { ChunkNumber = _currPeekChunk; return EVERYTHING_FINE; } else { PVMF_MP4FFPARSER_LOGERROR((0, "ERROR=>SampleToChunkAtom::getChunkNumberForSamplePeek sampleNum = %d", sampleNum)); return READ_SAMPLE_TO_CHUNK_ATOM_FAILED; } } else if (_numPeekChunksInRun <= 1) { if (_majorPeekIndex < (int32)(_entryCount - 1)) { uint32 prevNextChunk = _pfirstChunkVec[_majorPeekIndex%_stbl_buff_size]; _numPeekSamplesPerChunk = _psamplesPerChunkVec[_majorPeekIndex%_stbl_buff_size]; _currPeekSDI = _psampleDescriptionIndexVec[_majorPeekIndex%_stbl_buff_size]; if (_parsing_mode == 1) { CheckAndParseEntry(_majorPeekIndex + 1); } uint32 nextfirstChunk = _pfirstChunkVec[(_majorPeekIndex+1)%_stbl_buff_size]; _numPeekChunksInRun = nextfirstChunk - prevNextChunk; _majorPeekIndex++; _firstPeekSampleInCurrChunk = _currPeekSampleCount; _currPeekSampleCount += _numPeekSamplesPerChunk; _currPeekChunk++; PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleToChunkAtom::getChunkNumberForSamplePeek- _numPeekChunksInRun =%d", _numPeekChunksInRun)); PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleToChunkAtom::getChunkNumberForSamplePeek- _numPeekSamplesPerChunk =%d", _numPeekSamplesPerChunk)); PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleToChunkAtom::getChunkNumberForSamplePeek- _majorPeekIndex =%d", _majorPeekIndex)); PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleToChunkAtom::getChunkNumberForSamplePeek- _firstPeekSampleInCurrChunk =%d", _firstPeekSampleInCurrChunk)); PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleToChunkAtom::getChunkNumberForSamplePeek- _currPeekSampleCount =%d", _currPeekSampleCount)); PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleToChunkAtom::getChunkNumberForSamplePeek- _numPeekSamplesPerChunk =%d", _numPeekSamplesPerChunk)); if (sampleNum < _currPeekSampleCount) { ChunkNumber = _currPeekChunk; return EVERYTHING_FINE; } else { PVMF_MP4FFPARSER_LOGERROR((0, "ERROR=>SampleToChunkAtom::getChunkNumberForSamplePeek sampleNum = %d", sampleNum)); return READ_SAMPLE_TO_CHUNK_ATOM_FAILED; } } else if (_majorPeekIndex == (int32)(_entryCount - 1)) { _numPeekChunksInRun = 1; _currPeekSDI = _psampleDescriptionIndexVec[_majorPeekIndex%_stbl_buff_size]; _numPeekSamplesPerChunk = _psamplesPerChunkVec[_majorPeekIndex%_stbl_buff_size]; _firstPeekSampleInCurrChunk = _currPeekSampleCount; _currPeekSampleCount += _numPeekSamplesPerChunk; _currPeekChunk++; PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleToChunkAtom::getChunkNumberForSamplePeek- _numPeekSamplesPerChunk =%d", _numPeekSamplesPerChunk)); PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleToChunkAtom::getChunkNumberForSamplePeek- _majorPeekIndex =%d", _majorPeekIndex)); PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleToChunkAtom::getChunkNumberForSamplePeek- _firstPeekSampleInCurrChunk =%d", _firstPeekSampleInCurrChunk)); PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleToChunkAtom::getChunkNumberForSamplePeek- _currPeekSampleCount =%d", _currPeekSampleCount)); PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleToChunkAtom::getChunkNumberForSamplePeek- _numPeekSamplesPerChunk =%d", _numPeekSamplesPerChunk)); if (sampleNum < _currPeekSampleCount) { ChunkNumber = _currPeekChunk; return EVERYTHING_FINE; } else { PVMF_MP4FFPARSER_LOGERROR((0, "ERROR=>SampleToChunkAtom::getChunkNumberForSamplePeek sampleNum = %d", sampleNum)); return READ_SAMPLE_TO_CHUNK_ATOM_FAILED; } } else { return READ_SAMPLE_TO_CHUNK_ATOM_FAILED; } } return READ_SAMPLE_TO_CHUNK_ATOM_FAILED; // Should never get here }
MP4_ERROR_CODE SampleToChunkAtom::getSamplesPerChunkCorrespondingToSample(uint32 sampleNum, uint32& SamplesPerChunk) { uint32 sampleCount = 0; if ((_pfirstChunkVec == NULL) || (_psamplesPerChunkVec == NULL)) { return READ_SAMPLE_TO_CHUNK_ATOM_FAILED; } for (uint32 i = 0; i < _entryCount; i++) { if (_parsing_mode == 1) { CheckAndParseEntry(i); } uint32 chunkNum = 0; uint32 samplesPerChunkInRun = 0; chunkNum = _pfirstChunkVec[(i%_stbl_buff_size)]; samplesPerChunkInRun = _psamplesPerChunkVec[(i%_stbl_buff_size)]; if ((i + 1) < _entryCount) { if (_parsing_mode == 1) { CheckAndParseEntry(i + 1); } uint32 nextChunkNum = _pfirstChunkVec[(int32)(((i+1)%_stbl_buff_size))]; uint32 numChunksInRun = nextChunkNum - chunkNum; uint32 count = sampleCount + samplesPerChunkInRun * numChunksInRun; if (count < sampleNum) { // Haven't found chunk yet - running count still less than sampleNum sampleCount = count; continue; } else { // Found run of chunks in which sample lies - now find actual chunk for (int32 j = 0; j < (int32)numChunksInRun; j++) { sampleCount += samplesPerChunkInRun; // samples for jth chunk if (sampleNum < sampleCount) { // Found specific chunk SamplesPerChunk = (samplesPerChunkInRun); return EVERYTHING_FINE; } } } } else { // Last run of chunks - simply find specific chunk int k = 0; int for_ever = 1; while (for_ever) { // Continue until find chunk number - we do not know how many chunks are in // this final run so keep going til we find a number sampleCount += samplesPerChunkInRun; if (sampleNum < sampleCount) { // Found specific chunk SamplesPerChunk = (samplesPerChunkInRun); // Since we do not actually know how many chunk are in this last run, // the chunkNum that is returned may not be a valid chunk! // This is handled in the exception handling in the chunkOffset atom return EVERYTHING_FINE; } k++; } } } return READ_SAMPLE_TO_CHUNK_ATOM_FAILED; // Should never get here }
int32 SampleToChunkAtom::resetStateVariables(uint32 sampleNum) { _majorGetIndex = 0; _currGetChunk = -1; _numGetChunksInRun = 0; _currGetSampleCount = 0; _firstGetSampleInCurrChunk = 0; _numGetSamplesPerChunk = 0; _currGetSDI = 0; _majorPeekIndex = 0; _currPeekChunk = -1; _numPeekChunksInRun = 0; _currPeekSampleCount = 0; _firstPeekSampleInCurrChunk = 0; _numPeekSamplesPerChunk = 0; _currPeekSDI = 0; if ((_pfirstChunkVec == NULL) || (_psamplesPerChunkVec == NULL)) { return DEFAULT_ERROR; } uint32 sampleCount = 0; for (uint32 i = 0; i < _entryCount; i++) { uint32 chunkNum = 0; uint32 samplesPerChunkInRun = 0; if (_parsing_mode == 1) { CheckAndParseEntry(i + 1); } chunkNum = _pfirstChunkVec[i%_stbl_buff_size]; samplesPerChunkInRun = _psamplesPerChunkVec[i%_stbl_buff_size]; if ((i + 1) < _entryCount) { uint32 nextChunkNum = _pfirstChunkVec[(int32)(i+1)%_stbl_buff_size]; uint32 numChunksInRun = nextChunkNum - chunkNum; uint32 count = sampleCount + samplesPerChunkInRun * numChunksInRun; if (count < sampleNum) { // Haven't found chunk yet - running count still less than sampleNum sampleCount = count; continue; } else { _numGetChunksInRun = numChunksInRun; // Found run of chunks in which sample lies - now find actual chunk for (int32 j = 0; j < (int32)numChunksInRun; j++) { // samples for jth chunk _firstGetSampleInCurrChunk = sampleCount; _numGetSamplesPerChunk = samplesPerChunkInRun; sampleCount += samplesPerChunkInRun; if (sampleNum < sampleCount) { _majorGetIndex = i; _numChunksInRun = numChunksInRun; _currGetSampleCount = sampleCount; _currGetChunk = chunkNum + j; _currGetSDI = _psampleDescriptionIndexVec[_majorGetIndex%_stbl_buff_size]; goto END_OF_RESET; } _numGetChunksInRun--; } } } else { // Last run of chunks - simply find specific chunk int k = 0; while (sampleNum >= sampleCount) { // Continue until find chunk number - we do not know how many chunks are in // this final run so keep going til we find a number _firstGetSampleInCurrChunk = sampleCount; _numGetSamplesPerChunk = samplesPerChunkInRun; sampleCount += samplesPerChunkInRun; if (sampleNum < sampleCount) { // Found specific chunk _majorGetIndex = i; _numGetChunksInRun = 1; _numChunksInRun = _numGetChunksInRun; _currGetSampleCount = sampleCount; _currGetChunk = chunkNum + k; _currGetSDI = _psampleDescriptionIndexVec[_majorGetIndex%_stbl_buff_size]; goto END_OF_RESET; // Return ith chunk in run // Since we do not actually know how many chunk are in this last run, // the chunkNum that is returned may not be a valid chunk! // This is handled in the exception handling in the chunkOffset atom } k++; } } } return DEFAULT_ERROR; // Should never get here END_OF_RESET: { if (_majorGetIndex < (int32)(_entryCount - 1)) { _majorGetIndex++; } _majorPeekIndex = _majorGetIndex; _currPeekChunk = _currGetChunk; _numPeekChunksInRun = _numGetChunksInRun; _currPeekSampleCount = _currGetSampleCount; _firstPeekSampleInCurrChunk = _firstGetSampleInCurrChunk; _numPeekSamplesPerChunk = _numGetSamplesPerChunk; _currPeekSDI = _currGetSDI; PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleToChunkAtom::resetStateVariables- _majorPeekIndex = _majorGetIndex =%d", _majorPeekIndex)); PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleToChunkAtom::resetStateVariables- _currPeekChunk = _currGetChunk =%d", _currPeekChunk)); PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleToChunkAtom::resetStateVariables- _numPeekChunksInRun = _numGetChunksInRun = %d", _numPeekChunksInRun)); PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleToChunkAtom::resetStateVariables- _currPeekSampleCount = _currGetSampleCount = %d", _currPeekSampleCount)); PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleToChunkAtom::resetStateVariables- _firstPeekSampleInCurrChunk = _firstGetSampleInCurrChunk = %d", _firstPeekSampleInCurrChunk)); PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleToChunkAtom::resetStateVariables- _numPeekSamplesPerChunk = _numGetSamplesPerChunk = %d", _numPeekSamplesPerChunk)); PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleToChunkAtom::resetStateVariables- _numPeekSamplesPerChunk = _currGetSDI = %d", _currPeekSDI)); return (EVERYTHING_FINE); } }
// Returns the sampleNum of the first sample in chunk with chunk number 'chunkNum' // Note that since the coding of this table does not indicate the total number of // chunks (i.e. don't know how many chunks in last run) this method may return a // sample number that is not valid. This should be taken care of in the exception // handling in the chunkoffset and samplesize atoms MP4_ERROR_CODE SampleToChunkAtom::getFirstSampleNumInChunk(uint32 chunkNum, uint32& SampleNum) { if ((_pfirstChunkVec == NULL) || (_psamplesPerChunkVec == NULL)) { return READ_SAMPLE_TO_CHUNK_ATOM_FAILED; // Error condition } uint32 firstChunkCurrentRun = 0; // chunk number of first chunk in this run uint32 firstChunkNextRun = 0; // chunk number of first chunk in next run uint32 firstSample = 0; // number of first sample in the run of chunks in which chunk 'chunkNum' lies // once we find the correct run, this value holds the sample number of the first // sample in chunk 'chunkNum' uint32 samplesInRun = 0; // Number of samples in the entire run of chunks (not just in each chunk) for (uint32 i = 0; i < _entryCount; i++) { // Go through vector of first chunks in runs if (_parsing_mode == 1) { CheckAndParseEntry(i); } firstChunkCurrentRun = _pfirstChunkVec[i%_stbl_buff_size]; // Get first chunk number for run i if (chunkNum < firstChunkCurrentRun) { // Chunk is in previous run of chunks firstSample -= samplesInRun; // Backtrack to first sample of last run // Now need to find specific chunk and sample in this run if (_parsing_mode == 1) { CheckAndParseEntry(i - 1); } firstChunkCurrentRun = _pfirstChunkVec[(int32)((i-1)%_stbl_buff_size)]; // Backtrack to last run uint32 samplesPerChunk = _psamplesPerChunkVec[(int32)((i-1)%_stbl_buff_size)]; uint32 chunkOffset = chunkNum - firstChunkCurrentRun; // Offset from firstChunk uint32 sampleOffset = chunkOffset * samplesPerChunk; firstSample += sampleOffset; SampleNum = firstSample; return EVERYTHING_FINE; } else if (chunkNum == firstChunkCurrentRun) { // Requested chunk is first in this run SampleNum = firstSample; // Return first sample in this run return EVERYTHING_FINE; } else { // Haven't found chunk in run if ((i + 1) < _entryCount) { if (_parsing_mode == 1) { CheckAndParseEntry(i + 1); } firstChunkNextRun = _pfirstChunkVec[(int32)(((i+1)%_stbl_buff_size))]; // If we are out of range of the vector // This means we are in the last run of chunks int32 numChunks = firstChunkNextRun - firstChunkCurrentRun; samplesInRun = _psamplesPerChunkVec[i%_stbl_buff_size] * numChunks; // Once you advance, this value maintains the // number of samples in the previous run firstSample += samplesInRun; } else { // In last run of chunks - we know the chunk is here // Now need to find specific chunk and sample firstChunkCurrentRun = _pfirstChunkVec[i%_stbl_buff_size]; // Get first chunk number for this run uint32 samplesPerChunk = _psamplesPerChunkVec[i%_stbl_buff_size]; uint32 chunkOffset = chunkNum - firstChunkCurrentRun; // Offset from firstChunk uint32 sampleOffset = chunkOffset * samplesPerChunk; firstSample += sampleOffset; SampleNum = firstSample; return EVERYTHING_FINE; } } } return READ_SAMPLE_TO_CHUNK_ATOM_FAILED; // Error condition }