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