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