diff options
Diffstat (limited to 'media')
-rw-r--r-- | media/libstagefright/AMRExtractor.cpp | 238 | ||||
-rw-r--r-- | media/libstagefright/Android.mk | 1 | ||||
-rw-r--r-- | media/libstagefright/DataSource.cpp | 2 | ||||
-rw-r--r-- | media/libstagefright/MediaExtractor.cpp | 4 | ||||
-rw-r--r-- | media/libstagefright/OMXCodec.cpp | 1 |
5 files changed, 246 insertions, 0 deletions
diff --git a/media/libstagefright/AMRExtractor.cpp b/media/libstagefright/AMRExtractor.cpp new file mode 100644 index 0000000..4772aca --- /dev/null +++ b/media/libstagefright/AMRExtractor.cpp @@ -0,0 +1,238 @@ +/* + * Copyright (C) 2009 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. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "AMRExtractor" +#include <utils/Log.h> + +#include <media/stagefright/AMRExtractor.h> +#include <media/stagefright/DataSource.h> +#include <media/stagefright/MediaBufferGroup.h> +#include <media/stagefright/MediaDebug.h> +#include <media/stagefright/MediaErrors.h> +#include <media/stagefright/MediaSource.h> +#include <media/stagefright/MetaData.h> +#include <utils/String8.h> + +namespace android { + +class AMRSource : public MediaSource { +public: + AMRSource(const sp<DataSource> &source, bool isWide); + + 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 ~AMRSource(); + +private: + sp<DataSource> mDataSource; + bool mIsWide; + + off_t mOffset; + int64_t mCurrentTimeUs; + bool mStarted; + MediaBufferGroup *mGroup; + + AMRSource(const AMRSource &); + AMRSource &operator=(const AMRSource &); +}; + +//////////////////////////////////////////////////////////////////////////////// + +AMRExtractor::AMRExtractor(const sp<DataSource> &source) + : mDataSource(source), + mInitCheck(NO_INIT) { + String8 mimeType; + float confidence; + if (SniffAMR(mDataSource, &mimeType, &confidence)) { + mInitCheck = OK; + mIsWide = (mimeType == "audio/amr-wb"); + } +} + +AMRExtractor::~AMRExtractor() { +} + +size_t AMRExtractor::countTracks() { + return mInitCheck == OK ? 1 : 0; +} + +sp<MediaSource> AMRExtractor::getTrack(size_t index) { + if (mInitCheck != OK || index != 0) { + return NULL; + } + + return new AMRSource(mDataSource, mIsWide); +} + +sp<MetaData> AMRExtractor::getTrackMetaData(size_t index) { + if (mInitCheck != OK || index != 0) { + return NULL; + } + + return makeAMRFormat(mIsWide); +} + +// static +sp<MetaData> AMRExtractor::makeAMRFormat(bool isWide) { + sp<MetaData> meta = new MetaData; + meta->setCString(kKeyMIMEType, isWide ? "audio/amr-wb" : "audio/3gpp"); + meta->setInt32(kKeyChannelCount, 1); + meta->setInt32(kKeySampleRate, isWide ? 16000 : 8000); + + return meta; +} + +//////////////////////////////////////////////////////////////////////////////// + +AMRSource::AMRSource(const sp<DataSource> &source, bool isWide) + : mDataSource(source), + mIsWide(isWide), + mOffset(mIsWide ? 9 : 6), + mCurrentTimeUs(0), + mStarted(false), + mGroup(NULL) { +} + +AMRSource::~AMRSource() { + if (mStarted) { + stop(); + } +} + +status_t AMRSource::start(MetaData *params) { + CHECK(!mStarted); + + mOffset = mIsWide ? 9 : 6; + mCurrentTimeUs = 0; + mGroup = new MediaBufferGroup; + mGroup->add_buffer(new MediaBuffer(128)); + mStarted = true; + + return OK; +} + +status_t AMRSource::stop() { + CHECK(mStarted); + + delete mGroup; + mGroup = NULL; + + mStarted = false; + return OK; +} + +sp<MetaData> AMRSource::getFormat() { + return AMRExtractor::makeAMRFormat(mIsWide); +} + +status_t AMRSource::read( + MediaBuffer **out, const ReadOptions *options) { + *out = NULL; + + uint8_t header; + ssize_t n = mDataSource->read_at(mOffset, &header, 1); + + if (n < 1) { + return ERROR_IO; + } + + MediaBuffer *buffer; + status_t err = mGroup->acquire_buffer(&buffer); + if (err != OK) { + return err; + } + + if (header & 0x83) { + // Padding bits must be 0. + + return ERROR_MALFORMED; + } + + unsigned FT = (header >> 3) & 0x0f; + + if (FT > 8 || (!mIsWide && FT > 7)) { + return ERROR_MALFORMED; + } + + static const size_t kFrameSizeNB[8] = { + 95, 103, 118, 134, 148, 159, 204, 244 + }; + static const size_t kFrameSizeWB[9] = { + 132, 177, 253, 285, 317, 365, 397, 461, 477 + }; + + size_t frameSize = mIsWide ? kFrameSizeWB[FT] : kFrameSizeNB[FT]; + + // Round up bits to bytes and add 1 for the header byte. + frameSize = (frameSize + 7) / 8 + 1; + + n = mDataSource->read_at(mOffset, buffer->data(), frameSize); + + if (n != (ssize_t)frameSize) { + buffer->release(); + buffer = NULL; + + return ERROR_IO; + } + + buffer->set_range(0, frameSize); + buffer->meta_data()->setInt32( + kKeyTimeUnits, (mCurrentTimeUs + 500) / 1000); + buffer->meta_data()->setInt32( + kKeyTimeScale, 1000); + + mOffset += frameSize; + mCurrentTimeUs += 20000; // Each frame is 20ms + + *out = buffer; + + return OK; +} + +//////////////////////////////////////////////////////////////////////////////// + +bool SniffAMR( + const sp<DataSource> &source, String8 *mimeType, float *confidence) { + char header[9]; + + if (source->read_at(0, header, sizeof(header)) != sizeof(header)) { + return false; + } + + if (!memcmp(header, "#!AMR\n", 6)) { + *mimeType = "audio/3gpp"; + *confidence = 0.5; + + return true; + } else if (!memcmp(header, "#!AMR-WB\n", 9)) { + *mimeType = "audio/amr-wb"; + *confidence = 0.5; + + return true; + } + + return false; +} + +} // namespace android diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk index 20b0da2..c3a4722 100644 --- a/media/libstagefright/Android.mk +++ b/media/libstagefright/Android.mk @@ -2,6 +2,7 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ + AMRExtractor.cpp \ CachingDataSource.cpp \ DataSource.cpp \ FileSource.cpp \ diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp index 02a276b..daac539 100644 --- a/media/libstagefright/DataSource.cpp +++ b/media/libstagefright/DataSource.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#include <media/stagefright/AMRExtractor.h> #include <media/stagefright/DataSource.h> #include <media/stagefright/MediaErrors.h> #include <media/stagefright/MP3Extractor.h> @@ -84,6 +85,7 @@ void DataSource::RegisterSniffer(SnifferFunc func) { void DataSource::RegisterDefaultSniffers() { RegisterSniffer(SniffMP3); RegisterSniffer(SniffMPEG4); + RegisterSniffer(SniffAMR); } } // namespace android diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp index 5f78e12..8afa8e1 100644 --- a/media/libstagefright/MediaExtractor.cpp +++ b/media/libstagefright/MediaExtractor.cpp @@ -18,6 +18,7 @@ #define LOG_TAG "MediaExtractor" #include <utils/Log.h> +#include <media/stagefright/AMRExtractor.h> #include <media/stagefright/DataSource.h> #include <media/stagefright/MP3Extractor.h> #include <media/stagefright/MPEG4Extractor.h> @@ -47,6 +48,9 @@ sp<MediaExtractor> MediaExtractor::Create( return new MPEG4Extractor(source); } else if (!strcasecmp(mime, "audio/mpeg")) { return new MP3Extractor(source); + } else if (!strcasecmp(mime, "audio/3gpp") + || !strcasecmp(mime, "audio/amr-wb")) { + return new AMRExtractor(source); } return NULL; diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp index 3cba142..b1e7069 100644 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -50,6 +50,7 @@ static const CodecInfo kDecoderInfo[] = { { "audio/3gpp", "OMX.TI.AMR.decode" }, { "audio/3gpp", "OMX.PV.amrdec" }, { "audio/amr-wb", "OMX.TI.WBAMR.decode" }, + { "audio/amr-wb", "OMX.PV.amrdec" }, { "audio/mp4a-latm", "OMX.TI.AAC.decode" }, { "audio/mp4a-latm", "OMX.PV.aacdec" }, { "video/mp4v-es", "OMX.qcom.video.decoder.mpeg4" }, |