AMRExtractor.cpp revision c7fc37a3dab9bd1f96713649f351b5990e6316ff
1f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber/*
2f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber * Copyright (C) 2009 The Android Open Source Project
3f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber *
4f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber * Licensed under the Apache License, Version 2.0 (the "License");
5f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber * you may not use this file except in compliance with the License.
6f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber * You may obtain a copy of the License at
7f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber *
8f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber *      http://www.apache.org/licenses/LICENSE-2.0
9f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber *
10f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber * Unless required by applicable law or agreed to in writing, software
11f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber * distributed under the License is distributed on an "AS IS" BASIS,
12f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber * See the License for the specific language governing permissions and
14f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber * limitations under the License.
15f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber */
16f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber
17f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber//#define LOG_NDEBUG 0
18f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber#define LOG_TAG "AMRExtractor"
19f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber#include <utils/Log.h>
20f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber
2166326a5ee0869f1ee4d136a477e6effba428b3cbAndreas Huber#include "include/AMRExtractor.h"
2266326a5ee0869f1ee4d136a477e6effba428b3cbAndreas Huber
23f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber#include <media/stagefright/DataSource.h>
24f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber#include <media/stagefright/MediaBufferGroup.h>
25f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber#include <media/stagefright/MediaDebug.h>
2618291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber#include <media/stagefright/MediaDefs.h>
27f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber#include <media/stagefright/MediaErrors.h>
28f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber#include <media/stagefright/MediaSource.h>
29f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber#include <media/stagefright/MetaData.h>
30f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber#include <utils/String8.h>
31f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber
32f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Hubernamespace android {
33f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber
34f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huberclass AMRSource : public MediaSource {
35f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huberpublic:
36bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber    AMRSource(const sp<DataSource> &source,
37bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber              const sp<MetaData> &meta,
38bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber              size_t frameSize,
39bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber              bool isWide);
40f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber
41f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber    virtual status_t start(MetaData *params = NULL);
42f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber    virtual status_t stop();
43f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber
44f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber    virtual sp<MetaData> getFormat();
45f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber
46f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber    virtual status_t read(
47f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber            MediaBuffer **buffer, const ReadOptions *options = NULL);
48f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber
49f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huberprotected:
50f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber    virtual ~AMRSource();
51f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber
52f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huberprivate:
53f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber    sp<DataSource> mDataSource;
54bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber    sp<MetaData> mMeta;
55bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber    size_t mFrameSize;
56f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber    bool mIsWide;
57f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber
58c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong    off64_t mOffset;
59f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber    int64_t mCurrentTimeUs;
60f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber    bool mStarted;
61f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber    MediaBufferGroup *mGroup;
62f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber
63f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber    AMRSource(const AMRSource &);
64f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber    AMRSource &operator=(const AMRSource &);
65f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber};
66f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber
67f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber////////////////////////////////////////////////////////////////////////////////
68f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber
69bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huberstatic size_t getFrameSize(bool isWide, unsigned FT) {
70bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber    static const size_t kFrameSizeNB[8] = {
71bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber        95, 103, 118, 134, 148, 159, 204, 244
72bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber    };
73bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber    static const size_t kFrameSizeWB[9] = {
74bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber        132, 177, 253, 285, 317, 365, 397, 461, 477
75bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber    };
76bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber
77bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber    size_t frameSize = isWide ? kFrameSizeWB[FT] : kFrameSizeNB[FT];
78bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber
79bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber    // Round up bits to bytes and add 1 for the header byte.
80bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber    frameSize = (frameSize + 7) / 8 + 1;
81bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber
82bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber    return frameSize;
83bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber}
84bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber
85f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas HuberAMRExtractor::AMRExtractor(const sp<DataSource> &source)
86f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber    : mDataSource(source),
87f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber      mInitCheck(NO_INIT) {
88f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber    String8 mimeType;
89f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber    float confidence;
905a1c3529e4fa2f8a11054181294e0ce79fff8dd3Andreas Huber    if (!SniffAMR(mDataSource, &mimeType, &confidence, NULL)) {
91bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber        return;
92f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber    }
93bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber
94bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber    mIsWide = (mimeType == MEDIA_MIMETYPE_AUDIO_AMR_WB);
95bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber
96bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber    mMeta = new MetaData;
97bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber    mMeta->setCString(
98bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber            kKeyMIMEType, mIsWide ? MEDIA_MIMETYPE_AUDIO_AMR_WB
99bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber                                  : MEDIA_MIMETYPE_AUDIO_AMR_NB);
100bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber
101bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber    mMeta->setInt32(kKeyChannelCount, 1);
102bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber    mMeta->setInt32(kKeySampleRate, mIsWide ? 16000 : 8000);
103bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber
104bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber    size_t offset = mIsWide ? 9 : 6;
105bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber    uint8_t header;
106bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber    if (mDataSource->readAt(offset, &header, 1) != 1) {
107bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber        return;
108bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber    }
109bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber
110bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber    unsigned FT = (header >> 3) & 0x0f;
111bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber
112bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber    if (FT > 8 || (!mIsWide && FT > 7)) {
113bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber        return;
114bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber    }
115bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber
116bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber    mFrameSize = getFrameSize(mIsWide, FT);
117bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber
118c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong    off64_t streamSize;
119bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber    if (mDataSource->getSize(&streamSize) == OK) {
120c7fc37a3dab9bd1f96713649f351b5990e6316ffJames Dong        off64_t numFrames = streamSize / mFrameSize;
121bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber
122bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber        mMeta->setInt64(kKeyDuration, 20000ll * numFrames);
123bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber    }
124bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber
125bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber    mInitCheck = OK;
126f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber}
127f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber
128f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas HuberAMRExtractor::~AMRExtractor() {
129f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber}
130f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber
1317be6407f2ad7f2b0782d195d9f792072c084d6f5Andreas Hubersp<MetaData> AMRExtractor::getMetaData() {
1327be6407f2ad7f2b0782d195d9f792072c084d6f5Andreas Huber    sp<MetaData> meta = new MetaData;
1337be6407f2ad7f2b0782d195d9f792072c084d6f5Andreas Huber
1347be6407f2ad7f2b0782d195d9f792072c084d6f5Andreas Huber    if (mInitCheck != OK) {
1357be6407f2ad7f2b0782d195d9f792072c084d6f5Andreas Huber        return meta;
1367be6407f2ad7f2b0782d195d9f792072c084d6f5Andreas Huber    }
1377be6407f2ad7f2b0782d195d9f792072c084d6f5Andreas Huber
1387be6407f2ad7f2b0782d195d9f792072c084d6f5Andreas Huber    meta->setCString(kKeyMIMEType, mIsWide ? "audio/amr-wb" : "audio/amr");
1397be6407f2ad7f2b0782d195d9f792072c084d6f5Andreas Huber
1407be6407f2ad7f2b0782d195d9f792072c084d6f5Andreas Huber    return meta;
1417be6407f2ad7f2b0782d195d9f792072c084d6f5Andreas Huber}
1427be6407f2ad7f2b0782d195d9f792072c084d6f5Andreas Huber
143f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Hubersize_t AMRExtractor::countTracks() {
144f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber    return mInitCheck == OK ? 1 : 0;
145f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber}
146f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber
147f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Hubersp<MediaSource> AMRExtractor::getTrack(size_t index) {
148f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber    if (mInitCheck != OK || index != 0) {
149f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber        return NULL;
150f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber    }
151f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber
152bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber    return new AMRSource(mDataSource, mMeta, mFrameSize, mIsWide);
153f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber}
154f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber
1557e04dcf8d6784dd56f53aa90bf34431ab4f0710cAndreas Hubersp<MetaData> AMRExtractor::getTrackMetaData(size_t index, uint32_t flags) {
156f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber    if (mInitCheck != OK || index != 0) {
157f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber        return NULL;
158f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber    }
159f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber
160bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber    return mMeta;
161f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber}
162f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber
163f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber////////////////////////////////////////////////////////////////////////////////
164f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber
165bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas HuberAMRSource::AMRSource(
166bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber        const sp<DataSource> &source, const sp<MetaData> &meta,
167bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber        size_t frameSize, bool isWide)
168f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber    : mDataSource(source),
169bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber      mMeta(meta),
170bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber      mFrameSize(frameSize),
171f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber      mIsWide(isWide),
172f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber      mOffset(mIsWide ? 9 : 6),
173f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber      mCurrentTimeUs(0),
174f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber      mStarted(false),
175f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber      mGroup(NULL) {
176f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber}
177f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber
178f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas HuberAMRSource::~AMRSource() {
179f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber    if (mStarted) {
180f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber        stop();
181f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber    }
182f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber}
183f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber
184f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huberstatus_t AMRSource::start(MetaData *params) {
185f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber    CHECK(!mStarted);
186f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber
187f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber    mOffset = mIsWide ? 9 : 6;
188f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber    mCurrentTimeUs = 0;
189f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber    mGroup = new MediaBufferGroup;
190f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber    mGroup->add_buffer(new MediaBuffer(128));
191f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber    mStarted = true;
192f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber
193f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber    return OK;
194f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber}
195f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber
196f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huberstatus_t AMRSource::stop() {
197f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber    CHECK(mStarted);
198f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber
199f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber    delete mGroup;
200f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber    mGroup = NULL;
201f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber
202f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber    mStarted = false;
203f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber    return OK;
204f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber}
205f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber
206f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Hubersp<MetaData> AMRSource::getFormat() {
207bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber    return mMeta;
208f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber}
209f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber
210f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huberstatus_t AMRSource::read(
211f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber        MediaBuffer **out, const ReadOptions *options) {
212f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber    *out = NULL;
213f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber
214bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber    int64_t seekTimeUs;
215abd1f4f870925d6776dbe4b930b759a1ab6595caAndreas Huber    ReadOptions::SeekMode mode;
216abd1f4f870925d6776dbe4b930b759a1ab6595caAndreas Huber    if (options && options->getSeekTo(&seekTimeUs, &mode)) {
217bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber        int64_t seekFrame = seekTimeUs / 20000ll;  // 20ms per frame.
218bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber        mCurrentTimeUs = seekFrame * 20000ll;
219bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber        mOffset = seekFrame * mFrameSize + (mIsWide ? 9 : 6);
220bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber    }
221bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber
222f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber    uint8_t header;
22334769bc913e9f6bb138e666d94a9d685bf3da217Andreas Huber    ssize_t n = mDataSource->readAt(mOffset, &header, 1);
224f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber
225f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber    if (n < 1) {
226aaaa12caef17f34cdcdf118fa7c2b4b8d0d7fe0eGlenn Kasten        return ERROR_END_OF_STREAM;
227f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber    }
228f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber
229f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber    if (header & 0x83) {
230f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber        // Padding bits must be 0.
231f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber
2320e917ec1e86477ca22ed8d5dc87a36f4641a6733Andreas Huber        LOGE("padding bits must be 0, header is 0x%02x", header);
2330e917ec1e86477ca22ed8d5dc87a36f4641a6733Andreas Huber
234f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber        return ERROR_MALFORMED;
235f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber    }
236f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber
237f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber    unsigned FT = (header >> 3) & 0x0f;
238f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber
239f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber    if (FT > 8 || (!mIsWide && FT > 7)) {
2400e917ec1e86477ca22ed8d5dc87a36f4641a6733Andreas Huber
2410e917ec1e86477ca22ed8d5dc87a36f4641a6733Andreas Huber        LOGE("illegal AMR frame type %d", FT);
2420e917ec1e86477ca22ed8d5dc87a36f4641a6733Andreas Huber
243f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber        return ERROR_MALFORMED;
244f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber    }
245f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber
246bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber    size_t frameSize = getFrameSize(mIsWide, FT);
247bfa6b2d7a1be1832ac40ed90aece1834f720b5c6Andreas Huber    CHECK_EQ(frameSize, mFrameSize);
248f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber
2490e917ec1e86477ca22ed8d5dc87a36f4641a6733Andreas Huber    MediaBuffer *buffer;
2500e917ec1e86477ca22ed8d5dc87a36f4641a6733Andreas Huber    status_t err = mGroup->acquire_buffer(&buffer);
2510e917ec1e86477ca22ed8d5dc87a36f4641a6733Andreas Huber    if (err != OK) {
2520e917ec1e86477ca22ed8d5dc87a36f4641a6733Andreas Huber        return err;
2530e917ec1e86477ca22ed8d5dc87a36f4641a6733Andreas Huber    }
2540e917ec1e86477ca22ed8d5dc87a36f4641a6733Andreas Huber
25534769bc913e9f6bb138e666d94a9d685bf3da217Andreas Huber    n = mDataSource->readAt(mOffset, buffer->data(), frameSize);
256f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber
257f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber    if (n != (ssize_t)frameSize) {
258f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber        buffer->release();
259f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber        buffer = NULL;
260f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber
261f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber        return ERROR_IO;
262f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber    }
263f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber
264f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber    buffer->set_range(0, frameSize);
26548c948b1137e7bbdb161b51908657ab72ac5e2daAndreas Huber    buffer->meta_data()->setInt64(kKeyTime, mCurrentTimeUs);
2668bf59e735760af0b6a85747fd90bf8cf1e5388d7Andreas Huber    buffer->meta_data()->setInt32(kKeyIsSyncFrame, 1);
267f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber
268f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber    mOffset += frameSize;
269f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber    mCurrentTimeUs += 20000;  // Each frame is 20ms
270f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber
271f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber    *out = buffer;
272f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber
273f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber    return OK;
274f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber}
275f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber
276f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber////////////////////////////////////////////////////////////////////////////////
277f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber
278f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huberbool SniffAMR(
2795a1c3529e4fa2f8a11054181294e0ce79fff8dd3Andreas Huber        const sp<DataSource> &source, String8 *mimeType, float *confidence,
2805a1c3529e4fa2f8a11054181294e0ce79fff8dd3Andreas Huber        sp<AMessage> *) {
281f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber    char header[9];
282f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber
28334769bc913e9f6bb138e666d94a9d685bf3da217Andreas Huber    if (source->readAt(0, header, sizeof(header)) != sizeof(header)) {
284f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber        return false;
285f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber    }
286f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber
287f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber    if (!memcmp(header, "#!AMR\n", 6)) {
28818291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber        *mimeType = MEDIA_MIMETYPE_AUDIO_AMR_NB;
289f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber        *confidence = 0.5;
290f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber
291f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber        return true;
292f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber    } else if (!memcmp(header, "#!AMR-WB\n", 9)) {
29318291bc20e55e8f3fd5feb786771a8ed32c19c59Andreas Huber        *mimeType = MEDIA_MIMETYPE_AUDIO_AMR_WB;
294f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber        *confidence = 0.5;
295f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber
296f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber        return true;
297f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber    }
298f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber
299f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber    return false;
300f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber}
301f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber
302f75978f63a25e79c683e96611f95cb5cd49efd3dAndreas Huber}  // namespace android
303