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