AMRExtractor.cpp revision 48c948b1137e7bbdb161b51908657ab72ac5e2da
1/* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17//#define LOG_NDEBUG 0 18#define LOG_TAG "AMRExtractor" 19#include <utils/Log.h> 20 21#include <media/stagefright/AMRExtractor.h> 22#include <media/stagefright/DataSource.h> 23#include <media/stagefright/MediaBufferGroup.h> 24#include <media/stagefright/MediaDebug.h> 25#include <media/stagefright/MediaDefs.h> 26#include <media/stagefright/MediaErrors.h> 27#include <media/stagefright/MediaSource.h> 28#include <media/stagefright/MetaData.h> 29#include <utils/String8.h> 30 31namespace android { 32 33class AMRSource : public MediaSource { 34public: 35 AMRSource(const sp<DataSource> &source, bool isWide); 36 37 virtual status_t start(MetaData *params = NULL); 38 virtual status_t stop(); 39 40 virtual sp<MetaData> getFormat(); 41 42 virtual status_t read( 43 MediaBuffer **buffer, const ReadOptions *options = NULL); 44 45protected: 46 virtual ~AMRSource(); 47 48private: 49 sp<DataSource> mDataSource; 50 bool mIsWide; 51 52 off_t mOffset; 53 int64_t mCurrentTimeUs; 54 bool mStarted; 55 MediaBufferGroup *mGroup; 56 57 AMRSource(const AMRSource &); 58 AMRSource &operator=(const AMRSource &); 59}; 60 61//////////////////////////////////////////////////////////////////////////////// 62 63AMRExtractor::AMRExtractor(const sp<DataSource> &source) 64 : mDataSource(source), 65 mInitCheck(NO_INIT) { 66 String8 mimeType; 67 float confidence; 68 if (SniffAMR(mDataSource, &mimeType, &confidence)) { 69 mInitCheck = OK; 70 mIsWide = (mimeType == MEDIA_MIMETYPE_AUDIO_AMR_WB); 71 } 72} 73 74AMRExtractor::~AMRExtractor() { 75} 76 77size_t AMRExtractor::countTracks() { 78 return mInitCheck == OK ? 1 : 0; 79} 80 81sp<MediaSource> AMRExtractor::getTrack(size_t index) { 82 if (mInitCheck != OK || index != 0) { 83 return NULL; 84 } 85 86 return new AMRSource(mDataSource, mIsWide); 87} 88 89sp<MetaData> AMRExtractor::getTrackMetaData(size_t index) { 90 if (mInitCheck != OK || index != 0) { 91 return NULL; 92 } 93 94 return makeAMRFormat(mIsWide); 95} 96 97// static 98sp<MetaData> AMRExtractor::makeAMRFormat(bool isWide) { 99 sp<MetaData> meta = new MetaData; 100 meta->setCString( 101 kKeyMIMEType, isWide ? MEDIA_MIMETYPE_AUDIO_AMR_WB 102 : MEDIA_MIMETYPE_AUDIO_AMR_NB); 103 104 meta->setInt32(kKeyChannelCount, 1); 105 meta->setInt32(kKeySampleRate, isWide ? 16000 : 8000); 106 107 return meta; 108} 109 110//////////////////////////////////////////////////////////////////////////////// 111 112AMRSource::AMRSource(const sp<DataSource> &source, bool isWide) 113 : mDataSource(source), 114 mIsWide(isWide), 115 mOffset(mIsWide ? 9 : 6), 116 mCurrentTimeUs(0), 117 mStarted(false), 118 mGroup(NULL) { 119} 120 121AMRSource::~AMRSource() { 122 if (mStarted) { 123 stop(); 124 } 125} 126 127status_t AMRSource::start(MetaData *params) { 128 CHECK(!mStarted); 129 130 mOffset = mIsWide ? 9 : 6; 131 mCurrentTimeUs = 0; 132 mGroup = new MediaBufferGroup; 133 mGroup->add_buffer(new MediaBuffer(128)); 134 mStarted = true; 135 136 return OK; 137} 138 139status_t AMRSource::stop() { 140 CHECK(mStarted); 141 142 delete mGroup; 143 mGroup = NULL; 144 145 mStarted = false; 146 return OK; 147} 148 149sp<MetaData> AMRSource::getFormat() { 150 return AMRExtractor::makeAMRFormat(mIsWide); 151} 152 153status_t AMRSource::read( 154 MediaBuffer **out, const ReadOptions *options) { 155 *out = NULL; 156 157 uint8_t header; 158 ssize_t n = mDataSource->read_at(mOffset, &header, 1); 159 160 if (n < 1) { 161 return ERROR_IO; 162 } 163 164 MediaBuffer *buffer; 165 status_t err = mGroup->acquire_buffer(&buffer); 166 if (err != OK) { 167 return err; 168 } 169 170 if (header & 0x83) { 171 // Padding bits must be 0. 172 173 return ERROR_MALFORMED; 174 } 175 176 unsigned FT = (header >> 3) & 0x0f; 177 178 if (FT > 8 || (!mIsWide && FT > 7)) { 179 return ERROR_MALFORMED; 180 } 181 182 static const size_t kFrameSizeNB[8] = { 183 95, 103, 118, 134, 148, 159, 204, 244 184 }; 185 static const size_t kFrameSizeWB[9] = { 186 132, 177, 253, 285, 317, 365, 397, 461, 477 187 }; 188 189 size_t frameSize = mIsWide ? kFrameSizeWB[FT] : kFrameSizeNB[FT]; 190 191 // Round up bits to bytes and add 1 for the header byte. 192 frameSize = (frameSize + 7) / 8 + 1; 193 194 n = mDataSource->read_at(mOffset, buffer->data(), frameSize); 195 196 if (n != (ssize_t)frameSize) { 197 buffer->release(); 198 buffer = NULL; 199 200 return ERROR_IO; 201 } 202 203 buffer->set_range(0, frameSize); 204 buffer->meta_data()->setInt64(kKeyTime, mCurrentTimeUs); 205 206 mOffset += frameSize; 207 mCurrentTimeUs += 20000; // Each frame is 20ms 208 209 *out = buffer; 210 211 return OK; 212} 213 214//////////////////////////////////////////////////////////////////////////////// 215 216bool SniffAMR( 217 const sp<DataSource> &source, String8 *mimeType, float *confidence) { 218 char header[9]; 219 220 if (source->read_at(0, header, sizeof(header)) != sizeof(header)) { 221 return false; 222 } 223 224 if (!memcmp(header, "#!AMR\n", 6)) { 225 *mimeType = MEDIA_MIMETYPE_AUDIO_AMR_NB; 226 *confidence = 0.5; 227 228 return true; 229 } else if (!memcmp(header, "#!AMR-WB\n", 9)) { 230 *mimeType = MEDIA_MIMETYPE_AUDIO_AMR_WB; 231 *confidence = 0.5; 232 233 return true; 234 } 235 236 return false; 237} 238 239} // namespace android 240