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/foundation/ADebug.h> 24#include <media/stagefright/DataSource.h> 25#include <media/stagefright/MediaBufferGroup.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 32namespace android { 33 34class AMRSource : public MediaSource { 35public: 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 50protected: 51 virtual ~AMRSource(); 52 53private: 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 72static 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 ALOGE("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 100static status_t getFrameSizeByOffset(const sp<DataSource> &source, 101 off64_t offset, bool isWide, size_t *frameSize) { 102 uint8_t header; 103 ssize_t count = source->readAt(offset, &header, 1); 104 if (count == 0) { 105 return ERROR_END_OF_STREAM; 106 } else if (count < 0) { 107 return ERROR_IO; 108 } 109 110 unsigned FT = (header >> 3) & 0x0f; 111 112 *frameSize = getFrameSize(isWide, FT); 113 if (*frameSize == 0) { 114 return ERROR_MALFORMED; 115 } 116 return OK; 117} 118 119AMRExtractor::AMRExtractor(const sp<DataSource> &source) 120 : mDataSource(source), 121 mInitCheck(NO_INIT), 122 mOffsetTableLength(0) { 123 String8 mimeType; 124 float confidence; 125 if (!SniffAMR(mDataSource, &mimeType, &confidence, NULL)) { 126 return; 127 } 128 129 mIsWide = (mimeType == MEDIA_MIMETYPE_AUDIO_AMR_WB); 130 131 mMeta = new MetaData; 132 mMeta->setCString( 133 kKeyMIMEType, mIsWide ? MEDIA_MIMETYPE_AUDIO_AMR_WB 134 : MEDIA_MIMETYPE_AUDIO_AMR_NB); 135 136 mMeta->setInt32(kKeyChannelCount, 1); 137 mMeta->setInt32(kKeySampleRate, mIsWide ? 16000 : 8000); 138 139 off64_t offset = mIsWide ? 9 : 6; 140 off64_t streamSize; 141 size_t frameSize, numFrames = 0; 142 int64_t duration = 0; 143 144 if (mDataSource->getSize(&streamSize) == OK) { 145 while (offset < streamSize) { 146 status_t status = getFrameSizeByOffset(source, offset, mIsWide, &frameSize); 147 if (status == ERROR_END_OF_STREAM) { 148 break; 149 } else if (status != OK) { 150 return; 151 } 152 153 if ((numFrames % 50 == 0) && (numFrames / 50 < OFFSET_TABLE_LEN)) { 154 CHECK_EQ(mOffsetTableLength, numFrames / 50); 155 mOffsetTable[mOffsetTableLength] = offset - (mIsWide ? 9: 6); 156 mOffsetTableLength ++; 157 } 158 159 offset += frameSize; 160 duration += 20000; // Each frame is 20ms 161 numFrames ++; 162 } 163 164 mMeta->setInt64(kKeyDuration, duration); 165 } 166 167 mInitCheck = OK; 168} 169 170AMRExtractor::~AMRExtractor() { 171} 172 173sp<MetaData> AMRExtractor::getMetaData() { 174 sp<MetaData> meta = new MetaData; 175 176 if (mInitCheck != OK) { 177 return meta; 178 } 179 180 meta->setCString(kKeyMIMEType, mIsWide ? "audio/amr-wb" : "audio/amr"); 181 182 return meta; 183} 184 185size_t AMRExtractor::countTracks() { 186 return mInitCheck == OK ? 1 : 0; 187} 188 189sp<IMediaSource> AMRExtractor::getTrack(size_t index) { 190 if (mInitCheck != OK || index != 0) { 191 return NULL; 192 } 193 194 return new AMRSource(mDataSource, mMeta, mIsWide, 195 mOffsetTable, mOffsetTableLength); 196} 197 198sp<MetaData> AMRExtractor::getTrackMetaData(size_t index, uint32_t /* flags */) { 199 if (mInitCheck != OK || index != 0) { 200 return NULL; 201 } 202 203 return mMeta; 204} 205 206//////////////////////////////////////////////////////////////////////////////// 207 208AMRSource::AMRSource( 209 const sp<DataSource> &source, const sp<MetaData> &meta, 210 bool isWide, const off64_t *offset_table, size_t offset_table_length) 211 : mDataSource(source), 212 mMeta(meta), 213 mIsWide(isWide), 214 mOffset(mIsWide ? 9 : 6), 215 mCurrentTimeUs(0), 216 mStarted(false), 217 mGroup(NULL), 218 mOffsetTableLength(offset_table_length) { 219 if (mOffsetTableLength > 0 && mOffsetTableLength <= OFFSET_TABLE_LEN) { 220 memcpy ((char*)mOffsetTable, (char*)offset_table, sizeof(off64_t) * mOffsetTableLength); 221 } 222} 223 224AMRSource::~AMRSource() { 225 if (mStarted) { 226 stop(); 227 } 228} 229 230status_t AMRSource::start(MetaData * /* params */) { 231 CHECK(!mStarted); 232 233 mOffset = mIsWide ? 9 : 6; 234 mCurrentTimeUs = 0; 235 mGroup = new MediaBufferGroup; 236 mGroup->add_buffer(new MediaBuffer(128)); 237 mStarted = true; 238 239 return OK; 240} 241 242status_t AMRSource::stop() { 243 CHECK(mStarted); 244 245 delete mGroup; 246 mGroup = NULL; 247 248 mStarted = false; 249 return OK; 250} 251 252sp<MetaData> AMRSource::getFormat() { 253 return mMeta; 254} 255 256status_t AMRSource::read( 257 MediaBuffer **out, const ReadOptions *options) { 258 *out = NULL; 259 260 int64_t seekTimeUs; 261 ReadOptions::SeekMode mode; 262 if (options && options->getSeekTo(&seekTimeUs, &mode)) { 263 size_t size; 264 int64_t seekFrame = seekTimeUs / 20000ll; // 20ms per frame. 265 mCurrentTimeUs = seekFrame * 20000ll; 266 267 size_t index = seekFrame < 0 ? 0 : seekFrame / 50; 268 if (index >= mOffsetTableLength) { 269 index = mOffsetTableLength - 1; 270 } 271 272 mOffset = mOffsetTable[index] + (mIsWide ? 9 : 6); 273 274 for (size_t i = 0; i< seekFrame - index * 50; i++) { 275 status_t err; 276 if ((err = getFrameSizeByOffset(mDataSource, mOffset, 277 mIsWide, &size)) != OK) { 278 return err; 279 } 280 mOffset += size; 281 } 282 } 283 284 uint8_t header; 285 ssize_t n = mDataSource->readAt(mOffset, &header, 1); 286 287 if (n < 1) { 288 return ERROR_END_OF_STREAM; 289 } 290 291 if (header & 0x83) { 292 // Padding bits must be 0. 293 294 ALOGE("padding bits must be 0, header is 0x%02x", header); 295 296 return ERROR_MALFORMED; 297 } 298 299 unsigned FT = (header >> 3) & 0x0f; 300 301 size_t frameSize = getFrameSize(mIsWide, FT); 302 if (frameSize == 0) { 303 return ERROR_MALFORMED; 304 } 305 306 MediaBuffer *buffer; 307 status_t err = mGroup->acquire_buffer(&buffer); 308 if (err != OK) { 309 return err; 310 } 311 312 n = mDataSource->readAt(mOffset, buffer->data(), frameSize); 313 314 if (n != (ssize_t)frameSize) { 315 buffer->release(); 316 buffer = NULL; 317 318 if (n < 0) { 319 return ERROR_IO; 320 } else { 321 // only partial frame is available, treat it as EOS. 322 mOffset += n; 323 return ERROR_END_OF_STREAM; 324 } 325 } 326 327 buffer->set_range(0, frameSize); 328 buffer->meta_data()->setInt64(kKeyTime, mCurrentTimeUs); 329 buffer->meta_data()->setInt32(kKeyIsSyncFrame, 1); 330 331 mOffset += frameSize; 332 mCurrentTimeUs += 20000; // Each frame is 20ms 333 334 *out = buffer; 335 336 return OK; 337} 338 339//////////////////////////////////////////////////////////////////////////////// 340 341bool SniffAMR( 342 const sp<DataSource> &source, String8 *mimeType, float *confidence, 343 sp<AMessage> *) { 344 char header[9]; 345 346 if (source->readAt(0, header, sizeof(header)) != sizeof(header)) { 347 return false; 348 } 349 350 if (!memcmp(header, "#!AMR\n", 6)) { 351 *mimeType = MEDIA_MIMETYPE_AUDIO_AMR_NB; 352 *confidence = 0.5; 353 354 return true; 355 } else if (!memcmp(header, "#!AMR-WB\n", 9)) { 356 *mimeType = MEDIA_MIMETYPE_AUDIO_AMR_WB; 357 *confidence = 0.5; 358 359 return true; 360 } 361 362 return false; 363} 364 365} // namespace android 366