Home | History | Annotate | Download | only in src
      1 /* ------------------------------------------------------------------
      2  * Copyright (C) 1998-2009 PacketVideo
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
     13  * express or implied.
     14  * See the License for the specific language governing permissions
     15  * and limitations under the License.
     16  * -------------------------------------------------------------------
     17  */
     18 /*********************************************************************************/
     19 /*     -------------------------------------------------------------------       */
     20 /*                        MPEG-4 CompositionOffsetAtom Class                          */
     21 /*     -------------------------------------------------------------------       */
     22 /*********************************************************************************/
     23 
     24 /*
     25 This atom gives difference between decoding time and composition time on each
     26 sample basis. This atom is optional and must be present only if Decoding time
     27 and Composition Time differ for any samples. As understood that Decoding time
     28 is always less than composition time, the offsets are termed as unsigned
     29 numbers such.
     30 
     31 */
     32 
     33 
     34 #define IMPLEMENT_CompositionOffsetAtom
     35 
     36 #include "compositionoffsetatom.h"
     37 #include "atomutils.h"
     38 
     39 #define CTTS_MIN_SAMPLE_TABLE_SIZE 4096
     40 #define MT_SAMPLECOUNT_INCREMENT 100 //this has to be atleast 3
     41 #define NUMBER_OF_SAMPLE_POPULATES_PER_RUNL 50
     42 #define ENABLE_MT_LOGIC_ON_CTTS_ENTRY_COUNT_VALUE 512
     43 
     44 // Stream-in ctor
     45 CompositionOffsetAtom::CompositionOffsetAtom(MP4_FF_FILE *fp,
     46         uint32 mediaType,
     47         uint32 size,
     48         uint32 type,
     49         OSCL_wString& filename,
     50         uint32 parsingMode):
     51         FullAtom(fp, size, type),
     52         OsclTimerObject(OsclActiveObject::EPriorityNominal, "CompositionOffsetAtom")
     53 {
     54     _psampleCountVec = NULL;
     55     _psampleOffsetVec = NULL;
     56     MT_SampleCount  = NULL;
     57     MT_EntryCount  = NULL;
     58     iMarkerTableCreation = false;
     59     MT_Table_Size = 0;
     60 
     61     _currGetSampleCount = 0;
     62     _currGetIndex = -1;
     63     _currGetTimeOffset = 0;
     64     _currPeekSampleCount = 0;
     65     _currPeekIndex = -1;
     66     _currPeekTimeOffset = 0;
     67 
     68     MT_Counter = 1;
     69     addSampleCount = 0;
     70     prevSampleCount = 0;
     71     entrycountTraversed = 0;
     72     refSample = MT_SAMPLECOUNT_INCREMENT;
     73     MT_j = 1;
     74 
     75     _mediaType = mediaType;
     76     _parsed_entry_cnt = 0;
     77     _fileptr = NULL;
     78     _parsing_mode = 0;
     79     _parsing_mode = parsingMode;
     80 
     81 
     82     _stbl_buff_size = CTTS_MIN_SAMPLE_TABLE_SIZE;
     83     _next_buff_number = 0;
     84     _curr_buff_number = 0;
     85     _curr_entry_point = 0;
     86     _stbl_fptr_vec = NULL;
     87 
     88     iLogger = PVLogger::GetLoggerObject("mp4ffparser");
     89     iStateVarLogger = PVLogger::GetLoggerObject("mp4ffparser_mediasamplestats");
     90     iParsedDataLogger = PVLogger::GetLoggerObject("mp4ffparser_parseddata");
     91 
     92     iMarkerTableCreation = false;
     93 
     94     /* Add this AO to the scheduler */
     95     if (OsclExecScheduler::Current() != NULL)
     96     {
     97         if (!IsAdded())
     98         {
     99             AddToScheduler();
    100         }
    101     }
    102 
    103     if (_success)
    104     {
    105         if (!AtomUtils::read32(fp, _entryCount))
    106         {
    107             _success = false;
    108         }
    109 
    110         PVMF_MP4FFPARSER_LOGPARSEDINFO((0, "CompositionOffsetAtom::CompositionOffsetAtom- _entryCount =%d", _entryCount));
    111         uint32 dataSize = _size - (DEFAULT_FULL_ATOM_SIZE + 4);
    112 
    113         uint32 entrySize = (4 + 4);
    114 
    115         if ((_entryCount*entrySize) > dataSize)
    116         {
    117             _success = false;
    118         }
    119 
    120         if (_success)
    121         {
    122             if (_entryCount > 0)
    123             {
    124                 if (parsingMode == 1)
    125                 {
    126                     // cache size is 4K so that optimization
    127                     // should work if entry_count is greater than 4K
    128                     if (_entryCount > _stbl_buff_size)
    129                     {
    130 
    131                         uint32 fptrBuffSize = (_entryCount / _stbl_buff_size) + 1;
    132 
    133                         PV_MP4_FF_ARRAY_NEW(NULL, uint32, (fptrBuffSize), _stbl_fptr_vec);
    134                         if (_stbl_fptr_vec == NULL)
    135                         {
    136                             _success = false;
    137                             _mp4ErrorCode = MEMORY_ALLOCATION_FAILED;
    138                             return;
    139                         }
    140 
    141 
    142                         PV_MP4_FF_ARRAY_NEW(NULL, uint32, (_stbl_buff_size), _psampleCountVec);
    143                         if (_psampleCountVec == NULL)
    144                         {
    145                             _success = false;
    146                             _mp4ErrorCode = MEMORY_ALLOCATION_FAILED;
    147                             return;
    148                         }
    149 
    150 
    151                         PV_MP4_FF_ARRAY_NEW(NULL, uint32, (_stbl_buff_size), _psampleOffsetVec);
    152                         if (_psampleOffsetVec == NULL)
    153                         {
    154                             PV_MP4_ARRAY_DELETE(NULL, _psampleOffsetVec);
    155                             _psampleOffsetVec = NULL;
    156                             _success = false;
    157                             _mp4ErrorCode = MEMORY_ALLOCATION_FAILED;
    158                             return;
    159                         }
    160 
    161                         for (uint32 idx = 0; idx < _stbl_buff_size; idx++)  //initialization
    162                         {
    163                             _psampleCountVec[idx] = 0;
    164                             _psampleOffsetVec[idx] = 0;
    165                         }
    166 
    167                         OsclAny* ptr = (MP4_FF_FILE *)(oscl_malloc(sizeof(MP4_FF_FILE)));
    168                         if (ptr == NULL)
    169                         {
    170                             _success = false;
    171                             _mp4ErrorCode = MEMORY_ALLOCATION_FAILED;
    172                             return;
    173                         }
    174 
    175                         _fileptr = OSCL_PLACEMENT_NEW(ptr, MP4_FF_FILE());
    176                         _fileptr->_fileServSession = fp->_fileServSession;
    177                         _fileptr->_pvfile.SetCPM(fp->_pvfile.GetCPM());
    178 
    179                         if (AtomUtils::OpenMP4File(filename,
    180                                                    Oscl_File::MODE_READ | Oscl_File::MODE_BINARY,
    181                                                    _fileptr) != 0)
    182                         {
    183                             _success = false;
    184                             _mp4ErrorCode = FILE_OPEN_FAILED;
    185                         }
    186 
    187                         _fileptr->_fileSize = fp->_fileSize;
    188 
    189                         int32 _head_offset = AtomUtils::getCurrentFilePosition(fp);
    190                         AtomUtils::seekFromCurrPos(fp, dataSize);
    191                         AtomUtils::seekFromStart(_fileptr, _head_offset);
    192 
    193                         return;
    194                     }
    195                     else
    196                     {
    197                         _parsing_mode = 0;
    198                         _stbl_buff_size = _entryCount;
    199                     }
    200                 }
    201                 else
    202                 {
    203                     _stbl_buff_size = _entryCount;
    204                 }
    205 
    206                 PV_MP4_FF_ARRAY_NEW(NULL, uint32, (_entryCount), _psampleCountVec);
    207                 if (_psampleCountVec == NULL)
    208                 {
    209                     _success = false;
    210                     _mp4ErrorCode = MEMORY_ALLOCATION_FAILED;
    211                     return;
    212                 }
    213 
    214                 PV_MP4_FF_ARRAY_NEW(NULL, uint32, (_entryCount), _psampleOffsetVec);
    215                 if (_psampleOffsetVec == NULL)
    216                 {
    217                     PV_MP4_ARRAY_DELETE(NULL, _psampleOffsetVec);
    218                     _psampleOffsetVec = NULL;
    219                     _success = false;
    220                     _mp4ErrorCode = MEMORY_ALLOCATION_FAILED;
    221                     return;
    222                 }
    223 
    224                 for (uint32 idx = 0; idx < _entryCount; idx++)  //initialization
    225                 {
    226                     _psampleCountVec[idx] = 0;
    227                     _psampleOffsetVec[idx] = 0;
    228                 }
    229 
    230                 uint32 number = 0;
    231                 uint32 offset = 0;
    232                 for (_parsed_entry_cnt = 0; _parsed_entry_cnt < _entryCount; _parsed_entry_cnt++)
    233                 {
    234                     if (!AtomUtils::read32(fp, number))
    235                     {
    236                         _success = false;
    237                         break;
    238                     }
    239                     if (!AtomUtils::read32(fp, offset))
    240                     {
    241                         _success = false;
    242                         break;
    243                     }
    244                     _psampleCountVec[_parsed_entry_cnt] = (number);
    245                     _psampleOffsetVec[_parsed_entry_cnt] = (offset);
    246                 }
    247             }
    248         }
    249 
    250         if (!_success)
    251         {
    252             _mp4ErrorCode = READ_TIME_TO_SAMPLE_ATOM_FAILED;
    253         }
    254     }
    255     else
    256     {
    257         if (_mp4ErrorCode != ATOM_VERSION_NOT_SUPPORTED)
    258             _mp4ErrorCode = READ_TIME_TO_SAMPLE_ATOM_FAILED;
    259     }
    260 }
    261 
    262 void CompositionOffsetAtom::setSamplesCount(uint32 SamplesCount)
    263 {
    264     _iTotalNumSamplesInTrack = SamplesCount;
    265 
    266     if (_entryCount > ENABLE_MT_LOGIC_ON_CTTS_ENTRY_COUNT_VALUE)
    267     {
    268         //Make this AO active so Run() will be called when scheduler is started
    269         if (OsclExecScheduler::Current() != NULL)
    270         {
    271             RunIfNotReady();
    272         }
    273     }
    274 }
    275 
    276 bool CompositionOffsetAtom::ParseEntryUnit(uint32 entry_cnt)
    277 {
    278     const uint32 threshold = 1024;
    279     entry_cnt += threshold;
    280 
    281     if (entry_cnt > _entryCount)
    282     {
    283         entry_cnt = _entryCount;
    284     }
    285 
    286     uint32 number = 0;
    287     uint32 offset = 0;
    288     while (_parsed_entry_cnt < entry_cnt)
    289     {
    290         _curr_entry_point = _parsed_entry_cnt % _stbl_buff_size;
    291         _curr_buff_number = _parsed_entry_cnt / _stbl_buff_size;
    292 
    293         if (_curr_buff_number  == _next_buff_number)
    294         {
    295             uint32 currFilePointer = AtomUtils::getCurrentFilePosition(_fileptr);
    296             _stbl_fptr_vec[_curr_buff_number] = currFilePointer;
    297             _next_buff_number++;
    298         }
    299 
    300         if (!_curr_entry_point)
    301         {
    302             uint32 currFilePointer = _stbl_fptr_vec[_curr_buff_number];
    303             AtomUtils::seekFromStart(_fileptr, currFilePointer);
    304         }
    305 
    306         if (!AtomUtils::read32(_fileptr, number))
    307         {
    308             return false;
    309         }
    310 
    311         if (!AtomUtils::read32(_fileptr, offset))
    312         {
    313             return false;
    314         }
    315         _psampleCountVec[_curr_entry_point] = (number);
    316         _psampleOffsetVec[_curr_entry_point] = (offset);
    317         _parsed_entry_cnt++;
    318     }
    319     return true;
    320 }
    321 
    322 // Destructor
    323 CompositionOffsetAtom::~CompositionOffsetAtom()
    324 {
    325     if (_psampleCountVec != NULL)
    326         PV_MP4_ARRAY_DELETE(NULL, _psampleCountVec);
    327 
    328     if (_psampleOffsetVec != NULL)
    329         PV_MP4_ARRAY_DELETE(NULL, _psampleOffsetVec);
    330 
    331     if (_stbl_fptr_vec != NULL)
    332         PV_MP4_ARRAY_DELETE(NULL, _stbl_fptr_vec);
    333 
    334     deleteMarkerTable();
    335 
    336     if (_fileptr != NULL)
    337     {
    338         if (_fileptr->IsOpen())
    339         {
    340             AtomUtils::CloseMP4File(_fileptr);
    341         }
    342         oscl_free(_fileptr);
    343     }
    344 
    345     if (IsAdded())
    346     {
    347         RemoveFromScheduler();
    348     }
    349 
    350 }
    351 
    352 // Return the number of samples  at index
    353 uint32
    354 CompositionOffsetAtom::getSampleCountAt(int32 index)
    355 {
    356     if (_psampleCountVec == NULL)
    357     {
    358         return (uint32) PV_ERROR;
    359     }
    360 
    361     if (index < (int32)_entryCount)
    362     {
    363         if (_parsing_mode == 1)
    364             CheckAndParseEntry(index);
    365 
    366         return (int32)(_psampleCountVec[index%_stbl_buff_size]);
    367     }
    368     else
    369     {
    370         PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>CompositionOffsetAtom::getSampleCountAt index = %d", index));
    371         return (uint32) PV_ERROR;
    372     }
    373 }
    374 
    375 // Return sample offset at index
    376 int32
    377 CompositionOffsetAtom::getSampleOffsetAt(int32 index)
    378 {
    379     if (_psampleOffsetVec == NULL)
    380     {
    381         return PV_ERROR;
    382     }
    383 
    384     if (index < (int32)_entryCount)
    385     {
    386         if (_parsing_mode == 1)
    387             CheckAndParseEntry(index);
    388 
    389         return (int32)(_psampleOffsetVec[index%_stbl_buff_size]);
    390     }
    391     else
    392     {
    393         PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>CompositionOffsetAtom::getSampleOffsetAt index = %d", index));
    394         return PV_ERROR;
    395     }
    396 }
    397 
    398 int32
    399 CompositionOffsetAtom::getTimeOffsetForSampleNumberPeek(uint32 sampleNum)
    400 {
    401     // It is assumed that sample 0 has a ts of 0 - i.e. the first
    402     // entry in the table starts with the delta between sample 1 and sample 0
    403     if ((_psampleOffsetVec == NULL) ||
    404             (_psampleCountVec == NULL) ||
    405             (_entryCount == 0))
    406     {
    407         return PV_ERROR;
    408     }
    409 
    410     // note that sampleNum is a zero based index while _currGetSampleCount is 1 based index
    411     if (sampleNum < _currPeekSampleCount)
    412     {
    413         return (_currPeekTimeOffset);
    414     }
    415     else
    416     {
    417         do
    418         {
    419             _currPeekIndex++;
    420             if (_parsing_mode)
    421                 CheckAndParseEntry(_currPeekIndex);
    422 
    423             _currPeekSampleCount += _psampleCountVec[_currPeekIndex%_stbl_buff_size];
    424             _currPeekTimeOffset    = _psampleOffsetVec[_currPeekIndex%_stbl_buff_size];
    425         }
    426         while (_currPeekSampleCount == 0);
    427 
    428         PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "CompositionOffsetAtom::getTimeOffsetForSampleNumberPeek- _currPeekIndex =%d", _currPeekIndex));
    429         PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "CompositionOffsetAtom::getTimeOffsetForSampleNumberPeek- _currPeekSampleCount =%d", _currPeekSampleCount));
    430         PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "CompositionOffsetAtom::getTimeOffsetForSampleNumberPeek- _currPeekTimeOffset =%d", _currPeekTimeOffset));
    431 
    432         if (sampleNum < _currPeekSampleCount)
    433         {
    434             return (_currPeekTimeOffset);
    435         }
    436         else
    437         {
    438             PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>CompositionOffsetAtom::getTimeOffsetForSampleNumberPeek sampleNum = %d", sampleNum));
    439             return (PV_ERROR);
    440         }
    441     }
    442 
    443 }
    444 
    445 // This is the most widely used API
    446 // Returns the offset (ms) for the  sample given by num.  This is used when
    447 // randomly accessing a frame and the timestamp has not been accumulated.
    448 int32 CompositionOffsetAtom::getTimeOffsetForSampleNumberGet(uint32 sampleNum)
    449 {
    450     if ((_psampleOffsetVec == NULL) ||
    451             (_psampleCountVec == NULL) ||
    452             (_entryCount == 0))
    453     {
    454         return PV_ERROR;
    455     }
    456 
    457     // note that sampleNum is a zero based index while _currGetSampleCount is 1 based index
    458     if (sampleNum < _currGetSampleCount)
    459     {
    460         return (_currGetTimeOffset);
    461     }
    462     else
    463     {
    464 
    465         do
    466         {
    467             _currGetIndex++;
    468             if (_parsing_mode)
    469                 CheckAndParseEntry(_currGetIndex);
    470             _currGetSampleCount += _psampleCountVec[_currGetIndex%_stbl_buff_size];
    471             _currGetTimeOffset    = _psampleOffsetVec[_currGetIndex%_stbl_buff_size];
    472         }
    473         while (_currGetSampleCount == 0);
    474 
    475         PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "CompositionOffsetAtom::getTimeOffsetForSampleNumberGet- _currGetIndex =%d", _currGetIndex));
    476         PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "CompositionOffsetAtom::getTimeOffsetForSampleNumberGet- _currGetSampleCount =%d", _currGetSampleCount));
    477         PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "CompositionOffsetAtom::getTimeOffsetForSampleNumberGet- _currGetTimeOffset =%d", _currGetTimeOffset));
    478 
    479         if (sampleNum < _currGetSampleCount)
    480         {
    481             return (_currGetTimeOffset);
    482         }
    483         else
    484         {
    485             PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>TimeToSampleAtom::getTimeDeltaForSampleNumberGet sampleNum = %d", sampleNum));
    486             return (PV_ERROR);
    487         }
    488     }
    489 
    490 }
    491 
    492 
    493 
    494 
    495 
    496 int32 CompositionOffsetAtom::getTimeOffsetFromMT(uint32 samplenum, uint32 currEC, uint32 currSampleCount)
    497 {
    498     if ((_psampleOffsetVec == NULL) ||
    499             (_psampleCountVec == NULL) ||
    500             (_entryCount == 0))
    501     {
    502         return PV_ERROR;
    503     }
    504 
    505     if (samplenum < currSampleCount)
    506     { // Sample num within current entry
    507         if (_parsing_mode == 1)
    508             CheckAndParseEntry(currEC);
    509 
    510         PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "CompositionOffsetAtom::getTimestampForSampleNumber- Time StampOffset = %d", _psampleOffsetVec[currEC%_stbl_buff_size]));
    511         return _psampleOffsetVec[currEC%_stbl_buff_size];
    512     }
    513     else
    514     {
    515 
    516         for (uint32 i = currEC + 1; i < _entryCount; i++)
    517         {
    518             if (_parsing_mode == 1)
    519                 CheckAndParseEntry(i);
    520 
    521 
    522             if (samplenum < (currSampleCount + _psampleCountVec[i%_stbl_buff_size]))
    523             {
    524                 PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "CompositionOffsetAtom::getTimestampForSampleNumber- Time StampOffset = %d", _psampleOffsetVec[i%_stbl_buff_size]));
    525                 return _psampleOffsetVec[i%_stbl_buff_size];
    526             }
    527             else
    528             {
    529                 currSampleCount += _psampleCountVec[i%_stbl_buff_size];
    530             }
    531         }
    532     }
    533 
    534     // Went past end of list - not a valid sample number
    535     return PV_ERROR;
    536 }
    537 
    538 int32 CompositionOffsetAtom::getTimeOffsetForSampleNumber(uint32 num)
    539 {
    540     uint32 currSample = 0;
    541     uint32 currEC = 0;
    542 
    543     if (iMarkerTableCreation == true)
    544     {
    545         uint32 MT_EC = num / (MT_SAMPLECOUNT_INCREMENT - 1); //where MT_SAMPLECOUNT_INCREMENT is the granuality of sample separation in Marker Table
    546 
    547         if (MT_EC > ((_iTotalNumSamplesInTrack / MT_SAMPLECOUNT_INCREMENT) - 1))
    548         {
    549             //boundary check, MT_EC valid value will always be between 0 to (_samples_count/MT_SAMPLECOUNT_INCREMENT)-1
    550             MT_EC = (_iTotalNumSamplesInTrack / MT_SAMPLECOUNT_INCREMENT) - 1;
    551         }
    552         //assign the last marker entry count created till now to look for sample from this location onwards instead of from start
    553         if (MT_EC > MT_Counter)
    554             MT_EC = MT_Counter;
    555 
    556         while ((num < MT_SampleCount[MT_EC]) && (MT_EC > 0))
    557         {
    558             //This check was put keeping in mind that it may happen (due to rounding off error),
    559             //that we choose a MT_EC greater than desired. So to avoid such a scenario.
    560             MT_EC = MT_EC - 1;
    561             currSample = MT_SampleCount[MT_EC];
    562             currEC = MT_EntryCount[MT_EC];
    563         }
    564 
    565         currSample = MT_SampleCount[MT_EC];
    566         currEC = MT_EntryCount[MT_EC];
    567 
    568 
    569 
    570         return getTimeOffsetFromMT(num, currEC, currSample);
    571     }
    572     else
    573     {
    574         if ((_psampleOffsetVec == NULL) ||
    575                 (_psampleCountVec == NULL) ||
    576                 (_entryCount == 0))
    577         {
    578             return PV_ERROR;
    579         }
    580 
    581         uint32 sampleCount = 0;
    582 
    583         for (uint32 i = 0; i < _entryCount; i++)
    584         {
    585             if (_parsing_mode == 1)
    586                 CheckAndParseEntry(i);
    587 
    588             if (num < (sampleCount + _psampleCountVec[i%_stbl_buff_size]))
    589             { // Sample num within current entry
    590 
    591                 PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "CompositionOffsetAtom::getTimestampForSampleNumber- Time StampOffset = %d", _psampleOffsetVec[i%_stbl_buff_size]));
    592                 return _psampleOffsetVec[i%_stbl_buff_size];
    593             }
    594             else
    595             {
    596                 sampleCount += _psampleCountVec[i%_stbl_buff_size];
    597             }
    598         }
    599 
    600         // Went past end of list - not a valid sample number
    601         return PV_ERROR;
    602     }
    603 }
    604 
    605 int32
    606 CompositionOffsetAtom::resetStateVariables()
    607 {
    608     uint32 sampleNum = 0;
    609     return (resetStateVariables(sampleNum));
    610 }
    611 
    612 int32
    613 CompositionOffsetAtom::resetStateVariables(uint32 sampleNum)
    614 {
    615     _currGetSampleCount = 0;
    616     _currGetIndex = -1;
    617     _currGetTimeOffset = 0;
    618     _currPeekSampleCount = 0;
    619     _currPeekIndex = -1;
    620     _currPeekTimeOffset = 0;
    621 
    622     // It is assumed that sample 0 has a ts of 0 - i.e. the first
    623     // entry in the table starts with the delta between sample 1 and sample 0
    624     if ((_psampleOffsetVec == NULL) ||
    625             (_psampleCountVec == NULL) ||
    626             (_entryCount == 0))
    627     {
    628         return PV_ERROR;
    629     }
    630 
    631     if (_parsing_mode)
    632     {
    633         if (_parsed_entry_cnt == 0)
    634         {
    635             ParseEntryUnit(sampleNum);
    636         }
    637     }
    638 
    639     for (uint32 i = 0; i < _entryCount; i++)
    640     {
    641         _currPeekIndex++;
    642         _currPeekSampleCount += _psampleCountVec[i%_stbl_buff_size];
    643         _currPeekTimeOffset    = _psampleOffsetVec[i%_stbl_buff_size];
    644 
    645         _currGetIndex++;
    646         _currGetSampleCount += _psampleCountVec[i%_stbl_buff_size];
    647         _currGetTimeOffset    = _psampleOffsetVec[i%_stbl_buff_size];
    648 
    649         if (sampleNum <= _currPeekSampleCount)
    650         {
    651             return (EVERYTHING_FINE);
    652         }
    653 
    654     }
    655 
    656     // Went past end of list - not a valid sample number
    657     return PV_ERROR;
    658 }
    659 
    660 int32 CompositionOffsetAtom::resetPeekwithGet()
    661 {
    662     _currPeekSampleCount = _currGetSampleCount;
    663     _currPeekIndex = _currGetIndex;
    664     _currPeekTimeOffset = _currGetTimeOffset;
    665     return (EVERYTHING_FINE);
    666 }
    667 
    668 void CompositionOffsetAtom::CheckAndParseEntry(uint32 i)
    669 {
    670     if (i >= _parsed_entry_cnt)
    671     {
    672         ParseEntryUnit(i);
    673     }
    674     else
    675     {
    676         uint32 entryLoc = i / _stbl_buff_size;
    677         if (_curr_buff_number != entryLoc)
    678         {
    679             _parsed_entry_cnt = entryLoc * _stbl_buff_size;
    680             while (_parsed_entry_cnt <= i)
    681                 ParseEntryUnit(_parsed_entry_cnt);
    682         }
    683     }
    684 }
    685 
    686 void CompositionOffsetAtom::Run()
    687 {
    688     // Create it for the first time
    689     if ((MT_SampleCount == NULL) && (MT_EntryCount == NULL))
    690     {
    691         int32 status = createMarkerTable();
    692         if (status == PVMFFailure)
    693         {
    694             OSCL_LEAVE(OsclErrNoMemory);
    695         }
    696         iMarkerTableCreation = true;
    697     }
    698 
    699     populateMarkerTable();
    700 
    701     // check for entry count being exhausted.. table iterated completely
    702     if ((entrycountTraversed < _entryCount) && (refSample < _iTotalNumSamplesInTrack)
    703             && (MT_Counter < _iTotalNumSamplesInTrack / MT_SAMPLECOUNT_INCREMENT))
    704     {
    705         RunIfNotReady();
    706     }
    707 
    708     return;
    709 
    710 }
    711 //Populate the Marker Table with SampleCount and EntryCount values
    712 //for every nth sample starting from n-1, where n=MT_SAMPLECOUNT_INCREMENT.
    713 
    714 uint32 CompositionOffsetAtom::populateMarkerTable()
    715 {
    716     uint32 increment = MT_SAMPLECOUNT_INCREMENT;
    717     uint32 numPopulated = 0;
    718 
    719 
    720 
    721     for (uint32 i = entrycountTraversed; i < _entryCount; i++)
    722     {
    723 
    724         if (refSample < _iTotalNumSamplesInTrack)
    725         {
    726 
    727             if (i == 0)
    728             {
    729                 if (_parsing_mode == 1)
    730                     CheckAndParseEntry(i);
    731 
    732                 MT_SampleCount[0] = _psampleCountVec[i%_stbl_buff_size];
    733                 prevSampleCount = MT_SampleCount[0];
    734                 addSampleCount = MT_SampleCount[0];
    735             }
    736             else if (addSampleCount < refSample)
    737             {
    738                 if (_parsing_mode == 1)
    739                     CheckAndParseEntry(MT_j);
    740 
    741                 prevSampleCount = addSampleCount;
    742                 addSampleCount += _psampleCountVec[MT_j%_stbl_buff_size];
    743                 MT_j++;
    744             }
    745             else
    746             {
    747                 entrycountTraversed = i - 1;
    748                 i = i - 1;
    749                 refSample += increment;
    750                 MT_SampleCount[MT_Counter] = prevSampleCount;
    751                 //Incase SampleCounts have same value for consecutive MT entries,
    752                 //even the same EntryCount should be mentioned in the Marker Table.
    753                 if (MT_SampleCount[MT_Counter] == MT_SampleCount[MT_Counter-1])
    754                 {
    755                     MT_EntryCount[MT_Counter] = MT_EntryCount[MT_Counter-1];
    756                 }
    757                 else
    758                 {
    759                     MT_EntryCount[MT_Counter] = MT_j - 2;
    760                 }
    761 
    762 
    763                 MT_Counter++;
    764                 numPopulated++;
    765                 if ((numPopulated == NUMBER_OF_SAMPLE_POPULATES_PER_RUNL) ||
    766                         (MT_Counter >= _iTotalNumSamplesInTrack / MT_SAMPLECOUNT_INCREMENT))
    767                     break;
    768             }
    769         }
    770         else
    771         {
    772             break;
    773         }
    774 
    775     }
    776 
    777     return numPopulated;
    778 
    779 }
    780 void CompositionOffsetAtom::deleteMarkerTable()
    781 {
    782     if (MT_SampleCount != NULL)
    783         PV_MP4_ARRAY_DELETE(NULL, MT_SampleCount);
    784 
    785     if (MT_EntryCount != NULL)
    786         PV_MP4_ARRAY_DELETE(NULL, MT_EntryCount);
    787 }
    788 // responsible for creation of data sturcture inside the table.
    789 PVMFStatus CompositionOffsetAtom::createMarkerTable()
    790 {
    791 
    792     MT_Table_Size = (_iTotalNumSamplesInTrack / MT_SAMPLECOUNT_INCREMENT);
    793     PV_MP4_FF_ARRAY_NEW(NULL, uint32, (MT_Table_Size), MT_SampleCount);
    794 
    795     if (MT_SampleCount == NULL)
    796     {
    797         PV_MP4_ARRAY_DELETE(NULL, MT_SampleCount);
    798         MT_SampleCount = NULL;
    799         _success = false;
    800         _mp4ErrorCode = MEMORY_ALLOCATION_FAILED;
    801         return PVMFFailure;
    802     }
    803 
    804     PV_MP4_FF_ARRAY_NEW(NULL, uint32, (MT_Table_Size), MT_EntryCount);
    805 
    806     if (MT_EntryCount == NULL)
    807     {
    808         PV_MP4_ARRAY_DELETE(NULL, MT_EntryCount);
    809         MT_EntryCount = NULL;
    810         PV_MP4_ARRAY_DELETE(NULL, MT_SampleCount);
    811         MT_SampleCount = NULL;
    812         _success = false;
    813         _mp4ErrorCode = MEMORY_ALLOCATION_FAILED;
    814         return PVMFFailure;
    815     }
    816 
    817     for (uint32 idx = 0; idx < MT_Table_Size; idx++)  //initialization
    818     {
    819 
    820         MT_EntryCount[idx] = 0;
    821         MT_SampleCount[idx] = 0;
    822     }
    823 
    824     return PVMFSuccess;
    825 }
    826 
    827 
    828