WAVExtractor.cpp revision abd1f4f870925d6776dbe4b930b759a1ab6595ca
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 "WAVExtractor" 19#include <utils/Log.h> 20 21#include "include/WAVExtractor.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 32namespace android { 33 34static uint16_t WAVE_FORMAT_PCM = 1; 35 36static uint32_t U32_LE_AT(const uint8_t *ptr) { 37 return ptr[3] << 24 | ptr[2] << 16 | ptr[1] << 8 | ptr[0]; 38} 39 40static uint16_t U16_LE_AT(const uint8_t *ptr) { 41 return ptr[1] << 8 | ptr[0]; 42} 43 44struct WAVSource : public MediaSource { 45 WAVSource( 46 const sp<DataSource> &dataSource, 47 const sp<MetaData> &meta, 48 int32_t bitsPerSample, 49 off_t offset, size_t size); 50 51 virtual status_t start(MetaData *params = NULL); 52 virtual status_t stop(); 53 virtual sp<MetaData> getFormat(); 54 55 virtual status_t read( 56 MediaBuffer **buffer, const ReadOptions *options = NULL); 57 58protected: 59 virtual ~WAVSource(); 60 61private: 62 static const size_t kMaxFrameSize; 63 64 sp<DataSource> mDataSource; 65 sp<MetaData> mMeta; 66 int32_t mSampleRate; 67 int32_t mNumChannels; 68 int32_t mBitsPerSample; 69 off_t mOffset; 70 size_t mSize; 71 bool mStarted; 72 MediaBufferGroup *mGroup; 73 off_t mCurrentPos; 74 75 WAVSource(const WAVSource &); 76 WAVSource &operator=(const WAVSource &); 77}; 78 79WAVExtractor::WAVExtractor(const sp<DataSource> &source) 80 : mDataSource(source), 81 mValidFormat(false) { 82 mInitCheck = init(); 83} 84 85WAVExtractor::~WAVExtractor() { 86} 87 88sp<MetaData> WAVExtractor::getMetaData() { 89 sp<MetaData> meta = new MetaData; 90 91 if (mInitCheck != OK) { 92 return meta; 93 } 94 95 meta->setCString(kKeyMIMEType, "audio/x-wav"); 96 97 return meta; 98} 99 100size_t WAVExtractor::countTracks() { 101 return mInitCheck == OK ? 1 : 0; 102} 103 104sp<MediaSource> WAVExtractor::getTrack(size_t index) { 105 if (mInitCheck != OK || index > 0) { 106 return NULL; 107 } 108 109 return new WAVSource( 110 mDataSource, mTrackMeta, 111 mBitsPerSample, mDataOffset, mDataSize); 112} 113 114sp<MetaData> WAVExtractor::getTrackMetaData( 115 size_t index, uint32_t flags) { 116 if (mInitCheck != OK || index > 0) { 117 return NULL; 118 } 119 120 return mTrackMeta; 121} 122 123status_t WAVExtractor::init() { 124 uint8_t header[12]; 125 if (mDataSource->readAt( 126 0, header, sizeof(header)) < (ssize_t)sizeof(header)) { 127 return NO_INIT; 128 } 129 130 if (memcmp(header, "RIFF", 4) || memcmp(&header[8], "WAVE", 4)) { 131 return NO_INIT; 132 } 133 134 size_t totalSize = U32_LE_AT(&header[4]); 135 136 off_t offset = 12; 137 size_t remainingSize = totalSize; 138 while (remainingSize >= 8) { 139 uint8_t chunkHeader[8]; 140 if (mDataSource->readAt(offset, chunkHeader, 8) < 8) { 141 return NO_INIT; 142 } 143 144 remainingSize -= 8; 145 offset += 8; 146 147 uint32_t chunkSize = U32_LE_AT(&chunkHeader[4]); 148 149 if (chunkSize > remainingSize) { 150 return NO_INIT; 151 } 152 153 if (!memcmp(chunkHeader, "fmt ", 4)) { 154 if (chunkSize < 16) { 155 return NO_INIT; 156 } 157 158 uint8_t formatSpec[16]; 159 if (mDataSource->readAt(offset, formatSpec, 16) < 16) { 160 return NO_INIT; 161 } 162 163 uint16_t format = U16_LE_AT(formatSpec); 164 if (format != WAVE_FORMAT_PCM) { 165 return ERROR_UNSUPPORTED; 166 } 167 168 mNumChannels = U16_LE_AT(&formatSpec[2]); 169 if (mNumChannels != 1 && mNumChannels != 2) { 170 return ERROR_UNSUPPORTED; 171 } 172 173 mSampleRate = U32_LE_AT(&formatSpec[4]); 174 175 if (mSampleRate == 0) { 176 return ERROR_MALFORMED; 177 } 178 179 mBitsPerSample = U16_LE_AT(&formatSpec[14]); 180 181 if (mBitsPerSample != 8 && mBitsPerSample != 16 182 && mBitsPerSample != 24) { 183 return ERROR_UNSUPPORTED; 184 } 185 186 mValidFormat = true; 187 } else if (!memcmp(chunkHeader, "data", 4)) { 188 if (mValidFormat) { 189 mDataOffset = offset; 190 mDataSize = chunkSize; 191 192 mTrackMeta = new MetaData; 193 mTrackMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW); 194 mTrackMeta->setInt32(kKeyChannelCount, mNumChannels); 195 mTrackMeta->setInt32(kKeySampleRate, mSampleRate); 196 197 size_t bytesPerSample = mBitsPerSample >> 3; 198 199 int64_t durationUs = 200 1000000LL * (mDataSize / (mNumChannels * bytesPerSample)) 201 / mSampleRate; 202 203 mTrackMeta->setInt64(kKeyDuration, durationUs); 204 205 return OK; 206 } 207 } 208 209 offset += chunkSize; 210 } 211 212 return NO_INIT; 213} 214 215const size_t WAVSource::kMaxFrameSize = 32768; 216 217WAVSource::WAVSource( 218 const sp<DataSource> &dataSource, 219 const sp<MetaData> &meta, 220 int32_t bitsPerSample, 221 off_t offset, size_t size) 222 : mDataSource(dataSource), 223 mMeta(meta), 224 mSampleRate(0), 225 mNumChannels(0), 226 mBitsPerSample(bitsPerSample), 227 mOffset(offset), 228 mSize(size), 229 mStarted(false), 230 mGroup(NULL) { 231 CHECK(mMeta->findInt32(kKeySampleRate, &mSampleRate)); 232 CHECK(mMeta->findInt32(kKeyChannelCount, &mNumChannels)); 233} 234 235WAVSource::~WAVSource() { 236 if (mStarted) { 237 stop(); 238 } 239} 240 241status_t WAVSource::start(MetaData *params) { 242 LOGV("WAVSource::start"); 243 244 CHECK(!mStarted); 245 246 mGroup = new MediaBufferGroup; 247 mGroup->add_buffer(new MediaBuffer(kMaxFrameSize)); 248 249 if (mBitsPerSample == 8) { 250 // As a temporary buffer for 8->16 bit conversion. 251 mGroup->add_buffer(new MediaBuffer(kMaxFrameSize)); 252 } 253 254 mCurrentPos = mOffset; 255 256 mStarted = true; 257 258 return OK; 259} 260 261status_t WAVSource::stop() { 262 LOGV("WAVSource::stop"); 263 264 CHECK(mStarted); 265 266 delete mGroup; 267 mGroup = NULL; 268 269 mStarted = false; 270 271 return OK; 272} 273 274sp<MetaData> WAVSource::getFormat() { 275 LOGV("WAVSource::getFormat"); 276 277 return mMeta; 278} 279 280status_t WAVSource::read( 281 MediaBuffer **out, const ReadOptions *options) { 282 *out = NULL; 283 284 int64_t seekTimeUs; 285 ReadOptions::SeekMode mode; 286 if (options != NULL && options->getSeekTo(&seekTimeUs, &mode)) { 287 int64_t pos = (seekTimeUs * mSampleRate) / 1000000 * mNumChannels * 2; 288 if (pos > mSize) { 289 pos = mSize; 290 } 291 mCurrentPos = pos + mOffset; 292 } 293 294 MediaBuffer *buffer; 295 status_t err = mGroup->acquire_buffer(&buffer); 296 if (err != OK) { 297 return err; 298 } 299 300 ssize_t n = mDataSource->readAt( 301 mCurrentPos, buffer->data(), 302 mBitsPerSample == 8 ? kMaxFrameSize / 2 : kMaxFrameSize); 303 304 if (n <= 0) { 305 buffer->release(); 306 buffer = NULL; 307 308 return ERROR_END_OF_STREAM; 309 } 310 311 mCurrentPos += n; 312 313 buffer->set_range(0, n); 314 315 if (mBitsPerSample == 8) { 316 // Convert 8-bit unsigned samples to 16-bit signed. 317 318 MediaBuffer *tmp; 319 CHECK_EQ(mGroup->acquire_buffer(&tmp), OK); 320 321 // The new buffer holds the sample number of samples, but each 322 // one is 2 bytes wide. 323 tmp->set_range(0, 2 * n); 324 325 int16_t *dst = (int16_t *)tmp->data(); 326 const uint8_t *src = (const uint8_t *)buffer->data(); 327 while (n-- > 0) { 328 *dst++ = ((int16_t)(*src) - 128) * 256; 329 ++src; 330 } 331 332 buffer->release(); 333 buffer = tmp; 334 } else if (mBitsPerSample == 24) { 335 // Convert 24-bit signed samples to 16-bit signed. 336 337 const uint8_t *src = 338 (const uint8_t *)buffer->data() + buffer->range_offset(); 339 int16_t *dst = (int16_t *)src; 340 341 size_t numSamples = buffer->range_length() / 3; 342 for (size_t i = 0; i < numSamples; ++i) { 343 int32_t x = (int32_t)(src[0] | src[1] << 8 | src[2] << 16); 344 x = (x << 8) >> 8; // sign extension 345 346 x = x >> 8; 347 *dst++ = (int16_t)x; 348 src += 3; 349 } 350 351 buffer->set_range(buffer->range_offset(), 2 * numSamples); 352 } 353 354 size_t bytesPerSample = mBitsPerSample >> 3; 355 356 buffer->meta_data()->setInt64( 357 kKeyTime, 358 1000000LL * (mCurrentPos - mOffset) 359 / (mNumChannels * bytesPerSample) / mSampleRate); 360 361 362 *out = buffer; 363 364 return OK; 365} 366 367//////////////////////////////////////////////////////////////////////////////// 368 369bool SniffWAV( 370 const sp<DataSource> &source, String8 *mimeType, float *confidence) { 371 char header[12]; 372 if (source->readAt(0, header, sizeof(header)) < (ssize_t)sizeof(header)) { 373 return false; 374 } 375 376 if (memcmp(header, "RIFF", 4) || memcmp(&header[8], "WAVE", 4)) { 377 return false; 378 } 379 380 *mimeType = MEDIA_MIMETYPE_CONTAINER_WAV; 381 *confidence = 0.3f; 382 383 return true; 384} 385 386} // namespace android 387 388