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