SampleTable.cpp revision c57b67905c2128ddadfeca96785ee1f593b6605a
1/*
2 * Copyright (C) 2009 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 "SampleTable"
18//#define LOG_NDEBUG 0
19#include <utils/Log.h>
20
21#include "include/SampleTable.h"
22#include "include/SampleIterator.h"
23
24#include <arpa/inet.h>
25
26#include <media/stagefright/DataSource.h>
27#include <media/stagefright/MediaDebug.h>
28#include <media/stagefright/Utils.h>
29
30namespace android {
31
32// static
33const uint32_t SampleTable::kChunkOffsetType32 = FOURCC('s', 't', 'c', 'o');
34// static
35const uint32_t SampleTable::kChunkOffsetType64 = FOURCC('c', 'o', '6', '4');
36// static
37const uint32_t SampleTable::kSampleSizeType32 = FOURCC('s', 't', 's', 'z');
38// static
39const uint32_t SampleTable::kSampleSizeTypeCompact = FOURCC('s', 't', 'z', '2');
40
41////////////////////////////////////////////////////////////////////////////////
42
43SampleTable::SampleTable(const sp<DataSource> &source)
44    : mDataSource(source),
45      mChunkOffsetOffset(-1),
46      mChunkOffsetType(0),
47      mNumChunkOffsets(0),
48      mSampleToChunkOffset(-1),
49      mNumSampleToChunkOffsets(0),
50      mSampleSizeOffset(-1),
51      mSampleSizeFieldSize(0),
52      mDefaultSampleSize(0),
53      mNumSampleSizes(0),
54      mTimeToSampleCount(0),
55      mTimeToSample(NULL),
56      mSyncSampleOffset(-1),
57      mNumSyncSamples(0),
58      mSampleToChunkEntries(NULL) {
59    mSampleIterator = new SampleIterator(this);
60}
61
62SampleTable::~SampleTable() {
63    delete[] mSampleToChunkEntries;
64    mSampleToChunkEntries = NULL;
65
66    delete[] mTimeToSample;
67    mTimeToSample = NULL;
68
69    delete mSampleIterator;
70    mSampleIterator = NULL;
71}
72
73status_t SampleTable::setChunkOffsetParams(
74        uint32_t type, off_t data_offset, size_t data_size) {
75    if (mChunkOffsetOffset >= 0) {
76        return ERROR_MALFORMED;
77    }
78
79    CHECK(type == kChunkOffsetType32 || type == kChunkOffsetType64);
80
81    mChunkOffsetOffset = data_offset;
82    mChunkOffsetType = type;
83
84    if (data_size < 8) {
85        return ERROR_MALFORMED;
86    }
87
88    uint8_t header[8];
89    if (mDataSource->readAt(
90                data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
91        return ERROR_IO;
92    }
93
94    if (U32_AT(header) != 0) {
95        // Expected version = 0, flags = 0.
96        return ERROR_MALFORMED;
97    }
98
99    mNumChunkOffsets = U32_AT(&header[4]);
100
101    if (mChunkOffsetType == kChunkOffsetType32) {
102        if (data_size < 8 + mNumChunkOffsets * 4) {
103            return ERROR_MALFORMED;
104        }
105    } else {
106        if (data_size < 8 + mNumChunkOffsets * 8) {
107            return ERROR_MALFORMED;
108        }
109    }
110
111    return OK;
112}
113
114status_t SampleTable::setSampleToChunkParams(
115        off_t data_offset, size_t data_size) {
116    if (mSampleToChunkOffset >= 0) {
117        return ERROR_MALFORMED;
118    }
119
120    mSampleToChunkOffset = data_offset;
121
122    if (data_size < 8) {
123        return ERROR_MALFORMED;
124    }
125
126    uint8_t header[8];
127    if (mDataSource->readAt(
128                data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
129        return ERROR_IO;
130    }
131
132    if (U32_AT(header) != 0) {
133        // Expected version = 0, flags = 0.
134        return ERROR_MALFORMED;
135    }
136
137    mNumSampleToChunkOffsets = U32_AT(&header[4]);
138
139    if (data_size < 8 + mNumSampleToChunkOffsets * 12) {
140        return ERROR_MALFORMED;
141    }
142
143    mSampleToChunkEntries =
144        new SampleToChunkEntry[mNumSampleToChunkOffsets];
145
146    for (uint32_t i = 0; i < mNumSampleToChunkOffsets; ++i) {
147        uint8_t buffer[12];
148        if (mDataSource->readAt(
149                    mSampleToChunkOffset + 8 + i * 12, buffer, sizeof(buffer))
150                != (ssize_t)sizeof(buffer)) {
151            return ERROR_IO;
152        }
153
154        CHECK(U32_AT(buffer) >= 1);  // chunk index is 1 based in the spec.
155
156        // We want the chunk index to be 0-based.
157        mSampleToChunkEntries[i].startChunk = U32_AT(buffer) - 1;
158        mSampleToChunkEntries[i].samplesPerChunk = U32_AT(&buffer[4]);
159        mSampleToChunkEntries[i].chunkDesc = U32_AT(&buffer[8]);
160    }
161
162    return OK;
163}
164
165status_t SampleTable::setSampleSizeParams(
166        uint32_t type, off_t data_offset, size_t data_size) {
167    if (mSampleSizeOffset >= 0) {
168        return ERROR_MALFORMED;
169    }
170
171    CHECK(type == kSampleSizeType32 || type == kSampleSizeTypeCompact);
172
173    mSampleSizeOffset = data_offset;
174
175    if (data_size < 12) {
176        return ERROR_MALFORMED;
177    }
178
179    uint8_t header[12];
180    if (mDataSource->readAt(
181                data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
182        return ERROR_IO;
183    }
184
185    if (U32_AT(header) != 0) {
186        // Expected version = 0, flags = 0.
187        return ERROR_MALFORMED;
188    }
189
190    mDefaultSampleSize = U32_AT(&header[4]);
191    mNumSampleSizes = U32_AT(&header[8]);
192
193    if (type == kSampleSizeType32) {
194        mSampleSizeFieldSize = 32;
195
196        if (mDefaultSampleSize != 0) {
197            return OK;
198        }
199
200        if (data_size < 12 + mNumSampleSizes * 4) {
201            return ERROR_MALFORMED;
202        }
203    } else {
204        if ((mDefaultSampleSize & 0xffffff00) != 0) {
205            // The high 24 bits are reserved and must be 0.
206            return ERROR_MALFORMED;
207        }
208
209        mSampleSizeFieldSize = mDefaultSampleSize & 0xf;
210        mDefaultSampleSize = 0;
211
212        if (mSampleSizeFieldSize != 4 && mSampleSizeFieldSize != 8
213            && mSampleSizeFieldSize != 16) {
214            return ERROR_MALFORMED;
215        }
216
217        if (data_size < 12 + (mNumSampleSizes * mSampleSizeFieldSize + 4) / 8) {
218            return ERROR_MALFORMED;
219        }
220    }
221
222    return OK;
223}
224
225status_t SampleTable::setTimeToSampleParams(
226        off_t data_offset, size_t data_size) {
227    if (mTimeToSample != NULL || data_size < 8) {
228        return ERROR_MALFORMED;
229    }
230
231    uint8_t header[8];
232    if (mDataSource->readAt(
233                data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
234        return ERROR_IO;
235    }
236
237    if (U32_AT(header) != 0) {
238        // Expected version = 0, flags = 0.
239        return ERROR_MALFORMED;
240    }
241
242    mTimeToSampleCount = U32_AT(&header[4]);
243    mTimeToSample = new uint32_t[mTimeToSampleCount * 2];
244
245    size_t size = sizeof(uint32_t) * mTimeToSampleCount * 2;
246    if (mDataSource->readAt(
247                data_offset + 8, mTimeToSample, size) < (ssize_t)size) {
248        return ERROR_IO;
249    }
250
251    for (uint32_t i = 0; i < mTimeToSampleCount * 2; ++i) {
252        mTimeToSample[i] = ntohl(mTimeToSample[i]);
253    }
254
255    return OK;
256}
257
258status_t SampleTable::setSyncSampleParams(off_t data_offset, size_t data_size) {
259    if (mSyncSampleOffset >= 0 || data_size < 8) {
260        return ERROR_MALFORMED;
261    }
262
263    mSyncSampleOffset = data_offset;
264
265    uint8_t header[8];
266    if (mDataSource->readAt(
267                data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
268        return ERROR_IO;
269    }
270
271    if (U32_AT(header) != 0) {
272        // Expected version = 0, flags = 0.
273        return ERROR_MALFORMED;
274    }
275
276    mNumSyncSamples = U32_AT(&header[4]);
277
278    if (mNumSyncSamples < 2) {
279        LOGW("Table of sync samples is empty or has only a single entry!");
280    }
281    return OK;
282}
283
284uint32_t SampleTable::countChunkOffsets() const {
285    return mNumChunkOffsets;
286}
287
288uint32_t SampleTable::countSamples() const {
289    return mNumSampleSizes;
290}
291
292status_t SampleTable::getMaxSampleSize(size_t *max_size) {
293    Mutex::Autolock autoLock(mLock);
294
295    *max_size = 0;
296
297    for (uint32_t i = 0; i < mNumSampleSizes; ++i) {
298        size_t sample_size;
299        status_t err = getSampleSize_l(i, &sample_size);
300
301        if (err != OK) {
302            return err;
303        }
304
305        if (sample_size > *max_size) {
306            *max_size = sample_size;
307        }
308    }
309
310    return OK;
311}
312
313uint32_t abs_difference(uint32_t time1, uint32_t time2) {
314    return time1 > time2 ? time1 - time2 : time2 - time1;
315}
316
317status_t SampleTable::findClosestSample(
318        uint32_t req_time, uint32_t *sample_index, uint32_t flags) {
319    Mutex::Autolock autoLock(mLock);
320
321    uint32_t cur_sample = 0;
322    uint32_t time = 0;
323    for (uint32_t i = 0; i < mTimeToSampleCount; ++i) {
324        uint32_t n = mTimeToSample[2 * i];
325        uint32_t delta = mTimeToSample[2 * i + 1];
326
327        if (req_time < time + n * delta) {
328            int j = (req_time - time) / delta;
329
330            uint32_t time1 = time + j * delta;
331            uint32_t time2 = time1 + delta;
332
333            if (i+1 == mTimeToSampleCount
334                    || (abs_difference(req_time, time1)
335                        < abs_difference(req_time, time2))) {
336                *sample_index = cur_sample + j;
337            } else {
338                *sample_index = cur_sample + j + 1;
339            }
340
341            if (flags & kSyncSample_Flag) {
342                return findClosestSyncSample_l(*sample_index, sample_index);
343            }
344
345            return OK;
346        }
347
348        time += delta * n;
349        cur_sample += n;
350    }
351
352    return ERROR_OUT_OF_RANGE;
353}
354
355status_t SampleTable::findClosestSyncSample_l(
356        uint32_t start_sample_index, uint32_t *sample_index) {
357    *sample_index = 0;
358
359    if (mSyncSampleOffset < 0) {
360        // All samples are sync-samples.
361        *sample_index = start_sample_index;
362        return OK;
363    }
364
365    uint32_t x;
366    uint32_t left = 0;
367    uint32_t right = mNumSyncSamples;
368    while (left < right) {
369        uint32_t mid = (left + right) / 2;
370
371        if (mDataSource->readAt(
372                    mSyncSampleOffset + 8 + mid * 4, &x, 4) != 4) {
373            return ERROR_IO;
374        }
375
376        x = ntohl(x);
377
378        if (x < (start_sample_index + 1)) {
379            left = mid + 1;
380        } else if (x > (start_sample_index + 1)) {
381            right = mid;
382        } else {
383            break;
384        }
385    }
386
387    *sample_index = x - 1;
388
389    return OK;
390}
391
392status_t SampleTable::findThumbnailSample(uint32_t *sample_index) {
393    Mutex::Autolock autoLock(mLock);
394
395    if (mSyncSampleOffset < 0) {
396        // All samples are sync-samples.
397        *sample_index = 0;
398        return OK;
399    }
400
401    uint32_t bestSampleIndex = 0;
402    size_t maxSampleSize = 0;
403
404    static const size_t kMaxNumSyncSamplesToScan = 20;
405
406    // Consider the first kMaxNumSyncSamplesToScan sync samples and
407    // pick the one with the largest (compressed) size as the thumbnail.
408
409    size_t numSamplesToScan = mNumSyncSamples;
410    if (numSamplesToScan > kMaxNumSyncSamplesToScan) {
411        numSamplesToScan = kMaxNumSyncSamplesToScan;
412    }
413
414    for (size_t i = 0; i < numSamplesToScan; ++i) {
415        uint32_t x;
416        if (mDataSource->readAt(
417                    mSyncSampleOffset + 8 + i * 4, &x, 4) != 4) {
418            return ERROR_IO;
419        }
420        x = ntohl(x);
421        --x;
422
423        // Now x is a sample index.
424        size_t sampleSize;
425        status_t err = getSampleSize_l(x, &sampleSize);
426        if (err != OK) {
427            return err;
428        }
429
430        if (i == 0 || sampleSize > maxSampleSize) {
431            bestSampleIndex = x;
432            maxSampleSize = sampleSize;
433        }
434    }
435
436    *sample_index = bestSampleIndex;
437
438    return OK;
439}
440
441status_t SampleTable::getSampleSize_l(
442        uint32_t sampleIndex, size_t *sampleSize) {
443    return mSampleIterator->getSampleSizeDirect(
444            sampleIndex, sampleSize);
445}
446
447status_t SampleTable::getMetaDataForSample(
448        uint32_t sampleIndex,
449        off_t *offset,
450        size_t *size,
451        uint32_t *decodingTime) {
452    Mutex::Autolock autoLock(mLock);
453
454    status_t err;
455    if ((err = mSampleIterator->seekTo(sampleIndex)) != OK) {
456        return err;
457    }
458
459    if (offset) {
460        *offset = mSampleIterator->getSampleOffset();
461    }
462
463    if (size) {
464        *size = mSampleIterator->getSampleSize();
465    }
466
467    if (decodingTime) {
468        *decodingTime = mSampleIterator->getSampleTime();
469    }
470
471    return OK;
472}
473
474}  // namespace android
475
476