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 SampleTableAtom Class                          */
21/*     -------------------------------------------------------------------       */
22/*********************************************************************************/
23/*
24    This SampleTableAtom Class contains all the time and data indexing of the
25    media samples in a track.
26*/
27
28
29#define IMPLEMENT_SampleTableAtom
30
31//HEADER FILES REQD FOR MULTIPLE SAMPLE RETRIEVAL API
32#include "sampletableatom.h"
33#include "atomutils.h"
34#include "atomdefs.h"
35#include "oscl_media_data.h"
36#include "pv_gau.h"
37#include "amrdecoderspecificinfo.h"
38#include "oscl_int64_utils.h"
39#if (PVLOGGER_INST_LEVEL > PVLOGMSG_INST_LLDBG)
40#include "oscl_tickcount.h"
41
42#define PV_MP4_PARSER_SAMPLE_READ_DIAGLOG_THRESHOLD_IN_MS 5
43#endif
44
45// Stream-in ctor
46SampleTableAtom::SampleTableAtom(MP4_FF_FILE *fp,
47                                 uint32 mediaType,
48                                 OSCL_wString& filename,
49                                 uint32 size,
50                                 uint32 type,
51                                 bool oPVContentDownloadable,
52                                 uint32 parsingMode)
53        : Atom(fp, size, type),
54        _currentPlaybackSampleTimestamp(0),
55        _currentPlaybackSampleNumber(0),
56        _trackStartTSOffset(0),
57        _fileSize(0),
58        _IsUpdateFileSize(0)
59{
60    _ptimeToSampleAtom      = NULL;
61    _pcompositionOffsetAtom = NULL;
62    _psampleDescriptionAtom = NULL;
63    _psampleSizeAtom        = NULL;
64    _psampleToChunkAtom     = NULL;
65    _pchunkOffsetAtom       = NULL;
66    _psyncSampleAtom        = NULL;
67
68    _SDIndex = 0;
69
70    SamplesCount = 0;
71
72    _oMultipleSampleDescription = false;
73    _numAMRFramesPerSample = 0;
74    _pAMRTempBuffer = NULL;
75    _oResidualSample = false;
76    _remainingFramesInSample = 0;
77    _amrTempBufferOffset = 0;
78    _amrFrameDelta = 0;
79    _pinput   = NULL;
80    _commonFilePtr = NULL;
81    _currChunkOffset = 0;
82
83    _defaultMimeType += _STRLIT_WCHAR("UNKNOWN");
84
85    iLogger = PVLogger::GetLoggerObject("mp4ffparser");
86    iStateVarLogger = PVLogger::GetLoggerObject("mp4ffparser_mediasamplestats");
87    iParsedDataLogger = PVLogger::GetLoggerObject("mp4ffparser_parseddata");
88    iDiagnosticsLogger = PVLogger::GetLoggerObject("pvplayerdiagnostics.mp4ffparser");
89
90    _oPVContentDownloadable = oPVContentDownloadable;
91
92    _parsingMode = parsingMode;
93
94    if (_success)
95    {
96        _filename = filename;
97        _pinput   = NULL;
98
99        OsclAny*ptr = oscl_malloc(sizeof(MP4_FF_FILE));
100        if (ptr == NULL)
101        {
102            _success = false;
103            _mp4ErrorCode = MEMORY_ALLOCATION_FAILED;
104            return;
105        }
106        _pinput = OSCL_PLACEMENT_NEW(ptr, MP4_FF_FILE());
107        _pinput->_fileServSession = fp->_fileServSession;
108        _pinput->_pvfile.SetCPM(fp->_pvfile.GetCPM());
109
110#ifndef OPEN_FILE_ONCE_PER_TRACK
111        ptr = oscl_malloc(sizeof(MP4_FF_FILE));
112        if (ptr == NULL)
113        {
114            _success = false;
115            _mp4ErrorCode = MEMORY_ALLOCATION_FAILED;
116            return;
117        }
118        _commonFilePtr = OSCL_PLACEMENT_NEW(ptr, MP4_FF_FILE(*fp));
119
120#endif
121
122        _currentPlaybackSampleNumber = 0; // Initializing playback start point
123
124        _pparent = NULL;
125        _success = true;
126
127        int32 count = _size - DEFAULT_ATOM_SIZE;
128
129        while (count > 0)
130        {
131            uint32 atomType = UNKNOWN_ATOM;
132            uint32 atomSize = 0;
133
134            AtomUtils::getNextAtomType(fp, atomSize, atomType);
135
136            if (atomType == TIME_TO_SAMPLE_ATOM)
137            {   //"stts"
138                PV_MP4_FF_NEW(fp->auditCB, TimeToSampleAtom,
139                              (fp, mediaType, atomSize,
140                               atomType, filename, parsingMode),
141                              _ptimeToSampleAtom);
142
143                // Check for success
144                if (!_ptimeToSampleAtom->MP4Success())
145                {
146                    _success = false;
147                    _mp4ErrorCode = _ptimeToSampleAtom->GetMP4Error();
148                    return;
149                }
150                _ptimeToSampleAtom->setParent(this);
151                count -= _ptimeToSampleAtom->getSize();
152            }
153
154            else if (atomType == COMPOSITION_OFFSET_ATOM)
155            {   //"ctts"
156                PV_MP4_FF_NEW(fp->auditCB, CompositionOffsetAtom,
157                              (fp, mediaType, atomSize,
158                               atomType, filename, parsingMode),
159                              _pcompositionOffsetAtom);
160
161                // Check for success
162                if (!_pcompositionOffsetAtom->MP4Success())
163                {
164                    _success = false;
165                    _mp4ErrorCode = _pcompositionOffsetAtom->GetMP4Error();
166                    return;
167                }
168                _pcompositionOffsetAtom->setParent(this);
169                count -= _pcompositionOffsetAtom->getSize();
170            }
171
172            else if ((atomType == UUID_ATOM)
173                     || (atomType == SHADOW_SYNC_SAMPLE_ATOM)
174                     || (atomType == UNKNOWN_ATOM)
175                     || (atomType == USER_DATA_ATOM)
176                     || (atomType == DEGRADATION_PRIORITY_ATOM))
177            {
178                if (atomSize < DEFAULT_ATOM_SIZE)
179                {
180                    _success = false;
181                    _mp4ErrorCode = ZERO_OR_NEGATIVE_ATOM_SIZE;
182                    PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>SampleTableAtom::SampleTableAtom ZERO_OR_NEGATIVE_ATOM_SIZE"));
183                    break;
184                }
185                if (count < (int32)atomSize)
186                {
187                    _success = false;
188                    _mp4ErrorCode = READ_FAILED;
189                    PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>SampleTableAtom::SampleTableAtom READ FAILED count<atomSize"));
190                    break;
191                }
192                count -= atomSize;
193                atomSize -= DEFAULT_ATOM_SIZE;
194                AtomUtils::seekFromCurrPos(fp, atomSize);
195            }
196            else if (atomType == SAMPLE_DESCRIPTION_ATOM)
197            {
198                int32 myOffset = AtomUtils::getCurrentFilePosition(fp);
199                //"stsd"
200                if (_psampleDescriptionAtom == NULL)
201                {
202                    PV_MP4_FF_NEW(fp->auditCB, SampleDescriptionAtom, (fp, mediaType, atomSize, atomType), _psampleDescriptionAtom);
203
204                    // Check for success
205                    if (!_psampleDescriptionAtom->MP4Success())
206                    {
207                        _success = false;
208                        _mp4ErrorCode = _psampleDescriptionAtom->GetMP4Error();
209                        PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>SampleTableAtom::SampleTableAtom Sample Description Atom Failed"));
210                        return;
211                    }
212                    _psampleDescriptionAtom->setParent(this);
213                    count -= _psampleDescriptionAtom->getSize();
214
215                    if (_psampleDescriptionAtom->Is3GPPAMR())
216                    {
217                        AMRSampleEntry *entry  = _psampleDescriptionAtom->getAMRSampleEntry();
218                        AMRSpecificAtom *amrAtom = NULL;
219                        _numAMRFramesPerSample = 0;
220
221                        if (entry != NULL)
222                        {
223                            amrAtom = entry->getDecoderSpecificInfo();
224                            if (amrAtom != NULL)
225                                _numAMRFramesPerSample = amrAtom->getFramesPerSample();
226                        }
227
228                        if (_numAMRFramesPerSample == 0)
229                        {
230                            _success = false;
231                            _mp4ErrorCode = READ_AMR_SAMPLE_ENTRY_FAILED;
232                            PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>SampleTableAtom::SampleTableAtom Read AMR SAmple Entry Failed"));
233                            return;
234                        }
235
236                        _pAMRTempBuffer = (uint8 *)(oscl_malloc(sizeof(uint8) * 512));
237                    }
238                    else
239                    {
240                        if (_psampleDescriptionAtom->getObjectTypeIndication() == AMR_AUDIO)
241                        {
242                            _numAMRFramesPerSample = 1;
243                        }
244                        else
245                        {
246                            _numAMRFramesPerSample = 0;
247                        }
248                    }
249                }
250                else
251                {
252                    //Duplicate stsd++++
253                    _oMultipleSampleDescription = true;
254                }
255                atomSize -= DEFAULT_ATOM_SIZE;
256                atomSize += myOffset;
257                AtomUtils::seekFromStart(fp, atomSize);
258            }
259            else if (atomType == SAMPLE_SIZE_ATOM)
260            { //"stsz"
261                PV_MP4_FF_NEW(fp->auditCB, SampleSizeAtom,
262                              (fp, mediaType, atomSize, atomType,
263                               filename, parsingMode),
264                              _psampleSizeAtom);
265
266                SamplesCount = _psampleSizeAtom->getSampleCount();
267                // Check for success
268                if (!_psampleSizeAtom->MP4Success())
269                {
270                    _success = false;
271                    _mp4ErrorCode = _psampleSizeAtom->GetMP4Error();
272                    PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>SampleTableAtom::Sample Sized Atom Failed"));
273                    return;
274                }
275                _psampleSizeAtom->setParent(this);
276                count -= _psampleSizeAtom->getSize();
277            }
278            else if (atomType == SAMPLE_TO_CHUNK_ATOM)
279            {
280                //"stsc"
281                PV_MP4_FF_NEW(fp->auditCB, SampleToChunkAtom, (fp, atomSize, atomType, filename, parsingMode), _psampleToChunkAtom);
282
283                // Check for success
284                if (!_psampleToChunkAtom->MP4Success())
285                {
286                    _success = false;
287                    _mp4ErrorCode = _psampleToChunkAtom->GetMP4Error();
288                    PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>SampleTableAtom::Sample to chunk atom failed"));
289                    return;
290                }
291                _psampleToChunkAtom->setParent(this);
292                count -= _psampleToChunkAtom->getSize();
293            }
294            else if (atomType == CHUNK_OFFSET_ATOM)
295            {
296                //"stco"
297                PV_MP4_FF_NEW(fp->auditCB, ChunkOffsetAtom, (fp, atomSize, atomType, filename, parsingMode), _pchunkOffsetAtom);
298
299                // Check for success
300                if (!_pchunkOffsetAtom->MP4Success())
301                {
302                    _success = false;
303                    _mp4ErrorCode = _pchunkOffsetAtom->GetMP4Error();
304                    PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>SampleTableAtom::Chunk Offset atom failed"));
305                    return;
306                }
307                _pchunkOffsetAtom->setParent(this);
308                count -= _pchunkOffsetAtom->getSize();
309            }
310            else if (atomType == SYNC_SAMPLE_ATOM)
311            {
312                //"stss"
313                PV_MP4_FF_NEW(fp->auditCB, SyncSampleAtom, (fp, atomSize, atomType), _psyncSampleAtom);
314
315                // Check for success
316                if (!_psyncSampleAtom->MP4Success())
317                {
318                    _success = false;
319                    _mp4ErrorCode = _psyncSampleAtom->GetMP4Error();
320                    PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>SampleTableAtom::Sync Sample Atom Failed"));
321                    return;
322                }
323                _psyncSampleAtom->setParent(this);
324                count -= _psyncSampleAtom->getSize();
325            }
326            else if (atomType == AVC_SAMPLE_DEPENDENCY_TYPE_BOX)
327            {
328                //"sdtp"
329                uint32 SamplesCount = _psampleSizeAtom->getSampleCount();
330
331                PV_MP4_FF_NEW(fp->auditCB, AVCSampleDependencyType,
332                              (fp, atomSize, atomType, SamplesCount),
333                              _pavcSampleDependencyType);
334
335                // Check for success
336                if (!_pavcSampleDependencyType->MP4Success())
337                {
338                    _success = false;
339                    _mp4ErrorCode = _pavcSampleDependencyType->GetMP4Error();
340                    PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>SampleTableAtom::AVC Sample Dependency Type Box failed"));
341                    return;
342                }
343                _pavcSampleDependencyType->setParent(this);
344                count -= _pavcSampleDependencyType->getSize();
345
346            }
347            else if (atomType == AVC_SAMPLE_TO_GROUP_BOX)
348            {
349                //"sgpd"
350                PV_MP4_FF_NEW(fp->auditCB, AVCSampleToGroup, (fp, atomSize, atomType), _pavcSampleToGroup);
351                // Check for success
352                if (!_pavcSampleToGroup->MP4Success())
353                {
354                    _success = false;
355                    _mp4ErrorCode = _pavcSampleToGroup->GetMP4Error();
356                    PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>SampleTableAtom::AVC Sample to group box failed"));
357                    return;
358                }
359                _pavcSampleToGroup->setParent(this);
360                count -= _pavcSampleToGroup->getSize();
361
362
363            }
364            else if (atomType == AVC_SAMPLE_DEPENDENCY_BOX)
365            {
366                uint32 SamplesCount = _psampleSizeAtom->getSampleCount();
367                PV_MP4_FF_NEW(fp->auditCB, AVCSampleDependency, (fp, atomSize, atomType, SamplesCount), _pavcSampleDependency);
368                // Check for success
369                if (!_pavcSampleDependency->MP4Success())
370                {
371                    _success = false;
372                    _mp4ErrorCode = _pavcSampleDependency->GetMP4Error();
373                    PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>SampleTableAtom::AVC Sample Dependency box failed"));
374                    return;
375                }
376                _pavcSampleDependency->setParent(this);
377                count -= _pavcSampleDependency->getSize();
378            }
379            else
380            {
381                count -= atomSize;
382                atomSize -= DEFAULT_ATOM_SIZE;
383                AtomUtils::seekFromCurrPos(fp, atomSize);
384
385            }
386
387        }
388
389        if (_pcompositionOffsetAtom != NULL)
390        {
391            if (SamplesCount != 0)
392            {
393                _pcompositionOffsetAtom->setSamplesCount(SamplesCount);
394            }
395        }
396        /*
397         * These 5 atoms are mandatory. In case any of it is absent
398         * return ERROR!!!
399         */
400        if ((_ptimeToSampleAtom    == NULL)   ||
401                (_psampleDescriptionAtom == NULL) ||
402                (_psampleSizeAtom == NULL)        ||
403                (_psampleToChunkAtom == NULL)     ||
404                (_pchunkOffsetAtom == NULL))
405        {
406            _success = false;
407            _mp4ErrorCode = READ_SAMPLE_TABLE_ATOM_FAILED;
408            return;
409        }
410
411        if (_psampleDescriptionAtom->Is3GPPAMR())
412        {
413            int32 sampleDelta = _ptimeToSampleAtom->getSampleDeltaAt(0);
414
415            // The notion of separate decode and composition timestamps is specific to
416            // video tracks. Therefore no ned to Adjust sampleDelta with CTTS value.
417
418            if (_numAMRFramesPerSample > 0)
419            {
420                _amrFrameDelta = ((sampleDelta) / (_numAMRFramesPerSample));
421            }
422            _amrSampleSize = 0;
423        }
424
425    }
426    else
427    {
428        _mp4ErrorCode = READ_SAMPLE_TABLE_ATOM_FAILED;
429        PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>SampleTableAtom::Read Sample Table Atom Failed"));
430    }
431}
432
433// Destructor
434SampleTableAtom::~SampleTableAtom()
435{
436    // Clean up member atoms
437    if (_ptimeToSampleAtom != NULL)
438    {
439        PV_MP4_FF_DELETE(NULL, TimeToSampleAtom, _ptimeToSampleAtom);
440    }
441
442    if (_pcompositionOffsetAtom != NULL)
443    {
444        PV_MP4_FF_DELETE(NULL, CompositionOffsetAtom, _pcompositionOffsetAtom);
445    }
446
447    if (_psampleDescriptionAtom != NULL)
448    {
449        PV_MP4_FF_DELETE(NULL, SampleDescriptionAtom, _psampleDescriptionAtom);
450    }
451
452    if (_psampleSizeAtom != NULL)
453    {
454        PV_MP4_FF_DELETE(NULL, SampleSizeAtom, _psampleSizeAtom);
455    }
456
457    if (_psampleToChunkAtom != NULL)
458    {
459        PV_MP4_FF_DELETE(NULL, SampleToChunkAtom, _psampleToChunkAtom);
460    }
461
462    if (_pchunkOffsetAtom != NULL)
463    {
464        PV_MP4_FF_DELETE(NULL, ChunkOffsetAtom, _pchunkOffsetAtom);
465    }
466
467    if (_psyncSampleAtom != NULL)
468    {
469        PV_MP4_FF_DELETE(NULL, SyncSampleAtom, _psyncSampleAtom);
470    }
471
472#ifdef OPEN_FILE_ONCE_PER_TRACK
473    if (_pinput != NULL)
474    {
475        AtomUtils::CloseMP4File(_pinput);
476        oscl_free(_pinput);
477    }
478#else
479    if (_pinput != NULL)
480    {
481        oscl_free(_pinput);
482    }
483    if (_commonFilePtr != NULL)
484    {
485        oscl_free(_commonFilePtr);
486    }
487#endif
488
489    if (_pAMRTempBuffer != NULL)
490    {
491        oscl_free(_pAMRTempBuffer);
492    }
493}
494
495
496// Returns the specific sample with number 'sampleNum'
497int32
498SampleTableAtom::getSample(uint32 sampleNum, uint8 *buf, int32 &size, uint32 &index, uint32 &SampleOffset)
499{
500    if ((_psampleSizeAtom    == NULL) ||
501            (_psampleToChunkAtom == NULL) ||
502            (_pchunkOffsetAtom   == NULL))
503    {
504        size = 0;
505        return DEFAULT_ERROR;
506    }
507
508    // return NULL if sampleNum is past end of stream
509    uint32 numSamples = _psampleSizeAtom->getSampleCount();
510    if (sampleNum >= numSamples)
511    {
512        size = 0;
513        return END_OF_TRACK; // Past end of samples
514    }
515
516    // Check sample size from SampleSizeAtom
517    int32 sampleSize = _psampleSizeAtom->getSampleSizeAt(sampleNum);
518    size = 0;
519    if (sampleSize == PV_ERROR)
520    {
521        return DEFAULT_ERROR;
522    }
523
524    // Find chunk
525    int32 chunk = _psampleToChunkAtom->getChunkNumberForSampleGet(sampleNum);
526    // Find first sample in that chunk
527    int32 first = _psampleToChunkAtom->getFirstSampleNumInChunkGet();
528
529    //set the sample description index
530    _SDIndex = _psampleToChunkAtom->getSDIndexGet();
531    if ((int32)_SDIndex <= 0)
532    {
533        PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>SampleTableAtom::getSample - Read Sample Description Atom Failed"));
534        return READ_SAMPLE_DESCRIPTION_ATOM_FAILED;
535    }
536    _SDIndex -= 1;
537    index = _SDIndex;
538
539    if (sampleSize == 0)
540    {   //shortcut
541        return EVERYTHING_FINE;
542    }
543
544    // Find chunk offset to file
545    int32 offset = _pchunkOffsetAtom->getChunkOffsetAt(chunk);
546    //uint32 offset to int32, possible error for large files
547    if (offset == PV_ERROR)
548    {
549        PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>SampleTableAtom::getSample - Read Chunk Offset Atom Failed"));
550        return READ_CHUNK_OFFSET_ATOM_FAILED;
551    }
552
553    // Need to add up all the sizes from the first sample in this run up to the
554    // the requested sample (but not including it)
555    int32 sampleSizeOffset = 0;
556    int32 tempSize = 0;
557    for (uint32 i = first; i < sampleNum; i++)
558    {
559        // Check sample size from SampleSizeAtom
560        tempSize = _psampleSizeAtom->getSampleSizeAt(i);
561        // Check for error condition
562        if (tempSize == PV_ERROR)
563        {
564            PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>SampleTableAtom::getSample - Read Sample Sized Atom Failed"));
565            return READ_SAMPLE_SIZE_ATOM_FAILED;
566        }
567
568        sampleSizeOffset += tempSize;
569    }
570
571    // Find actual file offset to sample
572    int32 sampleFileOffset = offset + sampleSizeOffset;
573
574    SampleOffset = sampleFileOffset;
575
576    PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleTableAtom::getSample- sampleFileOffset =%d", sampleFileOffset));
577    // Open file
578    if (!_pinput->IsOpen())
579    {
580#ifdef OPEN_FILE_ONCE_PER_TRACK
581        // Check if file is already open
582        // Opens file in binary mode with read sharing permissions
583        // Return Error in case the file open fails.
584        if (AtomUtils::OpenMP4File(_filename,
585                                   Oscl_File::MODE_READ | Oscl_File::MODE_BINARY,
586                                   _pinput) != 0)
587        {
588            return FILE_OPEN_FAILED;
589        }
590#else
591        _pinput->_fileSize = _commonFilePtr->_fileSize;
592        _pinput->_pvfile.Copy(_commonFilePtr->_pvfile);
593        AtomUtils::Flush(_pinput);
594        AtomUtils::seekFromStart(_pinput, 0);
595#endif
596        if (!_IsUpdateFileSize)
597        {
598            if (AtomUtils::getCurrentFileSize(_pinput, _fileSize) == false)
599            {
600                return READ_FAILED;
601            }
602        }
603    }
604
605    if (sampleFileOffset + sampleSize > (int32)_fileSize)
606    {
607        return INSUFFICIENT_DATA;
608    }
609
610#ifdef OPEN_FILE_ONCE_PER_TRACK
611    if (_oPVContentDownloadable)
612    {
613        if (sampleNum == 0)
614        {
615            AtomUtils::seekFromStart(_pinput, sampleFileOffset);
616        }
617    }
618    else
619    {
620        AtomUtils::seekFromStart(_pinput, sampleFileOffset);
621    }
622#else
623    AtomUtils::seekFromStart(_pinput, sampleFileOffset);
624#endif
625
626    // Read byte data into buffer
627    if (AtomUtils::readByteData(_pinput, sampleSize, buf))
628    {
629        size = sampleSize;
630        return EVERYTHING_FINE;
631    }
632    else
633    {
634        return DEFAULT_ERROR;
635    }
636}
637
638MP4_ERROR_CODE SampleTableAtom::getKeyMediaSampleNumAt(uint32 aKeySampleNum,
639        GAU    *pgau)
640{
641    uint32 n = 1;
642    if (_psyncSampleAtom == NULL)
643    {
644        //all samples are key frames
645        _currentPlaybackSampleNumber = aKeySampleNum;
646    }
647    else
648    {
649        uint32 totalNumSyncSamples = getSyncSampleAtom()->getEntryCount();
650        if (aKeySampleNum >= totalNumSyncSamples)
651        {
652            aKeySampleNum = 0;
653        }
654        _currentPlaybackSampleNumber =
655            getSyncSampleAtom()->getSampleNumberAt(aKeySampleNum);
656    }
657    int32 retValA = _ptimeToSampleAtom->resetStateVariables(_currentPlaybackSampleNumber);
658    if (retValA == PV_ERROR)
659    {
660        _currentPlaybackSampleNumber = 0;
661        _currentPlaybackSampleTimestamp = _trackStartTSOffset;
662        _ptimeToSampleAtom->resetStateVariables();
663        return READ_FAILED;
664    }
665    int32 retValB = _psampleToChunkAtom->resetStateVariables(_currentPlaybackSampleNumber);
666    if (retValB == PV_ERROR)
667    {
668        _currentPlaybackSampleNumber = 0;
669        _currentPlaybackSampleTimestamp = _trackStartTSOffset;
670        _psampleToChunkAtom->resetStateVariables();
671        return READ_FAILED;
672    }
673    if (NULL != _pcompositionOffsetAtom)
674    {
675        int32 retValC = _pcompositionOffsetAtom->resetStateVariables(_currentPlaybackSampleNumber);
676        if (PV_ERROR == retValC)
677        {
678            _currentPlaybackSampleNumber = 0;
679            _currentPlaybackSampleTimestamp = _trackStartTSOffset;
680            _pcompositionOffsetAtom->resetStateVariables();
681            return READ_FAILED;
682        }
683    }
684    if (_currentPlaybackSampleNumber > 0)
685    {
686        _currentPlaybackSampleTimestamp =
687            getTimestampForSampleNumber(_currentPlaybackSampleNumber);
688        _currentPlaybackSampleTimestamp += _trackStartTSOffset;
689    }
690    else
691    {
692        _currentPlaybackSampleTimestamp = _trackStartTSOffset + getCttsOffsetForSampleNumber(0);
693    }
694    //Reset the file pointer to the correct location. In case of non-interleaved
695    //pv content, we do not seek for every media sample.
696    if (_oPVContentDownloadable)
697    {
698        int32 sampleSize =
699            _psampleSizeAtom->getSampleSizeAt(_currentPlaybackSampleNumber);
700
701        // Find chunk
702        int32 chunk =
703            _psampleToChunkAtom->getChunkNumberForSample(_currentPlaybackSampleNumber);
704
705        // Find first sample in that chunk
706        int32 first = _psampleToChunkAtom->getFirstSampleNumInChunk(chunk);
707
708        // Find chunk offset to file
709        int32 offset = _pchunkOffsetAtom->getChunkOffsetAt(chunk);
710
711        //uint32 offset to int32, possible error for large files
712        if (offset == PV_ERROR)
713        {
714            _currentPlaybackSampleNumber = 0;
715            return (READ_FAILED);
716        }
717
718        // Need to add up all the sizes from the first sample in this run up to the
719        // the requested sample (but not including it)
720        int32 sampleSizeOffset = 0;
721        int32 tempSize = 0;
722        for (uint32 i = first; i < (uint32)_currentPlaybackSampleNumber; i++)
723        {
724            // Check sample size from SampleSizeAtom
725            tempSize = _psampleSizeAtom->getSampleSizeAt(i);
726            // Check for error condition
727            if (tempSize == PV_ERROR)
728            {
729                _currentPlaybackSampleNumber = 0;
730                return (READ_FAILED);
731            }
732            sampleSizeOffset += tempSize;
733        }
734
735        // Find actual file offset to sample
736        int32 sampleFileOffset = offset + sampleSizeOffset;
737
738        if (!_pinput->IsOpen())
739        {
740#ifdef OPEN_FILE_ONCE_PER_TRACK
741            // Check if file is already open
742            // Opens file in binary mode with read sharing permissions
743            // Return Error in case the file open fails.
744            if (AtomUtils::OpenMP4File(_filename,
745                                       Oscl_File::MODE_READ | Oscl_File::MODE_BINARY,
746                                       _pinput) != 0)
747            {
748                return FILE_OPEN_FAILED;
749            }
750#else
751            _pinput->_fileSize = _commonFilePtr->_fileSize;
752            _pinput->_pvfile.Copy(_commonFilePtr->_pvfile);
753            AtomUtils::Flush(_pinput);
754            AtomUtils::seekFromStart(_pinput, 0);
755#endif
756            if (!_IsUpdateFileSize)
757            {
758                if (AtomUtils::getCurrentFileSize(_pinput, _fileSize) == false)
759                {
760                    _currentPlaybackSampleNumber = 0;
761                    return (READ_FAILED);
762                }
763            }
764        }
765
766        if (sampleFileOffset + sampleSize > (int32)_fileSize)
767        {
768            _currentPlaybackSampleNumber = 0;
769            return (READ_FAILED);
770        }
771        AtomUtils::seekFromStart(_pinput, sampleFileOffset);
772    }
773
774    {
775        int32 chunk =
776            getMutableSampleToChunkAtom().
777            getChunkNumberForSampleGet(_currentPlaybackSampleNumber);
778
779        uint32 FirstSampleNumInChunk =
780            getSampleToChunkAtom().getFirstSampleNumInChunkGet();
781
782        uint32 offsetIntoRunOfChunks =
783            (_currentPlaybackSampleNumber - FirstSampleNumInChunk);
784
785        int32 offset = _pchunkOffsetAtom->getChunkOffsetAt(chunk);
786
787        if (offset == PV_ERROR)
788        {
789            _currentPlaybackSampleNumber = 0;
790            return READ_FAILED;
791        }
792
793        int32 sampleSizeOffset = 0;
794        int32 tempSize = 0;
795
796        _currChunkOffset = 0;
797        for (uint32 i = FirstSampleNumInChunk; i < FirstSampleNumInChunk +
798                offsetIntoRunOfChunks; i++)
799        {
800            tempSize = _psampleSizeAtom->getSampleSizeAt(i);
801            if (tempSize == PV_ERROR)
802            {
803                _currentPlaybackSampleNumber = 0;
804                return READ_FAILED;
805            }
806            sampleSizeOffset += tempSize;
807        }
808        _currChunkOffset = sampleSizeOffset;
809    }
810
811    int32 retVal = getNextNSamples(_currentPlaybackSampleNumber, &n, pgau);
812    MP4_ERROR_CODE errCode = (MP4_ERROR_CODE)retVal;
813    return errCode;
814}
815
816int32
817SampleTableAtom::getPrevKeyMediaSample(uint32 inputtimestamp, uint32 &aKeySampleNum, uint32 *n, GAU    *pgau)
818{
819    if (_ptimeToSampleAtom  == NULL)
820    {
821        return PV_ERROR;
822    }
823
824    // Get sample number at timestamp
825    _currentPlaybackSampleNumber =
826        _ptimeToSampleAtom->getSampleNumberFromTimestamp(inputtimestamp);
827    // Go for composition offset adjustment.
828    _currentPlaybackSampleNumber =
829        getSampleNumberAdjustedWithCTTS(inputtimestamp, _currentPlaybackSampleNumber);
830
831    // Check if sample is an I-frame.  If not, need to find the sample number of the
832    // first I-frame sample that follows ts
833    // Need to check syncSampleAtom for this - if not present, all samples are synch samples
834    // (i.e. all audio samples are synch samples)
835    if (_psyncSampleAtom  != NULL)
836    {
837        _currentPlaybackSampleNumber =
838            getSyncSampleAtom()->getSyncSampleBefore(_currentPlaybackSampleNumber);
839    }
840
841    if (_currentPlaybackSampleNumber == PV_ERROR)
842    {
843        return PV_ERROR;
844    }
845
846    aKeySampleNum = _currentPlaybackSampleNumber;
847
848    // Increment ts for current sample in this random access:No more correct in case of CTTS presence
849    if (_currentPlaybackSampleNumber != 0)
850    {
851        // ts for sample 0 is 0
852        _currentPlaybackSampleTimestamp =
853            getTimestampForSampleNumber(_currentPlaybackSampleNumber);
854    }
855    else
856    {
857        _currentPlaybackSampleTimestamp = getCttsOffsetForSampleNumber(0);
858
859    }
860    int32 retValA = _ptimeToSampleAtom->resetStateVariables(_currentPlaybackSampleNumber);
861    if (retValA == PV_ERROR)
862    {
863        _currentPlaybackSampleNumber = 0;
864        _currentPlaybackSampleTimestamp = _trackStartTSOffset;
865        _ptimeToSampleAtom->resetStateVariables();
866        return 0;
867    }
868    int32 retValB = _psampleToChunkAtom->resetStateVariables(_currentPlaybackSampleNumber);
869    if (retValB == PV_ERROR)
870    {
871        _currentPlaybackSampleNumber = 0;
872        _currentPlaybackSampleTimestamp = _trackStartTSOffset;
873        _psampleToChunkAtom->resetStateVariables();
874        return 0;
875    }
876    if (NULL != _pcompositionOffsetAtom)
877    {
878        int32 retValC = _pcompositionOffsetAtom->resetStateVariables(_currentPlaybackSampleNumber);
879        if (PV_ERROR == retValC)
880        {
881            _currentPlaybackSampleNumber = 0;
882            _currentPlaybackSampleTimestamp = _trackStartTSOffset;
883            _pcompositionOffsetAtom->resetStateVariables();
884            return 0;
885        }
886    }
887    if (_currentPlaybackSampleNumber > 0)
888    {
889        _currentPlaybackSampleTimestamp =
890            getTimestampForSampleNumber(_currentPlaybackSampleNumber);
891        _currentPlaybackSampleTimestamp += _trackStartTSOffset;
892    }
893    else
894    {
895        _currentPlaybackSampleTimestamp = _trackStartTSOffset + getCttsOffsetForSampleNumber(0);
896    }
897    //Reset the file pointer to the correct location. In case of non-interleaved
898    //pv content, we do not seek for every media sample.
899    if (_oPVContentDownloadable)
900    {
901        int32 sampleSize =
902            _psampleSizeAtom->getSampleSizeAt(_currentPlaybackSampleNumber);
903
904        // Find chunk
905        int32 chunk =
906            _psampleToChunkAtom->getChunkNumberForSample(_currentPlaybackSampleNumber);
907
908        // Find first sample in that chunk
909        int32 first = _psampleToChunkAtom->getFirstSampleNumInChunk(chunk);
910
911        // Find chunk offset to file
912        int32 offset = _pchunkOffsetAtom->getChunkOffsetAt(chunk);
913
914        //uint32 offset to int32, possible error for large files
915        if (offset == PV_ERROR)
916        {
917            _currentPlaybackSampleNumber = 0;
918            return (READ_FAILED);
919        }
920
921        // Need to add up all the sizes from the first sample in this run up to the
922        // the requested sample (but not including it)
923        int32 sampleSizeOffset = 0;
924        int32 tempSize = 0;
925        for (uint32 i = first; i < (uint32)_currentPlaybackSampleNumber; i++)
926        {
927            // Check sample size from SampleSizeAtom
928            tempSize = _psampleSizeAtom->getSampleSizeAt(i);
929            // Check for error condition
930            if (tempSize == PV_ERROR)
931            {
932                _currentPlaybackSampleNumber = 0;
933                return (READ_FAILED);
934            }
935            sampleSizeOffset += tempSize;
936        }
937
938        // Find actual file offset to sample
939        int32 sampleFileOffset = offset + sampleSizeOffset;
940
941        if (!_pinput->IsOpen())
942        {
943#ifdef OPEN_FILE_ONCE_PER_TRACK
944            // Check if file is already open
945            // Opens file in binary mode with read sharing permissions
946            // Return Error in case the file open fails.
947            if (AtomUtils::OpenMP4File(_filename,
948                                       Oscl_File::MODE_READ | Oscl_File::MODE_BINARY,
949                                       _pinput) != 0)
950            {
951                return FILE_OPEN_FAILED;
952            }
953#else
954            _pinput->_fileSize = _commonFilePtr->_fileSize;
955            _pinput->_pvfile.Copy(_commonFilePtr->_pvfile);
956            AtomUtils::Flush(_pinput);
957            AtomUtils::seekFromStart(_pinput, 0);
958#endif
959            if (!_IsUpdateFileSize)
960            {
961                if (AtomUtils::getCurrentFileSize(_pinput, _fileSize) == false)
962                {
963                    _currentPlaybackSampleNumber = 0;
964                    return (READ_FAILED);
965                }
966            }
967        }
968
969        if (sampleFileOffset + sampleSize > (int32)_fileSize)
970        {
971            _currentPlaybackSampleNumber = 0;
972            return (READ_FAILED);
973        }
974        AtomUtils::seekFromStart(_pinput, sampleFileOffset);
975    }
976
977    {
978        int32 chunk =
979            getMutableSampleToChunkAtom().
980            getChunkNumberForSampleGet(_currentPlaybackSampleNumber);
981
982        uint32 FirstSampleNumInChunk =
983            getSampleToChunkAtom().getFirstSampleNumInChunkGet();
984
985        uint32 offsetIntoRunOfChunks =
986            (_currentPlaybackSampleNumber - FirstSampleNumInChunk);
987
988        int32 offset = _pchunkOffsetAtom->getChunkOffsetAt(chunk);
989
990        if (offset == PV_ERROR)
991        {
992            _currentPlaybackSampleNumber = 0;
993            return READ_FAILED;
994        }
995
996        int32 sampleSizeOffset = 0;
997        int32 tempSize = 0;
998
999        _currChunkOffset = 0;
1000        for (uint32 i = FirstSampleNumInChunk; i < FirstSampleNumInChunk +
1001                offsetIntoRunOfChunks; i++)
1002        {
1003            tempSize = _psampleSizeAtom->getSampleSizeAt(i);
1004            if (tempSize == PV_ERROR)
1005            {
1006                _currentPlaybackSampleNumber = 0;
1007                return READ_FAILED;
1008            }
1009            sampleSizeOffset += tempSize;
1010        }
1011        _currChunkOffset = sampleSizeOffset;
1012    }
1013    int32 retVal = getNextNSamples(_currentPlaybackSampleNumber, n, pgau);
1014    MP4_ERROR_CODE errCode = (MP4_ERROR_CODE)retVal;
1015    return errCode;
1016}
1017
1018int32
1019SampleTableAtom::getNextKeyMediaSample(uint32 inputtimestamp, uint32 &aKeySampleNum, uint32 *n, GAU    *pgau)
1020{
1021    if (_ptimeToSampleAtom  == NULL)
1022    {
1023        return PV_ERROR;
1024    }
1025
1026    // Get sample number at timestamp
1027    _currentPlaybackSampleNumber =
1028        _ptimeToSampleAtom->getSampleNumberFromTimestamp(inputtimestamp);
1029    // Go far composition offset adjustment.
1030    _currentPlaybackSampleNumber =
1031        getSampleNumberAdjustedWithCTTS(inputtimestamp, _currentPlaybackSampleNumber);
1032
1033    // Check if sample is an I-frame.  If not, need to find the sample number of the
1034    // first I-frame sample that follows ts
1035    // Need to check syncSampleAtom for this - if not present, all samples are synch samples
1036    // (i.e. all audio samples are synch samples)
1037    if (_psyncSampleAtom != NULL)
1038    {
1039        _currentPlaybackSampleNumber =
1040            getSyncSampleAtom()->getSyncSampleFollowing(_currentPlaybackSampleNumber);
1041    }
1042
1043    if (_currentPlaybackSampleNumber == PV_ERROR)
1044    {
1045        return PV_ERROR;
1046    }
1047
1048    aKeySampleNum = _currentPlaybackSampleNumber;
1049
1050    // Increment ts for current sample in this random access: No more correct incase CTTS exits
1051    if (_currentPlaybackSampleNumber != 0)
1052    {
1053        // ts for sample 0 is 0
1054        _currentPlaybackSampleTimestamp =
1055            getTimestampForSampleNumber(_currentPlaybackSampleNumber);
1056    }
1057    else
1058    {
1059        _currentPlaybackSampleTimestamp = getCttsOffsetForSampleNumber(0);
1060    }
1061
1062    int32 retValA = _ptimeToSampleAtom->resetStateVariables(_currentPlaybackSampleNumber);
1063    if (retValA == PV_ERROR)
1064    {
1065        _currentPlaybackSampleNumber = 0;
1066        _currentPlaybackSampleTimestamp = _trackStartTSOffset;
1067        _ptimeToSampleAtom->resetStateVariables();
1068        return 0;
1069    }
1070    int32 retValB = _psampleToChunkAtom->resetStateVariables(_currentPlaybackSampleNumber);
1071    if (retValB == PV_ERROR)
1072    {
1073        _currentPlaybackSampleNumber = 0;
1074        _currentPlaybackSampleTimestamp = _trackStartTSOffset;
1075        _psampleToChunkAtom->resetStateVariables();
1076        return 0;
1077    }
1078    if (NULL != _pcompositionOffsetAtom)
1079    {
1080        int32 retValC = _pcompositionOffsetAtom->resetStateVariables(_currentPlaybackSampleNumber);
1081        if (PV_ERROR == retValC)
1082        {
1083            _currentPlaybackSampleNumber = 0;
1084            _currentPlaybackSampleTimestamp = _trackStartTSOffset;
1085            _pcompositionOffsetAtom->resetStateVariables();
1086            return 0;
1087        }
1088    }
1089
1090    if (_currentPlaybackSampleNumber > 0)
1091    {
1092        _currentPlaybackSampleTimestamp =
1093            getTimestampForSampleNumber(_currentPlaybackSampleNumber);
1094        _currentPlaybackSampleTimestamp += _trackStartTSOffset;
1095    }
1096    else
1097    {
1098        _currentPlaybackSampleTimestamp = _trackStartTSOffset + getCttsOffsetForSampleNumber(0);
1099    }
1100    //Reset the file pointer to the correct location. In case of non-interleaved
1101    //pv content, we do not seek for every media sample.
1102    if (_oPVContentDownloadable)
1103    {
1104        int32 sampleSize =
1105            _psampleSizeAtom->getSampleSizeAt(_currentPlaybackSampleNumber);
1106
1107        // Find chunk
1108        int32 chunk =
1109            _psampleToChunkAtom->getChunkNumberForSample(_currentPlaybackSampleNumber);
1110
1111        // Find first sample in that chunk
1112        int32 first = _psampleToChunkAtom->getFirstSampleNumInChunk(chunk);
1113
1114        // Find chunk offset to file
1115        int32 offset = _pchunkOffsetAtom->getChunkOffsetAt(chunk);
1116
1117        //uint32 offset to int32, possible error for large files
1118        if (offset == PV_ERROR)
1119        {
1120            _currentPlaybackSampleNumber = 0;
1121            return (READ_FAILED);
1122        }
1123
1124        // Need to add up all the sizes from the first sample in this run up to the
1125        // the requested sample (but not including it)
1126        int32 sampleSizeOffset = 0;
1127        int32 tempSize = 0;
1128        for (uint32 i = first; i < (uint32)_currentPlaybackSampleNumber; i++)
1129        {
1130            // Check sample size from SampleSizeAtom
1131            tempSize = _psampleSizeAtom->getSampleSizeAt(i);
1132            // Check for error condition
1133            if (tempSize == PV_ERROR)
1134            {
1135                _currentPlaybackSampleNumber = 0;
1136                return (READ_FAILED);
1137            }
1138            sampleSizeOffset += tempSize;
1139        }
1140
1141        // Find actual file offset to sample
1142        int32 sampleFileOffset = offset + sampleSizeOffset;
1143
1144        if (!_pinput->IsOpen())
1145        {
1146#ifdef OPEN_FILE_ONCE_PER_TRACK
1147            // Check if file is already open
1148            // Opens file in binary mode with read sharing permissions
1149            // Return Error in case the file open fails.
1150            if (AtomUtils::OpenMP4File(_filename,
1151                                       Oscl_File::MODE_READ | Oscl_File::MODE_BINARY,
1152                                       _pinput) != 0)
1153            {
1154                return FILE_OPEN_FAILED;
1155            }
1156#else
1157            _pinput->_fileSize = _commonFilePtr->_fileSize;
1158            _pinput->_pvfile.Copy(_commonFilePtr->_pvfile);
1159            AtomUtils::Flush(_pinput);
1160            AtomUtils::seekFromStart(_pinput, 0);
1161#endif
1162            if (!_IsUpdateFileSize)
1163            {
1164                if (AtomUtils::getCurrentFileSize(_pinput, _fileSize) == false)
1165                {
1166                    _currentPlaybackSampleNumber = 0;
1167                    return (READ_FAILED);
1168                }
1169            }
1170        }
1171
1172        if (sampleFileOffset + sampleSize > (int32)_fileSize)
1173        {
1174            _currentPlaybackSampleNumber = 0;
1175            return (READ_FAILED);
1176        }
1177        AtomUtils::seekFromStart(_pinput, sampleFileOffset);
1178    }
1179
1180    {
1181        int32 chunk =
1182            getMutableSampleToChunkAtom().
1183            getChunkNumberForSampleGet(_currentPlaybackSampleNumber);
1184
1185        uint32 FirstSampleNumInChunk =
1186            getSampleToChunkAtom().getFirstSampleNumInChunkGet();
1187
1188        uint32 offsetIntoRunOfChunks =
1189            (_currentPlaybackSampleNumber - FirstSampleNumInChunk);
1190
1191        int32 offset = _pchunkOffsetAtom->getChunkOffsetAt(chunk);
1192
1193        if (offset == PV_ERROR)
1194        {
1195            _currentPlaybackSampleNumber = 0;
1196            return READ_FAILED;
1197        }
1198
1199        int32 sampleSizeOffset = 0;
1200        int32 tempSize = 0;
1201
1202        _currChunkOffset = 0;
1203        for (uint32 i = FirstSampleNumInChunk; i < FirstSampleNumInChunk +
1204                offsetIntoRunOfChunks; i++)
1205        {
1206            tempSize = _psampleSizeAtom->getSampleSizeAt(i);
1207            if (tempSize == PV_ERROR)
1208            {
1209                _currentPlaybackSampleNumber = 0;
1210                return READ_FAILED;
1211            }
1212            sampleSizeOffset += tempSize;
1213        }
1214        _currChunkOffset = sampleSizeOffset;
1215    }
1216
1217    int32 retVal =  getNextNSamples(_currentPlaybackSampleNumber, n, pgau);
1218    MP4_ERROR_CODE errCode = (MP4_ERROR_CODE)retVal;
1219    return errCode;
1220}
1221
1222// Returns next video frame
1223// Can optimize this by having the getNext()... use the seekg pointer to maintain the
1224// location where to read from
1225int32
1226SampleTableAtom::getNextSample(uint8 *buf, int32 &size, uint32 &index, uint32 &SampleOffset)
1227{
1228    int8 aFrameSizes[16] = {12, 13, 15, 17, 19, 20, 26, 31,
1229                            5,  0,  0,  0,  0,  0,  0,  0
1230                           };
1231
1232    if (_ptimeToSampleAtom == NULL)
1233    {
1234        return READ_TIME_TO_SAMPLE_ATOM_FAILED;
1235    }
1236
1237    if (!_IsUpdateFileSize)
1238    {
1239        if (_pinput->IsOpen())
1240        {
1241            if (AtomUtils::getCurrentFileSize(_pinput, _fileSize) == false)
1242            {
1243                return READ_FAILED;
1244            }
1245        }
1246    }
1247
1248    int32 tsDelta = 0;
1249
1250    PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleTableAtom::getNextSample- _currentPlaybackSampleNumber =%d", _currentPlaybackSampleNumber));
1251    if (_currentPlaybackSampleNumber != 0)
1252    {
1253        tsDelta = _ptimeToSampleAtom->getTimeDeltaForSampleNumberGet(_currentPlaybackSampleNumber);
1254
1255        PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleTableAtom::getNextSample- tsDelta =%d", tsDelta));
1256
1257        if (tsDelta == PV_ERROR)
1258        {
1259            PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>SampleTableAtom::getNextSample - Read Time to Sample Atom Failed"));
1260            return (READ_TIME_TO_SAMPLE_ATOM_FAILED);
1261        }
1262
1263        _currentPlaybackSampleTimestamp += (tsDelta + getCttsOffsetForSampleNumberGet(_currentPlaybackSampleNumber));
1264
1265    }
1266    else
1267    {
1268        // Add TS offset to sample timestamps
1269        _currentPlaybackSampleTimestamp = _trackStartTSOffset;
1270    }
1271    PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleTableAtom::getNextSample- _currentPlaybackSampleTimestamp =%d", _currentPlaybackSampleTimestamp));
1272    if (_psampleDescriptionAtom->Is3GPPAMR())
1273    {
1274        if (_amrSampleSize > 0)
1275        {
1276            uint8 frame_type = *(_pAMRTempBuffer + _amrTempBufferOffset);
1277
1278            frame_type = (uint8)((frame_type >> 3) & 0x0F);
1279
1280            _amrTempBufferOffset += 1;
1281            _amrSampleSize -= 1;
1282
1283            if ((frame_type > 9) && (frame_type != 15))
1284            {//in fact, this should be "INVALID_AMR_FRAME_TYPE"
1285                PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>SampleTableAtom::getNextSample - Read AMR SAmple Entry Failed"));
1286                return (READ_AMR_SAMPLE_ENTRY_FAILED);
1287            }
1288
1289            int32 frame_size = aFrameSizes[(uint16)frame_type];
1290            index = frame_type;
1291
1292            if (frame_size > size)
1293            {
1294                size = frame_size;
1295                PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>SampleTableAtom::getNextSample - Insufficient Buffer Size"));
1296                return (INSUFFICIENT_BUFFER_SIZE);
1297            }
1298
1299            oscl_memcpy((void *)(buf),
1300                        (void *)(_pAMRTempBuffer + _amrTempBufferOffset),
1301                        frame_size);
1302
1303            _amrTempBufferOffset += frame_size;
1304            _amrSampleSize       -= frame_size;
1305
1306            size = frame_size;
1307            return EVERYTHING_FINE;
1308        }
1309        else
1310        {
1311            _amrTempBufferOffset = 0;
1312
1313            _amrSampleSize = 512;
1314            int32 retval = getSample(_currentPlaybackSampleNumber, _pAMRTempBuffer, _amrSampleSize, index, SampleOffset);
1315
1316            if (retval != EVERYTHING_FINE)
1317            {
1318                // Reset Time Stamp
1319                _currentPlaybackSampleTimestamp -= (tsDelta + getCttsOffsetForSampleNumber(_currentPlaybackSampleNumber));
1320
1321                return retval;
1322            }
1323            _currentPlaybackSampleNumber++;
1324
1325            _amrFrameTimeStamp = _currentPlaybackSampleTimestamp;
1326
1327            uint8 frame_type = *(_pAMRTempBuffer + _amrTempBufferOffset);
1328
1329            frame_type = (uint8)((frame_type >> 3) & 0x0F);
1330
1331            _amrTempBufferOffset += 1;
1332            _amrSampleSize -= 1;
1333
1334            if ((frame_type > 9) && (frame_type != 15))
1335            {//in fact, this should be "INVALID_AMR_FRAME_TYPE"
1336                PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>SampleTableAtom::getNextSample - Read AMR SAmple Entry Failed"));
1337                return (READ_AMR_SAMPLE_ENTRY_FAILED);
1338            }
1339
1340            int32 frame_size = aFrameSizes[(uint16)frame_type];
1341
1342            index = frame_type;
1343
1344            if (frame_size > size)
1345            {
1346                size = frame_size;
1347                PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>SampleTableAtom::getNextSample - Insufficient Buffer Size"));
1348                return (INSUFFICIENT_BUFFER_SIZE);
1349            }
1350
1351            oscl_memcpy((void *)(buf),
1352                        (void *)(_pAMRTempBuffer + _amrTempBufferOffset),
1353                        frame_size);
1354
1355            _amrTempBufferOffset += frame_size;
1356            _amrSampleSize       -= frame_size;
1357
1358            size = frame_size;
1359            return EVERYTHING_FINE;
1360        }
1361    }
1362    else
1363    {
1364        int32 retVal = getSample(_currentPlaybackSampleNumber, buf, size, index, SampleOffset);
1365
1366        if (retVal == EVERYTHING_FINE)
1367        {
1368            _currentPlaybackSampleNumber++;
1369        }
1370        else
1371        {
1372            // Reset Time Stamp
1373            _currentPlaybackSampleTimestamp -= (tsDelta + getCttsOffsetForSampleNumber(_currentPlaybackSampleNumber));
1374        }
1375
1376        return retVal;
1377    }
1378}
1379
1380/*Reset PlayBack from Beginning*/
1381void SampleTableAtom :: resetPlayBack()
1382{
1383    _currentPlaybackSampleNumber    = 0;
1384    _currentPlaybackSampleTimestamp = 0;
1385    _oResidualSample = false;
1386    _remainingFramesInSample = 0;
1387    _amrTempBufferOffset = 0;
1388    _ptimeToSampleAtom->resetStateVariables();
1389    if (NULL != _pcompositionOffsetAtom)
1390    {
1391        _pcompositionOffsetAtom->resetStateVariables();
1392    }
1393    _psampleToChunkAtom->resetStateVariables();
1394    _currChunkOffset = 0;
1395}
1396
1397void SampleTableAtom ::resetTrackToEOT()
1398{
1399    _currentPlaybackSampleNumber    = getSampleSizeAtom().getSampleCount();
1400}
1401int32 SampleTableAtom::queryRepositionTime(int32 time, bool oDependsOn, bool bBeforeRequestedTime)
1402{
1403    int32 trueTS = 0;
1404    int32 currPlaybackSampleNum = 0;
1405    int32 currPlaybackSampleTS = 0;
1406
1407    if ((_psampleSizeAtom    == NULL) ||
1408            (_psampleToChunkAtom == NULL) ||
1409            (_ptimeToSampleAtom  == NULL) ||
1410            (_pchunkOffsetAtom   == NULL))
1411    {
1412        return 0;
1413    }
1414
1415    if (time > (int32)_trackStartTSOffset)
1416    {
1417        currPlaybackSampleNum =
1418            getTimeToSampleAtom().getSampleNumberFromTimestamp(time - _trackStartTSOffset);
1419        // Go for composition offset adjustment.
1420        currPlaybackSampleNum =
1421            getSampleNumberAdjustedWithCTTS((time - _trackStartTSOffset), currPlaybackSampleNum);
1422    }
1423    else
1424    {
1425        trueTS = _trackStartTSOffset;
1426        return (trueTS);
1427    }
1428
1429    if (currPlaybackSampleNum == PV_ERROR)
1430    {
1431        // SHOULD COME HERE ONLY IN CASE OF AUDIO & TEXT AND WE WANT TO SET THE
1432        // SAMPLE NUMBER IN THAT CASE TO THE LAST SAMPLE IN THE FILE
1433        if (getSampleSizeAtom().getSampleCount() > 0)
1434        {
1435            currPlaybackSampleNum =
1436                (getSampleSizeAtom().getSampleCount() - 1);
1437
1438            // This is to ensure that _currentPlaybackSampleTimestamp is set to the previous
1439            // sample, and not to the current sample, as this sample is yet to be read.
1440            if (currPlaybackSampleNum > 0)
1441            {
1442                currPlaybackSampleTS =
1443                    getTimestampForSampleNumber(currPlaybackSampleNum - 1);
1444
1445                currPlaybackSampleTS += _trackStartTSOffset;
1446            }
1447            else //
1448            {
1449                currPlaybackSampleTS += getCttsOffsetForSampleNumber(0);
1450            }
1451        }
1452        else
1453        {
1454            currPlaybackSampleNum = 0;
1455            currPlaybackSampleTS = 0;
1456        }
1457        trueTS =  currPlaybackSampleTS;
1458        return (trueTS);
1459
1460    }
1461
1462    //for video reset, we need to locate I frame
1463    if (_psampleDescriptionAtom->getMediaType() == MEDIA_TYPE_VISUAL)
1464    {
1465        //get the nearest I frame in front only for Base layer
1466        if (!oDependsOn)
1467        {
1468
1469            if (getSyncSampleAtom() != NULL)
1470            {
1471                if (getSyncSampleAtom()->getEntryCount() != 0)
1472                {
1473                    if (bBeforeRequestedTime == true)
1474                    {
1475                        currPlaybackSampleNum =
1476                            getSyncSampleAtom()->getSyncSampleBefore(currPlaybackSampleNum);
1477                    }
1478                    else
1479                    {
1480                        currPlaybackSampleNum =
1481                            getSyncSampleAtom()->getSyncSampleFollowing(currPlaybackSampleNum);
1482                        if (currPlaybackSampleNum == PV_ERROR)
1483                        {
1484                            currPlaybackSampleNum = 0;
1485                        }
1486                    }
1487                }
1488                else
1489                {
1490                    // ZERO SYNC SAMPLE ENTRIES - ERROR CONDITION - RESET TO THR BEGINNING OF THE
1491                    // CLIP
1492                    currPlaybackSampleNum = 0;
1493                    trueTS = _trackStartTSOffset;
1494                    return (trueTS);
1495                }
1496            }
1497            else
1498            {
1499                // NO SYNC SAMPLE ATOM - ERROR CONDITION - RESET TO THR BEGINNING OF THE
1500                // CLIP
1501                currPlaybackSampleNum = 0;
1502                trueTS = _trackStartTSOffset;
1503                return (trueTS);
1504            }
1505            //get the timestamp based on the sample number
1506        }
1507        if (currPlaybackSampleNum != 0)
1508        { // ts for sample 0 is 0: No more correct incase CTTS exists
1509            currPlaybackSampleTS =
1510                getTimestampForSampleNumber(currPlaybackSampleNum);
1511        }
1512        else
1513        {
1514            currPlaybackSampleTS = getCttsOffsetForSampleNumber(0);
1515        }
1516    }
1517    else if (_psampleDescriptionAtom->getMediaType() == MEDIA_TYPE_AUDIO)
1518    {
1519
1520
1521        if (currPlaybackSampleNum > 0)
1522        {
1523            currPlaybackSampleTS =
1524                getTimestampForSampleNumber(currPlaybackSampleNum);
1525
1526            if (oDependsOn)
1527            {
1528
1529                /*
1530                 * This check is required to ensure that audio track is positioned
1531                 * ahead of the intra frame. This is 'cos the getSampleNumberFromTimestamp
1532                 * returns the sample just before the passed time - This inturn is required
1533                 * for video tracks where in the positioning has to be the closest intra frame
1534                 * in the past.
1535                 */
1536
1537                if (currPlaybackSampleTS < time)
1538                {
1539                    if ((currPlaybackSampleNum + 1) < (int32)getSampleSizeAtom().getSampleCount())
1540                    {
1541                        currPlaybackSampleTS =
1542                            getTimestampForSampleNumber(currPlaybackSampleNum);
1543                    }
1544                }
1545            }
1546        }
1547        else
1548        {
1549            currPlaybackSampleTS = getCttsOffsetForSampleNumber(0);
1550        }
1551    }
1552    trueTS = currPlaybackSampleTS + _trackStartTSOffset;
1553    return trueTS;
1554}
1555
1556int32 SampleTableAtom::resetPlayBackbyTime(int32 time, bool oDependsOn)
1557{
1558    int32 trueTS = 0;
1559    int32 retValA = 0 , retValB = 0;
1560
1561    if ((_psampleSizeAtom    == NULL) ||
1562            (_psampleToChunkAtom == NULL) ||
1563            (_ptimeToSampleAtom  == NULL) ||
1564            (_pchunkOffsetAtom   == NULL))
1565    {
1566        return 0;
1567    }
1568
1569    _oResidualSample = false;
1570    _remainingFramesInSample = 0;
1571    _amrTempBufferOffset = 0;
1572
1573    if (time > (int32)_trackStartTSOffset)
1574    {
1575        int32 _tempSampleNumber =
1576            getTimeToSampleAtom().getSampleNumberFromTimestamp(time - _trackStartTSOffset);
1577        _tempSampleNumber =
1578            getSampleNumberAdjustedWithCTTS((time - _trackStartTSOffset), _tempSampleNumber);
1579
1580        if (_currentPlaybackSampleNumber > _tempSampleNumber)
1581        {
1582            // In case of Backward Repos,the flag _SkipOldEntry in samplesizeatom.cpp is set to true to prevent
1583            // old entries from getting used.
1584            getSampleSizeAtom()._SkipOldEntry = true;
1585        }
1586        _currentPlaybackSampleNumber =
1587            getTimeToSampleAtom().getSampleNumberFromTimestamp(time - _trackStartTSOffset);
1588
1589        // Go for composition offset adjustment.
1590        _currentPlaybackSampleNumber =
1591            getSampleNumberAdjustedWithCTTS((time - _trackStartTSOffset), _currentPlaybackSampleNumber);
1592
1593    }
1594    else
1595    {
1596        _currentPlaybackSampleNumber = 0;
1597        _currChunkOffset  = 0;
1598        trueTS = _trackStartTSOffset;
1599        _ptimeToSampleAtom->resetStateVariables();
1600        if (NULL != _pcompositionOffsetAtom)
1601        {
1602            _pcompositionOffsetAtom->resetStateVariables();
1603        }
1604        _psampleToChunkAtom->resetStateVariables();
1605        return (trueTS);
1606    }
1607
1608    if (_currentPlaybackSampleNumber == PV_ERROR)
1609    {
1610        // SHOULD COME HERE ONLY IN CASE OF AUDIO & TEXT AND WE WANT TO SET THE
1611        // SAMPLE NUMBER IN THAT CASE TO THE LAST SAMPLE IN THE FILE
1612        if (getSampleSizeAtom().getSampleCount() > 0)
1613        {
1614            _currentPlaybackSampleNumber =
1615                (getSampleSizeAtom().getSampleCount());
1616
1617            retValA = _ptimeToSampleAtom->resetStateVariables(_currentPlaybackSampleNumber);
1618            if (retValA == PV_ERROR)
1619            {
1620                _currentPlaybackSampleNumber = 0;
1621                _currentPlaybackSampleTimestamp = _trackStartTSOffset;
1622                _ptimeToSampleAtom->resetStateVariables();
1623                return 0;
1624            }
1625            int32 retValB = _psampleToChunkAtom->resetStateVariables(_currentPlaybackSampleNumber);
1626            if (retValB == PV_ERROR)
1627            {
1628                _currentPlaybackSampleNumber = 0;
1629                _currentPlaybackSampleTimestamp = _trackStartTSOffset;
1630                _psampleToChunkAtom->resetStateVariables();
1631                return 0;
1632            }
1633            if (NULL != _pcompositionOffsetAtom)
1634            {
1635                int32 retValC = _pcompositionOffsetAtom->resetStateVariables(_currentPlaybackSampleNumber);
1636                if (PV_ERROR == retValC)
1637                {
1638                    _currentPlaybackSampleNumber = 0;
1639                    _currentPlaybackSampleTimestamp = _trackStartTSOffset;
1640                    _pcompositionOffsetAtom->resetStateVariables();
1641                    return 0;
1642                }
1643            }
1644            if (_currentPlaybackSampleNumber > 0)
1645            {
1646                _currentPlaybackSampleTimestamp =
1647                    getTimestampForSampleNumber(_currentPlaybackSampleNumber);
1648
1649                _currentPlaybackSampleTimestamp += _trackStartTSOffset;
1650            }
1651            else
1652            {
1653                _currentPlaybackSampleTimestamp = getCttsOffsetForSampleNumber(0);
1654            }
1655        }
1656        else
1657        {
1658            _currentPlaybackSampleNumber = 0;
1659            _currentPlaybackSampleTimestamp = 0;
1660        }
1661        trueTS =  _currentPlaybackSampleTimestamp;
1662        goto check_for_file_pointer_reset;
1663    }
1664
1665    //for video reset, we need to locate I frame
1666    if (_psampleDescriptionAtom->getMediaType() == MEDIA_TYPE_VISUAL)
1667    {
1668        //get the nearest I frame in front only for Base layer
1669        if (!oDependsOn)
1670        {
1671            if (getSyncSampleAtom() != NULL)
1672            {
1673                if (getSyncSampleAtom()->getEntryCount() != 0)
1674                {
1675                    _currentPlaybackSampleNumber =
1676                        getSyncSampleAtom()->getSyncSampleBefore(_currentPlaybackSampleNumber);
1677                }
1678                else
1679                {
1680
1681                    // ZERO SYNC SAMPLE ENTRIES - ERROR CONDITION - RESET TO THR BEGINNING OF THE
1682                    // CLIP
1683                    _currentPlaybackSampleNumber = 0;
1684                    trueTS = _trackStartTSOffset;
1685                    retValA = _ptimeToSampleAtom->resetStateVariables(_currentPlaybackSampleNumber);
1686                    if (retValA == PV_ERROR)
1687                    {
1688                        _currentPlaybackSampleNumber = 0;
1689                        _currentPlaybackSampleTimestamp = _trackStartTSOffset;
1690                        _ptimeToSampleAtom->resetStateVariables();
1691                        return 0;
1692                    }
1693
1694                    int32 retValB = _psampleToChunkAtom->resetStateVariables(_currentPlaybackSampleNumber);
1695                    if (retValB == PV_ERROR)
1696                    {
1697                        _currentPlaybackSampleNumber = 0;
1698                        _currentPlaybackSampleTimestamp = _trackStartTSOffset;
1699                        _psampleToChunkAtom->resetStateVariables();
1700                        return 0;
1701                    }
1702
1703                    if (NULL != _pcompositionOffsetAtom)
1704                    {
1705                        int32 retValC = _pcompositionOffsetAtom->resetStateVariables(_currentPlaybackSampleNumber);
1706                        if (PV_ERROR == retValC)
1707                        {
1708                            _currentPlaybackSampleNumber = 0;
1709                            _currentPlaybackSampleTimestamp = _trackStartTSOffset;
1710                            _pcompositionOffsetAtom->resetStateVariables();
1711                            return 0;
1712                        }
1713                    }
1714                    return (trueTS);
1715                }
1716            }
1717            else
1718            {
1719                // NO SYNC SAMPLE ATOM - ERROR CONDITION - RESET TO THR BEGINNING OF THE
1720                // CLIP
1721                _currentPlaybackSampleNumber = 0;
1722                trueTS = _trackStartTSOffset;
1723                _ptimeToSampleAtom->resetStateVariables();
1724                if (NULL != _pcompositionOffsetAtom)
1725                {
1726                    _pcompositionOffsetAtom->resetStateVariables();
1727                }
1728                _psampleToChunkAtom->resetStateVariables();
1729                return (trueTS);
1730            }
1731        }
1732        else
1733        {
1734            const uint32 totalnumSamples = getSampleSizeAtom().getSampleCount();
1735            if ((uint32)_currentPlaybackSampleNumber < totalnumSamples)
1736            {
1737                // FOR ENHANCE LAYER GET THE SAMPLE CLOSEST TO THE CORRESPONDING BASE LAYER
1738                // AND INCREMENT IT BY ONE, AS THE SAMPLE CLOSEST ALWAYS RETURNS ONE PREVIOUS
1739                _currentPlaybackSampleNumber++;
1740            }
1741        }
1742        //get the timestamp based on the sample number
1743        if (_currentPlaybackSampleNumber != 0)
1744        { // ts for sample 0 is 0
1745            _currentPlaybackSampleTimestamp =
1746                getTimestampForSampleNumber(_currentPlaybackSampleNumber);
1747        }
1748        else
1749        {
1750            _currentPlaybackSampleTimestamp = getCttsOffsetForSampleNumber(0);
1751        }
1752    }
1753    else if (_psampleDescriptionAtom->getMediaType() == MEDIA_TYPE_AUDIO)
1754    {
1755        if (_currentPlaybackSampleNumber > 0)
1756        {
1757            _currentPlaybackSampleTimestamp =
1758                getTimestampForSampleNumber(_currentPlaybackSampleNumber);
1759
1760            if (oDependsOn)
1761            {
1762                /*
1763                 * This check is required to ensure that audio tracks are positioned
1764                 * ahead of the intra frame. This is 'cos the getSampleNumberFromTimestamp
1765                 * returns the sample just before the passed time - This inturn is required
1766                 * for video tracks where in the positioning has to be the closest intra frame
1767                 * in the past.
1768                 */
1769                if (_currentPlaybackSampleTimestamp < (uint32)time)
1770                {
1771                    if ((_currentPlaybackSampleNumber + 1) < (int32)getSampleSizeAtom().getSampleCount())
1772                    {
1773                        _currentPlaybackSampleNumber++;
1774                        _currentPlaybackSampleTimestamp =
1775                            getTimestampForSampleNumber(_currentPlaybackSampleNumber);
1776                    }
1777                }
1778            }
1779        }
1780        else
1781        {
1782            _currentPlaybackSampleTimestamp = getCttsOffsetForSampleNumber(0);
1783        }
1784    }
1785    else
1786    {
1787        if (_currentPlaybackSampleNumber > 0)
1788        {
1789            _currentPlaybackSampleTimestamp =
1790                getTimestampForSampleNumber(_currentPlaybackSampleNumber);
1791        }
1792        else
1793        {
1794            _currentPlaybackSampleTimestamp = getCttsOffsetForSampleNumber(0);
1795        }
1796    }
1797
1798    trueTS = _currentPlaybackSampleTimestamp + _trackStartTSOffset;
1799
1800    PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleTableAtom::resetPlayBackbyTime- _currentPlaybackSampleTimestamp =%d", _currentPlaybackSampleTimestamp));
1801    PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleTableAtom::resetPlayBackbyTime- _currentPlaybackSampleNumber =%d", _currentPlaybackSampleNumber));
1802    PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleTableAtom::resetPlayBackbyTime- trueTS =%d", trueTS));
1803
1804    retValA = _ptimeToSampleAtom->resetStateVariables(_currentPlaybackSampleNumber);
1805    if (retValA == PV_ERROR)
1806    {
1807        _currentPlaybackSampleNumber = 0;
1808        _currentPlaybackSampleTimestamp = _trackStartTSOffset;
1809        _ptimeToSampleAtom->resetStateVariables();
1810        return 0;
1811    }
1812    retValB = _psampleToChunkAtom->resetStateVariables(_currentPlaybackSampleNumber);
1813    if (retValB == PV_ERROR)
1814    {
1815        _currentPlaybackSampleNumber = 0;
1816        _currentPlaybackSampleTimestamp = _trackStartTSOffset;
1817        _psampleToChunkAtom->resetStateVariables();
1818        return 0;
1819    }
1820    if (NULL != _pcompositionOffsetAtom)
1821    {
1822        int32 retValC = _pcompositionOffsetAtom->resetStateVariables(_currentPlaybackSampleNumber);
1823        if (PV_ERROR == retValC)
1824        {
1825            _currentPlaybackSampleNumber = 0;
1826            _currentPlaybackSampleTimestamp = _trackStartTSOffset;
1827            _pcompositionOffsetAtom->resetStateVariables();
1828            return 0;
1829        }
1830    }
1831
1832    {
1833        int32 chunk =
1834            getMutableSampleToChunkAtom().
1835            getChunkNumberForSampleGet(_currentPlaybackSampleNumber);
1836
1837        uint32 FirstSampleNumInChunk =
1838            getSampleToChunkAtom().getFirstSampleNumInChunkGet();
1839
1840        uint32 offsetIntoRunOfChunks =
1841            (_currentPlaybackSampleNumber - FirstSampleNumInChunk);
1842
1843        int32 offset = _pchunkOffsetAtom->getChunkOffsetAt(chunk);
1844
1845        if (offset == PV_ERROR)
1846        {
1847            trueTS = 0;
1848            _currentPlaybackSampleNumber = 0;
1849            trueTS = _trackStartTSOffset;
1850            return (trueTS);
1851        }
1852
1853        int32 sampleSizeOffset = 0;
1854        int32 tempSize = 0;
1855
1856        _currChunkOffset = 0;
1857        for (uint32 i = FirstSampleNumInChunk; i < FirstSampleNumInChunk +
1858                offsetIntoRunOfChunks; i++)
1859        {
1860            tempSize = _psampleSizeAtom->getSampleSizeAt(i);
1861            if (tempSize == PV_ERROR)
1862            {
1863                trueTS = 0;
1864                _currentPlaybackSampleNumber = 0;
1865                trueTS = _trackStartTSOffset;
1866                return (trueTS);
1867            }
1868            sampleSizeOffset += tempSize;
1869        }
1870        _currChunkOffset = sampleSizeOffset;
1871    }
1872
1873check_for_file_pointer_reset:
1874    //Reset the file pointer to the correct location. In case of non-interleaved
1875    //pv content, we do not seek for every media sample.
1876    if (_oPVContentDownloadable)
1877    {
1878        int32 sampleSize =
1879            _psampleSizeAtom->getSampleSizeAt(_currentPlaybackSampleNumber);
1880
1881        // Find chunk
1882        int32 chunk =
1883            _psampleToChunkAtom->getChunkNumberForSample(_currentPlaybackSampleNumber);
1884
1885        // Find first sample in that chunk
1886        int32 first = _psampleToChunkAtom->getFirstSampleNumInChunk(chunk);
1887
1888        // Find chunk offset to file
1889        int32 offset = _pchunkOffsetAtom->getChunkOffsetAt(chunk);
1890
1891        //uint32 offset to int32, possible error for large files
1892        if (offset == PV_ERROR)
1893        {
1894            trueTS = 0;
1895            _currentPlaybackSampleNumber = 0;
1896            trueTS = _trackStartTSOffset;
1897            return (trueTS);
1898        }
1899
1900        // Need to add up all the sizes from the first sample in this run up to the
1901        // the requested sample (but not including it)
1902        int32 sampleSizeOffset = 0;
1903        int32 tempSize = 0;
1904        for (uint32 i = first; i < (uint32)_currentPlaybackSampleNumber; i++)
1905        {
1906            // Check sample size from SampleSizeAtom
1907            tempSize = _psampleSizeAtom->getSampleSizeAt(i);
1908            // Check for error condition
1909            if (tempSize == PV_ERROR)
1910            {
1911                trueTS = 0;
1912                _currentPlaybackSampleNumber = 0;
1913                trueTS = _trackStartTSOffset;
1914                return (trueTS);
1915            }
1916            sampleSizeOffset += tempSize;
1917        }
1918
1919        // Find actual file offset to sample
1920        int32 sampleFileOffset = offset + sampleSizeOffset;
1921
1922        if (!_pinput->IsOpen())
1923        {
1924#ifdef OPEN_FILE_ONCE_PER_TRACK
1925            // Check if file is already open
1926            // Opens file in binary mode with read sharing permissions
1927            // Return Error in case the file open fails.
1928            if (AtomUtils::OpenMP4File(_filename,
1929                                       Oscl_File::MODE_READ | Oscl_File::MODE_BINARY,
1930                                       _pinput) != 0)
1931            {
1932                return FILE_OPEN_FAILED;
1933            }
1934#else
1935            _pinput->_fileSize = _commonFilePtr->_fileSize;
1936            _pinput->_pvfile.Copy(_commonFilePtr->_pvfile);
1937            AtomUtils::Flush(_pinput);
1938            AtomUtils::seekFromStart(_pinput, 0);
1939#endif
1940            if (!_IsUpdateFileSize)
1941            {
1942                if (AtomUtils::getCurrentFileSize(_pinput, _fileSize) == false)
1943                {
1944                    trueTS = 0;
1945                    _currentPlaybackSampleNumber = 0;
1946                    trueTS = _trackStartTSOffset;
1947                    return (trueTS);
1948                }
1949            }
1950        }
1951
1952        if (sampleFileOffset + sampleSize > (int32)_fileSize)
1953        {
1954            trueTS = 0;
1955            _currentPlaybackSampleNumber = 0;
1956            trueTS = _trackStartTSOffset;
1957            return (trueTS);
1958        }
1959        AtomUtils::seekFromStart(_pinput, sampleFileOffset);
1960    }
1961
1962    return trueTS;
1963}
1964
1965//querySyncFrameBeforeTime
1966int32 SampleTableAtom::IsResetNeeded(int32 time)
1967{
1968    if (_psyncSampleAtom != NULL)
1969    {//not all I frames
1970        if ((uint32)time > _currentPlaybackSampleTimestamp)
1971        {//forward
1972            int32 nextSyncNum =
1973                _psyncSampleAtom->getSyncSampleFollowing(_currentPlaybackSampleNumber);
1974            if ((PV_ERROR == nextSyncNum)
1975                    || (time < (int32)getTimestampForSampleNumber(nextSyncNum)))
1976            {//1. past the last sync frame, no reset is needed
1977                //2. the sync frame is after the repositioning time, no reset is needed
1978                return DEFAULT_ERROR;
1979            }
1980        }
1981    }
1982    return EVERYTHING_FINE;
1983}
1984
1985int32 SampleTableAtom::getTimestampForRandomAccessPoints(uint32 *num, uint32 *tsBuf, uint32* numBuf, uint32* offsetBuf)
1986{
1987    if (_psyncSampleAtom == NULL)
1988    {
1989        if (_psampleSizeAtom != NULL)
1990        {
1991            *num = _psampleSizeAtom->getSampleCount();
1992        }
1993        return 2;   //success : every sample is a random access point
1994    }
1995
1996    if (_ptimeToSampleAtom == NULL)
1997    {
1998        return 0;   //fail
1999    }
2000
2001    uint32 tmp = _psyncSampleAtom->getEntryCount();
2002
2003    if (*num == 0)
2004    {
2005        *num = tmp;
2006        return 1;   //success. This is only the query mode.
2007    }
2008    if (*num > tmp)
2009        *num = tmp;
2010
2011    oscl_memcpy(numBuf, _psyncSampleAtom->getSampleNumberVector(),
2012                sizeof(uint32 *)*(*num));
2013
2014    for (uint32 i = 0; i < *num; i++)
2015    {//it may crash if this buffer is not big enough
2016        tsBuf[i] = getTimestampForSampleNumber(numBuf[i] - 1);
2017        // Timestamps returned here should be presentation timestamps (must include
2018        // the ctts offset. Calling getTimestampForSampleNumber will take care of it.
2019        numBuf[i] = numBuf[i] - 1;
2020        int32 offset = 0;
2021        if (offsetBuf != NULL)
2022        {
2023            if (getOffsetByTime(tsBuf[i], &offset) != DEFAULT_ERROR)
2024                offsetBuf[i] = offset;
2025        }
2026    }
2027    return  1;  //success
2028}
2029
2030
2031int32 SampleTableAtom::getTimestampForRandomAccessPointsBeforeAfter(uint32 ts, uint32 *tsBuf, uint32* numBuf, uint32& numsamplestoget, uint32 howManyKeySamples)
2032{
2033    if (_psyncSampleAtom == NULL)
2034    {
2035        return 2;   //success : every sample is a random access point
2036    }
2037
2038    if (_ptimeToSampleAtom == NULL)
2039    {
2040        return 0;   //fail
2041    }
2042
2043
2044    uint32 numSyncSamples = _psyncSampleAtom->getEntryCount();
2045    int32 SampleNumber =
2046        _ptimeToSampleAtom->getSampleNumberFromTimestamp(ts);
2047
2048    // Go for composition offset adjustment.
2049    SampleNumber =
2050        getSampleNumberAdjustedWithCTTS(ts, SampleNumber);
2051
2052    if ((int32)SampleNumber == PV_ERROR)
2053    {
2054        return PV_ERROR;
2055    }
2056
2057
2058    int32 SampleNumberForTS =  _psyncSampleAtom->getSyncSampleBefore(SampleNumber);
2059    if (SampleNumberForTS  == PV_ERROR)
2060    {
2061        return PV_ERROR;
2062    }
2063    uint32 startIdx = 0, endIdx = 0, k = 0, idx = 0;
2064    for (idx = 0; idx < numSyncSamples; idx++)
2065    {
2066        int32 tempSampleNum = _psyncSampleAtom->getSampleNumberAt(idx);
2067        if (SampleNumberForTS == tempSampleNum)
2068        {
2069            startIdx = idx + 1;
2070            endIdx = numSyncSamples;
2071            break;
2072        }
2073    }
2074
2075    if ((startIdx + howManyKeySamples) <= numSyncSamples)
2076        endIdx = startIdx + howManyKeySamples;
2077
2078    if (startIdx >= howManyKeySamples)
2079        startIdx -= howManyKeySamples;
2080    else
2081        startIdx = 0;
2082
2083    idx = 0;
2084    for (idx = startIdx; idx < endIdx; idx++)
2085    {
2086        int32 keySampleNum =  _psyncSampleAtom->getSampleNumberAt(idx);
2087        int32 keySampleTS = getTimestampForSampleNumber(keySampleNum);
2088        // Timestamps returned here should be presentation timestamps (must include
2089        // the ctts offset. Calling getTimestampForSampleNumber will take care of it.
2090
2091        if (keySampleNum != PV_ERROR &&
2092                keySampleTS != PV_ERROR)
2093        {
2094            numBuf[k] = keySampleNum;
2095            tsBuf[k] = keySampleTS;
2096            k++;
2097        }
2098    }
2099    numsamplestoget = k;
2100
2101    return  1;  //success
2102}
2103
2104uint32 SampleTableAtom::getTimestampForSampleNumber(uint32 sampleNumber)
2105{
2106    if ((NULL != _ptimeToSampleAtom) && (NULL != _pcompositionOffsetAtom))
2107    {
2108        return (_ptimeToSampleAtom->getTimestampForSampleNumber(sampleNumber)
2109                + _pcompositionOffsetAtom->getTimeOffsetForSampleNumber(sampleNumber));
2110    }
2111
2112    else if (NULL != _ptimeToSampleAtom)
2113    {
2114        return  _ptimeToSampleAtom->getTimestampForSampleNumber(sampleNumber);
2115    }
2116
2117    // It is not permitted that _pcompositionOffsetAtom without _ptimeToSampleAtom. Thus for any other
2118    // combination return 0.
2119    else
2120    {
2121        return 0;
2122    }
2123}
2124
2125int32 SampleTableAtom::getCttsOffsetForSampleNumberPeek(uint32 sampleNumber)
2126{
2127    int32 tempCompositionOffset = 0;
2128    // compositionOffsetAtom adjustment if compositionOffsetAtom exits
2129    if (NULL != _pcompositionOffsetAtom)
2130    {
2131        tempCompositionOffset = _pcompositionOffsetAtom->getTimeOffsetForSampleNumberPeek(sampleNumber);
2132        if (PV_ERROR != tempCompositionOffset)
2133        {
2134            PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleTableAtom::getCttsOffsetForSampleNumberPeek- CTTS(%d) = %d", sampleNumber, tempCompositionOffset));
2135            return tempCompositionOffset;
2136        }
2137        else
2138        {
2139            // It's not an issue if the CTTS is not present or not parsed correctly.
2140            return 0;
2141        }
2142    }
2143    return 0;
2144}
2145
2146// The difference between getCttsOffsetForSampleNumber and getCttsOffsetForSampleNumberGet
2147// is that the getCttsOffsetForSampleNumberGet is meant to be caled in a consequtive manner,
2148// However getCttsOffsetForSampleNumber could be called anywhere without past reference.
2149int32 SampleTableAtom::getCttsOffsetForSampleNumber(uint32 sampleNumber)
2150{
2151    int32 tempCompositionOffset = 0;
2152    // compositionOffsetAtom adjustment if compositionOffsetAtom exits
2153    if (NULL != _pcompositionOffsetAtom)
2154    {
2155        tempCompositionOffset = _pcompositionOffsetAtom->getTimeOffsetForSampleNumber(sampleNumber);
2156        if (PV_ERROR != tempCompositionOffset)
2157        {
2158            PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleTableAtom::getCttsOffsetForSampleNumber- CTTS(%d) = %d", sampleNumber, tempCompositionOffset));
2159            return tempCompositionOffset;
2160        }
2161        else
2162        {
2163            // It's not an issue if the CTTS is not present or not parsed correctly.
2164            return 0;
2165        }
2166    }
2167    return 0;
2168}
2169
2170int32 SampleTableAtom::getCttsOffsetForSampleNumberGet(uint32 sampleNumber)
2171{
2172    int32 tempCompositionOffset = 0;
2173    // compositionOffsetAtom adjustment if compositionOffsetAtom exits
2174    if (NULL != _pcompositionOffsetAtom)
2175    {
2176        tempCompositionOffset = _pcompositionOffsetAtom->getTimeOffsetForSampleNumberGet(sampleNumber);
2177        if (PV_ERROR != tempCompositionOffset)
2178        {
2179            PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleTableAtom::getCttsOffsetForSampleNumberGet- CTTS(%d) = %d", sampleNumber, tempCompositionOffset));
2180            return tempCompositionOffset;
2181        }
2182        else
2183        {
2184            // It's not an issue if the CTTS is not present or not parsed correctly.
2185            return 0;
2186        }
2187    }
2188    return 0;
2189}
2190
2191
2192// Returns next I-frame at time ts (in milliseconds) - or the very next I-frame in the stream
2193int32
2194SampleTableAtom::getNextSampleAtTime(uint32 ts, uint8 *buf, int32 &size, uint32 &index, uint32 &SampleOffset)
2195{
2196    if ((_ptimeToSampleAtom  == NULL) ||
2197            (_psyncSampleAtom    == NULL))
2198    {
2199        size = 0;
2200        return 0;
2201    }
2202
2203    // Get sample number at timestamp
2204    _currentPlaybackSampleNumber =
2205        _ptimeToSampleAtom->getSampleNumberFromTimestamp(ts);
2206
2207    if (_currentPlaybackSampleNumber == PV_ERROR)
2208    {
2209        size = 0;
2210        return 0;
2211    }
2212
2213    // Go for composition offset adjustment.
2214    _currentPlaybackSampleNumber =
2215        getSampleNumberAdjustedWithCTTS(ts, _currentPlaybackSampleNumber);
2216
2217    // Check if sample is an I-frame.  If not, need to find the sample number of the
2218    // first I-frame sample that follows ts
2219    // Need to check syncSampleAtom for this - if not present, all samples are synch samples
2220    // (i.e. all audio samples are synch samples)
2221    _currentPlaybackSampleNumber =
2222        _psyncSampleAtom->getSyncSampleFollowing(_currentPlaybackSampleNumber);
2223
2224    if (_currentPlaybackSampleNumber == PV_ERROR)
2225    {
2226        size = 0;
2227        return 0;
2228    }
2229
2230    // Increment ts for current sample in this random access; No more correct in case of CTTS presence
2231    if (_currentPlaybackSampleNumber != 0)
2232    {
2233        // ts for sample 0 is 0
2234        _currentPlaybackSampleTimestamp =
2235            getTimestampForSampleNumber(_currentPlaybackSampleNumber);
2236    }
2237    else
2238    {
2239        _currentPlaybackSampleTimestamp = getCttsOffsetForSampleNumber(0);
2240    }
2241
2242    return getSample(_currentPlaybackSampleNumber++, buf, size, index, SampleOffset);
2243}
2244
2245
2246int32
2247SampleTableAtom::getNextBundledAccessUnits(uint32 *n,
2248        GAU    *pgau)
2249{
2250    int32 nReturn = -1;
2251
2252    if ((_psampleSizeAtom    == NULL) ||
2253            (_psampleToChunkAtom == NULL) ||
2254            (_ptimeToSampleAtom  == NULL) ||
2255            (_pchunkOffsetAtom   == NULL))
2256    {
2257        return (nReturn);
2258    }
2259
2260    if (_currentPlaybackSampleNumber == 0)
2261    {
2262        // Add TS offset to sample timestamps
2263        _currentPlaybackSampleTimestamp = _trackStartTSOffset;
2264    }
2265
2266    uint32 numSamples = getSampleSizeAtom().getSampleCount();
2267
2268    if (_currentPlaybackSampleNumber >= (int32)numSamples)
2269    {
2270        *n = 0;
2271        pgau->info[0].ts = 0;   //_currentPlaybackSampleTimestamp;
2272        nReturn = END_OF_TRACK;
2273        return nReturn;
2274    }
2275
2276    nReturn = getNextNSamples(_currentPlaybackSampleNumber, n, pgau);
2277
2278    if (nReturn == INSUFFICIENT_BUFFER_SIZE)
2279    {
2280        return nReturn;
2281    }
2282
2283    /*
2284     * This check is intentionally not done in case of 3GPP AMR as there can
2285     * still be frames in the temp buffer, and they will be retrieved when
2286     * get N is called the next time.
2287     */
2288    if (!_psampleDescriptionAtom->Is3GPPAMR())
2289    {
2290        if (_currentPlaybackSampleNumber >= (int32)numSamples)
2291        {
2292            nReturn = END_OF_TRACK;
2293            return nReturn;
2294        }
2295    }
2296
2297    if ((nReturn == INVALID_SAMPLE_SIZE) ||
2298            (nReturn == INVALID_CHUNK_OFFSET))
2299    {
2300        nReturn = READ_FAILED;
2301        return nReturn;
2302    }
2303    return nReturn;
2304}
2305
2306int32
2307SampleTableAtom::peekNextBundledAccessUnits(uint32 *n,
2308        MediaMetaInfo *mInfo)
2309{
2310    int32 nReturn = -1;
2311
2312    if ((_psampleSizeAtom    == NULL) ||
2313            (_psampleToChunkAtom == NULL) ||
2314            (_ptimeToSampleAtom  == NULL) ||
2315            (_pchunkOffsetAtom   == NULL))
2316    {
2317        return -1;
2318    }
2319
2320    if (_currentPlaybackSampleNumber == 0)
2321    {
2322        // Add TS offset to sample timestamps
2323        _currentPlaybackSampleTimestamp = _trackStartTSOffset;
2324    }
2325
2326    nReturn = peekNextNSamples(_currentPlaybackSampleNumber, n, mInfo);
2327
2328    if ((nReturn == INVALID_SAMPLE_SIZE) ||
2329            (nReturn == INVALID_CHUNK_OFFSET))
2330    {
2331        nReturn = READ_FAILED;
2332        return nReturn;
2333    }
2334
2335    return nReturn;
2336}
2337
2338int32
2339SampleTableAtom::getNextNSamples(uint32 startSampleNum,
2340                                 uint32 *n,
2341                                 GAU    *pgau)
2342{
2343    uint32 chunk = 0;
2344    int32  numSamplesPerChunk = 0, currTSBase = 0;
2345    uint32 numChunksInRun = 0, FirstSampleNumInChunk = 0;
2346    uint32 offsetIntoRunOfChunks = 0, samplesLeftInChunk = 0;
2347    uint32 numSamples = 0;
2348    uint32 startSampleNumTSBase = 0;
2349    uint32 samplesYetToBeRead = *n;
2350    uint32 sampleNum = startSampleNum;
2351    bool oStoreOffset = false;
2352    int32 sampleBeforeGet = (int32)startSampleNum;
2353
2354    uint32 s = 0;
2355    uint32 end = 0;
2356
2357    uint32 i = 0, j = 0, k = 0;
2358
2359    int32  _mp4ErrorCode = EVERYTHING_FINE;
2360
2361    if (!_IsUpdateFileSize)
2362    {
2363        if (_pinput->IsOpen())
2364        {
2365            if (AtomUtils::getCurrentFileSize(_pinput, _fileSize) == false)
2366            {
2367                *n = 0;
2368                _mp4ErrorCode = READ_FAILED;
2369                return _mp4ErrorCode;
2370            }
2371        }
2372    }
2373
2374    currTSBase = _currentPlaybackSampleTimestamp;
2375    startSampleNumTSBase = _currentPlaybackSampleTimestamp;
2376    end = pgau->buf.num_fragments;
2377
2378    GAU tempGau;
2379    tempGau = *pgau;
2380    GAU* tempgauPtr = &tempGau;
2381
2382    k = 0;
2383
2384    uint32 totalnumSamples = getSampleSizeAtom().getSampleCount();
2385
2386    if (sampleNum >= totalnumSamples)
2387    {
2388        *n = 0;
2389        PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>SampleTableAtom::getNextNSamples - End Of Track"));
2390        _mp4ErrorCode = END_OF_TRACK;
2391        return (_mp4ErrorCode);
2392    }
2393
2394#if (PVLOGGER_INST_LEVEL > PVLOGMSG_INST_LLDBG)
2395    uint32 totalTimeSTSC = 0;
2396    uint32 totalTimeSTSZ = 0;
2397    uint32 totalTimeSTTS = 0;
2398    uint32 totalTimeCTTS = 0;
2399    uint32 totalTimeFileSeek = 0;
2400    uint32 totalTimeFileRead = 0;
2401
2402    uint32 currticks, StartTime, EndTime;
2403#endif
2404    uint32 totalBytesRead = 0;
2405    while (samplesYetToBeRead)
2406    {
2407#if (PVLOGGER_INST_LEVEL > PVLOGMSG_INST_LLDBG)
2408        currticks = OsclTickCount::TickCount();
2409        StartTime = OsclTickCount::TicksToMsec(currticks);
2410#endif
2411        // Find chunk
2412        chunk =
2413            getMutableSampleToChunkAtom().
2414            getChunkNumberForSampleGet(sampleNum);
2415
2416        //This method needs to be added to sample to chunk atom
2417        numChunksInRun =
2418            getSampleToChunkAtom().getNumChunksInRunofChunksGet();
2419
2420        if (numChunksInRun == uint32(PV_ERROR))
2421        {
2422            *n = 0;
2423            _mp4ErrorCode = READ_SAMPLE_TO_CHUNK_ATOM_FAILED;
2424            PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>SampleTableAtom::getNextNSamples - Read Sample to Chunk Atom Failed"));
2425            return (_mp4ErrorCode);
2426        }
2427
2428        numSamplesPerChunk =
2429            getSampleToChunkAtom().getSamplesPerChunkCorrespondingToSampleGet();
2430
2431        FirstSampleNumInChunk =
2432            getSampleToChunkAtom().getFirstSampleNumInChunkGet();
2433#if (PVLOGGER_INST_LEVEL > PVLOGMSG_INST_LLDBG)
2434        currticks = OsclTickCount::TickCount();
2435        EndTime = OsclTickCount::TicksToMsec(currticks);
2436        totalTimeSTSC += (EndTime - StartTime);
2437#endif
2438
2439        offsetIntoRunOfChunks =
2440            (sampleNum - FirstSampleNumInChunk);
2441
2442        // All chunks in a run of chunks ARE NOT CONTIGUOUS!!!!
2443        samplesLeftInChunk =
2444            ((numSamplesPerChunk) - offsetIntoRunOfChunks);
2445
2446        if (samplesLeftInChunk  >  samplesYetToBeRead)
2447        {
2448            numSamples = samplesYetToBeRead;
2449            samplesYetToBeRead = 0;
2450            oStoreOffset = true;
2451        }
2452        else
2453        {
2454            samplesYetToBeRead -= samplesLeftInChunk;
2455            numSamples = samplesLeftInChunk;
2456            oStoreOffset = false;
2457        }
2458
2459        int32 SDIndex = getSampleToChunkAtom().getSDIndexGet();
2460
2461        if (SDIndex > 0)
2462        {
2463            SDIndex -= 1;
2464        }
2465
2466
2467        // Find chunk offset to file
2468        int32 offset = _pchunkOffsetAtom->getChunkOffsetAt(chunk);
2469
2470
2471        if (offset == PV_ERROR)
2472        {
2473            _mp4ErrorCode =  INVALID_CHUNK_OFFSET;
2474            PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>SampleTableAtom::getNextNSamples - Invalid Chunk Offset"));
2475            break;
2476        }
2477
2478        // Need to add up all the sizes from the first sample in this run up to the
2479        // the requested sample (but not including it)
2480
2481        int32 sampleSizeOffset = 0;
2482        int32 tempSize = 0;
2483
2484        uint32 sigmaSampleSize = 0;
2485
2486        for (j = sampleNum;
2487                j < (sampleNum + numSamples);
2488                j++)
2489        {
2490            // Check sample size from SampleSizeAtom
2491            tempSize = getSampleSizeAtom().getDefaultSampleSize();
2492
2493            if (tempSize == 0)
2494            {
2495#if (PVLOGGER_INST_LEVEL > PVLOGMSG_INST_LLDBG)
2496                currticks = OsclTickCount::TickCount();
2497                StartTime = OsclTickCount::TicksToMsec(currticks);
2498#endif
2499                // Need to get specific sample size
2500                tempSize = getSampleSizeAtom().getSampleSizeAt(j);
2501#if (PVLOGGER_INST_LEVEL > PVLOGMSG_INST_LLDBG)
2502                currticks = OsclTickCount::TickCount();
2503                EndTime = OsclTickCount::TicksToMsec(currticks);
2504                totalTimeSTSZ += (EndTime - StartTime);
2505#endif
2506            }
2507
2508            // Check for error condition
2509            if (tempSize == -1)
2510            {
2511                *n = 0;
2512                _mp4ErrorCode =  INVALID_SAMPLE_SIZE;
2513                PVMF_MP4FFPARSER_LOGERROR((0, "ERROR =>SampleTableAtom::getNextNSamples - Invalid Sample Size"));
2514                return (_mp4ErrorCode);
2515            }
2516
2517            sigmaSampleSize += tempSize;
2518
2519            pgau->info[s].len = tempSize;
2520
2521            int32 tsDelta = 0;
2522
2523            if (j == 0)
2524            {
2525                // Add TS offset to sample timestamps if it is the first sample
2526                currTSBase = _trackStartTSOffset;
2527            }
2528
2529#if (PVLOGGER_INST_LEVEL > PVLOGMSG_INST_LLDBG)
2530            currticks = OsclTickCount::TickCount();
2531            StartTime = OsclTickCount::TicksToMsec(currticks);
2532#endif
2533            tsDelta = _ptimeToSampleAtom->getTimeDeltaForSampleNumberGet(j);
2534#if (PVLOGGER_INST_LEVEL > PVLOGMSG_INST_LLDBG)
2535            currticks = OsclTickCount::TickCount();
2536            EndTime = OsclTickCount::TicksToMsec(currticks);
2537            totalTimeSTTS += (EndTime - StartTime);
2538#endif
2539
2540            if (tsDelta == PV_ERROR)
2541            {
2542                *n = 0;
2543                _mp4ErrorCode = READ_FAILED;
2544                return (_mp4ErrorCode);
2545            }
2546
2547#ifdef OUTPUT_AMR_TOC
2548            uint8 objectType = getObjectTypeIndication();
2549            if (objectType == AMR_AUDIO)
2550            {
2551                AMRDecoderSpecificInfo *pinfo =
2552                    (AMRDecoderSpecificInfo *)(getDecoderSpecificInfoForSDI(SDIndex));
2553
2554                if (pgau->info[s].sample_info != pinfo->getFrameType())
2555                {
2556                    pgau->info[s].sample_info = pinfo->getFrameType();
2557                }
2558                else
2559                {
2560                    pgau->info[s].sample_info = pinfo->getFrameType();
2561                }
2562
2563            }
2564            else
2565            {
2566                pgau->info[s].sample_info = SDIndex;
2567            }
2568#else
2569            pgau->info[s].sample_info = SDIndex;
2570#endif
2571
2572            pgau->info[s].ts_delta = tsDelta;
2573
2574#if (PVLOGGER_INST_LEVEL > PVLOGMSG_INST_LLDBG)
2575            currticks = OsclTickCount::TickCount();
2576            StartTime = OsclTickCount::TicksToMsec(currticks);
2577#endif
2578            pgau->info[s].ts = currTSBase + getCttsOffsetForSampleNumberGet(j);
2579#if (PVLOGGER_INST_LEVEL > PVLOGMSG_INST_LLDBG)
2580            currticks = OsclTickCount::TickCount();
2581            EndTime = OsclTickCount::TicksToMsec(currticks);
2582            totalTimeCTTS += (EndTime - StartTime);
2583#endif
2584
2585            currTSBase += tsDelta;
2586
2587
2588            PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleTableAtom::getNextNSamples- pgau->info[%d].sample_info =%d", s, pgau->info[s].sample_info));
2589            PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleTableAtom::getNextNSamples- pgau->info[%d].ts_delta =%d", s, pgau->info[s].ts_delta));
2590            PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleTableAtom::getNextNSamples- pgau->info[%d].ts =%d", s, pgau->info[s].ts));
2591
2592
2593            s++;
2594        }
2595
2596        // Find actual file offset to sample
2597        int32 sampleFileOffset = offset + _currChunkOffset;
2598        Oscl_Int64_Utils::set_uint64(pgau->SampleOffset, 0, (uint32)sampleFileOffset);
2599
2600        // Open file
2601        if (!_pinput->IsOpen())
2602        {
2603#ifdef OPEN_FILE_ONCE_PER_TRACK
2604            // Check if file is already open
2605            // Opens file in binary mode with read sharing permissions
2606            // Return Error in case the file open fails.
2607            if (AtomUtils::OpenMP4File(_filename,
2608                                       Oscl_File::MODE_READ | Oscl_File::MODE_BINARY,
2609                                       _pinput) != 0)
2610            {
2611                *n = 0;
2612                return FILE_OPEN_FAILED;
2613            }
2614#else
2615            _pinput->_fileSize = _commonFilePtr->_fileSize;
2616            _pinput->_pvfile.Copy(_commonFilePtr->_pvfile);
2617            AtomUtils::Flush(_pinput);
2618            AtomUtils::seekFromStart(_pinput, 0);
2619#endif
2620            if (!_IsUpdateFileSize)
2621            {
2622                if (AtomUtils::getCurrentFileSize(_pinput, _fileSize) == false)
2623                {
2624                    *n = 0;
2625                    _mp4ErrorCode = READ_FAILED;
2626                    return _mp4ErrorCode;
2627                }
2628            }
2629        }
2630
2631        uint32 bufStart = 0;
2632        uint32 bufEnd = _fileSize;
2633        uint32 bufCap = AtomUtils::getFileBufferingCapacity(_pinput);
2634        if (bufCap)
2635        {
2636            // progressive playback
2637            // MBDS contains only a range of bytes
2638            // first byte is not always 0
2639            AtomUtils::getCurrentByteRange(_pinput, bufStart, bufEnd);
2640
2641            // bufEnd is the offset of the last byte
2642            // need to turn it into a length, like _fileSize above
2643            bufEnd++;
2644        }
2645
2646        if (((uint32)sampleFileOffset < bufStart) || ((sigmaSampleSize + sampleFileOffset) > bufEnd))
2647        {
2648            if ((uint32)_currentPlaybackSampleNumber != startSampleNum)
2649            {
2650                _currentPlaybackSampleNumber = startSampleNum;
2651                _currentPlaybackSampleTimestamp = startSampleNumTSBase;
2652                int32 retValA = _ptimeToSampleAtom->resetStateVariables(_currentPlaybackSampleNumber);
2653                if (retValA == PV_ERROR)
2654                {
2655                    _currentPlaybackSampleNumber = 0;
2656                    _currentPlaybackSampleTimestamp = _trackStartTSOffset;
2657                    _ptimeToSampleAtom->resetStateVariables();
2658                    return retValA;
2659                }
2660                int32 retValB = _psampleToChunkAtom->resetStateVariables(_currentPlaybackSampleNumber);
2661                if (retValB == PV_ERROR)
2662                {
2663                    _currentPlaybackSampleNumber = 0;
2664                    _currentPlaybackSampleTimestamp = _trackStartTSOffset;
2665                    _psampleToChunkAtom->resetStateVariables();
2666                    return retValB;
2667                }
2668                if (NULL != _pcompositionOffsetAtom)
2669                {
2670                    int32 retValC = _pcompositionOffsetAtom->resetStateVariables(_currentPlaybackSampleNumber);
2671                    if (retValC == PV_ERROR)
2672                    {
2673                        _currentPlaybackSampleNumber = 0;
2674                        _currentPlaybackSampleTimestamp = _trackStartTSOffset;
2675                        _pcompositionOffsetAtom->resetStateVariables();
2676                        return retValC;
2677                    }
2678                }
2679                chunk =
2680                    getMutableSampleToChunkAtom().
2681                    getChunkNumberForSampleGet(_currentPlaybackSampleNumber);
2682
2683                //This method needs to be added to sample to chunk atom
2684                numChunksInRun =
2685                    getSampleToChunkAtom().getNumChunksInRunofChunksGet();
2686
2687                FirstSampleNumInChunk =
2688                    getSampleToChunkAtom().getFirstSampleNumInChunkGet();
2689
2690                offsetIntoRunOfChunks =
2691                    (_currentPlaybackSampleNumber - FirstSampleNumInChunk);
2692
2693                sampleSizeOffset = 0;
2694                for (i = FirstSampleNumInChunk; i < FirstSampleNumInChunk +
2695                        offsetIntoRunOfChunks; i++)
2696                {
2697                    tempSize = _psampleSizeAtom->getSampleSizeAt(i);
2698                    sampleSizeOffset += tempSize;
2699                }
2700                _currChunkOffset = sampleSizeOffset;
2701            }
2702
2703            _mp4ErrorCode = INSUFFICIENT_DATA;
2704            if (bufCap)
2705            {
2706                // if MBDS, may need to kick of a http request
2707                uint32 contentLength = AtomUtils::getContentLength(_pinput);
2708                if ((0 != contentLength) && ((sigmaSampleSize + sampleFileOffset) > contentLength))
2709                {
2710                    // do not skip beyond end of clip
2711                    // if content length is known
2712                    _mp4ErrorCode = READ_FAILED;
2713                }
2714                else
2715                {
2716                    AtomUtils::skipFromStart(_pinput, sampleFileOffset);
2717                }
2718            }
2719
2720            *n = 0;
2721            for (uint32 i = 0; i < pgau->numMediaSamples; i++)
2722            {
2723                pgau->info[i].len         = 0;
2724                pgau->info[i].ts          = 0;
2725                pgau->info[i].sample_info = 0;
2726            }
2727
2728            return (_mp4ErrorCode);
2729        }
2730        uint32 start = 0;
2731        uint32 rewindPos = 0;
2732        uint32 totalFragmentLength = 0;
2733        for (k = start; k < end; k++)
2734        {
2735            totalFragmentLength += tempgauPtr->buf.fragments[k].len;
2736        }
2737
2738        if (totalFragmentLength < sigmaSampleSize)
2739        {
2740            //INSUFFICIENT BUFFER SIZE
2741            _currentPlaybackSampleNumber = startSampleNum;
2742            _currentPlaybackSampleTimestamp = _trackStartTSOffset;
2743            int32 retValA = _ptimeToSampleAtom->resetStateVariables(_currentPlaybackSampleNumber);
2744            if (retValA == PV_ERROR)
2745            {
2746                _currentPlaybackSampleNumber = 0;
2747                _currentPlaybackSampleTimestamp = _trackStartTSOffset;
2748                _ptimeToSampleAtom->resetStateVariables();
2749                return retValA;
2750            }
2751            int32 retValB = _psampleToChunkAtom->resetStateVariables(_currentPlaybackSampleNumber);
2752            if (retValB == PV_ERROR)
2753            {
2754                _currentPlaybackSampleNumber = 0;
2755                _currentPlaybackSampleTimestamp = _trackStartTSOffset;
2756                _psampleToChunkAtom->resetStateVariables();
2757                return retValB;
2758            }
2759            if (NULL != _pcompositionOffsetAtom)
2760            {
2761                int32 retValC = _pcompositionOffsetAtom->resetStateVariables(_currentPlaybackSampleNumber);
2762                if (retValC == PV_ERROR)
2763                {
2764                    _currentPlaybackSampleNumber = 0;
2765                    _currentPlaybackSampleTimestamp = _trackStartTSOffset;
2766                    _pcompositionOffsetAtom->resetStateVariables();
2767                    return retValC;
2768                }
2769            }
2770            return INSUFFICIENT_BUFFER_SIZE;
2771        }
2772
2773        if (oStoreOffset)
2774            _currChunkOffset += sigmaSampleSize;
2775        else
2776            _currChunkOffset  = 0;
2777#if (PVLOGGER_INST_LEVEL > PVLOGMSG_INST_LLDBG)
2778        currticks = OsclTickCount::TickCount();
2779        StartTime = OsclTickCount::TicksToMsec(currticks);
2780#endif
2781#ifdef OPEN_FILE_ONCE_PER_TRACK
2782        if (_oPVContentDownloadable)
2783        {
2784            if (_currentPlaybackSampleNumber == 0)
2785            {
2786                AtomUtils::seekFromStart(_pinput, sampleFileOffset);
2787            }
2788        }
2789        else
2790        {
2791            AtomUtils::seekFromStart(_pinput, sampleFileOffset);
2792        }
2793#else
2794        AtomUtils::seekFromStart(_pinput, sampleFileOffset);
2795#endif
2796#if (PVLOGGER_INST_LEVEL > PVLOGMSG_INST_LLDBG)
2797        currticks = OsclTickCount::TickCount();
2798        EndTime = OsclTickCount::TicksToMsec(currticks);
2799        totalTimeFileSeek += (EndTime - StartTime);
2800
2801        currticks = OsclTickCount::TickCount();
2802        StartTime = OsclTickCount::TicksToMsec(currticks);
2803#endif
2804        start = 0;
2805        rewindPos = 0;
2806        for (k = start; k < end; k++)
2807        {
2808            uint32 tmpSize =
2809                (tempgauPtr->buf.fragments[k].len > sigmaSampleSize) ? sigmaSampleSize : tempgauPtr->buf.fragments[k].len;
2810            if (tmpSize)
2811            {
2812                if (!AtomUtils::readByteData(_pinput, tmpSize,
2813                                             (uint8 *)(tempgauPtr->buf.fragments[k].ptr)))
2814                {
2815                    *n = 0;
2816                    _mp4ErrorCode =  READ_FAILED;
2817                    return (_mp4ErrorCode);
2818                }
2819                tempgauPtr->buf.fragments[k].len -= tmpSize;
2820
2821                uint8* fragment_ptr = NULL;
2822                fragment_ptr = (uint8 *)(tempgauPtr->buf.fragments[k].ptr);
2823                fragment_ptr += tmpSize;
2824                tempgauPtr->buf.fragments[k].ptr = fragment_ptr;
2825
2826                sigmaSampleSize -= tmpSize;
2827                totalBytesRead += tmpSize;
2828
2829            }
2830            rewindPos += tmpSize;
2831
2832            if (sigmaSampleSize == 0)
2833            {
2834                break;
2835            }
2836        }
2837#if (PVLOGGER_INST_LEVEL > PVLOGMSG_INST_LLDBG)
2838        currticks = OsclTickCount::TickCount();
2839        EndTime = OsclTickCount::TicksToMsec(currticks);
2840        totalTimeFileRead += (EndTime - StartTime);
2841#endif
2842
2843        sampleNum = sampleNum + numSamples;
2844
2845        /*
2846         * This check is required to protect the FF lib from context
2847         * switching.
2848         */
2849        if (_currentPlaybackSampleNumber == sampleBeforeGet)
2850        {
2851            _currentPlaybackSampleNumber += numSamples;
2852            sampleBeforeGet += numSamples;
2853        }
2854        else
2855        {
2856            break;
2857        }
2858
2859        if (_currentPlaybackSampleNumber >= (int32)totalnumSamples)
2860        {
2861            _mp4ErrorCode = END_OF_TRACK;
2862            break;
2863        }
2864    }
2865
2866    if (_currentPlaybackSampleNumber == sampleBeforeGet)
2867    {
2868        _currentPlaybackSampleTimestamp = currTSBase;
2869        *n = (*n - samplesYetToBeRead);
2870#if (PVLOGGER_INST_LEVEL > PVLOGMSG_INST_LLDBG)
2871        if (totalTimeSTSC > PV_MP4_PARSER_SAMPLE_READ_DIAGLOG_THRESHOLD_IN_MS)
2872        {
2873            PVMF_MP4FFPARSER_LOGDIAGNOSTICS((0, "PVMFMP4FFParserNode - SampleTableAtom::totalTimeSTSZ - NPT=%d, N=%d, Time=%d",
2874                                             currTSBase,
2875                                             *n,
2876                                             totalTimeSTSC));
2877        }
2878        if (totalTimeSTSZ > PV_MP4_PARSER_SAMPLE_READ_DIAGLOG_THRESHOLD_IN_MS)
2879        {
2880            PVMF_MP4FFPARSER_LOGDIAGNOSTICS((0, "SampleTableAtom::totalTimeSTSZ - NPT=%d, N=%d, Time=%d",
2881                                             currTSBase,
2882                                             *n,
2883                                             totalTimeSTSZ));
2884        }
2885        if (totalTimeSTTS > PV_MP4_PARSER_SAMPLE_READ_DIAGLOG_THRESHOLD_IN_MS)
2886        {
2887            PVMF_MP4FFPARSER_LOGDIAGNOSTICS((0, "SampleTableAtom::totalTimeSTTS - NPT=%d, N=%d, Time=%d",
2888                                             currTSBase,
2889                                             *n,
2890                                             totalTimeSTTS));
2891        }
2892        if (totalTimeCTTS > PV_MP4_PARSER_SAMPLE_READ_DIAGLOG_THRESHOLD_IN_MS)
2893        {
2894            PVMF_MP4FFPARSER_LOGDIAGNOSTICS((0, "SampleTableAtom::totalTimeCTTS - NPT=%d, N=%d, Time=%d",
2895                                             currTSBase,
2896                                             *n,
2897                                             totalTimeCTTS));
2898        }
2899        if (totalTimeFileSeek > PV_MP4_PARSER_SAMPLE_READ_DIAGLOG_THRESHOLD_IN_MS)
2900        {
2901            PVMF_MP4FFPARSER_LOGDIAGNOSTICS((0, "SampleTableAtom::totalTimeFileSeek - NPT=%d, N=%d, Time=%d",
2902                                             currTSBase,
2903                                             *n,
2904                                             totalTimeFileSeek));
2905        }
2906        if (totalTimeFileRead > PV_MP4_PARSER_SAMPLE_READ_DIAGLOG_THRESHOLD_IN_MS)
2907        {
2908            PVMF_MP4FFPARSER_LOGDIAGNOSTICS((0, "SampleTableAtom::totalTimeFileRead - NPT=%d, N=%d, BytesRead=%d, Time=%d",
2909                                             currTSBase,
2910                                             *n,
2911                                             totalBytesRead,
2912                                             totalTimeFileRead));
2913        }
2914#endif
2915    }
2916    else
2917    {
2918        if (_currentPlaybackSampleNumber > 0)
2919        {
2920            _currentPlaybackSampleTimestamp =
2921                getTimestampForSampleNumber(_currentPlaybackSampleNumber - 1);
2922
2923            _currentPlaybackSampleTimestamp += _trackStartTSOffset;
2924        }
2925        else
2926        {
2927            _currentPlaybackSampleTimestamp = _trackStartTSOffset + getCttsOffsetForSampleNumber(0);
2928        }
2929
2930        *n = 0;
2931        if (_mp4ErrorCode != INSUFFICIENT_BUFFER_SIZE)
2932        {
2933            _mp4ErrorCode = READ_FAILED;
2934        }
2935    }
2936    return (_mp4ErrorCode);
2937}
2938
2939int32
2940SampleTableAtom::peekNextNSamples(uint32 startSampleNum,
2941                                  uint32 *n,
2942                                  MediaMetaInfo    *mInfo)
2943{//this API is only called in peekNextBundledAccessUnits(), which already check _psampleSizeAtom is NULL
2944
2945
2946    int32 currTSBase = _currentPlaybackSampleTimestamp;
2947    int32 i = 0;
2948    uint32 sampleNum = startSampleNum;
2949    int32 samplesToBePeeked = *n;
2950
2951    int32  _mp4ErrorCode = EVERYTHING_FINE;
2952
2953    if (_psampleToChunkAtom->getCurrPeekSampleCount() !=
2954            (uint32)_currentPlaybackSampleNumber)
2955    {
2956        _psampleToChunkAtom->resetPeekwithGet();
2957    }
2958
2959    if (_ptimeToSampleAtom->getCurrPeekSampleCount() !=
2960            (uint32)_currentPlaybackSampleNumber)
2961    {
2962        _ptimeToSampleAtom->resetPeekwithGet();
2963    }
2964
2965
2966
2967    // return NULL if sampleNum is past end of stream
2968    uint32 numSamples = _psampleSizeAtom->getSampleCount();
2969
2970    if (startSampleNum + samplesToBePeeked >= numSamples)
2971    {
2972        _mp4ErrorCode = END_OF_TRACK;
2973        if (startSampleNum >= numSamples)
2974        {
2975            *n = 0;
2976            return (_mp4ErrorCode); // Past end of samples
2977        }
2978        samplesToBePeeked = numSamples - startSampleNum;
2979        *n = samplesToBePeeked;
2980    }
2981
2982    if ((_IsUpdateFileSize)
2983            && (_psampleDescriptionAtom->getMediaType() != MEDIA_TYPE_TEXT))
2984    {
2985        //1. check if the data is available for PS
2986        //!!!!!!!!!!!!!!!!ASSUME the sample arranged in time order in the file!!!!!!!!
2987        // Find chunk
2988        uint32 lastSampleNum = startSampleNum + samplesToBePeeked - 1;
2989
2990        int32 chunk =   _psampleToChunkAtom->getChunkNumberForSamplePeek(sampleNum);
2991
2992        if (chunk == PV_ERROR)
2993        {
2994            *n = 0;
2995            return READ_SAMPLE_TO_CHUNK_ATOM_FAILED;
2996        }
2997        // Find first sample in that chunk
2998        int32 first = _psampleToChunkAtom->getFirstSampleNumInChunkPeek();
2999
3000        // Find chunk offset to file
3001        int32 sampleSizeOffset = _pchunkOffsetAtom->getChunkOffsetAt(chunk);
3002        if (sampleSizeOffset == PV_ERROR)
3003        {
3004            *n = 0;
3005            return READ_FAILED;
3006        }
3007
3008        int32 tempSize = 0;
3009        for (uint32 i = first; i < lastSampleNum; i++)
3010        {
3011            // Check sample size from SampleSizeAtom
3012            tempSize = _psampleSizeAtom->getSampleSizeAt(i);
3013
3014            // Check for error condition
3015            if (tempSize == -1)
3016            {
3017                *n = 0;
3018                return READ_SAMPLE_SIZE_ATOM_FAILED;
3019            }
3020
3021            sampleSizeOffset += tempSize;
3022        }
3023        if (sampleSizeOffset > (int32)_fileSize)
3024        {
3025            *n = 0;
3026            return READ_FAILED;
3027        }
3028    }
3029
3030    if (sampleNum == 0)
3031    {
3032        // Add TS offset to sample timestamps
3033        currTSBase = _trackStartTSOffset;
3034    }
3035
3036    for (i = 0; i < samplesToBePeeked; i++)
3037    {
3038        // Find chunk
3039        int32 chunk = _psampleToChunkAtom->getChunkNumberForSamplePeek(sampleNum);
3040
3041        if (chunk == PV_ERROR)
3042        {
3043            *n = (*n - samplesToBePeeked);
3044            return READ_SAMPLE_TO_CHUNK_ATOM_FAILED;
3045        }
3046
3047        int32 SDIndex = _psampleToChunkAtom->getSDIndexPeek();
3048
3049        if (SDIndex > 0)
3050        {
3051            SDIndex -= 1;
3052        }
3053        int32    tempSize = _psampleSizeAtom->getSampleSizeAt(sampleNum);
3054
3055        // Check for error condition
3056        if (tempSize == PV_ERROR)
3057        {
3058            *n = (*n - samplesToBePeeked);
3059            return INVALID_SAMPLE_SIZE;
3060        }
3061
3062        int32 tsDelta =
3063            _ptimeToSampleAtom->getTimeDeltaForSampleNumberPeek(sampleNum);
3064
3065        if (tsDelta == PV_ERROR)
3066        {
3067            *n = 0;
3068            return READ_TIME_TO_SAMPLE_ATOM_FAILED;
3069        }
3070
3071
3072        mInfo[i].sample_info = SDIndex;
3073
3074        //SET THE META INFO HERE
3075        mInfo[i].len = tempSize;
3076        mInfo[i].ts_delta = tsDelta;
3077        mInfo[i].ts = currTSBase + getCttsOffsetForSampleNumberPeek(sampleNum);
3078        currTSBase += tsDelta;
3079
3080        PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleTableAtom::peekNextNSamples- mInfo[%d].len =%d", i, mInfo[i].len));
3081        PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleTableAtom::peekNextNSamples- mInfo[%d].ts_delta =%d", i, mInfo[i].ts_delta));
3082        PVMF_MP4FFPARSER_LOGMEDIASAMPELSTATEVARIABLES((0, "SampleTableAtom::peekNextNSamples- mInfo[%d].ts =%d", i, mInfo[i].ts));
3083
3084        sampleNum ++;
3085    }
3086    return (_mp4ErrorCode);
3087}
3088
3089int32 SampleTableAtom::getOffsetByTime(uint32 ts, int32* sampleFileOffset)
3090{
3091
3092    if ((_psampleSizeAtom    == NULL) ||
3093            (_psampleToChunkAtom == NULL) ||
3094            (_ptimeToSampleAtom == NULL) ||
3095            (_pchunkOffsetAtom   == NULL))
3096    {
3097        return DEFAULT_ERROR;
3098    }
3099
3100    int32 sampleNum = _ptimeToSampleAtom->getSampleNumberFromTimestamp(ts, true);
3101
3102    if (sampleNum == PV_ERROR)
3103    {
3104        return DEFAULT_ERROR;
3105    }
3106    // Go for composition offset adjustment.
3107    sampleNum =
3108        getSampleNumberAdjustedWithCTTS(ts, sampleNum);
3109
3110    // return NULL if sampleNum is past end of stream
3111    uint32 numSamples = _psampleSizeAtom->getSampleCount();
3112
3113    if (sampleNum >= (int32)numSamples)
3114    {
3115        sampleNum = numSamples - 1;
3116    }
3117
3118    int32 sampleSizeOffset = 0;
3119    if (ts != (uint32) getTimestampForSampleNumber(sampleNum))
3120    {
3121        sampleSizeOffset = _psampleSizeAtom->getSampleSizeAt(sampleNum);
3122        if (sampleSizeOffset <= 0)
3123        {
3124            return DEFAULT_ERROR;
3125        }
3126    }
3127
3128    // Find chunk
3129    int32 chunk = getMutableSampleToChunkAtom().getChunkNumberForSample(sampleNum);
3130    // Find first sample in that chunk
3131    int32 first = _psampleToChunkAtom->getFirstSampleNumInChunk(chunk);
3132
3133    // Find chunk offset to file
3134    int32 offset = _pchunkOffsetAtom->getChunkOffsetAt(chunk);
3135    if (offset == PV_ERROR)
3136    {
3137        return DEFAULT_ERROR;
3138    }
3139
3140    // Need to add up all the sizes from the first sample in this run up to the
3141    // the requested sample (but not including it)
3142    int32 tempSize = 0;
3143
3144
3145    for (int32 i = first; i < sampleNum; i++)
3146    {
3147        // Check sample size from SampleSizeAtom
3148        tempSize = _psampleSizeAtom->getSampleSizeAt(i);;
3149        if (tempSize <= 0)
3150        {
3151            return DEFAULT_ERROR;
3152        }
3153
3154        sampleSizeOffset += tempSize;
3155    }
3156
3157    // Find actual file offset to sample
3158    *sampleFileOffset = offset + sampleSizeOffset;
3159    getSampleSizeAtom()._SkipOldEntry = true;
3160    if (sampleNum == (int32)(numSamples - 1))
3161    {
3162        return LAST_SAMPLE_IN_MOOV;
3163    }
3164    else
3165    {
3166        return EVERYTHING_FINE;
3167    }
3168}
3169
3170int32 SampleTableAtom::updateFileSize(uint32 filesize)
3171{
3172    _fileSize = filesize;
3173    _IsUpdateFileSize = 1;
3174    if (_pinput->IsOpen())
3175    {
3176        if (AtomUtils::Flush(_pinput))
3177        {
3178            return DEFAULT_ERROR;   //error
3179        }
3180    }
3181    return EVERYTHING_FINE;
3182}
3183
3184MP4_ERROR_CODE
3185SampleTableAtom::getMaxTrackTimeStamp(uint32 fileSize, uint32& timeStamp)
3186{
3187    timeStamp = 0;
3188
3189    /*
3190     * Get the chunk that is closest to "fileSize"
3191     */
3192    int32 chunk;
3193
3194    int32 retVal =
3195        _pchunkOffsetAtom->getChunkClosestToOffset(fileSize, chunk);
3196
3197    if (retVal == EVERYTHING_FINE)
3198    {
3199        /*
3200         * Get chunk offset for the chunk
3201         */
3202        int32 chunkOffset = _pchunkOffsetAtom->getChunkOffsetAt(chunk);
3203
3204        /*
3205         * Find the first sample in chunk
3206         */
3207        uint32 FirstSampleNumInChunk =
3208            _psampleToChunkAtom->getFirstSampleNumInChunk(chunk);
3209
3210        /*
3211         * Get number of samples in this chunk
3212         */
3213        uint32 numSamplesPerChunk =
3214            getSampleToChunkAtom().getSamplesPerChunkCorrespondingToSampleGet();
3215
3216        /*
3217         * Get the sample closest to the specified fileSize.
3218         * Need to add up all the sizes from the first sample in this run
3219         * up to the the closest sample
3220         */
3221        int32 tempSize = 0;
3222        uint32 sampleNum = FirstSampleNumInChunk ? (FirstSampleNumInChunk - 1) : 0;
3223
3224        do
3225        {
3226            // Check sample size from SampleSizeAtom
3227            tempSize = getSampleSizeAtom().getDefaultSampleSize();
3228
3229            if (tempSize == 0)
3230            {
3231                // Need to get specific sample size
3232                tempSize = getSampleSizeAtom().getSampleSizeAt(sampleNum);
3233            }
3234            sampleNum++;
3235            if (tempSize == PV_ERROR)
3236            {
3237                return READ_FAILED;
3238            }
3239            chunkOffset += tempSize;
3240
3241            if ((uint32)chunkOffset > fileSize)
3242            {
3243                sampleNum--;
3244                break;
3245            }
3246        }
3247        while (sampleNum < (FirstSampleNumInChunk + numSamplesPerChunk - 1));
3248
3249        /*
3250         * Get time stamp corresponding to sampleNum
3251         */
3252        int32 ts = getTimestampForSampleNumber(sampleNum);
3253
3254        if (ts == PV_ERROR)
3255        {
3256            return (READ_FAILED);
3257        }
3258        timeStamp = ts + getCttsOffsetForSampleNumber(sampleNum);
3259    }
3260    return (EVERYTHING_FINE);
3261}
3262
3263MP4_ERROR_CODE
3264SampleTableAtom::getSampleNumberClosestToTimeStamp(uint32 &sampleNumber,
3265        uint32 timeStamp,
3266        uint32 sampleOffset)
3267{
3268    sampleNumber = 0;
3269
3270    if ((_psampleSizeAtom    == NULL) ||
3271            (_psampleToChunkAtom == NULL) ||
3272            (_ptimeToSampleAtom  == NULL) ||
3273            (_pchunkOffsetAtom   == NULL))
3274    {
3275        return (READ_FAILED);
3276    }
3277
3278    uint32 totalNumSamplesInTrack = getSampleSizeAtom().getSampleCount();
3279
3280    if (totalNumSamplesInTrack > 0)
3281    {
3282        if (timeStamp > _trackStartTSOffset)
3283        {
3284            sampleNumber =
3285                getTimeToSampleAtom().getSampleNumberFromTimestamp((timeStamp - _trackStartTSOffset), true);
3286            // Go for composition offset adjustment.
3287            sampleNumber =
3288                getSampleNumberAdjustedWithCTTS((timeStamp - _trackStartTSOffset), sampleNumber);
3289
3290
3291            if ((int32)sampleNumber == PV_ERROR)
3292            {
3293                return (READ_FAILED);
3294            }
3295            else if ((sampleNumber + sampleOffset) >= totalNumSamplesInTrack)
3296            {
3297                sampleNumber = (totalNumSamplesInTrack - 1);
3298                return (END_OF_TRACK);
3299            }
3300        }
3301        else
3302        {
3303            sampleNumber = 0;
3304        }
3305        sampleNumber += sampleOffset;
3306        return (EVERYTHING_FINE);
3307    }
3308    else
3309    {
3310        return (READ_FAILED);
3311    }
3312}
3313
3314
3315// This function takes the presentation time stamp and the sample number calculated
3316// referring stts api getSampleNumberFromTimestamp.
3317// We look for all the samples which has (decode time  + ctts >= presentation timestamp)
3318// before this sample and return the most nearest to presentation timestamp.
3319int32 SampleTableAtom::
3320getSampleNumberAdjustedWithCTTS(uint32 aTs, int32 aSampleNumber)
3321{
3322    uint32 minimumTimestamp   = 0; //stores minimum ts encountered
3323    int32  minimumTsFrameNum  = 0; //stores frame num of minimum ts
3324    int32  curSampleParsed   = 0; //stores number of sample currently parsed
3325    uint32 curSampleTs       = 0; //stores timestamp of current sample
3326
3327    // CTTS not present do nothing.
3328    if (NULL == _pcompositionOffsetAtom)
3329    {
3330        return aSampleNumber;
3331    }
3332
3333    //initially we beleive that sample number that we have received is
3334    //minimum sample number available and ts corresponding to this sample number
3335    //is the minimum sample time(including its ctts offset as well)
3336
3337    minimumTsFrameNum = aSampleNumber;
3338    // getTimestampForSampleNumber has CTTS already adjusted
3339    minimumTimestamp  = getTimestampForSampleNumber(minimumTsFrameNum);
3340
3341    //assign curSampleParsed the value of current minimumTsFrameNum
3342    curSampleParsed = minimumTsFrameNum;
3343
3344    for (int loopIndex = 0; loopIndex < BACK_TRAVERSE_FRAME_COUNT; loopIndex++)
3345    {
3346        if (0 == curSampleParsed)
3347        {
3348            // For loop termination
3349            return minimumTsFrameNum;
3350        }
3351        else
3352        {
3353            //get the timestamp of the current sample
3354            curSampleTs = getTimestampForSampleNumber(curSampleParsed);
3355
3356            //if curSampleTs = aTs then this is the sample we needed so return
3357            if (curSampleTs == aTs)
3358            {
3359                return curSampleParsed;
3360            }
3361
3362            //if curSampleTs > aTs and is less than minimumTimestamp
3363            //then this may be the minimum sample that we need to start with
3364            if ((curSampleTs > aTs) && (curSampleTs < minimumTimestamp))
3365            {
3366                minimumTsFrameNum = curSampleParsed;
3367                minimumTimestamp = curSampleTs;
3368            }
3369
3370            //decrement the curSampleParsed to move back to the previous sample
3371            curSampleParsed--;
3372        }
3373    }
3374    return minimumTsFrameNum;
3375}
3376
3377// Returns the timestamp (in milliseconds) for the last sample returned
3378// This is mainly to be used when seeking in the bitstream - you request a frame at timestamp
3379// X, but the actual frame you get is Y, this method returns the timestamp for Y so you know which
3380// audio sample to request.
3381int32 SampleTableAtom::
3382getTimestampForCurrentSample()
3383{
3384    return _currentPlaybackSampleTimestamp;
3385}
3386
3387