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
}