diff options
author | Stefan Ekenberg <stefan.ekenberg@stericsson.com> | 2012-08-20 12:00:26 +0200 |
---|---|---|
committer | Gerrit Code Review <gerrit@review.cyanogenmod.com> | 2013-01-30 00:16:57 -0800 |
commit | 69d8d46c5985ed76947f875ee3b7d32febfcf201 (patch) | |
tree | 8ccac17232e22005b25277ba9f9bb85a494e04cc /media/libstagefright/PCMExtractor.cpp | |
parent | 95dc7fae7a3d8ddbd020e588a33d9215e9105c50 (diff) | |
download | frameworks_av-69d8d46c5985ed76947f875ee3b7d32febfcf201.zip frameworks_av-69d8d46c5985ed76947f875ee3b7d32febfcf201.tar.gz frameworks_av-69d8d46c5985ed76947f875ee3b7d32febfcf201.tar.bz2 |
FM Radio: Add support for FM Radio in Android
Creating interface and framework for using FM Radio
RX and TX from different vendors.
Change-Id: I1a71aed01bfffdddfabf1cdfbfa3707cb1ed016b
Signed-off-by: Benn Porscke <benn.porscke@stericsson.com>
Diffstat (limited to 'media/libstagefright/PCMExtractor.cpp')
-rw-r--r-- | media/libstagefright/PCMExtractor.cpp | 302 |
1 files changed, 302 insertions, 0 deletions
diff --git a/media/libstagefright/PCMExtractor.cpp b/media/libstagefright/PCMExtractor.cpp new file mode 100644 index 0000000..bb26bcd --- /dev/null +++ b/media/libstagefright/PCMExtractor.cpp @@ -0,0 +1,302 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Author: Andreas Gustafsson (andreas.a.gustafsson@stericsson.com) + * for ST-Ericsson + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "PCMExtractor" +#include <utils/Log.h> + +#include "include/PCMExtractor.h" + +#include <media/stagefright/MediaBufferGroup.h> +#include <media/stagefright/MediaDefs.h> +#include <media/stagefright/MediaErrors.h> +#include <media/stagefright/MetaData.h> +#include <media/stagefright/foundation/ADebug.h> + +namespace android { + +/** +* The default buffer size. +*/ +static const uint16_t kDefaultNumChannels = 2; + +/** +* The default Sample rate. +*/ +static const uint32_t kDefaultSampleRate = 48000; + +/** +* Bits per sample. +*/ +static const uint16_t kDefaultBitsPerSample = 16; + +/** +* The default buffer size. +*/ +static const uint32_t kDefaultBufferSize = 4800; + +/** +* Buffer duration in ms, to be used for input +*/ +static const uint16_t kInputBufferDuration = 64; + +/** +* Buffer granulairity in samples to be used for input. +*/ +static const uint16_t kBufferGranularityInSamples = 16; + +struct PCMSource : public MediaSource { + PCMSource( + const sp<DataSource> &dataSource, + const sp<MetaData> &meta, + int32_t bitsPerSample, + off_t offset, size_t size); + + virtual status_t start(MetaData *params = NULL); + virtual status_t stop(); + virtual sp<MetaData> getFormat(); + + virtual status_t read( + MediaBuffer **buffer, const ReadOptions *options = NULL); + +protected: + virtual ~PCMSource(); + +private: + static const size_t kMaxFrameSize; + + sp<DataSource> mDataSource; + sp<MetaData> mMeta; + int32_t mSampleRate; + int32_t mNumChannels; + int32_t mBitsPerSample; + off_t mOffset; + size_t mSize; + bool mStarted; + MediaBufferGroup *mGroup; + off_t mCurrentPos; + uint32_t mBufferSize; + + DISALLOW_EVIL_CONSTRUCTORS(PCMSource); +}; + +PCMExtractor::PCMExtractor(const sp<DataSource> &source) + : mDataSource(source), + mValidFormat(false) { + mInitCheck = init(); +} + +PCMExtractor::~PCMExtractor() { +} + +sp<MetaData> PCMExtractor::getMetaData() { + sp<MetaData> meta = new MetaData; + + if (mInitCheck != OK) { + return meta; + } + + meta->setCString(kKeyMIMEType, "audio/raw"); + + return meta; +} + +size_t PCMExtractor::countTracks() { + return mInitCheck == OK ? 1 : 0; +} + +sp<MediaSource> PCMExtractor::getTrack(size_t index) { + if (mInitCheck != OK || index > 0) { + return NULL; + } + + return new PCMSource( + mDataSource, mTrackMeta, + kDefaultBitsPerSample, mDataOffset, mDataSize); +} + +sp<MetaData> PCMExtractor::getTrackMetaData( + size_t index, uint32_t flags) { + if (mInitCheck != OK || index > 0) { + return NULL; + } + + return mTrackMeta; +} + +status_t PCMExtractor::init() { + mDataOffset = 0; + mDataSize = 0; + mValidFormat = true; + mTrackMeta = new MetaData;mTrackMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW); + mTrackMeta->setInt32(kKeyChannelCount, kDefaultNumChannels); + mTrackMeta->setInt32(kKeySampleRate, kDefaultSampleRate); + return OK; +} + +const size_t PCMSource::kMaxFrameSize = 4800; + +PCMSource::PCMSource( + const sp<DataSource> &dataSource, + const sp<MetaData> &meta, + int32_t bitsPerSample, + off_t offset, size_t size) + : mDataSource(dataSource), + mMeta(meta), + mSampleRate(0), + mNumChannels(0), + mBitsPerSample(bitsPerSample), + mOffset(offset), + mSize(size), + mStarted(false), + mGroup(NULL), + mBufferSize(0) { + CHECK(mMeta->findInt32(kKeySampleRate, &mSampleRate)); + CHECK(mMeta->findInt32(kKeyChannelCount, &mNumChannels)); +} + +PCMSource::~PCMSource() { + if (mStarted) { + stop(); + } +} + +status_t PCMSource::start(MetaData *params) { + CHECK(!mStarted); + + size_t size = kDefaultBufferSize; + + if (mSampleRate != 0 && mNumChannels != 0) { + mBufferSize = mSampleRate * kInputBufferDuration / 1000 * mNumChannels * 2; + size_t granularity = kBufferGranularityInSamples * 2 * mNumChannels; + mBufferSize = (mBufferSize / granularity) * granularity; + } + mGroup = new MediaBufferGroup; + mGroup->add_buffer(new MediaBuffer(mBufferSize)); + + if (mBitsPerSample == 8) { + // As a temporary buffer for 8->16 bit conversion. + mGroup->add_buffer(new MediaBuffer(mBufferSize)); + } + + mCurrentPos = mOffset; + + mStarted = true; + return OK; +} + +status_t PCMSource::stop() { + + CHECK(mStarted); + delete mGroup; + mGroup = NULL; + + mStarted = false; + return OK; +} + +sp<MetaData> PCMSource::getFormat() { + return mMeta; +} + +status_t PCMSource::read( + MediaBuffer **out, const ReadOptions *options) { + *out = NULL; + int64_t seekTimeUs; + ReadOptions::SeekMode seek = ReadOptions::SEEK_CLOSEST_SYNC; + if (options != NULL && options->getSeekTo(&seekTimeUs,&seek)) { + int64_t pos = (seekTimeUs * mSampleRate) / 1000000 * mNumChannels * 2; + if (pos > mSize) { + pos = mSize; + } + mCurrentPos = pos + mOffset; + } + + MediaBuffer *buffer; + status_t err = mGroup->acquire_buffer(&buffer); + if (err != OK) { + return err; + } + + ssize_t n = mDataSource->readAt( + mCurrentPos, buffer->data(), mBufferSize); + if (n <= 0) { + buffer->release(); + buffer = NULL; + return ERROR_END_OF_STREAM; + } + + mCurrentPos += n; + + buffer->set_range(0, n); + + if (mBitsPerSample == 8) { + // Convert 8-bit unsigned samples to 16-bit signed. + + MediaBuffer *tmp; + CHECK_EQ(mGroup->acquire_buffer(&tmp), (status_t)OK); + + // The new buffer holds the sample number of samples, but each + // one is 2 bytes wide. + tmp->set_range(0, 2 * n); + + int16_t *dst = (int16_t *)tmp->data(); + const uint8_t *src = (const uint8_t *)buffer->data(); + while (n-- > 0) { + *dst++ = ((int16_t)(*src) - 128) * 256; + ++src; + } + + buffer->release(); + buffer = tmp; + } else if (mBitsPerSample == 24) { + // Convert 24-bit signed samples to 16-bit signed. + + const uint8_t *src = + (const uint8_t *)buffer->data() + buffer->range_offset(); + int16_t *dst = (int16_t *)src; + + size_t numSamples = buffer->range_length() / 3; + for (size_t i = 0; i < numSamples; ++i) { + int32_t x = (int32_t)(src[0] | src[1] << 8 | src[2] << 16); + x = (x << 8) >> 8; // sign extension + + x = x >> 8; + *dst++ = (int16_t)x; + src += 3; + } + + buffer->set_range(buffer->range_offset(), 2 * numSamples); + } + + size_t bytesPerSample = mBitsPerSample >> 3; + + buffer->meta_data()->setInt64( + kKeyTime, + 1000000LL * (mCurrentPos - mOffset) + / (mNumChannels * bytesPerSample) / mSampleRate); + + + *out = buffer; + + return OK; +} + +} // namespace android |