• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 The Android Open Source Project
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 express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define LOG_TAG "SampleIterator"
18 //#define LOG_NDEBUG 0
19 #include <utils/Log.h>
20 
21 #include "SampleIterator.h"
22 
23 #include <arpa/inet.h>
24 
25 #include <media/stagefright/foundation/ADebug.h>
26 #include <media/stagefright/foundation/ByteUtils.h>
27 
28 #include "SampleTable.h"
29 
30 namespace android {
31 
SampleIterator(SampleTable * table)32 SampleIterator::SampleIterator(SampleTable *table)
33     : mTable(table),
34       mInitialized(false),
35       mTimeToSampleIndex(0),
36       mTTSSampleIndex(0),
37       mTTSSampleTime(0),
38       mTTSCount(0),
39       mTTSDuration(0) {
40     reset();
41 }
42 
reset()43 void SampleIterator::reset() {
44     mSampleToChunkIndex = 0;
45     mFirstChunk = 0;
46     mFirstChunkSampleIndex = 0;
47     mStopChunk = 0;
48     mStopChunkSampleIndex = 0;
49     mSamplesPerChunk = 0;
50     mChunkDesc = 0;
51 }
52 
seekTo(uint32_t sampleIndex)53 status_t SampleIterator::seekTo(uint32_t sampleIndex) {
54     ALOGV("seekTo(%d)", sampleIndex);
55 
56     if (sampleIndex >= mTable->mNumSampleSizes) {
57         return ERROR_END_OF_STREAM;
58     }
59 
60     if (mTable->mSampleToChunkOffset < 0
61             || mTable->mChunkOffsetOffset < 0
62             || mTable->mSampleSizeOffset < 0
63             || mTable->mTimeToSampleCount == 0) {
64 
65         return ERROR_MALFORMED;
66     }
67 
68     if (mInitialized && mCurrentSampleIndex == sampleIndex) {
69         return OK;
70     }
71 
72     if (!mInitialized || sampleIndex < mFirstChunkSampleIndex) {
73         reset();
74     }
75 
76     if (sampleIndex >= mStopChunkSampleIndex) {
77         status_t err;
78         if ((err = findChunkRange(sampleIndex)) != OK) {
79             ALOGE("findChunkRange failed");
80             return err;
81         }
82     }
83 
84     CHECK(sampleIndex < mStopChunkSampleIndex);
85 
86     if (mSamplesPerChunk == 0) {
87         ALOGE("b/22802344");
88         return ERROR_MALFORMED;
89     }
90 
91     uint32_t chunk =
92         (sampleIndex - mFirstChunkSampleIndex) / mSamplesPerChunk
93         + mFirstChunk;
94 
95     if (!mInitialized || chunk != mCurrentChunkIndex) {
96         status_t err;
97         if ((err = getChunkOffset(chunk, &mCurrentChunkOffset)) != OK) {
98             ALOGE("getChunkOffset return error");
99             return err;
100         }
101 
102         mCurrentChunkSampleSizes.clear();
103 
104         uint32_t firstChunkSampleIndex =
105             mFirstChunkSampleIndex
106                 + mSamplesPerChunk * (chunk - mFirstChunk);
107 
108         for (uint32_t i = 0; i < mSamplesPerChunk; ++i) {
109             size_t sampleSize;
110             if ((err = getSampleSizeDirect(
111                             firstChunkSampleIndex + i, &sampleSize)) != OK) {
112                 ALOGE("getSampleSizeDirect return error");
113                 // stsc sample count is not sync with stsz sample count
114                 if (err == ERROR_OUT_OF_RANGE) {
115                     ALOGW("stsc samples(%d) not sync with stsz samples(%d)", mSamplesPerChunk, i);
116                     mSamplesPerChunk = i;
117                     break;
118                 } else{
119                     mCurrentChunkSampleSizes.clear();
120                     return err;
121                 }
122             }
123 
124             mCurrentChunkSampleSizes.push(sampleSize);
125         }
126 
127         mCurrentChunkIndex = chunk;
128     }
129 
130     uint32_t chunkRelativeSampleIndex =
131         (sampleIndex - mFirstChunkSampleIndex) % mSamplesPerChunk;
132 
133     mCurrentSampleOffset = mCurrentChunkOffset;
134     for (uint32_t i = 0; i < chunkRelativeSampleIndex; ++i) {
135         mCurrentSampleOffset += mCurrentChunkSampleSizes[i];
136     }
137 
138     mCurrentSampleSize = mCurrentChunkSampleSizes[chunkRelativeSampleIndex];
139     if (sampleIndex < mTTSSampleIndex) {
140         mTimeToSampleIndex = 0;
141         mTTSSampleIndex = 0;
142         mTTSSampleTime = 0;
143         mTTSCount = 0;
144         mTTSDuration = 0;
145     }
146 
147     status_t err;
148     if ((err = findSampleTimeAndDuration(
149             sampleIndex, &mCurrentSampleTime, &mCurrentSampleDuration)) != OK) {
150         ALOGE("findSampleTime return error");
151         return err;
152     }
153 
154     mCurrentSampleIndex = sampleIndex;
155 
156     mInitialized = true;
157 
158     return OK;
159 }
160 
findChunkRange(uint32_t sampleIndex)161 status_t SampleIterator::findChunkRange(uint32_t sampleIndex) {
162     CHECK(sampleIndex >= mFirstChunkSampleIndex);
163 
164     while (sampleIndex >= mStopChunkSampleIndex) {
165         if (mSampleToChunkIndex == mTable->mNumSampleToChunkOffsets) {
166             return ERROR_OUT_OF_RANGE;
167         }
168 
169         mFirstChunkSampleIndex = mStopChunkSampleIndex;
170 
171         const SampleTable::SampleToChunkEntry *entry =
172             &mTable->mSampleToChunkEntries[mSampleToChunkIndex];
173 
174         mFirstChunk = entry->startChunk;
175         mSamplesPerChunk = entry->samplesPerChunk;
176         mChunkDesc = entry->chunkDesc;
177 
178         if (mSampleToChunkIndex + 1 < mTable->mNumSampleToChunkOffsets) {
179             mStopChunk = entry[1].startChunk;
180 
181             if (mSamplesPerChunk == 0 || mStopChunk < mFirstChunk ||
182                 (mStopChunk - mFirstChunk) > UINT32_MAX / mSamplesPerChunk ||
183                 ((mStopChunk - mFirstChunk) * mSamplesPerChunk >
184                  UINT32_MAX - mFirstChunkSampleIndex)) {
185 
186                 return ERROR_OUT_OF_RANGE;
187             }
188             mStopChunkSampleIndex =
189                 mFirstChunkSampleIndex
190                     + (mStopChunk - mFirstChunk) * mSamplesPerChunk;
191         } else {
192             mStopChunk = 0xffffffff;
193             mStopChunkSampleIndex = 0xffffffff;
194         }
195 
196         ++mSampleToChunkIndex;
197     }
198 
199     return OK;
200 }
201 
getChunkOffset(uint32_t chunk,off64_t * offset)202 status_t SampleIterator::getChunkOffset(uint32_t chunk, off64_t *offset) {
203     *offset = 0;
204 
205     if (chunk >= mTable->mNumChunkOffsets) {
206         return ERROR_OUT_OF_RANGE;
207     }
208 
209     if (mTable->mChunkOffsetType == SampleTable::kChunkOffsetType32) {
210         uint32_t offset32;
211 
212         if (mTable->mDataSource->readAt(
213                     mTable->mChunkOffsetOffset + 8 + 4 * chunk,
214                     &offset32,
215                     sizeof(offset32)) < (ssize_t)sizeof(offset32)) {
216             return ERROR_IO;
217         }
218 
219         *offset = ntohl(offset32);
220     } else {
221         CHECK_EQ(mTable->mChunkOffsetType, SampleTable::kChunkOffsetType64);
222 
223         uint64_t offset64;
224         if (mTable->mDataSource->readAt(
225                     mTable->mChunkOffsetOffset + 8 + 8 * chunk,
226                     &offset64,
227                     sizeof(offset64)) < (ssize_t)sizeof(offset64)) {
228             return ERROR_IO;
229         }
230 
231         *offset = ntoh64(offset64);
232     }
233 
234     return OK;
235 }
236 
getSampleSizeDirect(uint32_t sampleIndex,size_t * size)237 status_t SampleIterator::getSampleSizeDirect(
238         uint32_t sampleIndex, size_t *size) {
239     *size = 0;
240 
241     if (sampleIndex >= mTable->mNumSampleSizes) {
242         return ERROR_OUT_OF_RANGE;
243     }
244 
245     if (mTable->mDefaultSampleSize > 0) {
246         *size = mTable->mDefaultSampleSize;
247         return OK;
248     }
249 
250     switch (mTable->mSampleSizeFieldSize) {
251         case 32:
252         {
253             uint32_t x;
254             if (mTable->mDataSource->readAt(
255                         mTable->mSampleSizeOffset + 12 + 4 * sampleIndex,
256                         &x, sizeof(x)) < (ssize_t)sizeof(x)) {
257                 return ERROR_IO;
258             }
259 
260             *size = ntohl(x);
261             break;
262         }
263 
264         case 16:
265         {
266             uint16_t x;
267             if (mTable->mDataSource->readAt(
268                         mTable->mSampleSizeOffset + 12 + 2 * sampleIndex,
269                         &x, sizeof(x)) < (ssize_t)sizeof(x)) {
270                 return ERROR_IO;
271             }
272 
273             *size = ntohs(x);
274             break;
275         }
276 
277         case 8:
278         {
279             uint8_t x;
280             if (mTable->mDataSource->readAt(
281                         mTable->mSampleSizeOffset + 12 + sampleIndex,
282                         &x, sizeof(x)) < (ssize_t)sizeof(x)) {
283                 return ERROR_IO;
284             }
285 
286             *size = x;
287             break;
288         }
289 
290         default:
291         {
292             CHECK_EQ(mTable->mSampleSizeFieldSize, 4u);
293 
294             uint8_t x;
295             if (mTable->mDataSource->readAt(
296                         mTable->mSampleSizeOffset + 12 + sampleIndex / 2,
297                         &x, sizeof(x)) < (ssize_t)sizeof(x)) {
298                 return ERROR_IO;
299             }
300 
301             *size = (sampleIndex & 1) ? x & 0x0f : x >> 4;
302             break;
303         }
304     }
305 
306     return OK;
307 }
308 
findSampleTimeAndDuration(uint32_t sampleIndex,uint64_t * time,uint64_t * duration)309 status_t SampleIterator::findSampleTimeAndDuration(
310         uint32_t sampleIndex, uint64_t *time, uint64_t *duration) {
311     if (sampleIndex >= mTable->mNumSampleSizes) {
312         return ERROR_OUT_OF_RANGE;
313     }
314 
315     while (true) {
316         if (mTTSSampleIndex > UINT32_MAX - mTTSCount) {
317             return ERROR_OUT_OF_RANGE;
318         }
319         if(sampleIndex < mTTSSampleIndex + mTTSCount) {
320             break;
321         }
322         if (mTimeToSampleIndex == mTable->mTimeToSampleCount ||
323             (mTTSDuration != 0 && mTTSCount > UINT64_MAX / mTTSDuration) ||
324             mTTSSampleTime > UINT64_MAX - (mTTSCount * mTTSDuration)) {
325             return ERROR_OUT_OF_RANGE;
326         }
327 
328         mTTSSampleIndex += mTTSCount;
329         mTTSSampleTime += mTTSCount * mTTSDuration;
330 
331         mTTSCount = mTable->mTimeToSample[2 * mTimeToSampleIndex];
332         mTTSDuration = mTable->mTimeToSample[2 * mTimeToSampleIndex + 1];
333 
334         ++mTimeToSampleIndex;
335     }
336 
337     // below is equivalent to:
338     // *time = mTTSSampleTime + mTTSDuration * (sampleIndex - mTTSSampleIndex);
339     uint64_t tmp;
340     if (__builtin_sub_overflow(sampleIndex, mTTSSampleIndex, &tmp) ||
341             __builtin_mul_overflow(mTTSDuration, tmp, &tmp) ||
342             __builtin_add_overflow(mTTSSampleTime, tmp, &tmp)) {
343         return ERROR_OUT_OF_RANGE;
344     }
345     *time = tmp;
346 
347     int32_t offset = mTable->getCompositionTimeOffset(sampleIndex);
348     if ((offset < 0 && *time < (offset == INT32_MIN ?
349             INT64_MAX : uint64_t(-offset))) ||
350             (offset > 0 && *time > UINT64_MAX - offset)) {
351         ALOGE("%llu + %d would overflow", (unsigned long long) *time, offset);
352         return ERROR_OUT_OF_RANGE;
353     }
354     if (offset > 0) {
355         *time += offset;
356     } else {
357         *time -= (offset == INT32_MIN ? INT64_MAX : (-offset));
358     }
359 
360     *duration = mTTSDuration;
361 
362     return OK;
363 }
364 
365 }  // namespace android
366 
367