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