am 2a1674b1: am 2d315667: For issue #2651381, allow library prelinking.

Merge commit '2a1674b1d00fda68980ec834d6ce61aacd379bc8' into kraken

* commit '2a1674b1d00fda68980ec834d6ce61aacd379bc8':
  For issue #2651381, allow library prelinking.
diff --git a/cmds/stagefright/record.cpp b/cmds/stagefright/record.cpp
index 845c854..5a87f4c 100644
--- a/cmds/stagefright/record.cpp
+++ b/cmds/stagefright/record.cpp
@@ -147,7 +147,7 @@
     OMXClient client;
     CHECK_EQ(client.connect(), OK);
 
-#if 1
+#if 0
     sp<MediaSource> source = createSource(argv[1]);
 
     if (source == NULL) {
@@ -165,14 +165,15 @@
     success = success && meta->findInt32(kKeyHeight, &height);
     CHECK(success);
 #else
-    int width = 800;
+    int width = 720;
     int height = 480;
     sp<MediaSource> decoder = new DummySource(width, height);
 #endif
 
     sp<MetaData> enc_meta = new MetaData;
     // enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263);
-    enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4);
+    // enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4);
+    enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
     enc_meta->setInt32(kKeyWidth, width);
     enc_meta->setInt32(kKeyHeight, height);
 
@@ -213,6 +214,8 @@
 
 #if 0
     CameraSource *source = CameraSource::Create();
+    source->start();
+
     printf("source = %p\n", source);
 
     for (int i = 0; i < 100; ++i) {
@@ -227,6 +230,8 @@
         buffer = NULL;
     }
 
+    source->stop();
+
     delete source;
     source = NULL;
 #endif
diff --git a/include/media/stagefright/AMRWriter.h b/include/media/stagefright/AMRWriter.h
index 372909a..34f3c4a 100644
--- a/include/media/stagefright/AMRWriter.h
+++ b/include/media/stagefright/AMRWriter.h
@@ -42,14 +42,12 @@
     virtual ~AMRWriter();
 
 private:
-    Mutex mLock;
-
     FILE *mFile;
     status_t mInitCheck;
     sp<MediaSource> mSource;
     bool mStarted;
     volatile bool mDone;
-    bool mReachedEOS;
+    volatile bool mReachedEOS;
     pthread_t mThread;
 
     static void *ThreadWrapper(void *);
diff --git a/include/media/stagefright/CameraSource.h b/include/media/stagefright/CameraSource.h
index ea435de..3afa598 100644
--- a/include/media/stagefright/CameraSource.h
+++ b/include/media/stagefright/CameraSource.h
@@ -34,7 +34,7 @@
 class CameraSource : public MediaSource {
 public:
     static CameraSource *Create();
-    static CameraSource *CreateFromICamera(const sp<ICamera> &icamera);
+    static CameraSource *CreateFromCamera(const sp<Camera> &camera);
 
     virtual ~CameraSource();
 
@@ -61,12 +61,18 @@
 
     int mWidth, mHeight;
     int64_t mFirstFrameTimeUs;
-    int32_t mNumFrames;
+    int64_t mLastFrameTimestampUs;
+    int32_t mNumFramesReceived;
+    int32_t mNumFramesEncoded;
+    int32_t mNumFramesDropped;
     bool mStarted;
 
     CameraSource(const sp<Camera> &camera);
 
-    void dataCallback(int32_t msgType, const sp<IMemory> &data);
+    void dataCallbackTimestamp(
+            int64_t timestampUs, int32_t msgType, const sp<IMemory> &data);
+
+    void releaseQueuedFrames();
 
     CameraSource(const CameraSource &);
     CameraSource &operator=(const CameraSource &);
diff --git a/include/media/stagefright/MPEG4Writer.h b/include/media/stagefright/MPEG4Writer.h
index 6b93f19..27d0f50 100644
--- a/include/media/stagefright/MPEG4Writer.h
+++ b/include/media/stagefright/MPEG4Writer.h
@@ -49,6 +49,8 @@
     void writeFourcc(const char *fourcc);
     void write(const void *data, size_t size);
     void endBox();
+    uint32_t interleaveDuration() const { return mInterleaveDurationUs; }
+    status_t setInterleaveDuration(uint32_t duration);
 
 protected:
     virtual ~MPEG4Writer();
@@ -59,14 +61,19 @@
     FILE *mFile;
     off_t mOffset;
     off_t mMdatOffset;
+    uint32_t mInterleaveDurationUs;
     Mutex mLock;
 
     List<Track *> mTracks;
 
     List<off_t> mBoxes;
 
-    off_t addSample(MediaBuffer *buffer);
-    off_t addLengthPrefixedSample(MediaBuffer *buffer);
+    void lock();
+    void unlock();
+
+    // Acquire lock before calling these methods
+    off_t addSample_l(MediaBuffer *buffer);
+    off_t addLengthPrefixedSample_l(MediaBuffer *buffer);
 
     MPEG4Writer(const MPEG4Writer &);
     MPEG4Writer &operator=(const MPEG4Writer &);
diff --git a/include/private/surfaceflinger/SharedBufferStack.h b/include/private/surfaceflinger/SharedBufferStack.h
index 9b5a1e0..2504d39 100644
--- a/include/private/surfaceflinger/SharedBufferStack.h
+++ b/include/private/surfaceflinger/SharedBufferStack.h
@@ -58,7 +58,7 @@
 // When changing these values, the COMPILE_TIME_ASSERT at the end of this
 // file need to be updated.
 const unsigned int NUM_LAYERS_MAX  = 31;
-const unsigned int NUM_BUFFER_MAX  = 4;
+const unsigned int NUM_BUFFER_MAX  = 16;
 const unsigned int NUM_DISPLAY_MAX = 4;
 
 // ----------------------------------------------------------------------------
@@ -69,7 +69,11 @@
 
 // ----------------------------------------------------------------------------
 
-// should be 128 bytes (32 longs)
+// 4 * (11 + 7 + (1 + 2*NUM_RECT_MAX) * NUM_BUFFER_MAX) * NUM_LAYERS_MAX
+// 4 * (11 + 7 + (1 + 2*7)*16) * 31
+// 1032 * 31
+// = ~27 KiB (31992)
+
 class SharedBufferStack
 {
     friend class SharedClient;
@@ -78,21 +82,31 @@
     friend class SharedBufferServer;
 
 public:
-    struct FlatRegion { // 12 bytes
-        static const unsigned int NUM_RECT_MAX = 1;
-        uint32_t    count;
-        uint16_t    rects[4*NUM_RECT_MAX];
-    };
-    
     struct Statistics { // 4 longs
         typedef int32_t usecs_t;
         usecs_t  totalTime;
         usecs_t  reserved[3];
     };
+
+    struct SmallRect {
+        uint16_t l, t, r, b;
+    };
+
+    struct FlatRegion { // 52 bytes = 4 * (1 + 2*N)
+        static const unsigned int NUM_RECT_MAX = 6;
+        uint32_t    count;
+        SmallRect   rects[NUM_RECT_MAX];
+    };
+    
+    struct BufferData {
+        FlatRegion dirtyRegion;
+        SmallRect  crop;
+    };
     
     SharedBufferStack();
     void init(int32_t identity);
     status_t setDirtyRegion(int buffer, const Region& reg);
+    status_t setCrop(int buffer, const Rect& reg);
     Region getDirtyRegion(int buffer) const;
 
     // these attributes are part of the conditions/updates
@@ -104,11 +118,13 @@
 
     // not part of the conditions
     volatile int32_t reallocMask;
+    volatile int8_t index[NUM_BUFFER_MAX];
 
     int32_t     identity;       // surface's identity (const)
-    int32_t     reserved32[9];
+    int32_t     reserved32[2];
     Statistics  stats;
-    FlatRegion  dirtyRegion[NUM_BUFFER_MAX];    // 12*4=48 bytes
+    int32_t     reserved;
+    BufferData  buffers[NUM_BUFFER_MAX];     // 960 bytes
 };
 
 // ----------------------------------------------------------------------------
@@ -152,6 +168,7 @@
     SharedBufferStack* const mSharedStack;
     const int mNumBuffers;
     const int mIdentity;
+    int32_t computeTail() const;
 
     friend struct Update;
     friend struct QueueUpdate;
@@ -160,61 +177,22 @@
         SharedBufferStack& stack;
         inline ConditionBase(SharedBufferBase* sbc) 
             : stack(*sbc->mSharedStack) { }
+        virtual ~ConditionBase() { };
+        virtual bool operator()() const = 0;
+        virtual const char* name() const = 0;
     };
+    status_t waitForCondition(const ConditionBase& condition);
 
     struct UpdateBase {
         SharedBufferStack& stack;
         inline UpdateBase(SharedBufferBase* sbb) 
             : stack(*sbb->mSharedStack) { }
     };
-
-    template <typename T>
-    status_t waitForCondition(T condition);
-
     template <typename T>
     status_t updateCondition(T update);
 };
 
 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()==false) &&
-            (stack.identity == mIdentity) &&
-            (stack.status == NO_ERROR))
-    {
-        status_t err = client.cv.waitRelative(client.lock, TIMEOUT);
-        
-        // handle errors and timeouts
-        if (CC_UNLIKELY(err != NO_ERROR)) {
-            if (err == TIMED_OUT) {
-                if (condition()) {
-                    LOGE("waitForCondition(%s) timed out (identity=%d), "
-                        "but condition is true! We recovered but it "
-                        "shouldn't happen." , T::name(),
-                        stack.identity);
-                    break;
-                } else {
-                    LOGW("waitForCondition(%s) timed out "
-                        "(identity=%d, status=%d). "
-                        "CPU may be pegged. trying again.", T::name(),
-                        stack.identity, stack.status);
-                }
-            } else {
-                LOGE("waitForCondition(%s) error (%s) ",
-                        T::name(), strerror(-err));
-                return err;
-            }
-        }
-    }
-    return (stack.identity != mIdentity) ? status_t(BAD_INDEX) : stack.status;
-}
-
-
-template <typename T>
 status_t SharedBufferBase::updateCondition(T update) {
     SharedClient& client( *mSharedClient );
     Mutex::Autolock _l(client.lock);
@@ -238,13 +216,12 @@
     status_t queue(int buf);
     bool needNewBuffer(int buffer) const;
     status_t setDirtyRegion(int buffer, const Region& reg);
+    status_t setCrop(int buffer, const Rect& reg);
     
 private:
     friend struct Condition;
     friend struct DequeueCondition;
     friend struct LockCondition;
-    
-    int32_t computeTail() const;
 
     struct QueueUpdate : public UpdateBase {
         inline QueueUpdate(SharedBufferBase* sbb);
@@ -260,18 +237,20 @@
 
     struct DequeueCondition : public ConditionBase {
         inline DequeueCondition(SharedBufferClient* sbc);
-        inline bool operator()();
-        static inline const char* name() { return "DequeueCondition"; }
+        inline bool operator()() const;
+        inline const char* name() const { return "DequeueCondition"; }
     };
 
     struct LockCondition : public ConditionBase {
         int buf;
         inline LockCondition(SharedBufferClient* sbc, int buf);
-        inline bool operator()();
-        static inline const char* name() { return "LockCondition"; }
+        inline bool operator()() const;
+        inline const char* name() const { return "LockCondition"; }
     };
 
     int32_t tail;
+    int32_t undoDequeueTail;
+    int32_t queued_head;
     // statistics...
     nsecs_t mDequeueTime[NUM_BUFFER_MAX];
 };
@@ -318,8 +297,8 @@
     struct ReallocateCondition : public ConditionBase {
         int buf;
         inline ReallocateCondition(SharedBufferBase* sbb, int buf);
-        inline bool operator()();
-        static inline const char* name() { return "ReallocateCondition"; }
+        inline bool operator()() const;
+        inline const char* name() const { return "ReallocateCondition"; }
     };
 };
 
@@ -349,8 +328,7 @@
 
 // ---------------------------------------------------------------------------
 
-COMPILE_TIME_ASSERT(sizeof(SharedClient) <= 4096)
-COMPILE_TIME_ASSERT(sizeof(SharedBufferStack) == 128)
+COMPILE_TIME_ASSERT(sizeof(SharedClient) <= 32768)
 COMPILE_TIME_ASSERT(sizeof(surface_flinger_cblk_t) <= 4096)
 
 // ---------------------------------------------------------------------------
diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp
index 01b6737..f3804b8 100644
--- a/media/libmedia/IOMX.cpp
+++ b/media/libmedia/IOMX.cpp
@@ -57,7 +57,7 @@
         return NULL;
     }
 
-    jfieldID surfaceID = env->GetFieldID(surfaceClass, "mSurface", "I");
+    jfieldID surfaceID = env->GetFieldID(surfaceClass, ANDROID_VIEW_SURFACE_JNI_ID, "I");
     if (surfaceID == NULL) {
         LOGE("Can't find Surface.mSurface");
         return NULL;
diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk
index cf97b23..3b678cb 100644
--- a/media/libmediaplayerservice/Android.mk
+++ b/media/libmediaplayerservice/Android.mk
@@ -37,6 +37,7 @@
 	libvorbisidec         			\
 	libsonivox            			\
 	libmedia              			\
+	libcamera_client      			\
 	libandroid_runtime    			\
 	libstagefright        			\
 	libstagefright_omx    			\
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 3e1f4a5..3100f6e 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -228,14 +228,10 @@
 
 sp<IMediaRecorder> MediaPlayerService::createMediaRecorder(pid_t pid)
 {
-#ifndef NO_OPENCORE
     sp<MediaRecorderClient> recorder = new MediaRecorderClient(this, pid);
     wp<MediaRecorderClient> w = recorder;
     Mutex::Autolock lock(mLock);
     mMediaRecorderClients.add(w);
-#else
-    sp<MediaRecorderClient> recorder = NULL;
-#endif
     LOGV("Create new media recorder client from pid %d", pid);
     return recorder;
 }
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 531fd11..57db7e4 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -20,6 +20,7 @@
 
 #include "StagefrightRecorder.h"
 
+#include <binder/IPCThreadState.h>
 #include <media/stagefright/AudioSource.h>
 #include <media/stagefright/AMRWriter.h>
 #include <media/stagefright/CameraSource.h>
@@ -30,8 +31,12 @@
 #include <media/stagefright/OMXClient.h>
 #include <media/stagefright/OMXCodec.h>
 #include <camera/ICamera.h>
+#include <camera/Camera.h>
 #include <surfaceflinger/ISurface.h>
 #include <utils/Errors.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <ctype.h>
 
 namespace android {
 
@@ -96,7 +101,25 @@
 }
 
 status_t StagefrightRecorder::setCamera(const sp<ICamera> &camera) {
-    mCamera = camera;
+    LOGV("setCamera: pid %d pid %d", IPCThreadState::self()->getCallingPid(), getpid());
+    if (camera == 0) {
+        LOGE("camera is NULL");
+        return UNKNOWN_ERROR;
+    }
+
+    mFlags &= ~ FLAGS_SET_CAMERA | FLAGS_HOT_CAMERA;
+    mCamera = Camera::create(camera);
+    if (mCamera == 0) {
+        LOGE("Unable to connect to camera");
+        return UNKNOWN_ERROR;
+    }
+
+    LOGV("Connected to camera");
+    mFlags |= FLAGS_SET_CAMERA;
+    if (mCamera->previewEnabled()) {
+        LOGV("camera is hot");
+        mFlags |= FLAGS_HOT_CAMERA;
+    }
 
     return OK;
 }
@@ -127,9 +150,160 @@
     return OK;
 }
 
-status_t StagefrightRecorder::setParameters(const String8 &params) {
-    mParams = params;
+// Attempt to parse an int64 literal optionally surrounded by whitespace,
+// returns true on success, false otherwise.
+static bool safe_strtoi64(const char *s, int32_t *val) {
+    char *end;
+    *val = static_cast<int32_t>(strtoll(s, &end, 10));
 
+    if (end == s || errno == ERANGE) {
+        return false;
+    }
+
+    // Skip trailing whitespace
+    while (isspace(*end)) {
+        ++end;
+    }
+
+    // For a successful return, the string must contain nothing but a valid
+    // int64 literal optionally surrounded by whitespace.
+
+    return *end == '\0';
+}
+
+// Trim both leading and trailing whitespace from the given string.
+static void TrimString(String8 *s) {
+    size_t num_bytes = s->bytes();
+    const char *data = s->string();
+
+    size_t leading_space = 0;
+    while (leading_space < num_bytes && isspace(data[leading_space])) {
+        ++leading_space;
+    }
+
+    size_t i = num_bytes;
+    while (i > leading_space && isspace(data[i - 1])) {
+        --i;
+    }
+
+    s->setTo(String8(&data[leading_space], i - leading_space));
+}
+
+status_t StagefrightRecorder::setParamAudioSamplingRate(int32_t sampleRate) {
+    LOGV("setParamAudioSamplingRate: %d", sampleRate);
+    mSampleRate = sampleRate;
+    return OK;
+}
+
+status_t StagefrightRecorder::setParamAudioNumberOfChannels(int32_t channels) {
+    LOGV("setParamAudioNumberOfChannels: %d", channels);
+    mAudioChannels = channels;
+    return OK;
+}
+
+status_t StagefrightRecorder::setParamAudioEncodingBitRate(int32_t bitRate) {
+    LOGV("setParamAudioEncodingBitRate: %d", bitRate);
+    mAudioBitRate = bitRate;
+    return OK;
+}
+
+status_t StagefrightRecorder::setParamVideoEncodingBitRate(int32_t bitRate) {
+    LOGV("setParamVideoEncodingBitRate: %d", bitRate);
+    mVideoBitRate = bitRate;
+    return OK;
+}
+
+status_t StagefrightRecorder::setParamMaxDurationOrFileSize(int32_t limit,
+        bool limit_is_duration) {
+    LOGV("setParamMaxDurationOrFileSize: limit (%d) for %s",
+            limit, limit_is_duration?"duration":"size");
+    return OK;
+}
+
+status_t StagefrightRecorder::setParamInterleaveDuration(int32_t durationUs) {
+    LOGV("setParamInterleaveDuration: %d", durationUs);
+    mInterleaveDurationUs = durationUs;
+    return OK;
+}
+status_t StagefrightRecorder::setParameter(
+        const String8 &key, const String8 &value) {
+    LOGV("setParameter: key (%s) => value (%s)", key.string(), value.string());
+    if (key == "max-duration") {
+        int32_t max_duration_ms;
+        if (safe_strtoi64(value.string(), &max_duration_ms)) {
+            return setParamMaxDurationOrFileSize(
+                    max_duration_ms, true /* limit_is_duration */);
+        }
+    } else if (key == "max-filesize") {
+        int32_t max_filesize_bytes;
+        if (safe_strtoi64(value.string(), &max_filesize_bytes)) {
+            return setParamMaxDurationOrFileSize(
+                    max_filesize_bytes, false /* limit is filesize */);
+        }
+    } else if (key == "audio-param-sampling-rate") {
+        int32_t sampling_rate;
+        if (safe_strtoi64(value.string(), &sampling_rate)) {
+            return setParamAudioSamplingRate(sampling_rate);
+        }
+    } else if (key == "audio-param-number-of-channels") {
+        int32_t number_of_channels;
+        if (safe_strtoi64(value.string(), &number_of_channels)) {
+            return setParamAudioNumberOfChannels(number_of_channels);
+        }
+    } else if (key == "audio-param-encoding-bitrate") {
+        int32_t audio_bitrate;
+        if (safe_strtoi64(value.string(), &audio_bitrate)) {
+            return setParamAudioEncodingBitRate(audio_bitrate);
+        }
+    } else if (key == "video-param-encoding-bitrate") {
+        int32_t video_bitrate;
+        if (safe_strtoi64(value.string(), &video_bitrate)) {
+            return setParamVideoEncodingBitRate(video_bitrate);
+        }
+    } else if (key == "param-interleave-duration-us") {
+        int32_t durationUs;
+        if (safe_strtoi64(value.string(), &durationUs)) {
+            return setParamInterleaveDuration(durationUs);
+        }
+    } else {
+        LOGE("setParameter: failed to find key %s", key.string());
+        return BAD_VALUE;
+    }
+    return OK;
+}
+
+status_t StagefrightRecorder::setParameters(const String8 &params) {
+    LOGV("setParameters: %s", params.string());
+    const char *cparams = params.string();
+    const char *key_start = cparams;
+    for (;;) {
+        const char *equal_pos = strchr(key_start, '=');
+        if (equal_pos == NULL) {
+            LOGE("Parameters %s miss a value", cparams);
+            return BAD_VALUE;
+        }
+        String8 key(key_start, equal_pos - key_start);
+        TrimString(&key);
+        if (key.length() == 0) {
+            LOGE("Parameters %s contains an empty key", cparams);
+            return BAD_VALUE;
+        }
+        const char *value_start = equal_pos + 1;
+        const char *semicolon_pos = strchr(value_start, ';');
+        String8 value;
+        if (semicolon_pos == NULL) {
+            value.setTo(value_start);
+        } else {
+            value.setTo(value_start, semicolon_pos - value_start);
+        }
+        if (setParameter(key, value) != OK) {
+            return BAD_VALUE;
+        }
+        if (semicolon_pos == NULL) {
+            break;  // Reaches the end
+        }
+        key_start = semicolon_pos + 1;
+    }
     return OK;
 }
 
@@ -163,35 +337,46 @@
     }
 }
 
-sp<MediaSource> StagefrightRecorder::createAMRAudioSource() {
-    uint32_t sampleRate =
-        mAudioEncoder == AUDIO_ENCODER_AMR_NB ? 8000 : 16000;
-
+sp<MediaSource> StagefrightRecorder::createAudioSource() {
     sp<AudioSource> audioSource =
         new AudioSource(
                 mAudioSource,
-                sampleRate,
+                mSampleRate,
                 AudioSystem::CHANNEL_IN_MONO);
 
     status_t err = audioSource->initCheck();
 
     if (err != OK) {
+        LOGE("audio source is not initialized");
         return NULL;
     }
 
     sp<MetaData> encMeta = new MetaData;
-    encMeta->setCString(
-            kKeyMIMEType,
-            mAudioEncoder == AUDIO_ENCODER_AMR_NB
-                ? MEDIA_MIMETYPE_AUDIO_AMR_NB : MEDIA_MIMETYPE_AUDIO_AMR_WB);
+    const char *mime;
+    switch (mAudioEncoder) {
+        case AUDIO_ENCODER_AMR_NB:
+        case AUDIO_ENCODER_DEFAULT:
+            mime = MEDIA_MIMETYPE_AUDIO_AMR_NB;
+            break;
+        case AUDIO_ENCODER_AMR_WB:
+            mime = MEDIA_MIMETYPE_AUDIO_AMR_WB;
+            break;
+        case AUDIO_ENCODER_AAC:
+            mime = MEDIA_MIMETYPE_AUDIO_AAC;
+            break;
+        default:
+            LOGE("Unknown audio encoder: %d", mAudioEncoder);
+            return NULL;
+    }
+    encMeta->setCString(kKeyMIMEType, mime);
 
     int32_t maxInputSize;
     CHECK(audioSource->getFormat()->findInt32(
                 kKeyMaxInputSize, &maxInputSize));
 
     encMeta->setInt32(kKeyMaxInputSize, maxInputSize);
-    encMeta->setInt32(kKeyChannelCount, 1);
-    encMeta->setInt32(kKeySampleRate, sampleRate);
+    encMeta->setInt32(kKeyChannelCount, mAudioChannels);
+    encMeta->setInt32(kKeySampleRate, mSampleRate);
 
     OMXClient client;
     CHECK_EQ(client.connect(), OK);
@@ -218,7 +403,7 @@
         return UNKNOWN_ERROR;
     }
 
-    sp<MediaSource> audioEncoder = createAMRAudioSource();
+    sp<MediaSource> audioEncoder = createAudioSource();
 
     if (audioEncoder == NULL) {
         return UNKNOWN_ERROR;
@@ -235,12 +420,32 @@
 status_t StagefrightRecorder::startMPEG4Recording() {
     mWriter = new MPEG4Writer(dup(mOutputFd));
 
+    // Add audio source first if it exists
+    if (mAudioSource != AUDIO_SOURCE_LIST_END) {
+        sp<MediaSource> audioEncoder;
+        switch(mAudioEncoder) {
+            case AUDIO_ENCODER_AMR_NB:
+            case AUDIO_ENCODER_AMR_WB:
+            case AUDIO_ENCODER_AAC:
+                audioEncoder = createAudioSource();
+                break;
+            default:
+                LOGE("Unsupported audio encoder: %d", mAudioEncoder);
+                return UNKNOWN_ERROR;
+        }
+
+        if (audioEncoder == NULL) {
+            return UNKNOWN_ERROR;
+        }
+
+        mWriter->addSource(audioEncoder);
+    }
     if (mVideoSource == VIDEO_SOURCE_DEFAULT
             || mVideoSource == VIDEO_SOURCE_CAMERA) {
         CHECK(mCamera != NULL);
 
         sp<CameraSource> cameraSource =
-            CameraSource::CreateFromICamera(mCamera);
+            CameraSource::CreateFromCamera(mCamera);
 
         CHECK(cameraSource != NULL);
 
@@ -286,16 +491,7 @@
         mWriter->addSource(encoder);
     }
 
-    if (mAudioSource != AUDIO_SOURCE_LIST_END) {
-        sp<MediaSource> audioEncoder = createAMRAudioSource();
-
-        if (audioEncoder == NULL) {
-            return UNKNOWN_ERROR;
-        }
-
-        mWriter->addSource(audioEncoder);
-    }
-
+    ((MPEG4Writer *)mWriter.get())->setInterleaveDuration(mInterleaveDurationUs);
     mWriter->start();
     return OK;
 }
@@ -314,21 +510,41 @@
 status_t StagefrightRecorder::close() {
     stop();
 
+    if (mCamera != 0) {
+        if ((mFlags & FLAGS_HOT_CAMERA) == 0) {
+            LOGV("Camera was cold when we started, stopping preview");
+            mCamera->stopPreview();
+        }
+        if (mFlags & FLAGS_SET_CAMERA) {
+            LOGV("Unlocking camera");
+            mCamera->unlock();
+        }
+        mFlags = 0;
+    }
     return OK;
 }
 
 status_t StagefrightRecorder::reset() {
     stop();
 
+    // No audio or video source by default
     mAudioSource = AUDIO_SOURCE_LIST_END;
     mVideoSource = VIDEO_SOURCE_LIST_END;
-    mOutputFormat = OUTPUT_FORMAT_LIST_END;
-    mAudioEncoder = AUDIO_ENCODER_LIST_END;
-    mVideoEncoder = VIDEO_ENCODER_LIST_END;
-    mVideoWidth = -1;
-    mVideoHeight = -1;
-    mFrameRate = -1;
+
+    // Default parameters
+    mOutputFormat  = OUTPUT_FORMAT_THREE_GPP;
+    mAudioEncoder  = AUDIO_ENCODER_AMR_NB;
+    mVideoEncoder  = VIDEO_ENCODER_H263;
+    mVideoWidth    = 176;
+    mVideoHeight   = 144;
+    mFrameRate     = 20;
+    mVideoBitRate  = 192000;
+    mSampleRate    = 8000;
+    mAudioChannels = 1;
+    mAudioBitRate  = 12200;
+
     mOutputFd = -1;
+    mFlags = 0;
 
     return OK;
 }
diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h
index 7ec412d..3b99e91 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.h
+++ b/media/libmediaplayerservice/StagefrightRecorder.h
@@ -23,6 +23,7 @@
 
 namespace android {
 
+class Camera;
 struct MediaSource;
 struct MediaWriter;
 
@@ -52,7 +53,12 @@
     virtual status_t getMaxAmplitude(int *max);
 
 private:
-    sp<ICamera> mCamera;
+    enum CameraFlags {
+        FLAGS_SET_CAMERA = 1L << 0,
+        FLAGS_HOT_CAMERA = 1L << 1,
+    };
+
+    sp<Camera> mCamera;
     sp<ISurface> mPreviewSurface;
     sp<IMediaPlayerClient> mListener;
     sp<MediaWriter> mWriter;
@@ -62,14 +68,28 @@
     output_format mOutputFormat;
     audio_encoder mAudioEncoder;
     video_encoder mVideoEncoder;
-    int mVideoWidth, mVideoHeight;
-    int mFrameRate;
+    int32_t mVideoWidth, mVideoHeight;
+    int32_t mFrameRate;
+    int32_t mVideoBitRate;
+    int32_t mAudioBitRate;
+    int32_t mAudioChannels;
+    int32_t mSampleRate;
+    int32_t mInterleaveDurationUs;
+
     String8 mParams;
     int mOutputFd;
+    int32_t mFlags;
 
     status_t startMPEG4Recording();
     status_t startAMRRecording();
-    sp<MediaSource> createAMRAudioSource();
+    sp<MediaSource> createAudioSource();
+    status_t setParameter(const String8 &key, const String8 &value);
+    status_t setParamVideoEncodingBitRate(int32_t bitRate);
+    status_t setParamAudioEncodingBitRate(int32_t bitRate);
+    status_t setParamAudioNumberOfChannels(int32_t channles);
+    status_t setParamAudioSamplingRate(int32_t sampleRate);
+    status_t setParamInterleaveDuration(int32_t durationUs);
+    status_t setParamMaxDurationOrFileSize(int32_t limit, bool limit_is_duration);
 
     StagefrightRecorder(const StagefrightRecorder &);
     StagefrightRecorder &operator=(const StagefrightRecorder &);
diff --git a/media/libstagefright/AMRWriter.cpp b/media/libstagefright/AMRWriter.cpp
index bf4424b..73ea56d 100644
--- a/media/libstagefright/AMRWriter.cpp
+++ b/media/libstagefright/AMRWriter.cpp
@@ -53,8 +53,6 @@
 }
 
 status_t AMRWriter::addSource(const sp<MediaSource> &source) {
-    Mutex::Autolock autoLock(mLock);
-
     if (mInitCheck != OK) {
         return mInitCheck;
     }
@@ -95,8 +93,6 @@
 }
 
 status_t AMRWriter::start() {
-    Mutex::Autolock autoLock(mLock);
-
     if (mInitCheck != OK) {
         return mInitCheck;
     }
@@ -127,16 +123,12 @@
 }
 
 void AMRWriter::stop() {
-    {
-        Mutex::Autolock autoLock(mLock);
-
-        if (!mStarted) {
-            return;
-        }
-
-        mDone = true;
+    if (!mStarted) {
+        return;
     }
 
+    mDone = true;
+
     void *dummy;
     pthread_join(mThread, &dummy);
 
@@ -153,13 +145,7 @@
 }
 
 void AMRWriter::threadFunc() {
-    for (;;) {
-        Mutex::Autolock autoLock(mLock);
-
-        if (mDone) {
-            break;
-        }
-
+    while (!mDone) {
         MediaBuffer *buffer;
         status_t err = mSource->read(&buffer);
 
@@ -184,12 +170,10 @@
         buffer = NULL;
     }
 
-    Mutex::Autolock autoLock(mLock);
     mReachedEOS = true;
 }
 
 bool AMRWriter::reachedEOS() {
-    Mutex::Autolock autoLock(mLock);
     return mReachedEOS;
 }
 
diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp
index edabaf9..abd8abc 100644
--- a/media/libstagefright/AudioSource.cpp
+++ b/media/libstagefright/AudioSource.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+//#define LOG_NDEBUG 0
+#define LOG_TAG "AudioSource"
+#include <utils/Log.h>
+
 #include <media/stagefright/AudioSource.h>
 
 #include <media/AudioRecord.h>
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index 075b1e3..b046a9c 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -14,12 +14,12 @@
  * limitations under the License.
  */
 
-#include <sys/time.h>
+//#define LOG_NDEBUG 0
+#define LOG_TAG "CameraSource"
+#include <utils/Log.h>
 
 #include <OMX_Component.h>
 
-#include <binder/IServiceManager.h>
-#include <cutils/properties.h> // for property_get
 #include <media/stagefright/CameraSource.h>
 #include <media/stagefright/MediaDebug.h>
 #include <media/stagefright/MediaDefs.h>
@@ -34,13 +34,6 @@
 
 namespace android {
 
-static int64_t getNowUs() {
-    struct timeval tv;
-    gettimeofday(&tv, NULL);
-
-    return (int64_t)tv.tv_usec + tv.tv_sec * 1000000;
-}
-
 struct DummySurface : public BnSurface {
     DummySurface() {}
 
@@ -100,17 +93,15 @@
 void CameraSourceListener::postData(int32_t msgType, const sp<IMemory> &dataPtr) {
     LOGV("postData(%d, ptr:%p, size:%d)",
          msgType, dataPtr->pointer(), dataPtr->size());
-
-    sp<CameraSource> source = mSource.promote();
-    if (source.get() != NULL) {
-        source->dataCallback(msgType, dataPtr);
-    }
 }
 
 void CameraSourceListener::postDataTimestamp(
         nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr) {
-    LOGV("postDataTimestamp(%lld, %d, ptr:%p, size:%d)",
-         timestamp, msgType, dataPtr->pointer(), dataPtr->size());
+
+    sp<CameraSource> source = mSource.promote();
+    if (source.get() != NULL) {
+        source->dataCallbackTimestamp(timestamp/1000, msgType, dataPtr);
+    }
 }
 
 // static
@@ -125,9 +116,7 @@
 }
 
 // static
-CameraSource *CameraSource::CreateFromICamera(const sp<ICamera> &icamera) {
-    sp<Camera> camera = Camera::create(icamera);
-
+CameraSource *CameraSource::CreateFromCamera(const sp<Camera> &camera) {
     if (camera.get() == NULL) {
         return NULL;
     }
@@ -140,15 +129,11 @@
       mWidth(0),
       mHeight(0),
       mFirstFrameTimeUs(0),
-      mNumFrames(0),
+      mLastFrameTimestampUs(0),
+      mNumFramesReceived(0),
+      mNumFramesEncoded(0),
+      mNumFramesDropped(0),
       mStarted(false) {
-    char value[PROPERTY_VALUE_MAX];
-    if (property_get("ro.hardware", value, NULL) && !strcmp(value, "sholes")) {
-        // The hardware encoder(s) do not support yuv420, but only YCbYCr,
-        // fortunately the camera also supports this, so we needn't transcode.
-        mCamera->setParameters(String8("preview-format=yuv422i-yuyv"));
-    }
-
     String8 s = mCamera->getParameters();
     printf("params: \"%s\"\n", s.string());
 
@@ -167,6 +152,7 @@
 }
 
 status_t CameraSource::start(MetaData *) {
+    LOGV("start");
     CHECK(!mStarted);
 
     mCamera->setListener(new CameraSourceListener(this));
@@ -176,11 +162,7 @@
                 mPreviewSurface != NULL ? mPreviewSurface : new DummySurface);
     CHECK_EQ(err, OK);
 
-    mCamera->setPreviewCallbackFlags(
-            FRAME_CALLBACK_FLAG_ENABLE_MASK
-            | FRAME_CALLBACK_FLAG_COPY_OUT_MASK);
-
-    err = mCamera->startPreview();
+    err = mCamera->startRecording();
     CHECK_EQ(err, OK);
 
     mStarted = true;
@@ -189,15 +171,32 @@
 }
 
 status_t CameraSource::stop() {
-    CHECK(mStarted);
-
-    mCamera->stopPreview();
-
+    LOGV("stop");
+    Mutex::Autolock autoLock(mLock);
     mStarted = false;
+    mFrameAvailableCondition.signal();
+    mCamera->setListener(NULL);
+    mCamera->stopRecording();
 
+    releaseQueuedFrames();
+    LOGI("Frames received/encoded/dropped: %d/%d/%d, timestamp (us) last/first: %lld/%lld",
+            mNumFramesReceived, mNumFramesEncoded, mNumFramesDropped,
+            mLastFrameTimestampUs, mFirstFrameTimeUs);
+
+    CHECK_EQ(mNumFramesReceived, mNumFramesEncoded + mNumFramesDropped);
     return OK;
 }
 
+void CameraSource::releaseQueuedFrames() {
+    List<sp<IMemory> >::iterator it;
+    while (!mFrames.empty()) {
+        it = mFrames.begin();
+        mCamera->releaseRecordingFrame(*it);
+        mFrames.erase(it);
+        ++mNumFramesDropped;
+    }
+}
+
 sp<MetaData> CameraSource::getFormat() {
     sp<MetaData> meta = new MetaData;
     meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW);
@@ -210,7 +209,7 @@
 
 status_t CameraSource::read(
         MediaBuffer **buffer, const ReadOptions *options) {
-    CHECK(mStarted);
+    LOGV("read");
 
     *buffer = NULL;
 
@@ -224,20 +223,24 @@
 
     {
         Mutex::Autolock autoLock(mLock);
-        while (mFrames.empty()) {
+        while (mStarted && mFrames.empty()) {
             mFrameAvailableCondition.wait(mLock);
         }
-
+        if (!mStarted) {
+            return OK;
+        }
         frame = *mFrames.begin();
         mFrames.erase(mFrames.begin());
 
         frameTime = *mFrameTimes.begin();
         mFrameTimes.erase(mFrameTimes.begin());
+        ++mNumFramesEncoded;
     }
 
     *buffer = new MediaBuffer(frame->size());
     memcpy((*buffer)->data(), frame->pointer(), frame->size());
     (*buffer)->set_range(0, frame->size());
+    mCamera->releaseRecordingFrame(frame);
 
     (*buffer)->meta_data()->clear();
     (*buffer)->meta_data()->setInt64(kKeyTime, frameTime);
@@ -245,17 +248,25 @@
     return OK;
 }
 
-void CameraSource::dataCallback(int32_t msgType, const sp<IMemory> &data) {
+void CameraSource::dataCallbackTimestamp(int64_t timestampUs,
+        int32_t msgType, const sp<IMemory> &data) {
+    LOGV("dataCallbackTimestamp: timestamp %lld us", timestampUs);
+    mLastFrameTimestampUs = timestampUs;
     Mutex::Autolock autoLock(mLock);
-
-    int64_t nowUs = getNowUs();
-    if (mNumFrames == 0) {
-        mFirstFrameTimeUs = nowUs;
+    if (!mStarted) {
+        mCamera->releaseRecordingFrame(data);
+        ++mNumFramesReceived;
+        ++mNumFramesDropped;
+        return;
     }
-    ++mNumFrames;
+
+    if (mNumFramesReceived == 0) {
+        mFirstFrameTimeUs = timestampUs;
+    }
+    ++mNumFramesReceived;
 
     mFrames.push_back(data);
-    mFrameTimes.push_back(nowUs - mFirstFrameTimeUs);
+    mFrameTimes.push_back(timestampUs - mFirstFrameTimeUs);
     mFrameAvailableCondition.signal();
 }
 
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 2cf0ddf..29ec876 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MPEG4Writer"
+#include <utils/Log.h>
+
 #include <arpa/inet.h>
 
 #include <ctype.h>
@@ -24,6 +28,7 @@
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/MediaDebug.h>
 #include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MediaSource.h>
 #include <media/stagefright/Utils.h>
 
@@ -52,34 +57,59 @@
 
     struct SampleInfo {
         size_t size;
-        off_t offset;
         int64_t timestamp;
     };
-    List<SampleInfo> mSampleInfos;
+    List<SampleInfo>    mSampleInfos;
+    List<MediaBuffer *> mChunkSamples;
+    List<off_t>         mChunkOffsets;
+
+    struct StscTableEntry {
+
+        StscTableEntry(uint32_t chunk, uint32_t samples, uint32_t id)
+            : firstChunk(chunk),
+              samplesPerChunk(samples),
+              sampleDescriptionId(id) {}
+
+        uint32_t firstChunk;
+        uint32_t samplesPerChunk;
+        uint32_t sampleDescriptionId;
+    };
+    List<StscTableEntry> mStscTableEntries;
+
+    List<int32_t> mStssTableEntries;
 
     void *mCodecSpecificData;
     size_t mCodecSpecificDataSize;
+    bool mGotAllCodecSpecificData;
 
     bool mReachedEOS;
 
     static void *ThreadWrapper(void *me);
     void threadEntry();
 
+    status_t makeAVCCodecSpecificData(
+            const uint8_t *data, size_t size);
+    void writeOneChunk(bool isAvc);
+
     Track(const Track &);
     Track &operator=(const Track &);
 };
 
+#define USE_NALLEN_FOUR         1
+
 MPEG4Writer::MPEG4Writer(const char *filename)
     : mFile(fopen(filename, "wb")),
       mOffset(0),
-      mMdatOffset(0) {
+      mMdatOffset(0),
+      mInterleaveDurationUs(500000) {
     CHECK(mFile != NULL);
 }
 
 MPEG4Writer::MPEG4Writer(int fd)
     : mFile(fdopen(fd, "wb")),
       mOffset(0),
-      mMdatOffset(0) {
+      mMdatOffset(0),
+      mInterleaveDurationUs(500000) {
     CHECK(mFile != NULL);
 }
 
@@ -200,9 +230,20 @@
     mFile = NULL;
 }
 
-off_t MPEG4Writer::addSample(MediaBuffer *buffer) {
-    Mutex::Autolock autoLock(mLock);
+status_t MPEG4Writer::setInterleaveDuration(uint32_t durationUs) {
+    mInterleaveDurationUs = durationUs;
+    return OK;
+}
 
+void MPEG4Writer::lock() {
+    mLock.lock();
+}
+
+void MPEG4Writer::unlock() {
+    mLock.unlock();
+}
+
+off_t MPEG4Writer::addSample_l(MediaBuffer *buffer) {
     off_t old_offset = mOffset;
 
     fwrite((const uint8_t *)buffer->data() + buffer->range_offset(),
@@ -213,23 +254,53 @@
     return old_offset;
 }
 
-off_t MPEG4Writer::addLengthPrefixedSample(MediaBuffer *buffer) {
-    Mutex::Autolock autoLock(mLock);
+static void StripStartcode(MediaBuffer *buffer) {
+    if (buffer->range_length() < 4) {
+        return;
+    }
+
+    const uint8_t *ptr =
+        (const uint8_t *)buffer->data() + buffer->range_offset();
+
+    if (!memcmp(ptr, "\x00\x00\x00\x01", 4)) {
+        buffer->set_range(
+                buffer->range_offset() + 4, buffer->range_length() - 4);
+    }
+}
+
+off_t MPEG4Writer::addLengthPrefixedSample_l(MediaBuffer *buffer) {
+    StripStartcode(buffer);
 
     off_t old_offset = mOffset;
 
     size_t length = buffer->range_length();
+
+#if USE_NALLEN_FOUR
+    uint8_t x = length >> 24;
+    fwrite(&x, 1, 1, mFile);
+    x = (length >> 16) & 0xff;
+    fwrite(&x, 1, 1, mFile);
+    x = (length >> 8) & 0xff;
+    fwrite(&x, 1, 1, mFile);
+    x = length & 0xff;
+    fwrite(&x, 1, 1, mFile);
+#else
     CHECK(length < 65536);
 
     uint8_t x = length >> 8;
     fwrite(&x, 1, 1, mFile);
     x = length & 0xff;
     fwrite(&x, 1, 1, mFile);
+#endif
 
     fwrite((const uint8_t *)buffer->data() + buffer->range_offset(),
            1, length, mFile);
 
+#if USE_NALLEN_FOUR
+    mOffset += length + 4;
+#else
     mOffset += length + 2;
+#endif
 
     return old_offset;
 }
@@ -320,6 +391,7 @@
       mMaxTimeStampUs(0),
       mCodecSpecificData(NULL),
       mCodecSpecificDataSize(0),
+      mGotAllCodecSpecificData(false),
       mReachedEOS(false) {
 }
 
@@ -380,73 +452,162 @@
     return NULL;
 }
 
+#include <ctype.h>
+static void hexdump(const void *_data, size_t size) {
+    const uint8_t *data = (const uint8_t *)_data;
+    size_t offset = 0;
+    while (offset < size) {
+        printf("0x%04x  ", offset);
+
+        size_t n = size - offset;
+        if (n > 16) {
+            n = 16;
+        }
+
+        for (size_t i = 0; i < 16; ++i) {
+            if (i == 8) {
+                printf(" ");
+            }
+
+            if (offset + i < size) {
+                printf("%02x ", data[offset + i]);
+            } else {
+                printf("   ");
+            }
+        }
+
+        printf(" ");
+
+        for (size_t i = 0; i < n; ++i) {
+            if (isprint(data[offset + i])) {
+                printf("%c", data[offset + i]);
+            } else {
+                printf(".");
+            }
+        }
+
+        printf("\n");
+
+        offset += 16;
+    }
+}
+
+
+status_t MPEG4Writer::Track::makeAVCCodecSpecificData(
+        const uint8_t *data, size_t size) {
+    // hexdump(data, size);
+
+    if (mCodecSpecificData != NULL) {
+        LOGE("Already have codec specific data");
+        return ERROR_MALFORMED;
+    }
+
+    if (size < 4 || memcmp("\x00\x00\x00\x01", data, 4)) {
+        LOGE("Must start with a start code");
+        return ERROR_MALFORMED;
+    }
+
+    size_t picParamOffset = 4;
+    while (picParamOffset + 3 < size
+            && memcmp("\x00\x00\x00\x01", &data[picParamOffset], 4)) {
+        ++picParamOffset;
+    }
+
+    if (picParamOffset + 3 >= size) {
+        LOGE("Could not find start-code for pictureParameterSet");
+        return ERROR_MALFORMED;
+    }
+
+    size_t seqParamSetLength = picParamOffset - 4;
+    size_t picParamSetLength = size - picParamOffset - 4;
+
+    mCodecSpecificDataSize =
+        6 + 1 + seqParamSetLength + 2 + picParamSetLength + 2;
+
+    mCodecSpecificData = malloc(mCodecSpecificDataSize);
+    uint8_t *header = (uint8_t *)mCodecSpecificData;
+    header[0] = 1;
+    header[1] = 0x42;  // profile
+    header[2] = 0x80;
+    header[3] = 0x1e;  // level
+
+#if USE_NALLEN_FOUR
+    header[4] = 0xfc | 3;  // length size == 4 bytes
+#else
+    header[4] = 0xfc | 1;  // length size == 2 bytes
+#endif
+
+    header[5] = 0xe0 | 1;
+    header[6] = seqParamSetLength >> 8;
+    header[7] = seqParamSetLength & 0xff;
+    memcpy(&header[8], &data[4], seqParamSetLength);
+    header += 8 + seqParamSetLength;
+    header[0] = 1;
+    header[1] = picParamSetLength >> 8;
+    header[2] = picParamSetLength & 0xff;
+    memcpy(&header[3], &data[picParamOffset + 4], picParamSetLength);
+
+    return OK;
+}
+
 void MPEG4Writer::Track::threadEntry() {
     sp<MetaData> meta = mSource->getFormat();
     const char *mime;
     meta->findCString(kKeyMIMEType, &mime);
-    bool is_mpeg4 = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4);
+    bool is_mpeg4 = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) ||
+                    !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC);
     bool is_avc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC);
     int32_t count = 0;
+    const int64_t interleaveDurationUs = mOwner->interleaveDuration();
+    int64_t chunkTimestampUs = 0;
+    int32_t nChunks = 0;
+    int32_t nZeroLengthFrames = 0;
 
     MediaBuffer *buffer;
     while (!mDone && mSource->read(&buffer) == OK) {
         if (buffer->range_length() == 0) {
             buffer->release();
             buffer = NULL;
-
+            ++nZeroLengthFrames;
             continue;
         }
 
         ++count;
 
-        if (is_avc && count < 3) {
-            size_t size = buffer->range_length();
+        int32_t isCodecConfig;
+        if (buffer->meta_data()->findInt32(kKeyIsCodecConfig, &isCodecConfig)
+                && isCodecConfig) {
+            CHECK(!mGotAllCodecSpecificData);
 
-            switch (count) {
-                case 1:
-                {
-                    CHECK_EQ(mCodecSpecificData, NULL);
-                    mCodecSpecificData = malloc(size + 8);
-                    uint8_t *header = (uint8_t *)mCodecSpecificData;
-                    header[0] = 1;
-                    header[1] = 0x42;  // profile
-                    header[2] = 0x80;
-                    header[3] = 0x1e;  // level
-                    header[4] = 0xfc | 3;
-                    header[5] = 0xe0 | 1;
-                    header[6] = size >> 8;
-                    header[7] = size & 0xff;
-                    memcpy(&header[8],
-                            (const uint8_t *)buffer->data() + buffer->range_offset(),
-                            size);
+            if (is_avc) {
+                status_t err = makeAVCCodecSpecificData(
+                        (const uint8_t *)buffer->data()
+                            + buffer->range_offset(),
+                        buffer->range_length());
 
-                    mCodecSpecificDataSize = size + 8;
+                if (err != OK) {
+                    LOGE("failed to parse avc codec specific data.");
                     break;
                 }
-
-                case 2:
-                {
-                    size_t offset = mCodecSpecificDataSize;
-                    mCodecSpecificDataSize += size + 3;
-                    mCodecSpecificData = realloc(mCodecSpecificData, mCodecSpecificDataSize);
-                    uint8_t *header = (uint8_t *)mCodecSpecificData;
-                    header[offset] = 1;
-                    header[offset + 1] = size >> 8;
-                    header[offset + 2] = size & 0xff;
-                    memcpy(&header[offset + 3],
-                            (const uint8_t *)buffer->data() + buffer->range_offset(),
-                            size);
-                    break;
-                }
+            } else if (is_mpeg4) {
+                mCodecSpecificDataSize = buffer->range_length();
+                mCodecSpecificData = malloc(mCodecSpecificDataSize);
+                memcpy(mCodecSpecificData,
+                        (const uint8_t *)buffer->data()
+                            + buffer->range_offset(),
+                       buffer->range_length());
             }
 
             buffer->release();
             buffer = NULL;
 
+            mGotAllCodecSpecificData = true;
             continue;
-        }
+        } else if (!mGotAllCodecSpecificData &&
+                count == 1 && is_mpeg4 && mCodecSpecificData == NULL) {
+            // The TI mpeg4 encoder does not properly set the
+            // codec-specific-data flag.
 
-        if (mCodecSpecificData == NULL && is_mpeg4) {
             const uint8_t *data =
                 (const uint8_t *)buffer->data() + buffer->range_offset();
 
@@ -474,14 +635,72 @@
             memcpy(mCodecSpecificData, data, offset);
 
             buffer->set_range(buffer->range_offset() + offset, size - offset);
+
+            if (size == offset) {
+                buffer->release();
+                buffer = NULL;
+
+                continue;
+            }
+
+            mGotAllCodecSpecificData = true;
+        } else if (!mGotAllCodecSpecificData && is_avc && count < 3) {
+            // The TI video encoder does not flag codec specific data
+            // as such and also splits up SPS and PPS across two buffers.
+
+            const uint8_t *data =
+                (const uint8_t *)buffer->data() + buffer->range_offset();
+
+            size_t size = buffer->range_length();
+
+            CHECK(count == 2 || mCodecSpecificData == NULL);
+
+            size_t offset = mCodecSpecificDataSize;
+            mCodecSpecificDataSize += size + 4;
+            mCodecSpecificData =
+                realloc(mCodecSpecificData, mCodecSpecificDataSize);
+
+            memcpy((uint8_t *)mCodecSpecificData + offset,
+                   "\x00\x00\x00\x01", 4);
+
+            memcpy((uint8_t *)mCodecSpecificData + offset + 4, data, size);
+
+            buffer->release();
+            buffer = NULL;
+
+            if (count == 2) {
+                void *tmp = mCodecSpecificData;
+                size = mCodecSpecificDataSize;
+                mCodecSpecificData = NULL;
+                mCodecSpecificDataSize = 0;
+
+                status_t err = makeAVCCodecSpecificData(
+                        (const uint8_t *)tmp, size);
+
+                free(tmp);
+                tmp = NULL;
+
+                if (err != OK) {
+                    LOGE("failed to parse avc codec specific data.");
+                    break;
+                }
+
+                mGotAllCodecSpecificData = true;
+            }
+
+            continue;
         }
 
-        off_t offset = is_avc ? mOwner->addLengthPrefixedSample(buffer)
-                              : mOwner->addSample(buffer);
-
         SampleInfo info;
-        info.size = is_avc ? buffer->range_length() + 2 : buffer->range_length();
-        info.offset = offset;
+        info.size = is_avc
+#if USE_NALLEN_FOUR
+                ? buffer->range_length() + 4
+#else
+                ? buffer->range_length() + 2
+#endif
+                : buffer->range_length();
+
+        bool is_audio = !strncasecmp(mime, "audio/", 6);
 
         int64_t timestampUs;
         CHECK(buffer->meta_data()->findInt64(kKeyTime, &timestampUs));
@@ -492,14 +711,80 @@
 
         // Our timestamp is in ms.
         info.timestamp = (timestampUs + 500) / 1000;
-
         mSampleInfos.push_back(info);
 
+////////////////////////////////////////////////////////////////////////////////
+        // Make a deep copy of the MediaBuffer less Metadata
+        MediaBuffer *copy = new MediaBuffer(buffer->range_length());
+        memcpy(copy->data(), (uint8_t *)buffer->data() + buffer->range_offset(),
+                buffer->range_length());
+        copy->set_range(0, buffer->range_length());
+
+        mChunkSamples.push_back(copy);
+        if (interleaveDurationUs == 0) {
+            StscTableEntry stscEntry(++nChunks, 1, 1);
+            mStscTableEntries.push_back(stscEntry);
+            writeOneChunk(is_avc);
+        } else {
+            if (chunkTimestampUs == 0) {
+                chunkTimestampUs = timestampUs;
+            } else {
+                if (timestampUs - chunkTimestampUs > interleaveDurationUs) {
+                    ++nChunks;
+                    if (nChunks == 1 ||  // First chunk
+                        (--(mStscTableEntries.end()))->samplesPerChunk !=
+                         mChunkSamples.size()) {
+                        StscTableEntry stscEntry(nChunks,
+                                mChunkSamples.size(), 1);
+                        mStscTableEntries.push_back(stscEntry);
+                    }
+                    writeOneChunk(is_avc);
+                    chunkTimestampUs = timestampUs;
+                }
+            }
+        }
+
+        int32_t isSync = false;
+        if (buffer->meta_data()->findInt32(kKeyIsSyncFrame, &isSync) &&
+            isSync != 0) {
+            mStssTableEntries.push_back(mSampleInfos.size());
+        }
+        // Our timestamp is in ms.
         buffer->release();
         buffer = NULL;
     }
 
+    // Last chunk
+    if (!mChunkSamples.empty()) {
+        ++nChunks;
+        StscTableEntry stscEntry(nChunks, mChunkSamples.size(), 1);
+        mStscTableEntries.push_back(stscEntry);
+        writeOneChunk(is_avc);
+    }
+
     mReachedEOS = true;
+    LOGI("Received total/0-length (%d/%d) buffers and encoded %d frames",
+            count, nZeroLengthFrames, mSampleInfos.size());
+}
+
+void MPEG4Writer::Track::writeOneChunk(bool isAvc) {
+    mOwner->lock();
+    for (List<MediaBuffer *>::iterator it = mChunkSamples.begin();
+         it != mChunkSamples.end(); ++it) {
+        off_t offset = isAvc? mOwner->addLengthPrefixedSample_l(*it)
+                            : mOwner->addSample_l(*it);
+        if (it == mChunkSamples.begin()) {
+            mChunkOffsets.push_back(offset);
+        }
+    }
+    mOwner->unlock();
+    while (!mChunkSamples.empty()) {
+        List<MediaBuffer *>::iterator it = mChunkSamples.begin();
+        (*it)->release();
+        (*it) = NULL;
+        mChunkSamples.erase(it);
+    }
+    mChunkSamples.clear();
 }
 
 int64_t MPEG4Writer::Track::getDurationUs() const {
@@ -550,8 +835,8 @@
             success = success && mMeta->findInt32(kKeyHeight, &height);
             CHECK(success);
 
-            mOwner->writeInt32(width);
-            mOwner->writeInt32(height);
+            mOwner->writeInt32(width << 16);   // 32-bit fixed-point value
+            mOwner->writeInt32(height << 16);  // 32-bit fixed-point value
         }
       mOwner->endBox();  // tkhd
 
@@ -569,26 +854,15 @@
 
         mOwner->beginBox("hdlr");
           mOwner->writeInt32(0);             // version=0, flags=0
-          mOwner->writeInt32(0);             // predefined
-          mOwner->writeFourcc(is_audio ? "soun" : "vide");
+          mOwner->writeInt32(0);             // component type: should be mhlr
+          mOwner->writeFourcc(is_audio ? "soun" : "vide");  // component subtype
           mOwner->writeInt32(0);             // reserved
           mOwner->writeInt32(0);             // reserved
           mOwner->writeInt32(0);             // reserved
-          mOwner->writeCString("");          // name
+          mOwner->writeCString("SoundHandler");          // name
         mOwner->endBox();
 
         mOwner->beginBox("minf");
-
-          mOwner->beginBox("dinf");
-            mOwner->beginBox("dref");
-              mOwner->writeInt32(0);  // version=0, flags=0
-              mOwner->writeInt32(1);
-              mOwner->beginBox("url ");
-                mOwner->writeInt32(1);  // version=0, flags=1
-              mOwner->endBox();  // url
-            mOwner->endBox();  // dref
-          mOwner->endBox();  // dinf
-
           if (is_audio) {
               mOwner->beginBox("smhd");
               mOwner->writeInt32(0);           // version=0, flags=0
@@ -604,7 +878,18 @@
               mOwner->writeInt16(0);
               mOwner->endBox();
           }
-        mOwner->endBox();  // minf
+
+          mOwner->beginBox("dinf");
+            mOwner->beginBox("dref");
+              mOwner->writeInt32(0);  // version=0, flags=0
+              mOwner->writeInt32(1);
+              mOwner->beginBox("url ");
+                mOwner->writeInt32(1);  // version=0, flags=1
+              mOwner->endBox();  // url
+            mOwner->endBox();  // dref
+          mOwner->endBox();  // dinf
+
+       mOwner->endBox();  // minf
 
         mOwner->beginBox("stbl");
 
@@ -617,6 +902,8 @@
                     fourcc = "samr";
                 } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) {
                     fourcc = "sawb";
+                } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) {
+                    fourcc = "mp4a";
                 } else {
                     LOGE("Unknown mime type '%s'.", mime);
                     CHECK(!"should not be here, unknown mime type.");
@@ -625,10 +912,12 @@
                 mOwner->beginBox(fourcc);          // audio format
                   mOwner->writeInt32(0);           // reserved
                   mOwner->writeInt16(0);           // reserved
-                  mOwner->writeInt16(0);           // data ref index
+                  mOwner->writeInt16(0x1);         // data ref index
                   mOwner->writeInt32(0);           // reserved
                   mOwner->writeInt32(0);           // reserved
-                  mOwner->writeInt16(2);           // channel count
+                  int32_t nChannels;
+                  CHECK_EQ(true, mMeta->findInt32(kKeyChannelCount, &nChannels));
+                  mOwner->writeInt16(nChannels);   // channel count
                   mOwner->writeInt16(16);          // sample size
                   mOwner->writeInt16(0);           // predefined
                   mOwner->writeInt16(0);           // reserved
@@ -638,6 +927,38 @@
                   CHECK(success);
 
                   mOwner->writeInt32(samplerate << 16);
+                  if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) {
+                    mOwner->beginBox("esds");
+
+                        mOwner->writeInt32(0);     // version=0, flags=0
+                        mOwner->writeInt8(0x03);   // ES_DescrTag
+                        mOwner->writeInt8(23 + mCodecSpecificDataSize);
+                        mOwner->writeInt16(0x0000);// ES_ID
+                        mOwner->writeInt8(0x00);
+
+                        mOwner->writeInt8(0x04);   // DecoderConfigDescrTag
+                        mOwner->writeInt8(15 + mCodecSpecificDataSize);
+                        mOwner->writeInt8(0x40);   // objectTypeIndication ISO/IEC 14492-2
+                        mOwner->writeInt8(0x15);   // streamType AudioStream
+
+                        mOwner->writeInt16(0x03);  // XXX
+                        mOwner->writeInt8(0x00);   // buffer size 24-bit
+                        mOwner->writeInt32(96000); // max bit rate
+                        mOwner->writeInt32(96000); // avg bit rate
+
+                        mOwner->writeInt8(0x05);   // DecoderSpecificInfoTag
+                        mOwner->writeInt8(mCodecSpecificDataSize);
+                        mOwner->write(mCodecSpecificData, mCodecSpecificDataSize);
+
+                        static const uint8_t kData2[] = {
+                            0x06,  // SLConfigDescriptorTag
+                            0x01,
+                            0x02
+                        };
+                        mOwner->write(kData2, sizeof(kData2));
+
+                    mOwner->endBox();  // esds
+                  }
                 mOwner->endBox();
             } else {
                 if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
@@ -698,7 +1019,7 @@
                             0x00, 0x03, 0xe8, 0x00
                         };
                         mOwner->write(kData, sizeof(kData));
-                        
+
                         mOwner->writeInt8(0x05);  // DecoderSpecificInfoTag
 
                         mOwner->writeInt8(mCodecSpecificDataSize);
@@ -733,21 +1054,42 @@
 
           mOwner->beginBox("stts");
             mOwner->writeInt32(0);  // version=0, flags=0
-            mOwner->writeInt32(mSampleInfos.size() - 1);
+            mOwner->writeInt32(mSampleInfos.size());
 
             List<SampleInfo>::iterator it = mSampleInfos.begin();
             int64_t last = (*it).timestamp;
+            int64_t lastDuration = 1;
+
             ++it;
             while (it != mSampleInfos.end()) {
                 mOwner->writeInt32(1);
-                mOwner->writeInt32((*it).timestamp - last);
+                lastDuration = (*it).timestamp - last;
+                mOwner->writeInt32(lastDuration);
 
                 last = (*it).timestamp;
 
                 ++it;
             }
+
+            // We don't really know how long the last frame lasts, since
+            // there is no frame time after it, just repeat the previous
+            // frame's duration.
+            mOwner->writeInt32(1);
+            mOwner->writeInt32(lastDuration);
+
           mOwner->endBox();  // stts
 
+          if (!is_audio) {
+            mOwner->beginBox("stss");
+              mOwner->writeInt32(0);  // version=0, flags=0
+              mOwner->writeInt32(mStssTableEntries.size());  // number of sync frames
+              for (List<int32_t>::iterator it = mStssTableEntries.begin();
+                   it != mStssTableEntries.end(); ++it) {
+                  mOwner->writeInt32(*it);
+              }
+            mOwner->endBox();  // stss
+          }
+
           mOwner->beginBox("stsz");
             mOwner->writeInt32(0);  // version=0, flags=0
             mOwner->writeInt32(0);  // default sample size
@@ -760,22 +1102,21 @@
 
           mOwner->beginBox("stsc");
             mOwner->writeInt32(0);  // version=0, flags=0
-            mOwner->writeInt32(mSampleInfos.size());
-            int32_t n = 1;
-            for (List<SampleInfo>::iterator it = mSampleInfos.begin();
-                 it != mSampleInfos.end(); ++it, ++n) {
-                mOwner->writeInt32(n);
-                mOwner->writeInt32(1);
-                mOwner->writeInt32(1);
+            mOwner->writeInt32(mStscTableEntries.size());
+            for (List<StscTableEntry>::iterator it = mStscTableEntries.begin();
+                 it != mStscTableEntries.end(); ++it) {
+                mOwner->writeInt32(it->firstChunk);
+                mOwner->writeInt32(it->samplesPerChunk);
+                mOwner->writeInt32(it->sampleDescriptionId);
             }
           mOwner->endBox();  // stsc
 
           mOwner->beginBox("co64");
             mOwner->writeInt32(0);  // version=0, flags=0
-            mOwner->writeInt32(mSampleInfos.size());
-            for (List<SampleInfo>::iterator it = mSampleInfos.begin();
-                 it != mSampleInfos.end(); ++it, ++n) {
-                mOwner->writeInt64((*it).offset);
+            mOwner->writeInt32(mChunkOffsets.size());
+            for (List<off_t>::iterator it = mChunkOffsets.begin();
+                 it != mChunkOffsets.end(); ++it) {
+                mOwner->writeInt64((*it));
             }
           mOwner->endBox();  // co64
 
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 6ed384c..b7d6d42 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -137,6 +137,7 @@
     { 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.qcom.video.encoder.avc" },
     { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.TI.Video.encoder" },
     { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.PV.avcenc" },
 };
@@ -519,6 +520,7 @@
 
         setAACFormat(numChannels, sampleRate);
     }
+
     if (!strncasecmp(mMIME, "video/", 6)) {
         int32_t width, height;
         bool success = meta->findInt32(kKeyWidth, &width);
@@ -566,7 +568,8 @@
     }
 
     if (!strcmp(mComponentName, "OMX.TI.AMR.encode")
-        || !strcmp(mComponentName, "OMX.TI.WBAMR.encode")) {
+        || !strcmp(mComponentName, "OMX.TI.WBAMR.encode")
+        || !strcmp(mComponentName, "OMX.TI.AAC.encode")) {
         setMinBufferSize(kPortIndexOutput, 8192);  // XXX
     }
 
@@ -679,6 +682,7 @@
         case OMX_COLOR_FormatCbYCrY:
             return width * height * 2;
 
+        case OMX_COLOR_FormatYUV420Planar:
         case OMX_COLOR_FormatYUV420SemiPlanar:
             return (width * height * 3) / 2;
 
@@ -709,21 +713,46 @@
         colorFormat = OMX_COLOR_FormatYCbYCr;
     }
 
+
+
+    status_t err;
+    OMX_PARAM_PORTDEFINITIONTYPE def;
+    OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
+
+    //////////////////////// Input port /////////////////////////
     CHECK_EQ(setVideoPortFormatType(
             kPortIndexInput, OMX_VIDEO_CodingUnused,
             colorFormat), OK);
+    InitOMXParams(&def);
+    def.nPortIndex = kPortIndexInput;
 
+    err = mOMX->getParameter(
+            mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+    CHECK_EQ(err, OK);
+
+    def.nBufferSize = getFrameSize(colorFormat, width, height);
+
+    CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
+
+    video_def->nFrameWidth = width;
+    video_def->nFrameHeight = height;
+    video_def->eCompressionFormat = OMX_VIDEO_CodingUnused;
+    video_def->eColorFormat = colorFormat;
+
+    video_def->xFramerate = (24 << 16);  // Q16 format
+
+    err = mOMX->setParameter(
+            mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+    CHECK_EQ(err, OK);
+
+    //////////////////////// Output port /////////////////////////
     CHECK_EQ(setVideoPortFormatType(
             kPortIndexOutput, compressionFormat, OMX_COLOR_FormatUnused),
             OK);
-
-    OMX_PARAM_PORTDEFINITIONTYPE def;
     InitOMXParams(&def);
     def.nPortIndex = kPortIndexOutput;
 
-    OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
-
-    status_t err = mOMX->getParameter(
+    err = mOMX->getParameter(
             mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
 
     CHECK_EQ(err, OK);
@@ -739,31 +768,7 @@
             mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
     CHECK_EQ(err, OK);
 
-    ////////////////////////////////////////////////////////////////////////////
-
-    InitOMXParams(&def);
-    def.nPortIndex = kPortIndexInput;
-
-    err = mOMX->getParameter(
-            mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
-    CHECK_EQ(err, OK);
-
-    def.nBufferSize = getFrameSize(colorFormat, width, height);
-    CODEC_LOGV("Setting nBufferSize = %ld", def.nBufferSize);
-
-    CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
-
-    video_def->nFrameWidth = width;
-    video_def->nFrameHeight = height;
-    video_def->eCompressionFormat = OMX_VIDEO_CodingUnused;
-    video_def->eColorFormat = colorFormat;
-
-    video_def->xFramerate = 24 << 16;  // XXX crucial!
-
-    err = mOMX->setParameter(
-            mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
-    CHECK_EQ(err, OK);
-
+    /////////////////// Codec-specific ////////////////////////
     switch (compressionFormat) {
         case OMX_VIDEO_CodingMPEG4:
         {
@@ -911,7 +916,7 @@
     CHECK_EQ(err, OK);
 
     bitrateType.eControlRate = OMX_Video_ControlRateVariable;
-    bitrateType.nTargetBitrate = 1000000;
+    bitrateType.nTargetBitrate = 3000000;
 
     err = mOMX->setParameter(
             mNode, OMX_IndexParamVideoBitrate,
@@ -2124,11 +2129,24 @@
 
 void OMXCodec::setRawAudioFormat(
         OMX_U32 portIndex, int32_t sampleRate, int32_t numChannels) {
+
+    // port definition
+    OMX_PARAM_PORTDEFINITIONTYPE def;
+    InitOMXParams(&def);
+    def.nPortIndex = portIndex;
+    status_t err = mOMX->getParameter(
+            mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
+    CHECK_EQ(err, OK);
+    def.format.audio.eEncoding = OMX_AUDIO_CodingPCM;
+    CHECK_EQ(mOMX->setParameter(mNode, OMX_IndexParamPortDefinition,
+            &def, sizeof(def)), OK);
+
+    // pcm param
     OMX_AUDIO_PARAM_PCMMODETYPE pcmParams;
     InitOMXParams(&pcmParams);
     pcmParams.nPortIndex = portIndex;
 
-    status_t err = mOMX->getParameter(
+    err = mOMX->getParameter(
             mNode, OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams));
 
     CHECK_EQ(err, OK);
@@ -2168,6 +2186,8 @@
     CHECK_EQ(err, OK);
 
     def.eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF;
+
+    // XXX: Select bandmode based on bit rate
     def.eAMRBandMode =
         isWAMR ? OMX_AUDIO_AMRBandModeWB0 : OMX_AUDIO_AMRBandModeNB0;
 
@@ -2188,8 +2208,60 @@
 }
 
 void OMXCodec::setAACFormat(int32_t numChannels, int32_t sampleRate) {
+    CHECK(numChannels == 1 || numChannels == 2);
     if (mIsEncoder) {
+        //////////////// input port ////////////////////
         setRawAudioFormat(kPortIndexInput, sampleRate, numChannels);
+
+        //////////////// output port ////////////////////
+        // format
+        OMX_AUDIO_PARAM_PORTFORMATTYPE format;
+        format.nPortIndex = kPortIndexOutput;
+        format.nIndex = 0;
+        status_t err = OMX_ErrorNone;
+        while (OMX_ErrorNone == err) {
+            CHECK_EQ(mOMX->getParameter(mNode, OMX_IndexParamAudioPortFormat,
+                    &format, sizeof(format)), OK);
+            if (format.eEncoding == OMX_AUDIO_CodingAAC) {
+                break;
+            }
+            format.nIndex++;
+        }
+        CHECK_EQ(OK, err);
+        CHECK_EQ(mOMX->setParameter(mNode, OMX_IndexParamAudioPortFormat,
+                &format, sizeof(format)), OK);
+
+        // port definition
+        OMX_PARAM_PORTDEFINITIONTYPE def;
+        InitOMXParams(&def);
+        def.nPortIndex = kPortIndexOutput;
+        CHECK_EQ(mOMX->getParameter(mNode, OMX_IndexParamPortDefinition,
+                &def, sizeof(def)), OK);
+        def.format.audio.bFlagErrorConcealment = OMX_TRUE;
+        def.format.audio.eEncoding = OMX_AUDIO_CodingAAC;
+        CHECK_EQ(mOMX->setParameter(mNode, OMX_IndexParamPortDefinition,
+                &def, sizeof(def)), OK);
+
+        // profile
+        OMX_AUDIO_PARAM_AACPROFILETYPE profile;
+        InitOMXParams(&profile);
+        profile.nPortIndex = kPortIndexOutput;
+        CHECK_EQ(mOMX->getParameter(mNode, OMX_IndexParamAudioAac,
+                &profile, sizeof(profile)), OK);
+        profile.nChannels = numChannels;
+        profile.eChannelMode = (numChannels == 1?
+                OMX_AUDIO_ChannelModeMono: OMX_AUDIO_ChannelModeStereo);
+        profile.nSampleRate = sampleRate;
+        profile.nBitRate = 96000;   // XXX
+        profile.nAudioBandWidth = 0;
+        profile.nFrameLength = 0;
+        profile.nAACtools = OMX_AUDIO_AACToolAll;
+        profile.nAACERtools = OMX_AUDIO_AACERNone;
+        profile.eAACProfile = OMX_AUDIO_AACObjectLC;
+        profile.eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4FF;
+        CHECK_EQ(mOMX->setParameter(mNode, OMX_IndexParamAudioAac,
+                &profile, sizeof(profile)), OK);
+
     } else {
         OMX_AUDIO_PARAM_AACPROFILETYPE profile;
         InitOMXParams(&profile);
@@ -2958,6 +3030,11 @@
             } else if (audio_def->eEncoding == OMX_AUDIO_CodingAAC) {
                 mOutputFormat->setCString(
                         kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC);
+                int32_t numChannels, sampleRate;
+                inputFormat->findInt32(kKeyChannelCount, &numChannels);
+                inputFormat->findInt32(kKeySampleRate, &sampleRate);
+                mOutputFormat->setInt32(kKeyChannelCount, numChannels);
+                mOutputFormat->setInt32(kKeySampleRate, sampleRate);
             } else {
                 CHECK(!"Should not be here. Unknown audio encoding.");
             }
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index c1a010c..5db516e 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -264,6 +264,8 @@
         return UNKNOWN_ERROR;
     }
 
+    CHECK_EQ(header->pAppPrivate, buffer_meta);
+
     *buffer = header;
 
     addActiveBuffer(portIndex, *buffer);
@@ -294,6 +296,8 @@
         return UNKNOWN_ERROR;
     }
 
+    CHECK_EQ(header->pAppPrivate, buffer_meta);
+
     *buffer = header;
     *buffer_data = header->pBuffer;
 
@@ -325,6 +329,8 @@
         return UNKNOWN_ERROR;
     }
 
+    CHECK_EQ(header->pAppPrivate, buffer_meta);
+
     *buffer = header;
 
     addActiveBuffer(portIndex, *buffer);