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 SyncSampleAtom Class                           */
21/*     -------------------------------------------------------------------       */
22/*********************************************************************************/
23/*
24    This SyncSampleAtom Class provides a compact marking of the random access
25    points within the stream.
26*/
27
28
29#define IMPLEMENT_SyncSampleAtom
30
31#include "syncsampleatom.h"
32#include "atomutils.h"
33#include "atomdefs.h"
34
35// Stream-in constructor
36SyncSampleAtom::SyncSampleAtom(MP4_FF_FILE *fp, uint32 size, uint32 type)
37        : FullAtom(fp, size, type)
38{
39    _psampleNumbers = NULL;
40
41    if (_success)
42    {
43
44        _nextSampleNumber = 0;
45
46        if (!AtomUtils::read32(fp, _entryCount))
47        {
48            _success = false;
49        }
50
51        uint32 dataSize = _size - (DEFAULT_FULL_ATOM_SIZE + 4);
52
53        uint32 entrySize = (4);
54
55        if ((_entryCount*entrySize) > dataSize)
56        {
57            _success = false;
58        }
59
60        if (_success)
61        {
62
63            PV_MP4_FF_ARRAY_NEW(NULL, uint32, (_entryCount), _psampleNumbers);
64
65            uint32 sync;
66            for (uint32 i = 0; i < _entryCount; i++)
67            {
68                if (!AtomUtils::read32(fp, sync))
69                {
70                    _success = false;
71                    break;
72                }
73                _psampleNumbers[i] = (sync);
74            }
75        }
76
77        if (!_success)
78            _mp4ErrorCode = READ_SYNC_SAMPLE_ATOM_FAILED;
79    }
80    else
81    {
82        if (_mp4ErrorCode != ATOM_VERSION_NOT_SUPPORTED)
83            _mp4ErrorCode = READ_SYNC_SAMPLE_ATOM_FAILED;
84    }
85}
86
87// Destructor
88SyncSampleAtom::~SyncSampleAtom()
89{
90    // Cleanup vector
91    if (_psampleNumbers != NULL)
92    {
93        PV_MP4_ARRAY_DELETE(NULL, _psampleNumbers);
94        _psampleNumbers = NULL;
95    }
96}
97
98// Returns the sync sample number at vector location 'index'
99int32
100SyncSampleAtom::getSampleNumberAt(int32 index) const
101{
102    if (index < (int32)_entryCount)
103    {
104        return (_psampleNumbers[index] - 1);
105    }
106    else
107    {
108        return PV_ERROR;
109    }
110}
111
112// Returns the first sync sample that occurs at or after 'sampleNum'.  This is used
113// when seeking in the bitstream trying to find a random access sample.  This method
114// returns the random access sample that is closest immediately following 'sampleNum'
115int32
116SyncSampleAtom::getSyncSampleFollowing(uint32 sampleNum) const
117{
118    uint32 sync = 0;
119    int32 count = 0;
120    while (sync < sampleNum)
121    {
122        if (count < (int32)_entryCount)
123        {
124            sync = _psampleNumbers[count] - 1;
125            count ++;
126        }
127        else
128        {
129            return PV_ERROR;
130        }
131    }
132
133    // Incase the sampleNum is one of the sync sample the existing sync
134    // is same as sampleNum In this way the sample return from getSyncSampleFollowing
135    // and getSyncSampleBefore become same causing repos issue. This check
136    // will advance the sync to next I frame incase it is available
137    if (sync == sampleNum)
138    {
139        if (count < (int32)_entryCount)
140        {
141            sync = _psampleNumbers[count] - 1;
142        }
143
144        // No I frame ahead exists, return 0 will ensure that engine ignore reposition and continue playing from current position
145        else
146        {
147            sync = 0;
148        }
149    }
150
151    return sync;
152}
153
154// Returns the first sync sample that occurs at or after 'sampleNum'.  This is used
155// when seeking in the bitstream trying to find a random access sample.  This method
156// returns the random access sample that is closest immediately following 'sampleNum'
157int32
158SyncSampleAtom::getSyncSampleBefore(uint32 sampleNum) const
159{
160    uint32 sync = 0;
161    int32 count = 0;
162
163    //fix resetPlayback at the end of bitstream
164    //_asm {int 3};
165
166    while ((sync < sampleNum) &&
167            (count < (int32)_entryCount))
168    {
169        sync = _psampleNumbers[count] - 1;
170        count ++;
171    }
172
173    //the nearest I frame before sampleNum
174    if (sync <= sampleNum)
175        return sync;
176    else
177    {
178        count = count - 2;
179        sync = _psampleNumbers[count] - 1;
180        return sync;
181    }
182}
183
184
185bool
186SyncSampleAtom::IsSyncSample(uint32 sampleNum) const
187{
188    for (int32 count = 0; count < (int32)_entryCount; count++)
189    {
190        if ((_psampleNumbers[count] - 1) == sampleNum)
191        {
192            return true;
193        }
194    }
195
196    return false;
197}
198
199
200