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 "include/AMRExtractor.h" 22 23 #include <media/stagefright/DataSource.h> 24 #include <media/stagefright/MediaBufferGroup.h> 25 #include <media/stagefright/MediaDebug.h> 26 #include <media/stagefright/MediaDefs.h> 27 #include <media/stagefright/MediaErrors.h> 28 #include <media/stagefright/MediaSource.h> 29 #include <media/stagefright/MetaData.h> 30 #include <utils/String8.h> 31 32 namespace android { 33 34 class AMRSource : public MediaSource { 35 public: 36 AMRSource(const sp<DataSource> &source, 37 const sp<MetaData> &meta, 38 size_t frameSize, 39 bool isWide); 40 41 virtual status_t start(MetaData *params = NULL); 42 virtual status_t stop(); 43 44 virtual sp<MetaData> getFormat(); 45 46 virtual status_t read( 47 MediaBuffer **buffer, const ReadOptions *options = NULL); 48 49 protected: 50 virtual ~AMRSource(); 51 52 private: 53 sp<DataSource> mDataSource; 54 sp<MetaData> mMeta; 55 size_t mFrameSize; 56 bool mIsWide; 57 58 off_t mOffset; 59 int64_t mCurrentTimeUs; 60 bool mStarted; 61 MediaBufferGroup *mGroup; 62 63 AMRSource(const AMRSource &); 64 AMRSource &operator=(const AMRSource &); 65 }; 66 67 //////////////////////////////////////////////////////////////////////////////// 68 69 static size_t getFrameSize(bool isWide, unsigned FT) { 70 static const size_t kFrameSizeNB[8] = { 71 95, 103, 118, 134, 148, 159, 204, 244 72 }; 73 static const size_t kFrameSizeWB[9] = { 74 132, 177, 253, 285, 317, 365, 397, 461, 477 75 }; 76 77 size_t frameSize = isWide ? kFrameSizeWB[FT] : kFrameSizeNB[FT]; 78 79 // Round up bits to bytes and add 1 for the header byte. 80 frameSize = (frameSize + 7) / 8 + 1; 81 82 return frameSize; 83 } 84 85 AMRExtractor::AMRExtractor(const sp<DataSource> &source) 86 : mDataSource(source), 87 mInitCheck(NO_INIT) { 88 String8 mimeType; 89 float confidence; 90 if (!SniffAMR(mDataSource, &mimeType, &confidence)) { 91 return; 92 } 93 94 mIsWide = (mimeType == MEDIA_MIMETYPE_AUDIO_AMR_WB); 95 96 mMeta = new MetaData; 97 mMeta->setCString( 98 kKeyMIMEType, mIsWide ? MEDIA_MIMETYPE_AUDIO_AMR_WB 99 : MEDIA_MIMETYPE_AUDIO_AMR_NB); 100 101 mMeta->setInt32(kKeyChannelCount, 1); 102 mMeta->setInt32(kKeySampleRate, mIsWide ? 16000 : 8000); 103 104 size_t offset = mIsWide ? 9 : 6; 105 uint8_t header; 106 if (mDataSource->readAt(offset, &header, 1) != 1) { 107 return; 108 } 109 110 unsigned FT = (header >> 3) & 0x0f; 111 112 if (FT > 8 || (!mIsWide && FT > 7)) { 113 return; 114 } 115 116 mFrameSize = getFrameSize(mIsWide, FT); 117 118 off_t streamSize; 119 if (mDataSource->getSize(&streamSize) == OK) { 120 off_t numFrames = streamSize / mFrameSize; 121 122 mMeta->setInt64(kKeyDuration, 20000ll * numFrames); 123 } 124 125 mInitCheck = OK; 126 } 127 128 AMRExtractor::~AMRExtractor() { 129 } 130 131 sp<MetaData> AMRExtractor::getMetaData() { 132 sp<MetaData> meta = new MetaData; 133 134 if (mInitCheck != OK) { 135 return meta; 136 } 137 138 meta->setCString(kKeyMIMEType, mIsWide ? "audio/amr-wb" : "audio/amr"); 139 140 return meta; 141 } 142 143 size_t AMRExtractor::countTracks() { 144 return mInitCheck == OK ? 1 : 0; 145 } 146 147 sp<MediaSource> AMRExtractor::getTrack(size_t index) { 148 if (mInitCheck != OK || index != 0) { 149 return NULL; 150 } 151 152 return new AMRSource(mDataSource, mMeta, mFrameSize, mIsWide); 153 } 154 155 sp<MetaData> AMRExtractor::getTrackMetaData(size_t index, uint32_t flags) { 156 if (mInitCheck != OK || index != 0) { 157 return NULL; 158 } 159 160 return mMeta; 161 } 162 163 //////////////////////////////////////////////////////////////////////////////// 164 165 AMRSource::AMRSource( 166 const sp<DataSource> &source, const sp<MetaData> &meta, 167 size_t frameSize, bool isWide) 168 : mDataSource(source), 169 mMeta(meta), 170 mFrameSize(frameSize), 171 mIsWide(isWide), 172 mOffset(mIsWide ? 9 : 6), 173 mCurrentTimeUs(0), 174 mStarted(false), 175 mGroup(NULL) { 176 } 177 178 AMRSource::~AMRSource() { 179 if (mStarted) { 180 stop(); 181 } 182 } 183 184 status_t AMRSource::start(MetaData *params) { 185 CHECK(!mStarted); 186 187 mOffset = mIsWide ? 9 : 6; 188 mCurrentTimeUs = 0; 189 mGroup = new MediaBufferGroup; 190 mGroup->add_buffer(new MediaBuffer(128)); 191 mStarted = true; 192 193 return OK; 194 } 195 196 status_t AMRSource::stop() { 197 CHECK(mStarted); 198 199 delete mGroup; 200 mGroup = NULL; 201 202 mStarted = false; 203 return OK; 204 } 205 206 sp<MetaData> AMRSource::getFormat() { 207 return mMeta; 208 } 209 210 status_t AMRSource::read( 211 MediaBuffer **out, const ReadOptions *options) { 212 *out = NULL; 213 214 int64_t seekTimeUs; 215 if (options && options->getSeekTo(&seekTimeUs)) { 216 int64_t seekFrame = seekTimeUs / 20000ll; // 20ms per frame. 217 mCurrentTimeUs = seekFrame * 20000ll; 218 mOffset = seekFrame * mFrameSize + (mIsWide ? 9 : 6); 219 } 220 221 uint8_t header; 222 ssize_t n = mDataSource->readAt(mOffset, &header, 1); 223 224 if (n < 1) { 225 return ERROR_END_OF_STREAM; 226 } 227 228 if (header & 0x83) { 229 // Padding bits must be 0. 230 231 LOGE("padding bits must be 0, header is 0x%02x", header); 232 233 return ERROR_MALFORMED; 234 } 235 236 unsigned FT = (header >> 3) & 0x0f; 237 238 if (FT > 8 || (!mIsWide && FT > 7)) { 239 240 LOGE("illegal AMR frame type %d", FT); 241 242 return ERROR_MALFORMED; 243 } 244 245 size_t frameSize = getFrameSize(mIsWide, FT); 246 CHECK_EQ(frameSize, mFrameSize); 247 248 MediaBuffer *buffer; 249 status_t err = mGroup->acquire_buffer(&buffer); 250 if (err != OK) { 251 return err; 252 } 253 254 n = mDataSource->readAt(mOffset, buffer->data(), frameSize); 255 256 if (n != (ssize_t)frameSize) { 257 buffer->release(); 258 buffer = NULL; 259 260 return ERROR_IO; 261 } 262 263 buffer->set_range(0, frameSize); 264 buffer->meta_data()->setInt64(kKeyTime, mCurrentTimeUs); 265 266 mOffset += frameSize; 267 mCurrentTimeUs += 20000; // Each frame is 20ms 268 269 *out = buffer; 270 271 return OK; 272 } 273 274 //////////////////////////////////////////////////////////////////////////////// 275 276 bool SniffAMR( 277 const sp<DataSource> &source, String8 *mimeType, float *confidence) { 278 char header[9]; 279 280 if (source->readAt(0, header, sizeof(header)) != sizeof(header)) { 281 return false; 282 } 283 284 if (!memcmp(header, "#!AMR\n", 6)) { 285 *mimeType = MEDIA_MIMETYPE_AUDIO_AMR_NB; 286 *confidence = 0.5; 287 288 return true; 289 } else if (!memcmp(header, "#!AMR-WB\n", 9)) { 290 *mimeType = MEDIA_MIMETYPE_AUDIO_AMR_WB; 291 *confidence = 0.5; 292 293 return true; 294 } 295 296 return false; 297 } 298 299 } // namespace android 300