Merge change 24337 into eclair

* changes:
  Fix issue 2107584: media server crash when AudioFlinger fails to allocate memory for track control block.
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
index 51a0649..39ed769 100644
--- a/cmds/stagefright/Android.mk
+++ b/cmds/stagefright/Android.mk
@@ -1,9 +1,10 @@
+ifeq ($(BUILD_WITH_FULL_STAGEFRIGHT),true)
+
 LOCAL_PATH:= $(call my-dir)
 
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:=       \
-        JPEGSource.cpp  \
 	stagefright.cpp
 
 LOCAL_SHARED_LIBRARIES := \
@@ -39,3 +40,5 @@
 LOCAL_MODULE:= record
 
 include $(BUILD_EXECUTABLE)
+
+endif
diff --git a/cmds/stagefright/SineSource.cpp b/cmds/stagefright/SineSource.cpp
index 3c25a7f..e5a6ccb 100644
--- a/cmds/stagefright/SineSource.cpp
+++ b/cmds/stagefright/SineSource.cpp
@@ -4,6 +4,7 @@
 
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MetaData.h>
 
 namespace android {
@@ -48,7 +49,7 @@
 
 sp<MetaData> SineSource::getFormat() {
     sp<MetaData> meta = new MetaData;
-    meta->setCString(kKeyMIMEType, "audio/raw");
+    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
     meta->setInt32(kKeyChannelCount, mNumChannels);
     meta->setInt32(kKeySampleRate, mSampleRate);
 
diff --git a/cmds/stagefright/record.cpp b/cmds/stagefright/record.cpp
index 81a1c0a..323d448 100644
--- a/cmds/stagefright/record.cpp
+++ b/cmds/stagefright/record.cpp
@@ -21,6 +21,7 @@
 #include <media/stagefright/CameraSource.h>
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/MPEG4Extractor.h>
 #include <media/stagefright/MPEG4Writer.h>
@@ -45,7 +46,7 @@
         sp<MetaData> meta = new MetaData;
         meta->setInt32(kKeyWidth, mWidth);
         meta->setInt32(kKeyHeight, mHeight);
-        meta->setCString(kKeyMIMEType, "video/raw");
+        meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW);
 
         return meta;
     }
@@ -149,8 +150,8 @@
 #endif
 
     sp<MetaData> enc_meta = new MetaData;
-    // enc_meta->setCString(kKeyMIMEType, "video/3gpp");
-    enc_meta->setCString(kKeyMIMEType, "video/mp4v-es");
+    // enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263);
+    enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4);
     enc_meta->setInt32(kKeyWidth, width);
     enc_meta->setInt32(kKeyHeight, height);
 
@@ -228,7 +229,8 @@
 #endif
 
     sp<MetaData> encMeta = new MetaData;
-    encMeta->setCString(kKeyMIMEType, 1 ? "audio/3gpp" : "audio/mp4a-latm");
+    encMeta->setCString(kKeyMIMEType,
+            1 ? MEDIA_MIMETYPE_AUDIO_AMR_WB : MEDIA_MIMETYPE_AUDIO_AAC);
     encMeta->setInt32(kKeySampleRate, kSampleRate);
     encMeta->setInt32(kKeyChannelCount, kNumChannels);
     encMeta->setInt32(kKeyMaxInputSize, 8192);
@@ -248,7 +250,7 @@
         buffer->release();
         buffer = NULL;
 
-        if (++n == 10000) {
+        if (++n == 100) {
             break;
         }
     }
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index a0b83fb..73215d3 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -25,7 +25,9 @@
 #include <media/IMediaPlayerService.h>
 #include <media/stagefright/CachingDataSource.h>
 #include <media/stagefright/HTTPDataSource.h>
+#include <media/stagefright/JPEGSource.h>
 #include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaPlayerImpl.h>
 #include <media/stagefright/MediaExtractor.h>
 #include <media/stagefright/MediaSource.h>
@@ -34,8 +36,6 @@
 #include <media/stagefright/OMXClient.h>
 #include <media/stagefright/OMXCodec.h>
 
-#include "JPEGSource.h"
-
 using namespace android;
 
 static long gNumRepetitions;
@@ -126,6 +126,7 @@
     fprintf(stderr, "       -l(ist) components\n");
     fprintf(stderr, "       -m max-number-of-frames-to-decode in each pass\n");
     fprintf(stderr, "       -b bug to reproduce\n");
+    fprintf(stderr, "       -p(rofiles) dump decoder profiles supported\n");
 }
 
 int main(int argc, char **argv) {
@@ -133,12 +134,13 @@
 
     bool audioOnly = false;
     bool listComponents = false;
+    bool dumpProfiles = false;
     gNumRepetitions = 1;
     gMaxNumFrames = 0;
     gReproduceBug = -1;
 
     int res;
-    while ((res = getopt(argc, argv, "han:lm:b:")) >= 0) {
+    while ((res = getopt(argc, argv, "han:lm:b:p")) >= 0) {
         switch (res) {
             case 'a':
             {
@@ -174,6 +176,12 @@
                 break;
             }
 
+            case 'p':
+            {
+                dumpProfiles = true;
+                break;
+            }
+
             case '?':
             case 'h':
             default:
@@ -188,6 +196,53 @@
     argc -= optind;
     argv += optind;
 
+    if (dumpProfiles) {
+        sp<IServiceManager> sm = defaultServiceManager();
+        sp<IBinder> binder = sm->getService(String16("media.player"));
+        sp<IMediaPlayerService> service =
+            interface_cast<IMediaPlayerService>(binder);
+
+        CHECK(service.get() != NULL);
+
+        sp<IOMX> omx = service->createOMX();
+        CHECK(omx.get() != NULL);
+
+        const char *kMimeTypes[] = {
+            MEDIA_MIMETYPE_VIDEO_AVC, MEDIA_MIMETYPE_VIDEO_MPEG4,
+            MEDIA_MIMETYPE_VIDEO_H263
+        };
+
+        for (size_t k = 0; k < sizeof(kMimeTypes) / sizeof(kMimeTypes[0]);
+             ++k) {
+            printf("type '%s':\n", kMimeTypes[k]);
+
+            Vector<CodecCapabilities> results;
+            CHECK_EQ(QueryCodecs(omx, kMimeTypes[k],
+                                 true, // queryDecoders
+                                 &results), OK);
+
+            for (size_t i = 0; i < results.size(); ++i) {
+                printf("  decoder '%s' supports ",
+                       results[i].mComponentName.string());
+
+                if (results[i].mProfileLevels.size() == 0) {
+                    printf("NOTHING.\n");
+                    continue;
+                }
+
+                for (size_t j = 0; j < results[i].mProfileLevels.size(); ++j) {
+                    const CodecProfileLevel &profileLevel =
+                        results[i].mProfileLevels[j];
+
+                    printf("%s%ld/%ld", j > 0 ? ", " : "",
+                           profileLevel.mProfile, profileLevel.mLevel);
+                }
+
+                printf("\n");
+            }
+        }
+    }
+
     if (listComponents) {
         sp<IServiceManager> sm = defaultServiceManager();
         sp<IBinder> binder = sm->getService(String16("media.player"));
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/cmds/stagefright/JPEGSource.h b/include/media/stagefright/JPEGSource.h
similarity index 97%
rename from cmds/stagefright/JPEGSource.h
rename to include/media/stagefright/JPEGSource.h
index 051c034..9d0a700 100644
--- a/cmds/stagefright/JPEGSource.h
+++ b/include/media/stagefright/JPEGSource.h
@@ -26,7 +26,6 @@
 class MediaBufferGroup;
 
 struct JPEGSource : public MediaSource {
-    // Assumes ownership of "source".
     JPEGSource(const sp<DataSource> &source);
 
     virtual status_t start(MetaData *params = NULL);
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 @@
     // 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/include/media/stagefright/MPEG4Writer.h b/include/media/stagefright/MPEG4Writer.h
index 5147de9..6b0399f 100644
--- a/include/media/stagefright/MPEG4Writer.h
+++ b/include/media/stagefright/MPEG4Writer.h
@@ -34,9 +34,9 @@
 public:
     MPEG4Writer(const char *filename);
 
-    // Caller retains ownership of both meta and source.
-    void addSource(const sp<MetaData> &meta, const sp<MediaSource> &source);
-    void start();
+    void addSource(const sp<MediaSource> &source);
+    status_t start();
+    bool reachedEOS();
     void stop();
 
     void beginBox(const char *fourcc);
diff --git a/include/media/stagefright/MediaDefs.h b/include/media/stagefright/MediaDefs.h
new file mode 100644
index 0000000..feb66e3
--- /dev/null
+++ b/include/media/stagefright/MediaDefs.h
@@ -0,0 +1,40 @@
+/*
+ * 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 MEDIA_DEFS_H_
+
+#define MEDIA_DEFS_H_
+
+namespace android {
+
+extern const char *MEDIA_MIMETYPE_IMAGE_JPEG;
+
+extern const char *MEDIA_MIMETYPE_VIDEO_AVC;
+extern const char *MEDIA_MIMETYPE_VIDEO_MPEG4;
+extern const char *MEDIA_MIMETYPE_VIDEO_H263;
+extern const char *MEDIA_MIMETYPE_VIDEO_RAW;
+
+extern const char *MEDIA_MIMETYPE_AUDIO_AMR_NB;
+extern const char *MEDIA_MIMETYPE_AUDIO_AMR_WB;
+extern const char *MEDIA_MIMETYPE_AUDIO_MPEG;
+extern const char *MEDIA_MIMETYPE_AUDIO_AAC;
+extern const char *MEDIA_MIMETYPE_AUDIO_RAW;
+
+extern const char *MEDIA_MIMETYPE_CONTAINER_MPEG4;
+
+}  // namespace android
+
+#endif  // MEDIA_DEFS_H_
diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h
index ac45481..ff7e34a 100644
--- a/include/media/stagefright/OMXCodec.h
+++ b/include/media/stagefright/OMXCodec.h
@@ -33,7 +33,12 @@
     static sp<OMXCodec> Create(
             const sp<IOMX> &omx,
             const sp<MetaData> &meta, bool createEncoder,
-            const sp<MediaSource> &source);
+            const sp<MediaSource> &source,
+            const char *matchComponentName = NULL);
+
+    static void setComponentRole(
+            const sp<IOMX> &omx, IOMX::node_id node, bool isEncoder,
+            const char *mime);
 
     virtual status_t start(MetaData *params = NULL);
     virtual status_t stop();
@@ -138,6 +143,7 @@
     void setComponentRole();
 
     void setAMRFormat();
+    void setAMRWBFormat();
     void setAACFormat(int32_t numChannels, int32_t sampleRate);
 
     status_t setVideoPortFormatType(
@@ -205,6 +211,32 @@
     OMXCodec &operator=(const OMXCodec &);
 };
 
+struct CodecProfileLevel {
+    OMX_U32 mProfile;
+    OMX_U32 mLevel;
+};
+
+struct CodecCapabilities {
+    String8 mComponentName;
+    Vector<CodecProfileLevel> mProfileLevels;
+};
+
+// Return a vector of componentNames with supported profile/level pairs
+// supporting the given mime type, if queryDecoders==true, returns components
+// that decode content of the given type, otherwise returns components
+// that encode content of the given type.
+// profile and level indications only make sense for h.263, mpeg4 and avc
+// video.
+// The profile/level values correspond to
+// OMX_VIDEO_H263PROFILETYPE, OMX_VIDEO_MPEG4PROFILETYPE,
+// OMX_VIDEO_AVCPROFILETYPE, OMX_VIDEO_H263LEVELTYPE, OMX_VIDEO_MPEG4LEVELTYPE
+// and OMX_VIDEO_AVCLEVELTYPE respectively.
+
+status_t QueryCodecs(
+        const sp<IOMX> &omx,
+        const char *mimeType, bool queryDecoders,
+        Vector<CodecCapabilities> *results);
+
 }  // namespace android
 
 #endif  // OMX_CODEC_H_
diff --git a/include/private/ui/SharedBufferStack.h b/include/private/ui/SharedBufferStack.h
index 2bd5344..6181f55 100644
--- a/include/private/ui/SharedBufferStack.h
+++ b/include/private/ui/SharedBufferStack.h
@@ -85,6 +85,7 @@
 
 public:
     SharedBufferStack();
+    void init(int32_t identity);
     status_t setDirtyRegion(int buffer, const Region& reg);
     Region getDirtyRegion(int buffer) const;
 
@@ -93,12 +94,12 @@
     volatile int32_t available; // number of dequeue-able buffers
     volatile int32_t queued;    // number of buffers waiting for post
     volatile int32_t inUse;     // buffer currently in use by SF
+    volatile status_t status;   // surface's status code
 
     // not part of the conditions
     volatile int32_t reallocMask;
 
     int32_t     identity;       // surface's identity (const)
-    status_t    status;         // surface's status code
     int32_t     reserved32[13];
     FlatRegion  dirtyRegion[NUM_BUFFER_MAX];    // 12*4=48 bytes
 };
@@ -114,7 +115,6 @@
 
     status_t validate(size_t token) const;
     uint32_t getIdentity(size_t token) const;
-    status_t setIdentity(size_t token, uint32_t identity);
 
 private:
     friend class SharedBufferBase;
@@ -168,10 +168,11 @@
 template <typename T>
 status_t SharedBufferBase::waitForCondition(T condition) 
 {
+    const SharedBufferStack& stack( *mSharedStack );
     SharedClient& client( *mSharedClient );
     const nsecs_t TIMEOUT = s2ns(1); 
     Mutex::Autolock _l(client.lock);
-    while (!condition()) {
+    while ((condition()==false) && (stack.status == NO_ERROR)) {
         status_t err = client.cv.waitRelative(client.lock, TIMEOUT);
         
         // handle errors and timeouts
@@ -195,7 +196,7 @@
             }
         }
     }
-    return NO_ERROR;
+    return stack.status;
 }
 
 
@@ -261,13 +262,15 @@
 class SharedBufferServer : public SharedBufferBase
 {
 public:
-    SharedBufferServer(SharedClient* sharedClient, int surface, int num);
+    SharedBufferServer(SharedClient* sharedClient, int surface, int num,
+            int32_t identity);
 
     ssize_t retireAndLock();
     status_t unlock(int buffer);
+    void setStatus(status_t status);
     status_t reallocate();
     status_t assertReallocate(int buffer);
-
+    
     Region getDirtyRegion(int buffer) const;
 
 private:
@@ -283,6 +286,12 @@
         inline ssize_t operator()();
     };
 
+    struct StatusUpdate : public UpdateBase {
+        const status_t status;
+        inline StatusUpdate(SharedBufferBase* sbb, status_t status);
+        inline ssize_t operator()();
+    };
+
     struct ReallocateCondition : public ConditionBase {
         int buf;
         inline ReallocateCondition(SharedBufferBase* sbb, int buf);
diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk
index 59ecde6..93b7a3a 100644
--- a/media/libmediaplayerservice/Android.mk
+++ b/media/libmediaplayerservice/Android.mk
@@ -10,13 +10,21 @@
     MediaRecorderClient.cpp     \
     MediaPlayerService.cpp      \
     MetadataRetrieverClient.cpp \
-    StagefrightPlayer.cpp       \
     TestPlayerStub.cpp          \
     VorbisPlayer.cpp            \
     VorbisMetadataRetriever.cpp \
     MidiMetadataRetriever.cpp \
     MidiFile.cpp
 
+ifeq ($(BUILD_WITH_FULL_STAGEFRIGHT),true)
+
+LOCAL_SRC_FILES +=              \
+    StagefrightPlayer.cpp
+
+LOCAL_CFLAGS += -DBUILD_WITH_FULL_STAGEFRIGHT=1
+
+endif
+
 ifeq ($(TARGET_OS)-$(TARGET_SIMULATOR),linux-true)
 LOCAL_LDLIBS += -ldl -lpthread
 endif
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 8998f10..8b1c9dc 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -602,11 +602,13 @@
 }
 
 static player_type getDefaultPlayerType() {
+#if BUILD_WITH_FULL_STAGEFRIGHT
     char value[PROPERTY_VALUE_MAX];
     if (property_get("media.stagefright.enable-player", value, NULL)
         && (!strcmp(value, "1") || !strcasecmp(value, "true"))) {
         return STAGEFRIGHT_PLAYER;
     }
+#endif
 
     return PV_PLAYER;
 }
@@ -684,10 +686,12 @@
             LOGV(" create VorbisPlayer");
             p = new VorbisPlayer();
             break;
+#if BUILD_WITH_FULL_STAGEFRIGHT
         case STAGEFRIGHT_PLAYER:
             LOGV(" create StagefrightPlayer");
             p = new StagefrightPlayer;
             break;
+#endif
         case TEST_PLAYER:
             LOGV("Create Test Player stub");
             p = new TestPlayerStub();
diff --git a/media/libstagefright/AMRExtractor.cpp b/media/libstagefright/AMRExtractor.cpp
new file mode 100644
index 0000000..8d85ce2
--- /dev/null
+++ b/media/libstagefright/AMRExtractor.cpp
@@ -0,0 +1,242 @@
+/*
+ * 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/MediaDefs.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 == MEDIA_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 ? MEDIA_MIMETYPE_AUDIO_AMR_WB
+                                 : MEDIA_MIMETYPE_AUDIO_AMR_NB);
+
+    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 = MEDIA_MIMETYPE_AUDIO_AMR_NB;
+        *confidence = 0.5;
+
+        return true;
+    } else if (!memcmp(header, "#!AMR-WB\n", 9)) {
+        *mimeType = MEDIA_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..79a32b5 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -2,32 +2,41 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:=                 \
+        ESDS.cpp                  \
+        MediaBuffer.cpp           \
+        MediaBufferGroup.cpp      \
+        MediaDefs.cpp             \
+        MediaSource.cpp           \
+        MetaData.cpp              \
+        OMXCodec.cpp              \
+        Utils.cpp                 \
+        OMXClient.cpp
+
+ifeq ($(BUILD_WITH_FULL_STAGEFRIGHT),true)
+
+LOCAL_SRC_FILES +=                \
+        AMRExtractor.cpp          \
         CachingDataSource.cpp     \
         DataSource.cpp            \
         FileSource.cpp            \
         HTTPDataSource.cpp        \
         HTTPStream.cpp            \
+        JPEGSource.cpp            \
+        MediaExtractor.cpp        \
         MP3Extractor.cpp          \
         MPEG4Extractor.cpp        \
         MPEG4Writer.cpp           \
-        MediaBuffer.cpp           \
-        MediaBufferGroup.cpp      \
-        MediaExtractor.cpp        \
         MediaPlayerImpl.cpp       \
-        MediaSource.cpp           \
-        MetaData.cpp              \
         MmapSource.cpp            \
-        OMXCodec.cpp              \
         SampleTable.cpp           \
         ShoutcastSource.cpp       \
         TimeSource.cpp            \
         TimedEventQueue.cpp       \
-        Utils.cpp                 \
         AudioPlayer.cpp           \
-        ESDS.cpp                  \
-        OMXClient.cpp             \
         string.cpp
 
+endif
+
 LOCAL_C_INCLUDES:= \
         $(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include \
         $(TOP)/external/opencore/android
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
index 140bc68..319488e 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -20,6 +20,7 @@
 #include <media/AudioTrack.h>
 #include <media/stagefright/AudioPlayer.h>
 #include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
 
@@ -61,7 +62,7 @@
     const char *mime;
     bool success = format->findCString(kKeyMIMEType, &mime);
     CHECK(success);
-    CHECK(!strcasecmp(mime, "audio/raw"));
+    CHECK(!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW));
 
     success = format->findInt32(kKeySampleRate, &mSampleRate);
     CHECK(success);
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index f75b173..596ab67 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -155,7 +155,7 @@
 
 sp<MetaData> CameraSource::getFormat() {
     sp<MetaData> meta = new MetaData;
-    meta->setCString(kKeyMIMEType, "video/raw");
+    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW);
     meta->setInt32(kKeyColorFormat, OMX_COLOR_FormatYUV420SemiPlanar);
     meta->setInt32(kKeyWidth, 480);
     meta->setInt32(kKeyHeight, 320);
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::RegisterDefaultSniffers() {
     RegisterSniffer(SniffMP3);
     RegisterSniffer(SniffMPEG4);
+    RegisterSniffer(SniffAMR);
 }
 
 }  // namespace android
diff --git a/cmds/stagefright/JPEGSource.cpp b/media/libstagefright/JPEGSource.cpp
similarity index 97%
rename from cmds/stagefright/JPEGSource.cpp
rename to media/libstagefright/JPEGSource.cpp
index 4e9ca4e..d1dfd83 100644
--- a/cmds/stagefright/JPEGSource.cpp
+++ b/media/libstagefright/JPEGSource.cpp
@@ -18,11 +18,11 @@
 #define LOG_TAG "JPEGSource"
 #include <utils/Log.h>
 
-#include "JPEGSource.h"
-
 #include <media/stagefright/DataSource.h>
+#include <media/stagefright/JPEGSource.h>
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MetaData.h>
 
@@ -99,7 +99,7 @@
 
 sp<MetaData> JPEGSource::getFormat() {
     sp<MetaData> meta = new MetaData;
-    meta->setCString(kKeyMIMEType, "image/jpeg");
+    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_IMAGE_JPEG);
     meta->setInt32(kKeyWidth, mWidth);
     meta->setInt32(kKeyHeight, mHeight);
     meta->setInt32(kKeyMaxInputSize, mSize);
diff --git a/media/libstagefright/MP3Extractor.cpp b/media/libstagefright/MP3Extractor.cpp
index 14f3e0c..7fd699f 100644
--- a/media/libstagefright/MP3Extractor.cpp
+++ b/media/libstagefright/MP3Extractor.cpp
@@ -23,6 +23,7 @@
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
@@ -330,7 +331,7 @@
 
         mMeta = new MetaData;
 
-        mMeta->setCString(kKeyMIMEType, "audio/mpeg");
+        mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
         mMeta->setInt32(kKeySampleRate, sample_rate);
         mMeta->setInt32(kKeyBitRate, bitrate);
         mMeta->setInt32(kKeyChannelCount, num_channels);
@@ -510,7 +511,7 @@
         return false;
     }
 
-    *mimeType = "audio/mpeg";
+    *mimeType = MEDIA_MIMETYPE_AUDIO_MPEG;
     *confidence = 0.3f;
 
     return true;
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 894d46c..9174d19 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -29,6 +29,7 @@
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/SampleTable.h>
@@ -116,22 +117,25 @@
     }
 }
 
-static const char *const FourCC2MIME(uint32_t fourcc) {
+static const char *FourCC2MIME(uint32_t fourcc) {
     switch (fourcc) {
         case FOURCC('m', 'p', '4', 'a'):
-            return "audio/mp4a-latm";
+            return MEDIA_MIMETYPE_AUDIO_AAC;
 
         case FOURCC('s', 'a', 'm', 'r'):
-            return "audio/3gpp";
+            return MEDIA_MIMETYPE_AUDIO_AMR_NB;
+
+        case FOURCC('s', 'a', 'w', 'b'):
+            return MEDIA_MIMETYPE_AUDIO_AMR_WB;
 
         case FOURCC('m', 'p', '4', 'v'):
-            return "video/mp4v-es";
+            return MEDIA_MIMETYPE_VIDEO_MPEG4;
 
         case FOURCC('s', '2', '6', '3'):
-            return "video/3gpp";
+            return MEDIA_MIMETYPE_VIDEO_H263;
 
         case FOURCC('a', 'v', 'c', '1'):
-            return "video/avc";
+            return MEDIA_MIMETYPE_VIDEO_AVC;
 
         default:
             CHECK(!"should not be here.");
@@ -189,6 +193,10 @@
         --index;
     }
 
+    if (track == NULL) {
+        return NULL;
+    }
+
     return track->meta;
 }
 
@@ -472,6 +480,7 @@
 
         case FOURCC('m', 'p', '4', 'a'):
         case FOURCC('s', 'a', 'm', 'r'):
+        case FOURCC('s', 'a', 'w', 'b'):
         {
             if (mHandlerType != FOURCC('s', 'o', 'u', 'n')) {
                 return ERROR_MALFORMED;
@@ -491,7 +500,10 @@
             uint16_t data_ref_index = U16_AT(&buffer[6]);
             uint16_t num_channels = U16_AT(&buffer[16]);
 
-            if (!strcasecmp("audio/3gpp", FourCC2MIME(chunk_type))) {
+            if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB,
+                            FourCC2MIME(chunk_type))
+                || !strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB,
+                               FourCC2MIME(chunk_type))) {
                 // AMR audio is always mono.
                 num_channels = 1;
             }
@@ -705,6 +717,10 @@
         --index;
     }
 
+    if (track == NULL) {
+        return NULL;
+    }
+
     return new MPEG4Source(
             track->meta, mDataSource, track->sampleTable);
 }
@@ -733,7 +749,7 @@
     success = mFormat->findInt32(kKeyTimeScale, &mTimescale);
     CHECK(success);
 
-    mIsAVC = !strcasecmp(mime, "video/avc");
+    mIsAVC = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC);
 }
 
 MPEG4Source::~MPEG4Source() {
@@ -965,7 +981,7 @@
 
     if (!memcmp(header, "ftyp3gp", 7) || !memcmp(header, "ftypmp42", 8)
         || !memcmp(header, "ftypisom", 8) || !memcmp(header, "ftypM4V ", 8)) {
-        *mimeType = "video/mp4";
+        *mimeType = MEDIA_MIMETYPE_CONTAINER_MPEG4;
         *confidence = 0.1;
 
         return true;
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 90b1b9a..fa35768 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -23,6 +23,7 @@
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaSource.h>
 #include <media/stagefright/Utils.h>
 
@@ -30,12 +31,12 @@
 
 class MPEG4Writer::Track {
 public:
-    Track(MPEG4Writer *owner,
-          const sp<MetaData> &meta, const sp<MediaSource> &source);
+    Track(MPEG4Writer *owner, const sp<MediaSource> &source);
     ~Track();
 
-    void start();
+    status_t start();
     void stop();
+    bool reachedEOS();
 
     int64_t getDuration() const;
     void writeTrackHeader(int32_t trackID);
@@ -58,6 +59,8 @@
     void *mCodecSpecificData;
     size_t mCodecSpecificDataSize;
 
+    bool mReachedEOS;
+
     static void *ThreadWrapper(void *me);
     void threadEntry();
 
@@ -82,15 +85,14 @@
     mTracks.clear();
 }
 
-void MPEG4Writer::addSource(
-        const sp<MetaData> &meta, const sp<MediaSource> &source) {
-    Track *track = new Track(this, meta, source);
+void MPEG4Writer::addSource(const sp<MediaSource> &source) {
+    Track *track = new Track(this, source);
     mTracks.push_back(track);
 }
 
-void MPEG4Writer::start() {
+status_t MPEG4Writer::start() {
     if (mFile == NULL) {
-        return;
+        return UNKNOWN_ERROR;
     }
 
     beginBox("ftyp");
@@ -104,8 +106,19 @@
 
     for (List<Track *>::iterator it = mTracks.begin();
          it != mTracks.end(); ++it) {
-        (*it)->start();
+        status_t err = (*it)->start();
+
+        if (err != OK) {
+            for (List<Track *>::iterator it2 = mTracks.begin();
+                 it2 != it; ++it2) {
+                (*it2)->stop();
+            }
+
+            return err;
+        }
     }
+
+    return OK;
 }
 
 void MPEG4Writer::stop() {
@@ -252,17 +265,30 @@
     mOffset += size;
 }
 
+bool MPEG4Writer::reachedEOS() {
+    bool allDone = true;
+    for (List<Track *>::iterator it = mTracks.begin();
+         it != mTracks.end(); ++it) {
+        if (!(*it)->reachedEOS()) {
+            allDone = false;
+            break;
+        }
+    }
+
+    return allDone;
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 
 MPEG4Writer::Track::Track(
-        MPEG4Writer *owner,
-        const sp<MetaData> &meta, const sp<MediaSource> &source)
+        MPEG4Writer *owner, const sp<MediaSource> &source)
     : mOwner(owner),
-      mMeta(meta),
+      mMeta(source->getFormat()),
       mSource(source),
       mDone(false),
       mCodecSpecificData(NULL),
-      mCodecSpecificDataSize(0) {
+      mCodecSpecificDataSize(0),
+      mReachedEOS(false) {
 }
 
 MPEG4Writer::Track::~Track() {
@@ -274,19 +300,25 @@
     }
 }
 
-void MPEG4Writer::Track::start() {
-    mSource->start();
+status_t MPEG4Writer::Track::start() {
+    status_t err = mSource->start();
+
+    if (err != OK) {
+        mDone = mReachedEOS = true;
+        return err;
+    }
 
     pthread_attr_t attr;
     pthread_attr_init(&attr);
     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
 
     mDone = false;
+    mReachedEOS = false;
 
-    int err = pthread_create(&mThread, &attr, ThreadWrapper, this);
-    CHECK_EQ(err, 0);
-
+    pthread_create(&mThread, &attr, ThreadWrapper, this);
     pthread_attr_destroy(&attr);
+
+    return OK;
 }
 
 void MPEG4Writer::Track::stop() {
@@ -302,6 +334,10 @@
     mSource->stop();
 }
 
+bool MPEG4Writer::Track::reachedEOS() {
+    return mReachedEOS;
+}
+
 // static
 void *MPEG4Writer::Track::ThreadWrapper(void *me) {
     Track *track = static_cast<Track *>(me);
@@ -316,7 +352,7 @@
     sp<MetaData> meta = mSource->getFormat();
     const char *mime;
     meta->findCString(kKeyMIMEType, &mime);
-    is_mpeg4 = !strcasecmp(mime, "video/mp4v-es");
+    is_mpeg4 = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4);
 
     MediaBuffer *buffer;
     while (!mDone && mSource->read(&buffer) == OK) {
@@ -378,6 +414,8 @@
         buffer->release();
         buffer = NULL;
     }
+
+    mReachedEOS = true;
 }
 
 int64_t MPEG4Writer::Track::getDuration() const {
@@ -490,7 +528,17 @@
             mOwner->writeInt32(0);               // version=0, flags=0
             mOwner->writeInt32(1);               // entry count
             if (is_audio) {
-                mOwner->beginBox("xxxx");          // audio format XXX
+                const char *fourcc = NULL;
+                if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime)) {
+                    fourcc = "samr";
+                } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) {
+                    fourcc = "sawb";
+                } else {
+                    LOGE("Unknown mime type '%s'.", mime);
+                    CHECK(!"should not be here, unknown mime type.");
+                }
+
+                mOwner->beginBox(fourcc);          // audio format
                   mOwner->writeInt32(0);           // reserved
                   mOwner->writeInt16(0);           // reserved
                   mOwner->writeInt16(0);           // data ref index
@@ -508,11 +556,12 @@
                   mOwner->writeInt32(samplerate << 16);
                 mOwner->endBox();
             } else {
-                if (!strcasecmp("video/mp4v-es", mime)) {
+                if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
                     mOwner->beginBox("mp4v");
-                } else if (!strcasecmp("video/3gpp", mime)) {
+                } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
                     mOwner->beginBox("s263");
                 } else {
+                    LOGE("Unknown mime type '%s'.", mime);
                     CHECK(!"should not be here, unknown mime type.");
                 }
 
@@ -542,7 +591,7 @@
 
                   CHECK(23 + mCodecSpecificDataSize < 128);
 
-                  if (!strcasecmp("video/mp4v-es", mime)) {
+                  if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
                       mOwner->beginBox("esds");
 
                         mOwner->writeInt32(0);           // version=0, flags=0
@@ -577,7 +626,7 @@
                         mOwner->write(kData2, sizeof(kData2));
 
                       mOwner->endBox();  // esds
-                  } else if (!strcasecmp("video/3gpp", mime)) {
+                  } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
                       mOwner->beginBox("d263");
 
                           mOwner->writeInt32(0);  // vendor
diff --git a/media/libstagefright/MediaDefs.cpp b/media/libstagefright/MediaDefs.cpp
new file mode 100644
index 0000000..87b5b24
--- /dev/null
+++ b/media/libstagefright/MediaDefs.cpp
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+#include <media/stagefright/MediaDefs.h>
+
+namespace android {
+
+const char *MEDIA_MIMETYPE_IMAGE_JPEG = "image/jpeg";
+
+const char *MEDIA_MIMETYPE_VIDEO_AVC = "video/avc";
+const char *MEDIA_MIMETYPE_VIDEO_MPEG4 = "video/mp4v-es";
+const char *MEDIA_MIMETYPE_VIDEO_H263 = "video/3gpp";
+const char *MEDIA_MIMETYPE_VIDEO_RAW = "video/raw";
+
+const char *MEDIA_MIMETYPE_AUDIO_AMR_NB = "audio/3gpp";
+const char *MEDIA_MIMETYPE_AUDIO_AMR_WB = "audio/amr-wb";
+const char *MEDIA_MIMETYPE_AUDIO_MPEG = "audio/mpeg";
+const char *MEDIA_MIMETYPE_AUDIO_AAC = "audio/mp4a-latm";
+const char *MEDIA_MIMETYPE_AUDIO_RAW = "audio/raw";
+
+const char *MEDIA_MIMETYPE_CONTAINER_MPEG4 = "video/mpeg4";
+
+}  // namespace android
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
index 5f78e12..8535f52 100644
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -18,7 +18,9 @@
 #define LOG_TAG "MediaExtractor"
 #include <utils/Log.h>
 
+#include <media/stagefright/AMRExtractor.h>
 #include <media/stagefright/DataSource.h>
+#include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MP3Extractor.h>
 #include <media/stagefright/MPEG4Extractor.h>
 #include <media/stagefright/MediaExtractor.h>
@@ -43,10 +45,14 @@
              mime, confidence);
     }
 
-    if (!strcasecmp(mime, "video/mp4") || !strcasecmp(mime, "audio/mp4")) {
+    if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG4)
+            || !strcasecmp(mime, "audio/mp4")) {
         return new MPEG4Extractor(source);
-    } else if (!strcasecmp(mime, "audio/mpeg")) {
+    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) {
         return new MP3Extractor(source);
+    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_NB)
+            || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_WB)) {
+        return new AMRExtractor(source);
     }
 
     return NULL;
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index d01d6af..a964d17 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -26,6 +26,7 @@
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaExtractor.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/MmapSource.h>
@@ -44,39 +45,43 @@
 };
 
 static const CodecInfo kDecoderInfo[] = {
-    { "image/jpeg", "OMX.TI.JPEG.decode" },
-    { "audio/mpeg", "OMX.TI.MP3.decode" },
-    { "audio/mpeg", "OMX.PV.mp3dec" },
-    { "audio/3gpp", "OMX.TI.AMR.decode" },
-    { "audio/3gpp", "OMX.PV.amrdec" },
-    { "audio/mp4a-latm", "OMX.TI.AAC.decode" },
-    { "audio/mp4a-latm", "OMX.PV.aacdec" },
-    { "video/mp4v-es", "OMX.qcom.video.decoder.mpeg4" },
-    { "video/mp4v-es", "OMX.TI.Video.Decoder" },
-    { "video/mp4v-es", "OMX.PV.mpeg4dec" },
-    { "video/3gpp", "OMX.qcom.video.decoder.h263" },
-    { "video/3gpp", "OMX.TI.Video.Decoder" },
-    { "video/3gpp", "OMX.PV.h263dec" },
-    { "video/avc", "OMX.qcom.video.decoder.avc" },
-    { "video/avc", "OMX.TI.Video.Decoder" },
-    { "video/avc", "OMX.PV.avcdec" },
+    { MEDIA_MIMETYPE_IMAGE_JPEG, "OMX.TI.JPEG.decode" },
+    { MEDIA_MIMETYPE_AUDIO_MPEG, "OMX.TI.MP3.decode" },
+    { MEDIA_MIMETYPE_AUDIO_MPEG, "OMX.PV.mp3dec" },
+    { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.TI.AMR.decode" },
+    { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.PV.amrdec" },
+    { MEDIA_MIMETYPE_AUDIO_AMR_WB, "OMX.TI.WBAMR.decode" },
+    { MEDIA_MIMETYPE_AUDIO_AMR_WB, "OMX.PV.amrdec" },
+    { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.TI.AAC.decode" },
+    { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.PV.aacdec" },
+    { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.qcom.video.decoder.mpeg4" },
+    { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.TI.Video.Decoder" },
+    { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.PV.mpeg4dec" },
+    { MEDIA_MIMETYPE_VIDEO_H263, "OMX.qcom.video.decoder.h263" },
+    { MEDIA_MIMETYPE_VIDEO_H263, "OMX.TI.Video.Decoder" },
+    { MEDIA_MIMETYPE_VIDEO_H263, "OMX.PV.h263dec" },
+    { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.qcom.video.decoder.avc" },
+    { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.TI.Video.Decoder" },
+    { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.PV.avcdec" },
 };
 
 static const CodecInfo kEncoderInfo[] = {
-    { "audio/3gpp", "OMX.TI.AMR.encode" },
-    { "audio/3gpp", "OMX.PV.amrencnb" },
-    { "audio/mp4a-latm", "OMX.TI.AAC.encode" },
-    { "audio/mp4a-latm", "OMX.PV.aacenc" },
-    { "video/mp4v-es", "OMX.qcom.video.encoder.mpeg4" },
-    { "video/mp4v-es", "OMX.TI.Video.encoder" },
-    { "video/mp4v-es", "OMX.PV.mpeg4enc" },
-    { "video/3gpp", "OMX.qcom.video.encoder.h263" },
-    { "video/3gpp", "OMX.TI.Video.encoder" },
-    { "video/3gpp", "OMX.PV.h263enc" },
-    { "video/avc", "OMX.TI.Video.encoder" },
-    { "video/avc", "OMX.PV.avcenc" },
+    { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.TI.AMR.encode" },
+    { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.PV.amrencnb" },
+    { MEDIA_MIMETYPE_AUDIO_AMR_WB, "OMX.TI.WBAMR.encode" },
+    { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.TI.AAC.encode" },
+    { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.PV.aacenc" },
+    { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.qcom.video.encoder.mpeg4" },
+    { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.TI.Video.encoder" },
+    { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.PV.mpeg4enc" },
+    { MEDIA_MIMETYPE_VIDEO_H263, "OMX.qcom.video.encoder.h263" },
+    { MEDIA_MIMETYPE_VIDEO_H263, "OMX.TI.Video.encoder" },
+    { MEDIA_MIMETYPE_VIDEO_H263, "OMX.PV.h263enc" },
+    { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.TI.Video.encoder" },
+    { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.PV.avcenc" },
 };
 
+#define CODEC_LOGI(x, ...) LOGI("[%s] "x, mComponentName, ##__VA_ARGS__)
 #define CODEC_LOGV(x, ...) LOGV("[%s] "x, mComponentName, ##__VA_ARGS__)
 
 struct OMXCodecObserver : public BnOMXObserver {
@@ -165,7 +170,8 @@
 sp<OMXCodec> OMXCodec::Create(
         const sp<IOMX> &omx,
         const sp<MetaData> &meta, bool createEncoder,
-        const sp<MediaSource> &source) {
+        const sp<MediaSource> &source,
+        const char *matchComponentName) {
     const char *mime;
     bool success = meta->findCString(kKeyMIMEType, &mime);
     CHECK(success);
@@ -187,6 +193,11 @@
             return NULL;
         }
 
+        // If a specific codec is requested, skip the non-matching ones.
+        if (matchComponentName && strcmp(componentName, matchComponentName)) {
+            continue;
+        }
+
         LOGV("Attempting to allocate OMX node '%s'", componentName);
 
         status_t err = omx->allocate_node(componentName, &node);
@@ -314,10 +325,13 @@
         }
     }
 
-    if (!strcasecmp("audio/3gpp", mime)) {
+    if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime)) {
         codec->setAMRFormat();
     }
-    if (!strcasecmp("audio/mp4a-latm", mime)) {
+    if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) {
+        codec->setAMRWBFormat();
+    }
+    if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) {
         int32_t numChannels, sampleRate;
         CHECK(meta->findInt32(kKeyChannelCount, &numChannels));
         CHECK(meta->findInt32(kKeySampleRate, &sampleRate));
@@ -336,7 +350,7 @@
             codec->setVideoOutputFormat(mime, width, height);
         }
     }
-    if (!strcasecmp(mime, "image/jpeg")
+    if (!strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_JPEG)
         && !strcmp(componentName, "OMX.TI.JPEG.decode")) {
         OMX_COLOR_FORMATTYPE format =
             OMX_COLOR_Format32bitARGB8888;
@@ -418,7 +432,7 @@
         // CHECK_EQ(format.nIndex, index);
 
 #if 1
-        LOGI("portIndex: %ld, index: %ld, eCompressionFormat=%d eColorFormat=%d",
+        CODEC_LOGI("portIndex: %ld, index: %ld, eCompressionFormat=%d eColorFormat=%d",
              portIndex,
              index, format.eCompressionFormat, format.eColorFormat);
 #endif
@@ -451,7 +465,7 @@
         return UNKNOWN_ERROR;
     }
 
-    LOGI("found a match.");
+    CODEC_LOGI("found a match.");
     status_t err = mOMX->set_parameter(
             mNode, OMX_IndexParamVideoPortFormat,
             &format, sizeof(format));
@@ -461,14 +475,14 @@
 
 void OMXCodec::setVideoInputFormat(
         const char *mime, OMX_U32 width, OMX_U32 height) {
-    LOGI("setVideoInputFormat width=%ld, height=%ld", width, height);
+    CODEC_LOGI("setVideoInputFormat width=%ld, height=%ld", width, height);
 
     OMX_VIDEO_CODINGTYPE compressionFormat = OMX_VIDEO_CodingUnused;
-    if (!strcasecmp("video/avc", mime)) {
+    if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
         compressionFormat = OMX_VIDEO_CodingAVC;
-    } else if (!strcasecmp("video/mp4v-es", mime)) {
+    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
         compressionFormat = OMX_VIDEO_CodingMPEG4;
-    } else if (!strcasecmp("video/3gpp", mime)) {
+    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
         compressionFormat = OMX_VIDEO_CodingH263;
     } else {
         LOGE("Not a supported video mime type: %s", mime);
@@ -521,7 +535,7 @@
     CHECK_EQ(err, OK);
 
     def.nBufferSize = (width * height * 2); // (width * height * 3) / 2;
-    LOGI("Setting nBufferSize = %ld", def.nBufferSize);
+    CODEC_LOGI("Setting nBufferSize = %ld", def.nBufferSize);
 
     CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
 
@@ -537,14 +551,14 @@
 
 void OMXCodec::setVideoOutputFormat(
         const char *mime, OMX_U32 width, OMX_U32 height) {
-    LOGI("setVideoOutputFormat width=%ld, height=%ld", width, height);
+    CODEC_LOGI("setVideoOutputFormat width=%ld, height=%ld", width, height);
 
     OMX_VIDEO_CODINGTYPE compressionFormat = OMX_VIDEO_CodingUnused;
-    if (!strcasecmp("video/avc", mime)) {
+    if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
         compressionFormat = OMX_VIDEO_CodingAVC;
-    } else if (!strcasecmp("video/mp4v-es", mime)) {
+    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
         compressionFormat = OMX_VIDEO_CodingMPEG4;
-    } else if (!strcasecmp("video/3gpp", mime)) {
+    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
         compressionFormat = OMX_VIDEO_CodingH263;
     } else {
         LOGE("Not a supported video mime type: %s", mime);
@@ -663,7 +677,10 @@
     setComponentRole();
 }
 
-void OMXCodec::setComponentRole() {
+// static
+void OMXCodec::setComponentRole(
+        const sp<IOMX> &omx, IOMX::node_id node, bool isEncoder,
+        const char *mime) {
     struct MimeToRole {
         const char *mime;
         const char *decoderRole;
@@ -671,12 +688,20 @@
     };
 
     static const MimeToRole kMimeToRole[] = {
-        { "audio/mpeg", "audio_decoder.mp3", "audio_encoder.mp3" },
-        { "audio/3gpp", "audio_decoder.amrnb", "audio_encoder.amrnb" },
-        { "audio/mp4a-latm", "audio_decoder.aac", "audio_encoder.aac" },
-        { "video/avc",  "video_decoder.avc", "video_encoder.avc" },
-        { "video/mp4v-es", "video_decoder.mpeg4", "video_encoder.mpeg4" },
-        { "video/3gpp", "video_decoder.h263", "video_encoder.h263" },
+        { MEDIA_MIMETYPE_AUDIO_MPEG,
+            "audio_decoder.mp3", "audio_encoder.mp3" },
+        { MEDIA_MIMETYPE_AUDIO_AMR_NB,
+            "audio_decoder.amrnb", "audio_encoder.amrnb" },
+        { MEDIA_MIMETYPE_AUDIO_AMR_WB,
+            "audio_decoder.amrwb", "audio_encoder.amrwb" },
+        { MEDIA_MIMETYPE_AUDIO_AAC,
+            "audio_decoder.aac", "audio_encoder.aac" },
+        { MEDIA_MIMETYPE_VIDEO_AVC,
+            "video_decoder.avc", "video_encoder.avc" },
+        { MEDIA_MIMETYPE_VIDEO_MPEG4,
+            "video_decoder.mpeg4", "video_encoder.mpeg4" },
+        { MEDIA_MIMETYPE_VIDEO_H263,
+            "video_decoder.h263", "video_encoder.h263" },
     };
 
     static const size_t kNumMimeToRole =
@@ -684,7 +709,7 @@
 
     size_t i;
     for (i = 0; i < kNumMimeToRole; ++i) {
-        if (!strcasecmp(mMIME, kMimeToRole[i].mime)) {
+        if (!strcasecmp(mime, kMimeToRole[i].mime)) {
             break;
         }
     }
@@ -694,12 +719,10 @@
     }
 
     const char *role =
-        mIsEncoder ? kMimeToRole[i].encoderRole
-                   : kMimeToRole[i].decoderRole;
+        isEncoder ? kMimeToRole[i].encoderRole
+                  : kMimeToRole[i].decoderRole;
 
     if (role != NULL) {
-        CODEC_LOGV("Setting component role '%s'.", role);
-
         OMX_PARAM_COMPONENTROLETYPE roleParams;
         InitOMXParams(&roleParams);
 
@@ -708,8 +731,8 @@
 
         roleParams.cRole[OMX_MAX_STRINGNAME_SIZE - 1] = '\0';
 
-        status_t err = mOMX->set_parameter(
-                mNode, OMX_IndexParamStandardComponentRole,
+        status_t err = omx->set_parameter(
+                node, OMX_IndexParamStandardComponentRole,
                 &roleParams, sizeof(roleParams));
 
         if (err != OK) {
@@ -718,6 +741,10 @@
     }
 }
 
+void OMXCodec::setComponentRole() {
+    setComponentRole(mOMX, mNode, mIsEncoder, mMIME);
+}
+
 OMXCodec::~OMXCodec() {
     CHECK(mState == LOADED || mState == ERROR);
 
@@ -1351,7 +1378,7 @@
 
         size_t size = specific->mSize;
 
-        if (!strcasecmp("video/avc", mMIME)
+        if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mMIME)
                 && !(mQuirks & kWantsNALFragments)) {
             static const uint8_t kNALStartCode[4] =
                     { 0x00, 0x00, 0x00, 0x01 };
@@ -1548,6 +1575,37 @@
     }
 }
 
+void OMXCodec::setAMRWBFormat() {
+    if (!mIsEncoder) {
+        OMX_AUDIO_PARAM_AMRTYPE def;
+        InitOMXParams(&def);
+        def.nPortIndex = kPortIndexInput;
+
+        status_t err =
+            mOMX->get_parameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
+
+        CHECK_EQ(err, OK);
+
+        def.eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF;
+        def.eAMRBandMode = OMX_AUDIO_AMRBandModeWB0;
+
+        err = mOMX->set_parameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
+        CHECK_EQ(err, OK);
+    }
+
+    ////////////////////////
+
+    if (mIsEncoder) {
+        sp<MetaData> format = mSource->getFormat();
+        int32_t sampleRate;
+        int32_t numChannels;
+        CHECK(format->findInt32(kKeySampleRate, &sampleRate));
+        CHECK(format->findInt32(kKeyChannelCount, &numChannels));
+
+        setRawAudioFormat(kPortIndexInput, sampleRate, numChannels);
+    }
+}
+
 void OMXCodec::setAACFormat(int32_t numChannels, int32_t sampleRate) {
     if (mIsEncoder) {
         setRawAudioFormat(kPortIndexInput, sampleRate, numChannels);
@@ -1621,6 +1679,15 @@
             break;
         }
 
+        case OMX_COLOR_Format16bitARGB4444:
+        case OMX_COLOR_Format16bitARGB1555:
+        case OMX_COLOR_Format16bitRGB565:
+        case OMX_COLOR_Format16bitBGR565:
+        {
+            def.nBufferSize = width * height * 2;
+            break;
+        }
+
         default:
             CHECK(!"Should not be here. Unknown color format.");
             break;
@@ -2020,6 +2087,55 @@
     }
 }
 
+static const char *amrBandModeString(OMX_AUDIO_AMRBANDMODETYPE type) {
+    static const char *kNames[] = {
+        "OMX_AUDIO_AMRBandModeUnused",
+        "OMX_AUDIO_AMRBandModeNB0",
+        "OMX_AUDIO_AMRBandModeNB1",
+        "OMX_AUDIO_AMRBandModeNB2",
+        "OMX_AUDIO_AMRBandModeNB3",
+        "OMX_AUDIO_AMRBandModeNB4",
+        "OMX_AUDIO_AMRBandModeNB5",
+        "OMX_AUDIO_AMRBandModeNB6",
+        "OMX_AUDIO_AMRBandModeNB7",
+        "OMX_AUDIO_AMRBandModeWB0",
+        "OMX_AUDIO_AMRBandModeWB1",
+        "OMX_AUDIO_AMRBandModeWB2",
+        "OMX_AUDIO_AMRBandModeWB3",
+        "OMX_AUDIO_AMRBandModeWB4",
+        "OMX_AUDIO_AMRBandModeWB5",
+        "OMX_AUDIO_AMRBandModeWB6",
+        "OMX_AUDIO_AMRBandModeWB7",
+        "OMX_AUDIO_AMRBandModeWB8",
+    };
+
+    size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
+
+    if (type < 0 || (size_t)type >= numNames) {
+        return "UNKNOWN";
+    } else {
+        return kNames[type];
+    }
+}
+
+static const char *amrFrameFormatString(OMX_AUDIO_AMRFRAMEFORMATTYPE type) {
+    static const char *kNames[] = {
+        "OMX_AUDIO_AMRFrameFormatConformance",
+        "OMX_AUDIO_AMRFrameFormatIF1",
+        "OMX_AUDIO_AMRFrameFormatIF2",
+        "OMX_AUDIO_AMRFrameFormatFSF",
+        "OMX_AUDIO_AMRFrameFormatRTPPayload",
+        "OMX_AUDIO_AMRFrameFormatITU",
+    };
+
+    size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
+
+    if (type < 0 || (size_t)type >= numNames) {
+        return "UNKNOWN";
+    } else {
+        return kNames[type];
+    }
+}
 
 void OMXCodec::dumpPortStatus(OMX_U32 portIndex) {
     OMX_PARAM_PORTDEFINITIONTYPE def;
@@ -2106,6 +2222,20 @@
                         ? "signed" : "unsigned");
 
                 printf("  ePCMMode = %s\n", audioPCMModeString(params.ePCMMode));
+            } else if (audioDef->eEncoding == OMX_AUDIO_CodingAMR) {
+                OMX_AUDIO_PARAM_AMRTYPE amr;
+                InitOMXParams(&amr);
+                amr.nPortIndex = portIndex;
+
+                err = mOMX->get_parameter(
+                        mNode, OMX_IndexParamAudioAmr, &amr, sizeof(amr));
+                CHECK_EQ(err, OK);
+
+                printf("  nChannels = %ld\n", amr.nChannels);
+                printf("  eAMRBandMode = %s\n",
+                        amrBandModeString(amr.eAMRBandMode));
+                printf("  eAMRFrameFormat = %s\n",
+                        amrFrameFormatString(amr.eAMRFrameFormat));
             }
 
             break;
@@ -2139,7 +2269,7 @@
             OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image;
             CHECK_EQ(imageDef->eCompressionFormat, OMX_IMAGE_CodingUnused);
 
-            mOutputFormat->setCString(kKeyMIMEType, "image/raw");
+            mOutputFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW);
             mOutputFormat->setInt32(kKeyColorFormat, imageDef->eColorFormat);
             mOutputFormat->setInt32(kKeyWidth, imageDef->nFrameWidth);
             mOutputFormat->setInt32(kKeyHeight, imageDef->nFrameHeight);
@@ -2172,7 +2302,8 @@
                          "the input stream contains.");
                 }
 
-                mOutputFormat->setCString(kKeyMIMEType, "audio/raw");
+                mOutputFormat->setCString(
+                        kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
 
                 // Use the codec-advertised number of channels, as some
                 // codecs appear to output stereo even if the input data is
@@ -2182,9 +2313,33 @@
                 // The codec-reported sampleRate is not reliable...
                 mOutputFormat->setInt32(kKeySampleRate, sampleRate);
             } else if (audio_def->eEncoding == OMX_AUDIO_CodingAMR) {
-                mOutputFormat->setCString(kKeyMIMEType, "audio/3gpp");
+                OMX_AUDIO_PARAM_AMRTYPE amr;
+                InitOMXParams(&amr);
+                amr.nPortIndex = kPortIndexOutput;
+
+                err = mOMX->get_parameter(
+                        mNode, OMX_IndexParamAudioAmr, &amr, sizeof(amr));
+                CHECK_EQ(err, OK);
+
+                CHECK_EQ(amr.nChannels, 1);
+                mOutputFormat->setInt32(kKeyChannelCount, 1);
+
+                if (amr.eAMRBandMode >= OMX_AUDIO_AMRBandModeNB0
+                    && amr.eAMRBandMode <= OMX_AUDIO_AMRBandModeNB7) {
+                    mOutputFormat->setCString(
+                            kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AMR_NB);
+                    mOutputFormat->setInt32(kKeySampleRate, 8000);
+                } else if (amr.eAMRBandMode >= OMX_AUDIO_AMRBandModeWB0
+                            && amr.eAMRBandMode <= OMX_AUDIO_AMRBandModeWB8) {
+                    mOutputFormat->setCString(
+                            kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AMR_WB);
+                    mOutputFormat->setInt32(kKeySampleRate, 16000);
+                } else {
+                    CHECK(!"Unknown AMR band mode.");
+                }
             } else if (audio_def->eEncoding == OMX_AUDIO_CodingAAC) {
-                mOutputFormat->setCString(kKeyMIMEType, "audio/mp4a-latm");
+                mOutputFormat->setCString(
+                        kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC);
             } else {
                 CHECK(!"Should not be here. Unknown audio encoding.");
             }
@@ -2196,13 +2351,17 @@
             OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
 
             if (video_def->eCompressionFormat == OMX_VIDEO_CodingUnused) {
-                mOutputFormat->setCString(kKeyMIMEType, "video/raw");
+                mOutputFormat->setCString(
+                        kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW);
             } else if (video_def->eCompressionFormat == OMX_VIDEO_CodingMPEG4) {
-                mOutputFormat->setCString(kKeyMIMEType, "video/mp4v-es");
+                mOutputFormat->setCString(
+                        kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4);
             } else if (video_def->eCompressionFormat == OMX_VIDEO_CodingH263) {
-                mOutputFormat->setCString(kKeyMIMEType, "video/3gpp");
+                mOutputFormat->setCString(
+                        kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263);
             } else if (video_def->eCompressionFormat == OMX_VIDEO_CodingAVC) {
-                mOutputFormat->setCString(kKeyMIMEType, "video/avc");
+                mOutputFormat->setCString(
+                        kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
             } else {
                 CHECK(!"Unknown compression format.");
             }
@@ -2230,4 +2389,67 @@
     }
 }
 
+////////////////////////////////////////////////////////////////////////////////
+
+status_t QueryCodecs(
+        const sp<IOMX> &omx,
+        const char *mime, bool queryDecoders,
+        Vector<CodecCapabilities> *results) {
+    results->clear();
+
+    for (int index = 0;; ++index) {
+        const char *componentName;
+
+        if (!queryDecoders) {
+            componentName = GetCodec(
+                    kEncoderInfo, sizeof(kEncoderInfo) / sizeof(kEncoderInfo[0]),
+                    mime, index);
+        } else {
+            componentName = GetCodec(
+                    kDecoderInfo, sizeof(kDecoderInfo) / sizeof(kDecoderInfo[0]),
+                    mime, index);
+        }
+
+        if (!componentName) {
+            return OK;
+        }
+
+        IOMX::node_id node;
+        status_t err = omx->allocate_node(componentName, &node);
+
+        if (err != OK) {
+            continue;
+        }
+
+        OMXCodec::setComponentRole(omx, node, queryDecoders, mime);
+
+        results->push();
+        CodecCapabilities *caps = &results->editItemAt(results->size() - 1);
+        caps->mComponentName = componentName;
+
+        OMX_VIDEO_PARAM_PROFILELEVELTYPE param;
+        InitOMXParams(&param);
+
+        param.nPortIndex = queryDecoders ? 0 : 1;
+
+        for (param.nProfileIndex = 0;; ++param.nProfileIndex) {
+            err = omx->get_parameter(
+                    node, OMX_IndexParamVideoProfileLevelQuerySupported,
+                    &param, sizeof(param));
+
+            if (err != OK) {
+                break;
+            }
+
+            CodecProfileLevel profileLevel;
+            profileLevel.mProfile = param.eProfile;
+            profileLevel.mLevel = param.eLevel;
+
+            caps->mProfileLevels.push(profileLevel);
+        }
+
+        CHECK_EQ(omx->free_node(node), OK);
+    }
+}
+
 }  // namespace android
diff --git a/media/libstagefright/ShoutcastSource.cpp b/media/libstagefright/ShoutcastSource.cpp
index 4375f38..8e8f4fa 100644
--- a/media/libstagefright/ShoutcastSource.cpp
+++ b/media/libstagefright/ShoutcastSource.cpp
@@ -20,6 +20,7 @@
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/ShoutcastSource.h>
 #include <media/stagefright/string.h>
@@ -77,7 +78,7 @@
 
 sp<MetaData> ShoutcastSource::getFormat() {
     sp<MetaData> meta = new MetaData;
-    meta->setCString(kKeyMIMEType, "audio/mpeg");
+    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
     meta->setInt32(kKeySampleRate, 44100);
     meta->setInt32(kKeyChannelCount, 2);  // XXX