AVIExtractor.cpp revision 7de73f4eb68f3aa478e19ba05a13bc84296f9894
1/*
2 * Copyright (C) 2011 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_NDEBUG 0
18#define LOG_TAG "AVIExtractor"
19#include <utils/Log.h>
20
21#include "include/AVIExtractor.h"
22
23#include <binder/ProcessState.h>
24#include <media/stagefright/foundation/hexdump.h>
25#include <media/stagefright/foundation/ABuffer.h>
26#include <media/stagefright/foundation/ADebug.h>
27#include <media/stagefright/DataSource.h>
28#include <media/stagefright/MediaBuffer.h>
29#include <media/stagefright/MediaBufferGroup.h>
30#include <media/stagefright/MediaDefs.h>
31#include <media/stagefright/MediaErrors.h>
32#include <media/stagefright/MetaData.h>
33#include <media/stagefright/Utils.h>
34
35namespace android {
36
37struct AVIExtractor::AVISource : public MediaSource {
38    AVISource(const sp<AVIExtractor> &extractor, size_t trackIndex);
39
40    virtual status_t start(MetaData *params);
41    virtual status_t stop();
42
43    virtual sp<MetaData> getFormat();
44
45    virtual status_t read(
46            MediaBuffer **buffer, const ReadOptions *options);
47
48protected:
49    virtual ~AVISource();
50
51private:
52    sp<AVIExtractor> mExtractor;
53    size_t mTrackIndex;
54    const AVIExtractor::Track &mTrack;
55    MediaBufferGroup *mBufferGroup;
56    size_t mSampleIndex;
57
58    DISALLOW_EVIL_CONSTRUCTORS(AVISource);
59};
60
61////////////////////////////////////////////////////////////////////////////////
62
63AVIExtractor::AVISource::AVISource(
64        const sp<AVIExtractor> &extractor, size_t trackIndex)
65    : mExtractor(extractor),
66      mTrackIndex(trackIndex),
67      mTrack(mExtractor->mTracks.itemAt(trackIndex)),
68      mBufferGroup(NULL) {
69}
70
71AVIExtractor::AVISource::~AVISource() {
72    if (mBufferGroup) {
73        stop();
74    }
75}
76
77status_t AVIExtractor::AVISource::start(MetaData *params) {
78    CHECK(!mBufferGroup);
79
80    mBufferGroup = new MediaBufferGroup;
81
82    mBufferGroup->add_buffer(new MediaBuffer(mTrack.mMaxSampleSize));
83    mBufferGroup->add_buffer(new MediaBuffer(mTrack.mMaxSampleSize));
84    mSampleIndex = 0;
85
86    return OK;
87}
88
89status_t AVIExtractor::AVISource::stop() {
90    CHECK(mBufferGroup);
91
92    delete mBufferGroup;
93    mBufferGroup = NULL;
94
95    return OK;
96}
97
98sp<MetaData> AVIExtractor::AVISource::getFormat() {
99    return mTrack.mMeta;
100}
101
102status_t AVIExtractor::AVISource::read(
103        MediaBuffer **buffer, const ReadOptions *options) {
104    CHECK(mBufferGroup);
105
106    *buffer = NULL;
107
108    int64_t seekTimeUs;
109    ReadOptions::SeekMode seekMode;
110    if (options && options->getSeekTo(&seekTimeUs, &seekMode)) {
111        status_t err =
112            mExtractor->getSampleIndexAtTime(
113                    mTrackIndex, seekTimeUs, seekMode, &mSampleIndex);
114
115        if (err != OK) {
116            return ERROR_END_OF_STREAM;
117        }
118    }
119
120    off64_t offset;
121    size_t size;
122    bool isKey;
123    int64_t timeUs;
124    status_t err = mExtractor->getSampleInfo(
125            mTrackIndex, mSampleIndex, &offset, &size, &isKey, &timeUs);
126
127    ++mSampleIndex;
128
129    if (err != OK) {
130        return ERROR_END_OF_STREAM;
131    }
132
133    MediaBuffer *out;
134    CHECK_EQ(mBufferGroup->acquire_buffer(&out), (status_t)OK);
135
136    ssize_t n = mExtractor->mDataSource->readAt(offset, out->data(), size);
137
138    if (n < (ssize_t)size) {
139        return n < 0 ? (status_t)n : (status_t)ERROR_MALFORMED;
140    }
141
142    out->set_range(0, size);
143
144    out->meta_data()->setInt64(kKeyTime, timeUs);
145
146    if (isKey) {
147        out->meta_data()->setInt32(kKeyIsSyncFrame, 1);
148    }
149
150    *buffer = out;
151
152    return OK;
153}
154
155////////////////////////////////////////////////////////////////////////////////
156
157AVIExtractor::AVIExtractor(const sp<DataSource> &dataSource)
158    : mDataSource(dataSource) {
159    mInitCheck = parseHeaders();
160
161    if (mInitCheck != OK) {
162        mTracks.clear();
163    }
164}
165
166AVIExtractor::~AVIExtractor() {
167}
168
169size_t AVIExtractor::countTracks() {
170    return mTracks.size();
171}
172
173sp<MediaSource> AVIExtractor::getTrack(size_t index) {
174    return index < mTracks.size() ? new AVISource(this, index) : NULL;
175}
176
177sp<MetaData> AVIExtractor::getTrackMetaData(
178        size_t index, uint32_t flags) {
179    return index < mTracks.size() ? mTracks.editItemAt(index).mMeta : NULL;
180}
181
182sp<MetaData> AVIExtractor::getMetaData() {
183    sp<MetaData> meta = new MetaData;
184
185    if (mInitCheck == OK) {
186        meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_AVI);
187    }
188
189    return meta;
190}
191
192status_t AVIExtractor::parseHeaders() {
193    mTracks.clear();
194    mMovieOffset = 0;
195    mFoundIndex = false;
196    mOffsetsAreAbsolute = false;
197
198    ssize_t res = parseChunk(0ll, -1ll);
199
200    if (res < 0) {
201        return (status_t)res;
202    }
203
204    if (mMovieOffset == 0ll || !mFoundIndex) {
205        return ERROR_MALFORMED;
206    }
207
208    return OK;
209}
210
211ssize_t AVIExtractor::parseChunk(off64_t offset, off64_t size, int depth) {
212    if (size >= 0 && size < 8) {
213        return ERROR_MALFORMED;
214    }
215
216    uint8_t tmp[12];
217    ssize_t n = mDataSource->readAt(offset, tmp, 8);
218
219    if (n < 8) {
220        return (n < 0) ? n : (ssize_t)ERROR_MALFORMED;
221    }
222
223    uint32_t fourcc = U32_AT(tmp);
224    uint32_t chunkSize = U32LE_AT(&tmp[4]);
225
226    if (size >= 0 && chunkSize + 8 > size) {
227        return ERROR_MALFORMED;
228    }
229
230    static const char kPrefix[] = "                              ";
231    const char *prefix = &kPrefix[strlen(kPrefix) - 2 * depth];
232
233    if (fourcc == FOURCC('L', 'I', 'S', 'T')
234            || fourcc == FOURCC('R', 'I', 'F', 'F')) {
235        // It's a list of chunks
236
237        if (size >= 0 && size < 12) {
238            return ERROR_MALFORMED;
239        }
240
241        n = mDataSource->readAt(offset + 8, &tmp[8], 4);
242
243        if (n < 4) {
244            return (n < 0) ? n : (ssize_t)ERROR_MALFORMED;
245        }
246
247        uint32_t subFourcc = U32_AT(&tmp[8]);
248
249        LOGV("%s offset 0x%08llx LIST of '%c%c%c%c', size %d",
250             prefix,
251             offset,
252             (char)(subFourcc >> 24),
253             (char)((subFourcc >> 16) & 0xff),
254             (char)((subFourcc >> 8) & 0xff),
255             (char)(subFourcc & 0xff),
256             chunkSize - 4);
257
258        if (subFourcc == FOURCC('m', 'o', 'v', 'i')) {
259            // We're not going to parse this, but will take note of the
260            // offset.
261
262            mMovieOffset = offset;
263        } else {
264            off64_t subOffset = offset + 12;
265            off64_t subOffsetLimit = subOffset + chunkSize - 4;
266            while (subOffset < subOffsetLimit) {
267                ssize_t res =
268                    parseChunk(subOffset, subOffsetLimit - subOffset, depth + 1);
269
270                if (res < 0) {
271                    return res;
272                }
273
274                subOffset += res;
275            }
276        }
277    } else {
278        LOGV("%s offset 0x%08llx CHUNK '%c%c%c%c'",
279             prefix,
280             offset,
281             (char)(fourcc >> 24),
282             (char)((fourcc >> 16) & 0xff),
283             (char)((fourcc >> 8) & 0xff),
284             (char)(fourcc & 0xff));
285
286        status_t err = OK;
287
288        switch (fourcc) {
289            case FOURCC('s', 't', 'r', 'h'):
290            {
291                err = parseStreamHeader(offset + 8, chunkSize);
292                break;
293            }
294
295            case FOURCC('s', 't', 'r', 'f'):
296            {
297                err = parseStreamFormat(offset + 8, chunkSize);
298                break;
299            }
300
301            case FOURCC('i', 'd', 'x', '1'):
302            {
303                err = parseIndex(offset + 8, chunkSize);
304                break;
305            }
306
307            default:
308                break;
309        }
310
311        if (err != OK) {
312            return err;
313        }
314    }
315
316    if (chunkSize & 1) {
317        ++chunkSize;
318    }
319
320    return chunkSize + 8;
321}
322
323static const char *GetMIMETypeForHandler(uint32_t handler) {
324    switch (handler) {
325        // Wow... shamelessly copied from
326        // http://wiki.multimedia.cx/index.php?title=ISO_MPEG-4
327
328        case FOURCC('3', 'I', 'V', '2'):
329        case FOURCC('3', 'i', 'v', '2'):
330        case FOURCC('B', 'L', 'Z', '0'):
331        case FOURCC('D', 'I', 'G', 'I'):
332        case FOURCC('D', 'I', 'V', '1'):
333        case FOURCC('d', 'i', 'v', '1'):
334        case FOURCC('D', 'I', 'V', 'X'):
335        case FOURCC('d', 'i', 'v', 'x'):
336        case FOURCC('D', 'X', '5', '0'):
337        case FOURCC('d', 'x', '5', '0'):
338        case FOURCC('D', 'X', 'G', 'M'):
339        case FOURCC('E', 'M', '4', 'A'):
340        case FOURCC('E', 'P', 'H', 'V'):
341        case FOURCC('F', 'M', 'P', '4'):
342        case FOURCC('f', 'm', 'p', '4'):
343        case FOURCC('F', 'V', 'F', 'W'):
344        case FOURCC('H', 'D', 'X', '4'):
345        case FOURCC('h', 'd', 'x', '4'):
346        case FOURCC('M', '4', 'C', 'C'):
347        case FOURCC('M', '4', 'S', '2'):
348        case FOURCC('m', '4', 's', '2'):
349        case FOURCC('M', 'P', '4', 'S'):
350        case FOURCC('m', 'p', '4', 's'):
351        case FOURCC('M', 'P', '4', 'V'):
352        case FOURCC('m', 'p', '4', 'v'):
353        case FOURCC('M', 'V', 'X', 'M'):
354        case FOURCC('R', 'M', 'P', '4'):
355        case FOURCC('S', 'E', 'D', 'G'):
356        case FOURCC('S', 'M', 'P', '4'):
357        case FOURCC('U', 'M', 'P', '4'):
358        case FOURCC('W', 'V', '1', 'F'):
359        case FOURCC('X', 'V', 'I', 'D'):
360        case FOURCC('X', 'v', 'i', 'D'):
361        case FOURCC('x', 'v', 'i', 'd'):
362        case FOURCC('X', 'V', 'I', 'X'):
363            return MEDIA_MIMETYPE_VIDEO_MPEG4;
364
365        default:
366            return NULL;
367    }
368}
369
370status_t AVIExtractor::parseStreamHeader(off64_t offset, size_t size) {
371    if (size != 56) {
372        return ERROR_MALFORMED;
373    }
374
375    if (mTracks.size() > 99) {
376        return -ERANGE;
377    }
378
379    sp<ABuffer> buffer = new ABuffer(size);
380    ssize_t n = mDataSource->readAt(offset, buffer->data(), buffer->size());
381
382    if (n < (ssize_t)size) {
383        return n < 0 ? (status_t)n : ERROR_MALFORMED;
384    }
385
386    const uint8_t *data = buffer->data();
387
388    uint32_t type = U32_AT(data);
389    uint32_t handler = U32_AT(&data[4]);
390    uint32_t flags = U32LE_AT(&data[8]);
391
392    sp<MetaData> meta = new MetaData;
393
394    uint32_t rate = U32LE_AT(&data[20]);
395    uint32_t scale = U32LE_AT(&data[24]);
396
397    uint32_t sampleSize = U32LE_AT(&data[44]);
398
399    const char *mime = NULL;
400    Track::Kind kind = Track::OTHER;
401
402    if (type == FOURCC('v', 'i', 'd', 's')) {
403        mime = GetMIMETypeForHandler(handler);
404
405        if (mime && strncasecmp(mime, "video/", 6)) {
406            return ERROR_MALFORMED;
407        }
408
409        kind = Track::VIDEO;
410    } else if (type == FOURCC('a', 'u', 'd', 's')) {
411        if (mime && strncasecmp(mime, "audio/", 6)) {
412            return ERROR_MALFORMED;
413        }
414
415        kind = Track::AUDIO;
416    }
417
418    if (!mime) {
419        mime = "application/octet-stream";
420    }
421
422    meta->setCString(kKeyMIMEType, mime);
423
424    mTracks.push();
425    Track *track = &mTracks.editItemAt(mTracks.size() - 1);
426
427    track->mMeta = meta;
428    track->mRate = rate;
429    track->mScale = scale;
430    track->mBytesPerSample = sampleSize;
431    track->mKind = kind;
432    track->mNumSyncSamples = 0;
433    track->mThumbnailSampleSize = 0;
434    track->mThumbnailSampleIndex = -1;
435    track->mMaxSampleSize = 0;
436
437    return OK;
438}
439
440status_t AVIExtractor::parseStreamFormat(off64_t offset, size_t size) {
441    if (mTracks.isEmpty()) {
442        return ERROR_MALFORMED;
443    }
444
445    Track *track = &mTracks.editItemAt(mTracks.size() - 1);
446
447    if (track->mKind == Track::OTHER) {
448        // We don't support this content, but that's not a parsing error.
449        return OK;
450    }
451
452    bool isVideo = (track->mKind == Track::VIDEO);
453
454    if ((isVideo && size < 40) || (!isVideo && size < 18)) {
455        // Expected a BITMAPINFO or WAVEFORMATEX structure, respectively.
456        return ERROR_MALFORMED;
457    }
458
459    sp<ABuffer> buffer = new ABuffer(size);
460    ssize_t n = mDataSource->readAt(offset, buffer->data(), buffer->size());
461
462    if (n < (ssize_t)size) {
463        return n < 0 ? (status_t)n : ERROR_MALFORMED;
464    }
465
466    const uint8_t *data = buffer->data();
467
468    if (isVideo) {
469        uint32_t width = U32LE_AT(&data[4]);
470        uint32_t height = U32LE_AT(&data[8]);
471
472        track->mMeta->setInt32(kKeyWidth, width);
473        track->mMeta->setInt32(kKeyHeight, height);
474    } else {
475        uint32_t format = U16LE_AT(data);
476        if (format == 0x55) {
477            track->mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
478        }
479
480        uint32_t numChannels = U16LE_AT(&data[2]);
481        uint32_t sampleRate = U32LE_AT(&data[4]);
482
483        track->mMeta->setInt32(kKeyChannelCount, numChannels);
484        track->mMeta->setInt32(kKeySampleRate, sampleRate);
485    }
486
487    return OK;
488}
489
490// static
491bool AVIExtractor::IsCorrectChunkType(
492        ssize_t trackIndex, Track::Kind kind, uint32_t chunkType) {
493    uint32_t chunkBase = chunkType & 0xffff;
494
495    switch (kind) {
496        case Track::VIDEO:
497        {
498            if (chunkBase != FOURCC(0, 0, 'd', 'c')
499                    && chunkBase != FOURCC(0, 0, 'd', 'b')) {
500                return false;
501            }
502            break;
503        }
504
505        case Track::AUDIO:
506        {
507            if (chunkBase != FOURCC(0, 0, 'w', 'b')) {
508                return false;
509            }
510            break;
511        }
512
513        default:
514            break;
515    }
516
517    if (trackIndex < 0) {
518        return true;
519    }
520
521    uint8_t hi = chunkType >> 24;
522    uint8_t lo = (chunkType >> 16) & 0xff;
523
524    if (hi < '0' || hi > '9' || lo < '0' || lo > '9') {
525        return false;
526    }
527
528    if (trackIndex != (10 * (hi - '0') + (lo - '0'))) {
529        return false;
530    }
531
532    return true;
533}
534
535status_t AVIExtractor::parseIndex(off64_t offset, size_t size) {
536    if ((size % 16) != 0) {
537        return ERROR_MALFORMED;
538    }
539
540    sp<ABuffer> buffer = new ABuffer(size);
541    ssize_t n = mDataSource->readAt(offset, buffer->data(), buffer->size());
542
543    if (n < (ssize_t)size) {
544        return n < 0 ? (status_t)n : ERROR_MALFORMED;
545    }
546
547    const uint8_t *data = buffer->data();
548
549    while (size > 0) {
550        uint32_t chunkType = U32_AT(data);
551
552        uint8_t hi = chunkType >> 24;
553        uint8_t lo = (chunkType >> 16) & 0xff;
554
555        if (hi < '0' || hi > '9' || lo < '0' || lo > '9') {
556            return ERROR_MALFORMED;
557        }
558
559        size_t trackIndex = 10 * (hi - '0') + (lo - '0');
560
561        if (trackIndex >= mTracks.size()) {
562            return ERROR_MALFORMED;
563        }
564
565        Track *track = &mTracks.editItemAt(trackIndex);
566
567        if (!IsCorrectChunkType(-1, track->mKind, chunkType)) {
568            return ERROR_MALFORMED;
569        }
570
571        if (track->mKind == Track::OTHER) {
572            data += 16;
573            size -= 16;
574            continue;
575        }
576
577        uint32_t flags = U32LE_AT(&data[4]);
578        uint32_t offset = U32LE_AT(&data[8]);
579        uint32_t chunkSize = U32LE_AT(&data[12]);
580
581        if (chunkSize > track->mMaxSampleSize) {
582            track->mMaxSampleSize = chunkSize;
583        }
584
585        track->mSamples.push();
586
587        SampleInfo *info =
588            &track->mSamples.editItemAt(track->mSamples.size() - 1);
589
590        info->mOffset = offset;
591        info->mIsKey = (flags & 0x10) != 0;
592
593        if (info->mIsKey) {
594            static const size_t kMaxNumSyncSamplesToScan = 20;
595
596            if (track->mNumSyncSamples < kMaxNumSyncSamplesToScan) {
597                if (chunkSize > track->mThumbnailSampleSize) {
598                    track->mThumbnailSampleSize = chunkSize;
599
600                    track->mThumbnailSampleIndex =
601                        track->mSamples.size() - 1;
602                }
603            }
604
605            ++track->mNumSyncSamples;
606        }
607
608        data += 16;
609        size -= 16;
610    }
611
612    if (!mTracks.isEmpty()) {
613        off64_t offset;
614        size_t size;
615        bool isKey;
616        int64_t timeUs;
617        status_t err = getSampleInfo(0, 0, &offset, &size, &isKey, &timeUs);
618
619        if (err != OK) {
620            mOffsetsAreAbsolute = !mOffsetsAreAbsolute;
621            err = getSampleInfo(0, 0, &offset, &size, &isKey, &timeUs);
622
623            if (err != OK) {
624                return err;
625            }
626        }
627
628        LOGV("Chunk offsets are %s",
629             mOffsetsAreAbsolute ? "absolute" : "movie-chunk relative");
630    }
631
632    for (size_t i = 0; i < mTracks.size(); ++i) {
633        Track *track = &mTracks.editItemAt(i);
634
635        int64_t durationUs;
636        CHECK_EQ((status_t)OK,
637                 getSampleTime(i, track->mSamples.size() - 1, &durationUs));
638
639        LOGV("track %d duration = %.2f secs", i, durationUs / 1E6);
640
641        track->mMeta->setInt64(kKeyDuration, durationUs);
642        track->mMeta->setInt32(kKeyMaxInputSize, track->mMaxSampleSize);
643
644        const char *tmp;
645        CHECK(track->mMeta->findCString(kKeyMIMEType, &tmp));
646
647        AString mime = tmp;
648
649        if (!strncasecmp("video/", mime.c_str(), 6)
650                && track->mThumbnailSampleIndex >= 0) {
651            int64_t thumbnailTimeUs;
652            CHECK_EQ((status_t)OK,
653                     getSampleTime(i, track->mThumbnailSampleIndex,
654                                   &thumbnailTimeUs));
655
656            track->mMeta->setInt64(kKeyThumbnailTime, thumbnailTimeUs);
657
658            if (!strcasecmp(mime.c_str(), MEDIA_MIMETYPE_VIDEO_MPEG4)) {
659                status_t err = addMPEG4CodecSpecificData(i);
660
661                if (err != OK) {
662                    return err;
663                }
664            }
665        }
666
667        if (track->mBytesPerSample != 0) {
668            // Assume all chunks are the same size for now.
669
670            off64_t offset;
671            size_t size;
672            bool isKey;
673            int64_t sampleTimeUs;
674            CHECK_EQ((status_t)OK,
675                     getSampleInfo(
676                         i, 0,
677                         &offset, &size, &isKey, &sampleTimeUs));
678
679            track->mRate *= size / track->mBytesPerSample;
680        }
681    }
682
683    mFoundIndex = true;
684
685    return OK;
686}
687
688static size_t GetSizeWidth(size_t x) {
689    size_t n = 1;
690    while (x > 127) {
691        ++n;
692        x >>= 7;
693    }
694    return n;
695}
696
697static uint8_t *EncodeSize(uint8_t *dst, size_t x) {
698    while (x > 127) {
699        *dst++ = (x & 0x7f) | 0x80;
700        x >>= 7;
701    }
702    *dst++ = x;
703    return dst;
704}
705
706sp<ABuffer> MakeMPEG4VideoCodecSpecificData(const sp<ABuffer> &config) {
707    size_t len1 = config->size() + GetSizeWidth(config->size()) + 1;
708    size_t len2 = len1 + GetSizeWidth(len1) + 1 + 13;
709    size_t len3 = len2 + GetSizeWidth(len2) + 1 + 3;
710
711    sp<ABuffer> csd = new ABuffer(len3);
712    uint8_t *dst = csd->data();
713    *dst++ = 0x03;
714    dst = EncodeSize(dst, len2 + 3);
715    *dst++ = 0x00;  // ES_ID
716    *dst++ = 0x00;
717    *dst++ = 0x00;  // streamDependenceFlag, URL_Flag, OCRstreamFlag
718
719    *dst++ = 0x04;
720    dst = EncodeSize(dst, len1 + 13);
721    *dst++ = 0x01;  // Video ISO/IEC 14496-2 Simple Profile
722    for (size_t i = 0; i < 12; ++i) {
723        *dst++ = 0x00;
724    }
725
726    *dst++ = 0x05;
727    dst = EncodeSize(dst, config->size());
728    memcpy(dst, config->data(), config->size());
729    dst += config->size();
730
731    // hexdump(csd->data(), csd->size());
732
733    return csd;
734}
735
736status_t AVIExtractor::addMPEG4CodecSpecificData(size_t trackIndex) {
737    Track *track = &mTracks.editItemAt(trackIndex);
738
739    off64_t offset;
740    size_t size;
741    bool isKey;
742    int64_t timeUs;
743    status_t err =
744        getSampleInfo(trackIndex, 0, &offset, &size, &isKey, &timeUs);
745
746    if (err != OK) {
747        return err;
748    }
749
750    sp<ABuffer> buffer = new ABuffer(size);
751    ssize_t n = mDataSource->readAt(offset, buffer->data(), buffer->size());
752
753    if (n < (ssize_t)size) {
754        return n < 0 ? (status_t)n : ERROR_MALFORMED;
755    }
756
757    // Extract everything up to the first VOP start code from the first
758    // frame's encoded data and use it to construct an ESDS with the
759    // codec specific data.
760
761    size_t i = 0;
762    bool found = false;
763    while (i + 3 < buffer->size()) {
764        if (!memcmp("\x00\x00\x01\xb6", &buffer->data()[i], 4)) {
765            found = true;
766            break;
767        }
768
769        ++i;
770    }
771
772    if (!found) {
773        return ERROR_MALFORMED;
774    }
775
776    buffer->setRange(0, i);
777
778    sp<ABuffer> csd = MakeMPEG4VideoCodecSpecificData(buffer);
779    track->mMeta->setData(kKeyESDS, kTypeESDS, csd->data(), csd->size());
780
781    return OK;
782}
783
784status_t AVIExtractor::getSampleInfo(
785        size_t trackIndex, size_t sampleIndex,
786        off64_t *offset, size_t *size, bool *isKey,
787        int64_t *sampleTimeUs) {
788    if (trackIndex >= mTracks.size()) {
789        return -ERANGE;
790    }
791
792    const Track &track = mTracks.itemAt(trackIndex);
793
794    if (sampleIndex >= track.mSamples.size()) {
795        return -ERANGE;
796    }
797
798    const SampleInfo &info = track.mSamples.itemAt(sampleIndex);
799
800    if (!mOffsetsAreAbsolute) {
801        *offset = info.mOffset + mMovieOffset + 8;
802    } else {
803        *offset = info.mOffset;
804    }
805
806    *size = 0;
807
808    uint8_t tmp[8];
809    ssize_t n = mDataSource->readAt(*offset, tmp, 8);
810
811    if (n < 8) {
812        return n < 0 ? (status_t)n : (status_t)ERROR_MALFORMED;
813    }
814
815    uint32_t chunkType = U32_AT(tmp);
816
817    if (!IsCorrectChunkType(trackIndex, track.mKind, chunkType)) {
818        return ERROR_MALFORMED;
819    }
820
821    *offset += 8;
822    *size = U32LE_AT(&tmp[4]);
823
824    *isKey = info.mIsKey;
825
826    *sampleTimeUs = (sampleIndex * 1000000ll * track.mRate) / track.mScale;
827
828    return OK;
829}
830
831status_t AVIExtractor::getSampleTime(
832        size_t trackIndex, size_t sampleIndex, int64_t *sampleTimeUs) {
833    off64_t offset;
834    size_t size;
835    bool isKey;
836    return getSampleInfo(
837            trackIndex, sampleIndex, &offset, &size, &isKey, sampleTimeUs);
838}
839
840status_t AVIExtractor::getSampleIndexAtTime(
841        size_t trackIndex,
842        int64_t timeUs, MediaSource::ReadOptions::SeekMode mode,
843        size_t *sampleIndex) const {
844    if (trackIndex >= mTracks.size()) {
845        return -ERANGE;
846    }
847
848    const Track &track = mTracks.itemAt(trackIndex);
849
850    ssize_t closestSampleIndex =
851        timeUs / track.mRate * track.mScale / 1000000ll;
852
853    ssize_t numSamples = track.mSamples.size();
854
855    if (closestSampleIndex < 0) {
856        closestSampleIndex = 0;
857    } else if (closestSampleIndex >= numSamples) {
858        closestSampleIndex = numSamples - 1;
859    }
860
861    if (mode == MediaSource::ReadOptions::SEEK_CLOSEST) {
862        *sampleIndex = closestSampleIndex;
863
864        return OK;
865    }
866
867    ssize_t prevSyncSampleIndex = closestSampleIndex;
868    while (prevSyncSampleIndex >= 0) {
869        const SampleInfo &info =
870            track.mSamples.itemAt(prevSyncSampleIndex);
871
872        if (info.mIsKey) {
873            break;
874        }
875
876        --prevSyncSampleIndex;
877    }
878
879    ssize_t nextSyncSampleIndex = closestSampleIndex;
880    while (nextSyncSampleIndex < numSamples) {
881        const SampleInfo &info =
882            track.mSamples.itemAt(nextSyncSampleIndex);
883
884        if (info.mIsKey) {
885            break;
886        }
887
888        ++nextSyncSampleIndex;
889    }
890
891    switch (mode) {
892        case MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC:
893        {
894            *sampleIndex = prevSyncSampleIndex;
895
896            return prevSyncSampleIndex >= 0 ? OK : UNKNOWN_ERROR;
897        }
898
899        case MediaSource::ReadOptions::SEEK_NEXT_SYNC:
900        {
901            *sampleIndex = nextSyncSampleIndex;
902
903            return nextSyncSampleIndex < numSamples ? OK : UNKNOWN_ERROR;
904        }
905
906        case MediaSource::ReadOptions::SEEK_CLOSEST_SYNC:
907        {
908            if (prevSyncSampleIndex < 0 && nextSyncSampleIndex >= numSamples) {
909                return UNKNOWN_ERROR;
910            }
911
912            if (prevSyncSampleIndex < 0) {
913                *sampleIndex = nextSyncSampleIndex;
914                return OK;
915            }
916
917            if (nextSyncSampleIndex >= numSamples) {
918                *sampleIndex = prevSyncSampleIndex;
919                return OK;
920            }
921
922            size_t dist1 = closestSampleIndex - prevSyncSampleIndex;
923            size_t dist2 = nextSyncSampleIndex - closestSampleIndex;
924
925            *sampleIndex =
926                (dist1 < dist2) ? prevSyncSampleIndex : nextSyncSampleIndex;
927
928            return OK;
929        }
930
931        default:
932            TRESPASS();
933            break;
934    }
935}
936
937bool SniffAVI(
938        const sp<DataSource> &source, String8 *mimeType, float *confidence,
939        sp<AMessage> *) {
940    char tmp[12];
941    if (source->readAt(0, tmp, 12) < 12) {
942        return false;
943    }
944
945    if (!memcmp(tmp, "RIFF", 4) && !memcmp(&tmp[8], "AVI ", 4)) {
946        mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_AVI);
947
948        // Just a tad over the mp3 extractor's confidence, since
949        // these .avi files may contain .mp3 content that otherwise would
950        // mistakenly lead to us identifying the entire file as a .mp3 file.
951        *confidence = 0.21;
952
953        return true;
954    }
955
956    return false;
957}
958
959}  // namespace android
960