summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Huber <andih@google.com>2009-09-08 16:07:15 -0700
committerAndreas Huber <andih@google.com>2009-09-09 11:05:42 -0700
commitf75978f63a25e79c683e96611f95cb5cd49efd3d (patch)
treedd74697325270da0b961fb6dadc2ecb2b95be9a4
parent03480f8ae9df41902b6523493fe19a2a513b8d98 (diff)
downloadframeworks_av-f75978f63a25e79c683e96611f95cb5cd49efd3d.zip
frameworks_av-f75978f63a25e79c683e96611f95cb5cd49efd3d.tar.gz
frameworks_av-f75978f63a25e79c683e96611f95cb5cd49efd3d.tar.bz2
Added a .amr file extractor (for AMR-NB and AMR-WB content).
-rw-r--r--include/media/stagefright/AMRExtractor.h54
-rw-r--r--include/media/stagefright/MP3Extractor.h6
-rw-r--r--media/libstagefright/AMRExtractor.cpp238
-rw-r--r--media/libstagefright/Android.mk1
-rw-r--r--media/libstagefright/DataSource.cpp2
-rw-r--r--media/libstagefright/MediaExtractor.cpp4
-rw-r--r--media/libstagefright/OMXCodec.cpp1
7 files changed, 303 insertions, 3 deletions
diff --git a/include/media/stagefright/AMRExtractor.h b/include/media/stagefright/AMRExtractor.h
new file mode 100644
index 0000000..c8710d3
--- /dev/null
+++ b/include/media/stagefright/AMRExtractor.h
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+#ifndef AMR_EXTRACTOR_H_
+
+#define AMR_EXTRACTOR_H_
+
+#include <media/stagefright/MediaExtractor.h>
+
+namespace android {
+
+class String8;
+
+class AMRExtractor : public MediaExtractor {
+public:
+ AMRExtractor(const sp<DataSource> &source);
+
+ virtual size_t countTracks();
+ virtual sp<MediaSource> getTrack(size_t index);
+ virtual sp<MetaData> getTrackMetaData(size_t index);
+
+ static sp<MetaData> makeAMRFormat(bool isWide);
+
+protected:
+ virtual ~AMRExtractor();
+
+private:
+ sp<DataSource> mDataSource;
+ status_t mInitCheck;
+ bool mIsWide;
+
+ AMRExtractor(const AMRExtractor &);
+ AMRExtractor &operator=(const AMRExtractor &);
+};
+
+bool SniffAMR(
+ const sp<DataSource> &source, String8 *mimeType, float *confidence);
+
+} // namespace android
+
+#endif // AMR_EXTRACTOR_H_
diff --git a/include/media/stagefright/MP3Extractor.h b/include/media/stagefright/MP3Extractor.h
index 4e1f3c3..11ba01d 100644
--- a/include/media/stagefright/MP3Extractor.h
+++ b/include/media/stagefright/MP3Extractor.h
@@ -30,9 +30,9 @@ public:
// Extractor assumes ownership of "source".
MP3Extractor(const sp<DataSource> &source);
- size_t countTracks();
- sp<MediaSource> getTrack(size_t index);
- sp<MetaData> getTrackMetaData(size_t index);
+ virtual size_t countTracks();
+ virtual sp<MediaSource> getTrack(size_t index);
+ virtual sp<MetaData> getTrackMetaData(size_t index);
protected:
virtual ~MP3Extractor();
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" },