WAVExtractor.cpp revision 7be6407f2ad7f2b0782d195d9f792072c084d6f5
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 int32_t sampleRate, int32_t numChannels, 48 off_t offset, size_t size); 49 50 virtual status_t start(MetaData *params = NULL); 51 virtual status_t stop(); 52 virtual sp<MetaData> getFormat(); 53 54 virtual status_t read( 55 MediaBuffer **buffer, const ReadOptions *options = NULL); 56 57protected: 58 virtual ~WAVSource(); 59 60private: 61 static const size_t kMaxFrameSize; 62 63 sp<DataSource> mDataSource; 64 int32_t mSampleRate; 65 int32_t mNumChannels; 66 off_t mOffset; 67 size_t mSize; 68 bool mStarted; 69 MediaBufferGroup *mGroup; 70 off_t mCurrentPos; 71 72 WAVSource(const WAVSource &); 73 WAVSource &operator=(const WAVSource &); 74}; 75 76WAVExtractor::WAVExtractor(const sp<DataSource> &source) 77 : mDataSource(source), 78 mValidFormat(false) { 79 mInitCheck = init(); 80} 81 82WAVExtractor::~WAVExtractor() { 83} 84 85sp<MetaData> WAVExtractor::getMetaData() { 86 sp<MetaData> meta = new MetaData; 87 88 if (mInitCheck != OK) { 89 return meta; 90 } 91 92 meta->setCString(kKeyMIMEType, "audio/x-wav"); 93 94 return meta; 95} 96 97size_t WAVExtractor::countTracks() { 98 return mInitCheck == OK ? 1 : 0; 99} 100 101sp<MediaSource> WAVExtractor::getTrack(size_t index) { 102 if (mInitCheck != OK || index > 0) { 103 return NULL; 104 } 105 106 return new WAVSource( 107 mDataSource, mSampleRate, mNumChannels, mDataOffset, mDataSize); 108} 109 110sp<MetaData> WAVExtractor::getTrackMetaData( 111 size_t index, uint32_t flags) { 112 if (mInitCheck != OK || index > 0) { 113 return NULL; 114 } 115 116 sp<MetaData> meta = new MetaData; 117 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW); 118 meta->setInt32(kKeyChannelCount, mNumChannels); 119 meta->setInt32(kKeySampleRate, mSampleRate); 120 121 int64_t durationUs = 122 1000000LL * (mDataSize / (mNumChannels * 2)) / mSampleRate; 123 124 meta->setInt64(kKeyDuration, durationUs); 125 126 return meta; 127} 128 129status_t WAVExtractor::init() { 130 uint8_t header[12]; 131 if (mDataSource->readAt( 132 0, header, sizeof(header)) < (ssize_t)sizeof(header)) { 133 return NO_INIT; 134 } 135 136 if (memcmp(header, "RIFF", 4) || memcmp(&header[8], "WAVE", 4)) { 137 return NO_INIT; 138 } 139 140 size_t totalSize = U32_LE_AT(&header[4]); 141 142 off_t offset = 12; 143 size_t remainingSize = totalSize; 144 while (remainingSize >= 8) { 145 uint8_t chunkHeader[8]; 146 if (mDataSource->readAt(offset, chunkHeader, 8) < 8) { 147 return NO_INIT; 148 } 149 150 remainingSize -= 8; 151 offset += 8; 152 153 uint32_t chunkSize = U32_LE_AT(&chunkHeader[4]); 154 155 if (chunkSize > remainingSize) { 156 return NO_INIT; 157 } 158 159 if (!memcmp(chunkHeader, "fmt ", 4)) { 160 if (chunkSize < 16) { 161 return NO_INIT; 162 } 163 164 uint8_t formatSpec[16]; 165 if (mDataSource->readAt(offset, formatSpec, 16) < 16) { 166 return NO_INIT; 167 } 168 169 uint16_t format = U16_LE_AT(formatSpec); 170 if (format != WAVE_FORMAT_PCM) { 171 return ERROR_UNSUPPORTED; 172 } 173 174 mNumChannels = U16_LE_AT(&formatSpec[2]); 175 if (mNumChannels != 1 && mNumChannels != 2) { 176 return ERROR_UNSUPPORTED; 177 } 178 179 mSampleRate = U32_LE_AT(&formatSpec[4]); 180 181 if (U16_LE_AT(&formatSpec[14]) != 16) { 182 return ERROR_UNSUPPORTED; 183 } 184 185 mValidFormat = true; 186 } else if (!memcmp(chunkHeader, "data", 4)) { 187 if (mValidFormat) { 188 mDataOffset = offset; 189 mDataSize = chunkSize; 190 191 return OK; 192 } 193 } 194 195 offset += chunkSize; 196 } 197 198 return NO_INIT; 199} 200 201const size_t WAVSource::kMaxFrameSize = 32768; 202 203WAVSource::WAVSource( 204 const sp<DataSource> &dataSource, 205 int32_t sampleRate, int32_t numChannels, 206 off_t offset, size_t size) 207 : mDataSource(dataSource), 208 mSampleRate(sampleRate), 209 mNumChannels(numChannels), 210 mOffset(offset), 211 mSize(size), 212 mStarted(false), 213 mGroup(NULL) { 214} 215 216WAVSource::~WAVSource() { 217 if (mStarted) { 218 stop(); 219 } 220} 221 222status_t WAVSource::start(MetaData *params) { 223 LOGV("WAVSource::start"); 224 225 CHECK(!mStarted); 226 227 mGroup = new MediaBufferGroup; 228 mGroup->add_buffer(new MediaBuffer(kMaxFrameSize)); 229 230 mCurrentPos = mOffset; 231 232 mStarted = true; 233 234 return OK; 235} 236 237status_t WAVSource::stop() { 238 LOGV("WAVSource::stop"); 239 240 CHECK(mStarted); 241 242 delete mGroup; 243 mGroup = NULL; 244 245 mStarted = false; 246 247 return OK; 248} 249 250sp<MetaData> WAVSource::getFormat() { 251 LOGV("WAVSource::getFormat"); 252 253 sp<MetaData> meta = new MetaData; 254 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW); 255 meta->setInt32(kKeyChannelCount, mNumChannels); 256 meta->setInt32(kKeySampleRate, mSampleRate); 257 258 int64_t durationUs = 259 1000000LL * (mSize / (mNumChannels * 2)) / mSampleRate; 260 261 meta->setInt64(kKeyDuration, durationUs); 262 263 return meta; 264} 265 266status_t WAVSource::read( 267 MediaBuffer **out, const ReadOptions *options) { 268 *out = NULL; 269 270 int64_t seekTimeUs; 271 if (options != NULL && options->getSeekTo(&seekTimeUs)) { 272 int64_t pos = (seekTimeUs * mSampleRate) / 1000000 * mNumChannels * 2; 273 if (pos > mSize) { 274 pos = mSize; 275 } 276 mCurrentPos = pos + mOffset; 277 } 278 279 MediaBuffer *buffer; 280 status_t err = mGroup->acquire_buffer(&buffer); 281 if (err != OK) { 282 return err; 283 } 284 285 ssize_t n = mDataSource->readAt( 286 mCurrentPos, buffer->data(), kMaxFrameSize); 287 288 if (n <= 0) { 289 buffer->release(); 290 buffer = NULL; 291 292 return ERROR_END_OF_STREAM; 293 } 294 295 mCurrentPos += n; 296 297 buffer->set_range(0, n); 298 buffer->meta_data()->setInt64( 299 kKeyTime, 300 1000000LL * (mCurrentPos - mOffset) 301 / (mNumChannels * 2) / mSampleRate); 302 303 304 *out = buffer; 305 306 return OK; 307} 308 309//////////////////////////////////////////////////////////////////////////////// 310 311bool SniffWAV( 312 const sp<DataSource> &source, String8 *mimeType, float *confidence) { 313 char header[12]; 314 if (source->readAt(0, header, sizeof(header)) < (ssize_t)sizeof(header)) { 315 return false; 316 } 317 318 if (memcmp(header, "RIFF", 4) || memcmp(&header[8], "WAVE", 4)) { 319 return false; 320 } 321 322 *mimeType = MEDIA_MIMETYPE_CONTAINER_WAV; 323 *confidence = 0.3f; 324 325 return true; 326} 327 328} // namespace android 329 330