SampleTable.cpp revision 7e04dcf8d6784dd56f53aa90bf34431ab4f0710c
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#include <utils/Log.h>
19
20#include "include/SampleTable.h"
21
22#include <arpa/inet.h>
23
24#include <media/stagefright/DataSource.h>
25#include <media/stagefright/MediaDebug.h>
26#include <media/stagefright/Utils.h>
27
28namespace android {
29
30static const uint32_t kChunkOffsetType32 = FOURCC('s', 't', 'c', 'o');
31static const uint32_t kChunkOffsetType64 = FOURCC('c', 'o', '6', '4');
32static const uint32_t kSampleSizeType32 = FOURCC('s', 't', 's', 'z');
33static const uint32_t kSampleSizeTypeCompact = FOURCC('s', 't', 'z', '2');
34
35SampleTable::SampleTable(const sp<DataSource> &source)
36    : mDataSource(source),
37      mChunkOffsetOffset(-1),
38      mChunkOffsetType(0),
39      mNumChunkOffsets(0),
40      mSampleToChunkOffset(-1),
41      mNumSampleToChunkOffsets(0),
42      mSampleSizeOffset(-1),
43      mSampleSizeFieldSize(0),
44      mDefaultSampleSize(0),
45      mNumSampleSizes(0),
46      mTimeToSampleCount(0),
47      mTimeToSample(NULL),
48      mSyncSampleOffset(-1),
49      mNumSyncSamples(0) {
50}
51
52SampleTable::~SampleTable() {
53    delete[] mTimeToSample;
54    mTimeToSample = NULL;
55}
56
57status_t SampleTable::setChunkOffsetParams(
58        uint32_t type, off_t data_offset, size_t data_size) {
59    if (mChunkOffsetOffset >= 0) {
60        return ERROR_MALFORMED;
61    }
62
63    CHECK(type == kChunkOffsetType32 || type == kChunkOffsetType64);
64
65    mChunkOffsetOffset = data_offset;
66    mChunkOffsetType = type;
67
68    if (data_size < 8) {
69        return ERROR_MALFORMED;
70    }
71
72    uint8_t header[8];
73    if (mDataSource->read_at(
74                data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
75        return ERROR_IO;
76    }
77
78    if (U32_AT(header) != 0) {
79        // Expected version = 0, flags = 0.
80        return ERROR_MALFORMED;
81    }
82
83    mNumChunkOffsets = U32_AT(&header[4]);
84
85    if (mChunkOffsetType == kChunkOffsetType32) {
86        if (data_size < 8 + mNumChunkOffsets * 4) {
87            return ERROR_MALFORMED;
88        }
89    } else {
90        if (data_size < 8 + mNumChunkOffsets * 8) {
91            return ERROR_MALFORMED;
92        }
93    }
94
95    return OK;
96}
97
98status_t SampleTable::setSampleToChunkParams(
99        off_t data_offset, size_t data_size) {
100    if (mSampleToChunkOffset >= 0) {
101        return ERROR_MALFORMED;
102    }
103
104    mSampleToChunkOffset = data_offset;
105
106    if (data_size < 8) {
107        return ERROR_MALFORMED;
108    }
109
110    uint8_t header[8];
111    if (mDataSource->read_at(
112                data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
113        return ERROR_IO;
114    }
115
116    if (U32_AT(header) != 0) {
117        // Expected version = 0, flags = 0.
118        return ERROR_MALFORMED;
119    }
120
121    mNumSampleToChunkOffsets = U32_AT(&header[4]);
122
123    if (data_size < 8 + mNumSampleToChunkOffsets * 12) {
124        return ERROR_MALFORMED;
125    }
126
127    return OK;
128}
129
130status_t SampleTable::setSampleSizeParams(
131        uint32_t type, off_t data_offset, size_t data_size) {
132    if (mSampleSizeOffset >= 0) {
133        return ERROR_MALFORMED;
134    }
135
136    CHECK(type == kSampleSizeType32 || type == kSampleSizeTypeCompact);
137
138    mSampleSizeOffset = data_offset;
139
140    if (data_size < 12) {
141        return ERROR_MALFORMED;
142    }
143
144    uint8_t header[12];
145    if (mDataSource->read_at(
146                data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
147        return ERROR_IO;
148    }
149
150    if (U32_AT(header) != 0) {
151        // Expected version = 0, flags = 0.
152        return ERROR_MALFORMED;
153    }
154
155    mDefaultSampleSize = U32_AT(&header[4]);
156    mNumSampleSizes = U32_AT(&header[8]);
157
158    if (type == kSampleSizeType32) {
159        mSampleSizeFieldSize = 32;
160
161        if (mDefaultSampleSize != 0) {
162            return OK;
163        }
164
165        if (data_size < 12 + mNumSampleSizes * 4) {
166            return ERROR_MALFORMED;
167        }
168    } else {
169        if ((mDefaultSampleSize & 0xffffff00) != 0) {
170            // The high 24 bits are reserved and must be 0.
171            return ERROR_MALFORMED;
172        }
173
174        mSampleSizeFieldSize = mDefaultSampleSize & 0xf;
175        mDefaultSampleSize = 0;
176
177        if (mSampleSizeFieldSize != 4 && mSampleSizeFieldSize != 8
178            && mSampleSizeFieldSize != 16) {
179            return ERROR_MALFORMED;
180        }
181
182        if (data_size < 12 + (mNumSampleSizes * mSampleSizeFieldSize + 4) / 8) {
183            return ERROR_MALFORMED;
184        }
185    }
186
187    return OK;
188}
189
190status_t SampleTable::setTimeToSampleParams(
191        off_t data_offset, size_t data_size) {
192    if (mTimeToSample != NULL || data_size < 8) {
193        return ERROR_MALFORMED;
194    }
195
196    uint8_t header[8];
197    if (mDataSource->read_at(
198                data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
199        return ERROR_IO;
200    }
201
202    if (U32_AT(header) != 0) {
203        // Expected version = 0, flags = 0.
204        return ERROR_MALFORMED;
205    }
206
207    mTimeToSampleCount = U32_AT(&header[4]);
208    mTimeToSample = new uint32_t[mTimeToSampleCount * 2];
209
210    size_t size = sizeof(uint32_t) * mTimeToSampleCount * 2;
211    if (mDataSource->read_at(
212                data_offset + 8, mTimeToSample, size) < (ssize_t)size) {
213        return ERROR_IO;
214    }
215
216    for (uint32_t i = 0; i < mTimeToSampleCount * 2; ++i) {
217        mTimeToSample[i] = ntohl(mTimeToSample[i]);
218    }
219
220    return OK;
221}
222
223status_t SampleTable::setSyncSampleParams(off_t data_offset, size_t data_size) {
224    if (mSyncSampleOffset >= 0 || data_size < 8) {
225        return ERROR_MALFORMED;
226    }
227
228    mSyncSampleOffset = data_offset;
229
230    uint8_t header[8];
231    if (mDataSource->read_at(
232                data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
233        return ERROR_IO;
234    }
235
236    if (U32_AT(header) != 0) {
237        // Expected version = 0, flags = 0.
238        return ERROR_MALFORMED;
239    }
240
241    mNumSyncSamples = U32_AT(&header[4]);
242
243    if (mNumSyncSamples < 2) {
244        LOGW("Table of sync samples is empty or has only a single entry!");
245    }
246    return OK;
247}
248
249uint32_t SampleTable::countChunkOffsets() const {
250    return mNumChunkOffsets;
251}
252
253status_t SampleTable::getChunkOffset(uint32_t chunk_index, off_t *offset) {
254    *offset = 0;
255
256    if (mChunkOffsetOffset < 0) {
257        return ERROR_MALFORMED;
258    }
259
260    if (chunk_index >= mNumChunkOffsets) {
261        return ERROR_OUT_OF_RANGE;
262    }
263
264    if (mChunkOffsetType == kChunkOffsetType32) {
265        uint32_t offset32;
266
267        if (mDataSource->read_at(
268                    mChunkOffsetOffset + 8 + 4 * chunk_index,
269                    &offset32,
270                    sizeof(offset32)) < (ssize_t)sizeof(offset32)) {
271            return ERROR_IO;
272        }
273
274        *offset = ntohl(offset32);
275    } else {
276        CHECK_EQ(mChunkOffsetType, kChunkOffsetType64);
277
278        uint64_t offset64;
279        if (mDataSource->read_at(
280                    mChunkOffsetOffset + 8 + 8 * chunk_index,
281                    &offset64,
282                    sizeof(offset64)) < (ssize_t)sizeof(offset64)) {
283            return ERROR_IO;
284        }
285
286        *offset = ntoh64(offset64);
287    }
288
289    return OK;
290}
291
292status_t SampleTable::getChunkForSample(
293        uint32_t sample_index,
294        uint32_t *chunk_index,
295        uint32_t *chunk_relative_sample_index,
296        uint32_t *desc_index) {
297    *chunk_index = 0;
298    *chunk_relative_sample_index = 0;
299    *desc_index = 0;
300
301    if (mSampleToChunkOffset < 0) {
302        return ERROR_MALFORMED;
303    }
304
305    if (sample_index >= countSamples()) {
306        return ERROR_END_OF_STREAM;
307    }
308
309    uint32_t first_chunk = 0;
310    uint32_t samples_per_chunk = 0;
311    uint32_t chunk_desc_index = 0;
312
313    uint32_t index = 0;
314    while (index < mNumSampleToChunkOffsets) {
315        uint8_t buffer[12];
316        if (mDataSource->read_at(mSampleToChunkOffset + 8 + index * 12,
317                                 buffer, sizeof(buffer)) < (ssize_t)sizeof(buffer)) {
318            return ERROR_IO;
319        }
320
321        uint32_t stop_chunk = U32_AT(buffer);
322        if (sample_index < (stop_chunk - first_chunk) * samples_per_chunk) {
323            break;
324        }
325
326        sample_index -= (stop_chunk - first_chunk) * samples_per_chunk;
327        first_chunk = stop_chunk;
328        samples_per_chunk = U32_AT(&buffer[4]);
329        chunk_desc_index = U32_AT(&buffer[8]);
330
331        ++index;
332    }
333
334    *chunk_index = sample_index / samples_per_chunk + first_chunk - 1;
335    *chunk_relative_sample_index = sample_index % samples_per_chunk;
336    *desc_index = chunk_desc_index;
337
338    return OK;
339}
340
341uint32_t SampleTable::countSamples() const {
342    return mNumSampleSizes;
343}
344
345status_t SampleTable::getSampleSize(
346        uint32_t sample_index, size_t *sample_size) {
347    *sample_size = 0;
348
349    if (mSampleSizeOffset < 0) {
350        return ERROR_MALFORMED;
351    }
352
353    if (sample_index >= mNumSampleSizes) {
354        return ERROR_OUT_OF_RANGE;
355    }
356
357    if (mDefaultSampleSize > 0) {
358        *sample_size = mDefaultSampleSize;
359        return OK;
360    }
361
362    switch (mSampleSizeFieldSize) {
363        case 32:
364        {
365            if (mDataSource->read_at(
366                        mSampleSizeOffset + 12 + 4 * sample_index,
367                        sample_size, sizeof(*sample_size)) < (ssize_t)sizeof(*sample_size)) {
368                return ERROR_IO;
369            }
370
371            *sample_size = ntohl(*sample_size);
372            break;
373        }
374
375        case 16:
376        {
377            uint16_t x;
378            if (mDataSource->read_at(
379                        mSampleSizeOffset + 12 + 2 * sample_index,
380                        &x, sizeof(x)) < (ssize_t)sizeof(x)) {
381                return ERROR_IO;
382            }
383
384            *sample_size = ntohs(x);
385            break;
386        }
387
388        case 8:
389        {
390            uint8_t x;
391            if (mDataSource->read_at(
392                        mSampleSizeOffset + 12 + sample_index,
393                        &x, sizeof(x)) < (ssize_t)sizeof(x)) {
394                return ERROR_IO;
395            }
396
397            *sample_size = x;
398            break;
399        }
400
401        default:
402        {
403            CHECK_EQ(mSampleSizeFieldSize, 4);
404
405            uint8_t x;
406            if (mDataSource->read_at(
407                        mSampleSizeOffset + 12 + sample_index / 2,
408                        &x, sizeof(x)) < (ssize_t)sizeof(x)) {
409                return ERROR_IO;
410            }
411
412            *sample_size = (sample_index & 1) ? x & 0x0f : x >> 4;
413            break;
414        }
415    }
416
417    return OK;
418}
419
420status_t SampleTable::getSampleOffsetAndSize(
421        uint32_t sample_index, off_t *offset, size_t *size) {
422    Mutex::Autolock autoLock(mLock);
423
424    *offset = 0;
425    *size = 0;
426
427    uint32_t chunk_index;
428    uint32_t chunk_relative_sample_index;
429    uint32_t desc_index;
430    status_t err = getChunkForSample(
431            sample_index, &chunk_index, &chunk_relative_sample_index,
432            &desc_index);
433
434    if (err != OK) {
435        return err;
436    }
437
438    err = getChunkOffset(chunk_index, offset);
439
440    if (err != OK) {
441        return err;
442    }
443
444    for (uint32_t j = 0; j < chunk_relative_sample_index; ++j) {
445        size_t sample_size;
446        err = getSampleSize(sample_index - j - 1, &sample_size);
447
448        if (err != OK) {
449            return err;
450        }
451
452        *offset += sample_size;
453    }
454
455    err = getSampleSize(sample_index, size);
456
457    if (err != OK) {
458        return err;
459    }
460
461    return OK;
462}
463
464status_t SampleTable::getMaxSampleSize(size_t *max_size) {
465    Mutex::Autolock autoLock(mLock);
466
467    *max_size = 0;
468
469    for (uint32_t i = 0; i < mNumSampleSizes; ++i) {
470        size_t sample_size;
471        status_t err = getSampleSize(i, &sample_size);
472
473        if (err != OK) {
474            return err;
475        }
476
477        if (sample_size > *max_size) {
478            *max_size = sample_size;
479        }
480    }
481
482    return OK;
483}
484
485status_t SampleTable::getDecodingTime(uint32_t sample_index, uint32_t *time) {
486    // XXX FIXME idiotic (for the common use-case) O(n) algorithm below...
487
488    Mutex::Autolock autoLock(mLock);
489
490    if (sample_index >= mNumSampleSizes) {
491        return ERROR_OUT_OF_RANGE;
492    }
493
494    uint32_t cur_sample = 0;
495    *time = 0;
496    for (uint32_t i = 0; i < mTimeToSampleCount; ++i) {
497        uint32_t n = mTimeToSample[2 * i];
498        uint32_t delta = mTimeToSample[2 * i + 1];
499
500        if (sample_index < cur_sample + n) {
501            *time += delta * (sample_index - cur_sample);
502
503            return OK;
504        }
505
506        *time += delta * n;
507        cur_sample += n;
508    }
509
510    return ERROR_OUT_OF_RANGE;
511}
512
513status_t SampleTable::findClosestSample(
514        uint32_t req_time, uint32_t *sample_index, uint32_t flags) {
515    Mutex::Autolock autoLock(mLock);
516
517    uint32_t cur_sample = 0;
518    uint32_t time = 0;
519    for (uint32_t i = 0; i < mTimeToSampleCount; ++i) {
520        uint32_t n = mTimeToSample[2 * i];
521        uint32_t delta = mTimeToSample[2 * i + 1];
522
523        if (req_time < time + n * delta) {
524            int j = (req_time - time) / delta;
525
526            *sample_index = cur_sample + j;
527
528            if (flags & kSyncSample_Flag) {
529                return findClosestSyncSample(*sample_index, sample_index);
530            }
531
532            return OK;
533        }
534
535        time += delta * n;
536        cur_sample += n;
537    }
538
539    return ERROR_OUT_OF_RANGE;
540}
541
542status_t SampleTable::findClosestSyncSample(
543        uint32_t start_sample_index, uint32_t *sample_index) {
544    *sample_index = 0;
545
546    if (mSyncSampleOffset < 0) {
547        // All samples are sync-samples.
548        *sample_index = start_sample_index;
549        return OK;
550    }
551
552    uint32_t x;
553    uint32_t left = 0;
554    uint32_t right = mNumSyncSamples;
555    while (left < right) {
556        uint32_t mid = (left + right) / 2;
557        if (mDataSource->read_at(
558                    mSyncSampleOffset + 8 + (mid - 1) * 4, &x, 4) != 4) {
559            return ERROR_IO;
560        }
561
562        x = ntohl(x);
563
564        if (x < (start_sample_index + 1)) {
565            left = mid + 1;
566        } else if (x > (start_sample_index + 1)) {
567            right = mid;
568        } else {
569            break;
570        }
571    }
572
573    *sample_index = x - 1;
574
575    return OK;
576}
577
578status_t SampleTable::findThumbnailSample(uint32_t *sample_index) {
579    if (mSyncSampleOffset < 0) {
580        // All samples are sync-samples.
581        *sample_index = 0;
582        return OK;
583    }
584
585    uint32_t bestSampleIndex = 0;
586    size_t maxSampleSize = 0;
587
588    static const size_t kMaxNumSyncSamplesToScan = 20;
589
590    // Consider the first kMaxNumSyncSamplesToScan sync samples and
591    // pick the one with the largest (compressed) size as the thumbnail.
592
593    size_t numSamplesToScan = mNumSyncSamples;
594    if (numSamplesToScan > kMaxNumSyncSamplesToScan) {
595        numSamplesToScan = kMaxNumSyncSamplesToScan;
596    }
597
598    for (size_t i = 0; i < numSamplesToScan; ++i) {
599        uint32_t x;
600        if (mDataSource->read_at(
601                    mSyncSampleOffset + 8 + i * 4, &x, 4) != 4) {
602            return ERROR_IO;
603        }
604        x = ntohl(x);
605        --x;
606
607        // Now x is a sample index.
608        size_t sampleSize;
609        status_t err = getSampleSize(x, &sampleSize);
610        if (err != OK) {
611            return err;
612        }
613
614        if (i == 0 || sampleSize > maxSampleSize) {
615            bestSampleIndex = x;
616            maxSampleSize = sampleSize;
617        }
618    }
619
620    *sample_index = bestSampleIndex;
621
622    return OK;
623}
624
625}  // namespace android
626
627