Merge "stagefright: Do not add silence data for compress offload" into lmp-dev
diff --git a/include/media/MediaCodecInfo.h b/include/media/MediaCodecInfo.h
index ab7a4b8..cd56adb 100644
--- a/include/media/MediaCodecInfo.h
+++ b/include/media/MediaCodecInfo.h
@@ -107,6 +107,7 @@
     status_t initializeCapabilities(const CodecCapabilities &caps);
     void addDetail(const AString &key, const AString &value);
     void addFeature(const AString &key, int32_t value);
+    void addFeature(const AString &key, const char *value);
     void removeMime(const char *mime);
     void complete();
 
diff --git a/media/libmedia/MediaCodecInfo.cpp b/media/libmedia/MediaCodecInfo.cpp
index 446c582..7b4c4e2 100644
--- a/media/libmedia/MediaCodecInfo.cpp
+++ b/media/libmedia/MediaCodecInfo.cpp
@@ -257,4 +257,10 @@
     mCurrentCaps->mDetails->setInt32(tag.c_str(), value);
 }
 
+void MediaCodecInfo::addFeature(const AString &key, const char *value) {
+    AString tag = "feature-";
+    tag.append(key);
+    mCurrentCaps->mDetails->setString(tag.c_str(), value);
+}
+
 }  // namespace android
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index 6676461..76e1d54 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -192,9 +192,26 @@
 }
 
 NuPlayer::GenericSource::~GenericSource() {
+    if (mLooper != NULL) {
+        mLooper->unregisterHandler(id());
+        mLooper->stop();
+    }
 }
 
 void NuPlayer::GenericSource::prepareAsync() {
+    if (mLooper == NULL) {
+        mLooper = new ALooper;
+        mLooper->setName("generic");
+        mLooper->start();
+
+        mLooper->registerHandler(this);
+    }
+
+    sp<AMessage> msg = new AMessage(kWhatPrepareAsync, id());
+    msg->post();
+}
+
+void NuPlayer::GenericSource::onPrepareAsync() {
     // delayed data source creation
     AString sniffedMIME;
     sp<DataSource> dataSource;
@@ -267,6 +284,11 @@
 
 void NuPlayer::GenericSource::onMessageReceived(const sp<AMessage> &msg) {
     switch (msg->what()) {
+      case kWhatPrepareAsync:
+      {
+          onPrepareAsync();
+          break;
+      }
       case kWhatFetchSubtitleData:
       {
           fetchTextData(kWhatSendSubtitleData, MEDIA_TRACK_TYPE_SUBTITLE,
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h
index 44d690e..d3081de 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.h
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.h
@@ -70,6 +70,7 @@
 
 private:
     enum {
+        kWhatPrepareAsync,
         kWhatFetchSubtitleData,
         kWhatFetchTimedTextData,
         kWhatSendSubtitleData,
@@ -104,12 +105,17 @@
     int64_t mOffset;
     int64_t mLength;
 
+    sp<ALooper> mLooper;
+
+
     void resetDataSource();
 
     status_t initFromDataSource(
             const sp<DataSource> &dataSource,
             const char *mime);
 
+    void onPrepareAsync();
+
     void fetchTextData(
             uint32_t what, media_track_type type,
             int32_t curGen, sp<AnotherPacketSource> packets, sp<AMessage> msg);
diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
index c713d39..a003c81 100644
--- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
@@ -62,17 +62,24 @@
 NuPlayer::HTTPLiveSource::~HTTPLiveSource() {
     if (mLiveSession != NULL) {
         mLiveSession->disconnect();
-        mLiveSession.clear();
 
+        mLiveLooper->unregisterHandler(mLiveSession->id());
+        mLiveLooper->unregisterHandler(id());
         mLiveLooper->stop();
+
+        mLiveSession.clear();
         mLiveLooper.clear();
     }
 }
 
 void NuPlayer::HTTPLiveSource::prepareAsync() {
-    mLiveLooper = new ALooper;
-    mLiveLooper->setName("http live");
-    mLiveLooper->start();
+    if (mLiveLooper == NULL) {
+        mLiveLooper = new ALooper;
+        mLiveLooper->setName("http live");
+        mLiveLooper->start();
+
+        mLiveLooper->registerHandler(this);
+    }
 
     sp<AMessage> notify = new AMessage(kWhatSessionNotify, id());
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 9a4e811..5e7ecfa 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -147,6 +147,7 @@
       mSourceFlags(0),
       mVideoIsAVC(false),
       mOffloadAudio(false),
+      mCurrentOffloadInfo(AUDIO_INFO_INITIALIZER),
       mAudioEOS(false),
       mVideoEOS(false),
       mScanSourcesPending(false),
@@ -372,7 +373,6 @@
             CHECK(msg->findObject("source", &obj));
             if (obj != NULL) {
                 mSource = static_cast<Source *>(obj.get());
-                looper()->registerHandler(mSource);
             } else {
                 err = UNKNOWN_ERROR;
             }
@@ -639,11 +639,18 @@
             bool mHadAnySourcesBefore =
                 (mAudioDecoder != NULL) || (mVideoDecoder != NULL);
 
+            // initialize video before audio because successful initialization of
+            // video may change deep buffer mode of audio.
             if (mNativeWindow != NULL) {
                 instantiateDecoder(false, &mVideoDecoder);
             }
 
             if (mAudioSink != NULL) {
+                if (mOffloadAudio) {
+                    // open audio sink early under offload mode.
+                    sp<AMessage> format = mSource->getFormat(true /*audio*/);
+                    openAudioSink(format, true /*offloadOnly*/);
+                }
                 instantiateDecoder(true, &mAudioDecoder);
             }
 
@@ -743,138 +750,7 @@
                 CHECK(msg->findMessage("format", &format));
 
                 if (audio) {
-                    int32_t numChannels;
-                    CHECK(format->findInt32(
-                                "channel-count", &numChannels));
-
-                    int32_t sampleRate;
-                    CHECK(format->findInt32("sample-rate", &sampleRate));
-
-                    ALOGV("Audio output format changed to %d Hz, %d channels",
-                         sampleRate, numChannels);
-
-                    mAudioSink->close();
-
-                    uint32_t flags;
-                    int64_t durationUs;
-                    // FIXME: we should handle the case where the video decoder
-                    // is created after we receive the format change indication.
-                    // Current code will just make that we select deep buffer
-                    // with video which should not be a problem as it should
-                    // not prevent from keeping A/V sync.
-                    if (mVideoDecoder == NULL &&
-                            mSource->getDuration(&durationUs) == OK &&
-                            durationUs
-                                > AUDIO_SINK_MIN_DEEP_BUFFER_DURATION_US) {
-                        flags = AUDIO_OUTPUT_FLAG_DEEP_BUFFER;
-                    } else {
-                        flags = AUDIO_OUTPUT_FLAG_NONE;
-                    }
-
-                    int32_t channelMask;
-                    if (!format->findInt32("channel-mask", &channelMask)) {
-                        channelMask = CHANNEL_MASK_USE_CHANNEL_ORDER;
-                    }
-
-                    if (mOffloadAudio) {
-                        audio_format_t audioFormat = AUDIO_FORMAT_PCM_16_BIT;
-                        audio_offload_info_t offloadInfo =
-                                AUDIO_INFO_INITIALIZER;
-
-                        AString mime;
-                        CHECK(format->findString("mime", &mime));
-
-                        status_t err =
-                            mapMimeToAudioFormat(audioFormat, mime.c_str());
-                        if (err != OK) {
-                            ALOGE("Couldn't map mime \"%s\" to a valid "
-                                    "audio_format", mime.c_str());
-                            mOffloadAudio = false;
-                        } else {
-                            ALOGV("Mime \"%s\" mapped to audio_format 0x%x",
-                                    mime.c_str(), audioFormat);
-
-                            int32_t aacProfile = -1;
-                            if (audioFormat == AUDIO_FORMAT_AAC
-                                    && format->findInt32("aac-profile", &aacProfile)) {
-                                // Redefine AAC format as per aac profile
-                                mapAACProfileToAudioFormat(
-                                        audioFormat,
-                                        aacProfile);
-                            }
-
-                            flags |= AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD;
-
-                            offloadInfo.duration_us = -1;
-                            format->findInt64(
-                                    "durationUs", &offloadInfo.duration_us);
-
-                            int avgBitRate = -1;
-                            format->findInt32("bit-rate", &avgBitRate);
-
-                            offloadInfo.sample_rate = sampleRate;
-                            offloadInfo.channel_mask = channelMask;
-                            offloadInfo.format = audioFormat;
-                            offloadInfo.stream_type = AUDIO_STREAM_MUSIC;
-                            offloadInfo.bit_rate = avgBitRate;
-                            offloadInfo.has_video = (mVideoDecoder != NULL);
-                            offloadInfo.is_streaming = true;
-
-                            ALOGV("try to open AudioSink in offload mode");
-                            err = mAudioSink->open(
-                                    sampleRate,
-                                    numChannels,
-                                    (audio_channel_mask_t)channelMask,
-                                    audioFormat,
-                                    8 /* bufferCount */,
-                                    &NuPlayer::Renderer::AudioSinkCallback,
-                                    mRenderer.get(),
-                                    (audio_output_flags_t)flags,
-                                    &offloadInfo);
-
-                            if (err == OK) {
-                                // If the playback is offloaded to h/w, we pass
-                                // the HAL some metadata information.
-                                // We don't want to do this for PCM because it
-                                // will be going through the AudioFlinger mixer
-                                // before reaching the hardware.
-                                sp<MetaData> audioMeta =
-                                    mSource->getFormatMeta(true /* audio */);
-                                sendMetaDataToHal(mAudioSink, audioMeta);
-
-                                err = mAudioSink->start();
-                            }
-                        }
-
-                        if (err != OK) {
-                            // Clean up, fall back to non offload mode.
-                            mAudioSink->close();
-                            mAudioDecoder.clear();
-                            mRenderer->signalDisableOffloadAudio();
-                            mOffloadAudio = false;
-
-                            instantiateDecoder(
-                                    true /* audio */, &mAudioDecoder);
-                        }
-                    }
-
-                    if (!mOffloadAudio) {
-                        flags &= ~AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD;
-                        ALOGV("open AudioSink in NON-offload mode");
-                        CHECK_EQ(mAudioSink->open(
-                                    sampleRate,
-                                    numChannels,
-                                    (audio_channel_mask_t)channelMask,
-                                    AUDIO_FORMAT_PCM_16_BIT,
-                                    8 /* bufferCount */,
-                                    NULL,
-                                    NULL,
-                                    (audio_output_flags_t)flags),
-                                 (status_t)OK);
-                        mAudioSink->start();
-                    }
-
-                    mRenderer->signalAudioSinkChanged();
+                    openAudioSink(format, false /*offloadOnly*/);
                 } else {
                     // video
                     sp<AMessage> inputFormat =
@@ -981,7 +857,7 @@
                 ALOGV("Tear down audio offload, fall back to s/w path");
                 int64_t positionUs;
                 CHECK(msg->findInt64("positionUs", &positionUs));
-                mAudioSink->close();
+                closeAudioSink();
                 mAudioDecoder.clear();
                 mRenderer->flush(true /* audio */);
                 if (mVideoDecoder != NULL) {
@@ -1108,6 +984,148 @@
     mScanSourcesPending = true;
 }
 
+void NuPlayer::openAudioSink(const sp<AMessage> &format, bool offloadOnly) {
+    ALOGV("openAudioSink: offloadOnly(%d) mOffloadAudio(%d)",
+            offloadOnly, mOffloadAudio);
+    bool audioSinkChanged = false;
+
+    int32_t numChannels;
+    CHECK(format->findInt32("channel-count", &numChannels));
+
+    int32_t channelMask;
+    if (!format->findInt32("channel-mask", &channelMask)) {
+        // signal to the AudioSink to derive the mask from count.
+        channelMask = CHANNEL_MASK_USE_CHANNEL_ORDER;
+    }
+
+    int32_t sampleRate;
+    CHECK(format->findInt32("sample-rate", &sampleRate));
+
+    uint32_t flags;
+    int64_t durationUs;
+    // FIXME: we should handle the case where the video decoder
+    // is created after we receive the format change indication.
+    // Current code will just make that we select deep buffer
+    // with video which should not be a problem as it should
+    // not prevent from keeping A/V sync.
+    if (mVideoDecoder == NULL &&
+            mSource->getDuration(&durationUs) == OK &&
+            durationUs
+                > AUDIO_SINK_MIN_DEEP_BUFFER_DURATION_US) {
+        flags = AUDIO_OUTPUT_FLAG_DEEP_BUFFER;
+    } else {
+        flags = AUDIO_OUTPUT_FLAG_NONE;
+    }
+
+    if (mOffloadAudio) {
+        audio_format_t audioFormat = AUDIO_FORMAT_PCM_16_BIT;
+        AString mime;
+        CHECK(format->findString("mime", &mime));
+        status_t err = mapMimeToAudioFormat(audioFormat, mime.c_str());
+
+        if (err != OK) {
+            ALOGE("Couldn't map mime \"%s\" to a valid "
+                    "audio_format", mime.c_str());
+            mOffloadAudio = false;
+        } else {
+            ALOGV("Mime \"%s\" mapped to audio_format 0x%x",
+                    mime.c_str(), audioFormat);
+
+            int avgBitRate = -1;
+            format->findInt32("bit-rate", &avgBitRate);
+
+            int32_t aacProfile = -1;
+            if (audioFormat == AUDIO_FORMAT_AAC
+                    && format->findInt32("aac-profile", &aacProfile)) {
+                // Redefine AAC format as per aac profile
+                mapAACProfileToAudioFormat(
+                        audioFormat,
+                        aacProfile);
+            }
+
+            audio_offload_info_t offloadInfo = AUDIO_INFO_INITIALIZER;
+            offloadInfo.duration_us = -1;
+            format->findInt64(
+                    "durationUs", &offloadInfo.duration_us);
+            offloadInfo.sample_rate = sampleRate;
+            offloadInfo.channel_mask = channelMask;
+            offloadInfo.format = audioFormat;
+            offloadInfo.stream_type = AUDIO_STREAM_MUSIC;
+            offloadInfo.bit_rate = avgBitRate;
+            offloadInfo.has_video = (mVideoDecoder != NULL);
+            offloadInfo.is_streaming = true;
+
+            if (memcmp(&mCurrentOffloadInfo, &offloadInfo, sizeof(offloadInfo)) == 0) {
+                ALOGV("openAudioSink: no change in offload mode");
+                return;  // no change from previous configuration, everything ok.
+            }
+            ALOGV("openAudioSink: try to open AudioSink in offload mode");
+            flags |= AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD;
+            audioSinkChanged = true;
+            mAudioSink->close();
+            err = mAudioSink->open(
+                    sampleRate,
+                    numChannels,
+                    (audio_channel_mask_t)channelMask,
+                    audioFormat,
+                    8 /* bufferCount */,
+                    &NuPlayer::Renderer::AudioSinkCallback,
+                    mRenderer.get(),
+                    (audio_output_flags_t)flags,
+                    &offloadInfo);
+
+            if (err == OK) {
+                // If the playback is offloaded to h/w, we pass
+                // the HAL some metadata information.
+                // We don't want to do this for PCM because it
+                // will be going through the AudioFlinger mixer
+                // before reaching the hardware.
+                sp<MetaData> audioMeta =
+                        mSource->getFormatMeta(true /* audio */);
+                sendMetaDataToHal(mAudioSink, audioMeta);
+                mCurrentOffloadInfo = offloadInfo;
+                err = mAudioSink->start();
+                ALOGV_IF(err == OK, "openAudioSink: offload succeeded");
+            }
+            if (err != OK) {
+                // Clean up, fall back to non offload mode.
+                mAudioSink->close();
+                mRenderer->signalDisableOffloadAudio();
+                mOffloadAudio = false;
+                mCurrentOffloadInfo = AUDIO_INFO_INITIALIZER;
+                ALOGV("openAudioSink: offload failed");
+            }
+        }
+    }
+    if (!offloadOnly && !mOffloadAudio) {
+        flags &= ~AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD;
+        ALOGV("openAudioSink: open AudioSink in NON-offload mode");
+
+        audioSinkChanged = true;
+        mAudioSink->close();
+        mCurrentOffloadInfo = AUDIO_INFO_INITIALIZER;
+        CHECK_EQ(mAudioSink->open(
+                    sampleRate,
+                    numChannels,
+                    (audio_channel_mask_t)channelMask,
+                    AUDIO_FORMAT_PCM_16_BIT,
+                    8 /* bufferCount */,
+                    NULL,
+                    NULL,
+                    (audio_output_flags_t)flags),
+                 (status_t)OK);
+        mAudioSink->start();
+    }
+    if (audioSinkChanged) {
+        mRenderer->signalAudioSinkChanged();
+    }
+}
+
+void NuPlayer::closeAudioSink() {
+    mAudioSink->close();
+    mCurrentOffloadInfo = AUDIO_INFO_INITIALIZER;
+}
+
 status_t NuPlayer::instantiateDecoder(bool audio, sp<Decoder> *decoder) {
     if (*decoder != NULL) {
         return OK;
@@ -1688,8 +1706,6 @@
     if (mSource != NULL) {
         mSource->stop();
 
-        looper()->unregisterHandler(mSource->id());
-
         mSource.clear();
     }
 
@@ -1722,13 +1738,6 @@
 
     // XXX - ignore error from setVideoScalingMode for now
     setVideoScalingMode(mVideoScalingMode);
-
-    if (mDriver != NULL) {
-        sp<NuPlayerDriver> driver = mDriver.promote();
-        if (driver != NULL) {
-            driver->notifySetSurfaceComplete();
-        }
-    }
 }
 
 void NuPlayer::onSourceNotify(const sp<AMessage> &msg) {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index fc456a4..48882c5 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -124,6 +124,7 @@
     sp<Decoder> mVideoDecoder;
     bool mVideoIsAVC;
     bool mOffloadAudio;
+    audio_offload_info_t mCurrentOffloadInfo;
     sp<Decoder> mAudioDecoder;
     sp<CCDecoder> mCCDecoder;
     sp<Renderer> mRenderer;
@@ -167,6 +168,9 @@
 
     bool mStarted;
 
+    void openAudioSink(const sp<AMessage> &format, bool offloadOnly);
+    void closeAudioSink();
+
     status_t instantiateDecoder(bool audio, sp<Decoder> *decoder);
 
     void updateVideoSize(
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index e33e647..bf7542f 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -34,7 +34,6 @@
     : mState(STATE_IDLE),
       mIsAsyncPrepare(false),
       mAsyncResult(UNKNOWN_ERROR),
-      mSetSurfaceInProgress(false),
       mDurationUs(-1),
       mPositionUs(-1),
       mNumFramesTotal(0),
@@ -135,10 +134,6 @@
         const sp<IGraphicBufferProducer> &bufferProducer) {
     Mutex::Autolock autoLock(mLock);
 
-    if (mSetSurfaceInProgress) {
-        return INVALID_OPERATION;
-    }
-
     switch (mState) {
         case STATE_SET_DATASOURCE_PENDING:
         case STATE_RESET_IN_PROGRESS:
@@ -148,14 +143,8 @@
             break;
     }
 
-    mSetSurfaceInProgress = true;
-
     mPlayer->setVideoSurfaceTextureAsync(bufferProducer);
 
-    while (mSetSurfaceInProgress) {
-        mCondition.wait(mLock);
-    }
-
     return OK;
 }
 
@@ -483,15 +472,6 @@
     mCondition.broadcast();
 }
 
-void NuPlayerDriver::notifySetSurfaceComplete() {
-    Mutex::Autolock autoLock(mLock);
-
-    CHECK(mSetSurfaceInProgress);
-    mSetSurfaceInProgress = false;
-
-    mCondition.broadcast();
-}
-
 void NuPlayerDriver::notifyDuration(int64_t durationUs) {
     Mutex::Autolock autoLock(mLock);
     mDurationUs = durationUs;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
index 9424aae..a9ff8b6 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
@@ -66,7 +66,6 @@
     void notifySetDataSourceCompleted(status_t err);
     void notifyPrepareCompleted(status_t err);
     void notifyResetComplete();
-    void notifySetSurfaceComplete();
     void notifyDuration(int64_t durationUs);
     void notifyPosition(int64_t positionUs);
     void notifySeekComplete();
@@ -99,7 +98,6 @@
 
     // The following are protected through "mLock"
     // >>>
-    bool mSetSurfaceInProgress;
     int64_t mDurationUs;
     int64_t mPositionUs;
     int64_t mNumFramesTotal;
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
index a911f6c..ffacb8f 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
@@ -70,6 +70,7 @@
 
 NuPlayer::RTSPSource::~RTSPSource() {
     if (mLooper != NULL) {
+        mLooper->unregisterHandler(id());
         mLooper->stop();
     }
 }
@@ -80,14 +81,13 @@
         mLooper->setName("rtsp");
         mLooper->start();
 
-        mReflector = new AHandlerReflector<RTSPSource>(this);
-        mLooper->registerHandler(mReflector);
+        mLooper->registerHandler(this);
     }
 
     CHECK(mHandler == NULL);
     CHECK(mSDPLoader == NULL);
 
-    sp<AMessage> notify = new AMessage(kWhatNotify, mReflector->id());
+    sp<AMessage> notify = new AMessage(kWhatNotify, id());
 
     CHECK_EQ(mState, (int)DISCONNECTED);
     mState = CONNECTING;
@@ -118,7 +118,7 @@
     if (mLooper == NULL) {
         return;
     }
-    sp<AMessage> msg = new AMessage(kWhatDisconnect, mReflector->id());
+    sp<AMessage> msg = new AMessage(kWhatDisconnect, id());
 
     sp<AMessage> dummy;
     msg->postAndAwaitResponse(&dummy);
@@ -305,7 +305,7 @@
 }
 
 status_t NuPlayer::RTSPSource::seekTo(int64_t seekTimeUs) {
-    sp<AMessage> msg = new AMessage(kWhatPerformSeek, mReflector->id());
+    sp<AMessage> msg = new AMessage(kWhatPerformSeek, id());
     msg->setInt32("generation", ++mSeekGeneration);
     msg->setInt64("timeUs", seekTimeUs);
     msg->post(200000ll);
@@ -613,7 +613,7 @@
             ALOGE("Unable to find url in SDP");
             err = UNKNOWN_ERROR;
         } else {
-            sp<AMessage> notify = new AMessage(kWhatNotify, mReflector->id());
+            sp<AMessage> notify = new AMessage(kWhatNotify, id());
 
             mHandler = new MyHandler(rtspUri.c_str(), notify, mUIDValid, mUID);
             mLooper->registerHandler(mHandler);
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.h b/media/libmediaplayerservice/nuplayer/RTSPSource.h
index 3718bf9..f1cae53 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.h
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.h
@@ -22,8 +22,6 @@
 
 #include "ATSParser.h"
 
-#include <media/stagefright/foundation/AHandlerReflector.h>
-
 namespace android {
 
 struct ALooper;
@@ -102,7 +100,6 @@
     bool mBuffering;
 
     sp<ALooper> mLooper;
-    sp<AHandlerReflector<RTSPSource> > mReflector;
     sp<MyHandler> mHandler;
     sp<SDPLoader> mSDPLoader;
 
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index b77e1cd..b44d5cc 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -1419,8 +1419,10 @@
         } else {
             if (encoder) {
                 if (!msg->findInt32(
+                            "complexity", &compressionLevel) &&
+                    !msg->findInt32(
                             "flac-compression-level", &compressionLevel)) {
-                    compressionLevel = 5;// default FLAC compression level
+                    compressionLevel = 5; // default FLAC compression level
                 } else if (compressionLevel < 0) {
                     ALOGW("compression level %d outside [0..8] range, "
                           "using 0",
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index cd05c54..ab8ac79 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -103,8 +103,9 @@
 
 struct AwesomeLocalRenderer : public AwesomeRenderer {
     AwesomeLocalRenderer(
-            const sp<ANativeWindow> &nativeWindow, const sp<MetaData> &meta)
-        : mTarget(new SoftwareRenderer(nativeWindow, meta)) {
+            const sp<ANativeWindow> &nativeWindow, const sp<AMessage> &format)
+        : mFormat(format),
+          mTarget(new SoftwareRenderer(nativeWindow)) {
     }
 
     virtual void render(MediaBuffer *buffer) {
@@ -116,7 +117,7 @@
     }
 
     void render(const void *data, size_t size, int64_t timestampNs) {
-        mTarget->render(data, size, timestampNs, NULL);
+        mTarget->render(data, size, timestampNs, NULL, mFormat);
     }
 
 protected:
@@ -126,6 +127,7 @@
     }
 
 private:
+    sp<AMessage> mFormat;
     SoftwareRenderer *mTarget;
 
     AwesomeLocalRenderer(const AwesomeLocalRenderer &);
@@ -1236,7 +1238,9 @@
         // allocate their buffers in local address space.  This renderer
         // then performs a color conversion and copy to get the data
         // into the ANativeBuffer.
-        mVideoRenderer = new AwesomeLocalRenderer(mNativeWindow, meta);
+        sp<AMessage> format;
+        convertMetaDataToMessage(meta, &format);
+        mVideoRenderer = new AwesomeLocalRenderer(mNativeWindow, format);
     }
 }
 
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
index 908cdca..008da5a 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -209,25 +209,29 @@
             uri = tmp.string();
         }
 
-        if (httpSource->connect(uri, headers) != OK) {
+        String8 cacheConfig;
+        bool disconnectAtHighwatermark;
+        KeyedVector<String8, String8> nonCacheSpecificHeaders;
+        if (headers != NULL) {
+            nonCacheSpecificHeaders = *headers;
+            NuCachedSource2::RemoveCacheSpecificHeaders(
+                    &nonCacheSpecificHeaders,
+                    &cacheConfig,
+                    &disconnectAtHighwatermark);
+        }
+
+        if (httpSource->connect(uri, &nonCacheSpecificHeaders) != OK) {
             ALOGE("Failed to connect http source!");
             return NULL;
         }
 
         if (!isWidevine) {
-            String8 cacheConfig;
-            bool disconnectAtHighwatermark;
-            if (headers != NULL) {
-                KeyedVector<String8, String8> copy = *headers;
-                NuCachedSource2::RemoveCacheSpecificHeaders(
-                        &copy, &cacheConfig, &disconnectAtHighwatermark);
-            }
+            String8 contentType = httpSource->getMIMEType();
 
             sp<NuCachedSource2> cachedSource = new NuCachedSource2(
                     httpSource,
-                    cacheConfig.isEmpty() ? NULL : cacheConfig.string());
-
-            String8 contentType = httpSource->getMIMEType();
+                    cacheConfig.isEmpty() ? NULL : cacheConfig.string(),
+                    disconnectAtHighwatermark);
 
             if (strncasecmp(contentType.string(), "audio/", 6)) {
                 // We're not doing this for streams that appear to be audio-only
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 42691b9..7bb7ed9 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -958,36 +958,14 @@
                 {
                     ALOGV("codec output format changed");
 
-                    if ((mFlags & kFlagIsSoftwareCodec)
-                            && mNativeWindow != NULL) {
+                    if (mSoftRenderer == NULL &&
+                            mNativeWindow != NULL &&
+                            (mFlags & kFlagIsSoftwareCodec)) {
                         AString mime;
                         CHECK(msg->findString("mime", &mime));
 
-                        if (!strncasecmp("video/", mime.c_str(), 6)) {
-                            delete mSoftRenderer;
-                            mSoftRenderer = NULL;
-
-                            int32_t width, height;
-                            CHECK(msg->findInt32("width", &width));
-                            CHECK(msg->findInt32("height", &height));
-
-                            int32_t cropLeft, cropTop, cropRight, cropBottom;
-                            CHECK(msg->findRect("crop",
-                                &cropLeft, &cropTop, &cropRight, &cropBottom));
-
-                            int32_t colorFormat;
-                            CHECK(msg->findInt32(
-                                        "color-format", &colorFormat));
-
-                            sp<MetaData> meta = new MetaData;
-                            meta->setInt32(kKeyWidth, width);
-                            meta->setInt32(kKeyHeight, height);
-                            meta->setRect(kKeyCropRect,
-                                cropLeft, cropTop, cropRight, cropBottom);
-                            meta->setInt32(kKeyColorFormat, colorFormat);
-
-                            mSoftRenderer =
-                                new SoftwareRenderer(mNativeWindow, meta);
+                        if (mime.startsWithIgnoreCase("video/")) {
+                            mSoftRenderer = new SoftwareRenderer(mNativeWindow);
                         }
                     }
 
@@ -1799,6 +1777,8 @@
             CHECK(info->mNotify == NULL);
             CHECK(msg->findMessage("reply", &info->mNotify));
 
+            info->mFormat =
+                (portIndex == kPortIndexInput) ? mInputFormat : mOutputFormat;
             mAvailPortBuffers[portIndex].push_back(i);
 
             return i;
@@ -1978,7 +1958,8 @@
 
         if (mSoftRenderer != NULL) {
             mSoftRenderer->render(
-                    info->mData->data(), info->mData->size(), timestampNs, NULL);
+                    info->mData->data(), info->mData->size(),
+                    timestampNs, NULL, info->mFormat);
         }
     }
 
@@ -2004,7 +1985,6 @@
     CHECK(!info->mOwnedByClient);
     {
         Mutex::Autolock al(mBufferLock);
-        info->mFormat = portIndex == kPortIndexInput ? mInputFormat : mOutputFormat;
         info->mOwnedByClient = true;
 
         // set image-data
diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp
index 2f2a0b3..5b8be46 100644
--- a/media/libstagefright/MediaCodecList.cpp
+++ b/media/libstagefright/MediaCodecList.cpp
@@ -783,6 +783,7 @@
     const char *name = NULL;
     int32_t optional = -1;
     int32_t required = -1;
+    const char *value = NULL;
 
     while (attrs[i] != NULL) {
         if (attrs[i + 1] == NULL) {
@@ -801,6 +802,9 @@
                 required = value;
             }
             ++i;
+        } else if (!strcmp(attrs[i], "value")) {
+            value = attrs[i + 1];
+            ++i;
         } else {
             return -EINVAL;
         }
@@ -816,7 +820,16 @@
         return -EINVAL;
     }
 
-    mCurrentInfo->addFeature(name, (required == 1) || (optional == 0));
+    if ((optional != -1 || required != -1) && (value != NULL)) {
+        ALOGE("feature '%s' has both a value and optional/required attribute", name);
+        return -EINVAL;
+    }
+
+    if (value != NULL) {
+        mCurrentInfo->addFeature(name, value);
+    } else {
+        mCurrentInfo->addFeature(name, (required == 1) || (optional == 0));
+    }
     return OK;
 }
 
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index 5f1d1c6..25afc5b 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -109,6 +109,25 @@
             msg->setInt32("sar-width", sarWidth);
             msg->setInt32("sar-height", sarHeight);
         }
+
+        int32_t colorFormat;
+        if (meta->findInt32(kKeyColorFormat, &colorFormat)) {
+            msg->setInt32("color-format", colorFormat);
+        }
+
+        int32_t cropLeft, cropTop, cropRight, cropBottom;
+        if (meta->findRect(kKeyCropRect,
+                           &cropLeft,
+                           &cropTop,
+                           &cropRight,
+                           &cropBottom)) {
+            msg->setRect("crop", cropLeft, cropTop, cropRight, cropBottom);
+        }
+
+        int32_t rotationDegrees;
+        if (meta->findInt32(kKeyRotation, &rotationDegrees)) {
+            msg->setInt32("rotation-degrees", rotationDegrees);
+        }
     } else if (!strncasecmp("audio/", mime, 6)) {
         int32_t numChannels, sampleRate;
         CHECK(meta->findInt32(kKeyChannelCount, &numChannels));
@@ -475,6 +494,25 @@
             meta->setInt32(kKeySARWidth, sarWidth);
             meta->setInt32(kKeySARHeight, sarHeight);
         }
+
+        int32_t colorFormat;
+        if (msg->findInt32("color-format", &colorFormat)) {
+            meta->setInt32(kKeyColorFormat, colorFormat);
+        }
+
+        int32_t cropLeft, cropTop, cropRight, cropBottom;
+        if (msg->findRect("crop",
+                          &cropLeft,
+                          &cropTop,
+                          &cropRight,
+                          &cropBottom)) {
+            meta->setRect(kKeyCropRect, cropLeft, cropTop, cropRight, cropBottom);
+        }
+
+        int32_t rotationDegrees;
+        if (msg->findInt32("rotation-degrees", &rotationDegrees)) {
+            meta->setInt32(kKeyRotation, rotationDegrees);
+        }
     } else if (mime.startsWith("audio/")) {
         int32_t numChannels;
         if (msg->findInt32("channel-count", &numChannels)) {
diff --git a/media/libstagefright/colorconversion/SoftwareRenderer.cpp b/media/libstagefright/colorconversion/SoftwareRenderer.cpp
index 0c5527a..cc98da0 100644
--- a/media/libstagefright/colorconversion/SoftwareRenderer.cpp
+++ b/media/libstagefright/colorconversion/SoftwareRenderer.cpp
@@ -21,7 +21,7 @@
 
 #include <cutils/properties.h> // for property_get
 #include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/MetaData.h>
+#include <media/stagefright/foundation/AMessage.h>
 #include <system/window.h>
 #include <ui/GraphicBufferMapper.h>
 #include <gui/IGraphicBufferProducer.h>
@@ -33,34 +33,71 @@
     return (property_get("ro.kernel.qemu", prop, NULL) > 0);
 }
 
-SoftwareRenderer::SoftwareRenderer(
-        const sp<ANativeWindow> &nativeWindow, const sp<MetaData> &meta)
-    : mConverter(NULL),
+static int ALIGN(int x, int y) {
+    // y must be a power of 2.
+    return (x + y - 1) & ~(y - 1);
+}
+
+SoftwareRenderer::SoftwareRenderer(const sp<ANativeWindow> &nativeWindow)
+    : mColorFormat(OMX_COLOR_FormatUnused),
+      mConverter(NULL),
       mYUVMode(None),
-      mNativeWindow(nativeWindow) {
-    int32_t tmp;
-    CHECK(meta->findInt32(kKeyColorFormat, &tmp));
-    mColorFormat = (OMX_COLOR_FORMATTYPE)tmp;
+      mNativeWindow(nativeWindow),
+      mWidth(0),
+      mHeight(0),
+      mCropLeft(0),
+      mCropTop(0),
+      mCropRight(0),
+      mCropBottom(0),
+      mCropWidth(0),
+      mCropHeight(0) {
+}
 
-    CHECK(meta->findInt32(kKeyWidth, &mWidth));
-    CHECK(meta->findInt32(kKeyHeight, &mHeight));
+SoftwareRenderer::~SoftwareRenderer() {
+    delete mConverter;
+    mConverter = NULL;
+}
 
-    if (!meta->findRect(
-                kKeyCropRect,
-                &mCropLeft, &mCropTop, &mCropRight, &mCropBottom)) {
-        mCropLeft = mCropTop = 0;
-        mCropRight = mWidth - 1;
-        mCropBottom = mHeight - 1;
+void SoftwareRenderer::resetFormatIfChanged(const sp<AMessage> &format) {
+    CHECK(format != NULL);
+
+    int32_t colorFormatNew;
+    CHECK(format->findInt32("color-format", &colorFormatNew));
+
+    int32_t widthNew, heightNew;
+    CHECK(format->findInt32("width", &widthNew));
+    CHECK(format->findInt32("height", &heightNew));
+
+    int32_t cropLeftNew, cropTopNew, cropRightNew, cropBottomNew;
+    if (!format->findRect(
+            "crop", &cropLeftNew, &cropTopNew, &cropRightNew, &cropBottomNew)) {
+        cropLeftNew = cropTopNew = 0;
+        cropRightNew = widthNew - 1;
+        cropBottomNew = heightNew - 1;
     }
 
+    if (static_cast<int32_t>(mColorFormat) == colorFormatNew &&
+        mWidth == widthNew &&
+        mHeight == heightNew &&
+        mCropLeft == cropLeftNew &&
+        mCropTop == cropTopNew &&
+        mCropRight == cropRightNew &&
+        mCropBottom == cropBottomNew) {
+        // Nothing changed, no need to reset renderer.
+        return;
+    }
+
+    mColorFormat = static_cast<OMX_COLOR_FORMATTYPE>(colorFormatNew);
+    mWidth = widthNew;
+    mHeight = heightNew;
+    mCropLeft = cropLeftNew;
+    mCropTop = cropTopNew;
+    mCropRight = cropRightNew;
+    mCropBottom = cropBottomNew;
+
     mCropWidth = mCropRight - mCropLeft + 1;
     mCropHeight = mCropBottom - mCropTop + 1;
 
-    int32_t rotationDegrees;
-    if (!meta->findInt32(kKeyRotation, &rotationDegrees)) {
-        rotationDegrees = 0;
-    }
-
     int halFormat;
     size_t bufWidth, bufHeight;
 
@@ -106,10 +143,12 @@
             NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW));
 
     // Width must be multiple of 32???
-    CHECK_EQ(0, native_window_set_buffers_geometry(
+    CHECK_EQ(0, native_window_set_buffers_dimensions(
                 mNativeWindow.get(),
                 bufWidth,
-                bufHeight,
+                bufHeight));
+    CHECK_EQ(0, native_window_set_buffers_format(
+                mNativeWindow.get(),
                 halFormat));
 
     // NOTE: native window uses extended right-bottom coordinate
@@ -123,6 +162,10 @@
 
     CHECK_EQ(0, native_window_set_crop(mNativeWindow.get(), &crop));
 
+    int32_t rotationDegrees;
+    if (!format->findInt32("rotation-degrees", &rotationDegrees)) {
+        rotationDegrees = 0;
+    }
     uint32_t transform;
     switch (rotationDegrees) {
         case 0: transform = 0; break;
@@ -132,24 +175,15 @@
         default: transform = 0; break;
     }
 
-    if (transform) {
-        CHECK_EQ(0, native_window_set_buffers_transform(
-                    mNativeWindow.get(), transform));
-    }
-}
-
-SoftwareRenderer::~SoftwareRenderer() {
-    delete mConverter;
-    mConverter = NULL;
-}
-
-static int ALIGN(int x, int y) {
-    // y must be a power of 2.
-    return (x + y - 1) & ~(y - 1);
+    CHECK_EQ(0, native_window_set_buffers_transform(
+                mNativeWindow.get(), transform));
 }
 
 void SoftwareRenderer::render(
-        const void *data, size_t size, int64_t timestampNs, void *platformPrivate) {
+        const void *data, size_t /*size*/, int64_t timestampNs,
+        void* /*platformPrivate*/, const sp<AMessage>& format) {
+    resetFormatIfChanged(format);
+
     ANativeWindowBuffer *buf;
     int err;
     if ((err = native_window_dequeue_buffer_and_wait(mNativeWindow.get(),
diff --git a/media/libstagefright/data/media_codecs_google_audio.xml b/media/libstagefright/data/media_codecs_google_audio.xml
index f6db0cc..f599004 100644
--- a/media/libstagefright/data/media_codecs_google_audio.xml
+++ b/media/libstagefright/data/media_codecs_google_audio.xml
@@ -16,21 +16,76 @@
 
 <Included>
     <Decoders>
-        <MediaCodec name="OMX.google.mp3.decoder" type="audio/mpeg" />
-        <MediaCodec name="OMX.google.amrnb.decoder" type="audio/3gpp" />
-        <MediaCodec name="OMX.google.amrwb.decoder" type="audio/amr-wb" />
-        <MediaCodec name="OMX.google.aac.decoder" type="audio/mp4a-latm" />
-        <MediaCodec name="OMX.google.g711.alaw.decoder" type="audio/g711-alaw" />
-        <MediaCodec name="OMX.google.g711.mlaw.decoder" type="audio/g711-mlaw" />
-        <MediaCodec name="OMX.google.vorbis.decoder" type="audio/vorbis" />
-        <MediaCodec name="OMX.google.opus.decoder" type="audio/opus" />
-        <MediaCodec name="OMX.google.raw.decoder" type="audio/raw" />
+        <MediaCodec name="OMX.google.mp3.decoder" type="audio/mpeg">
+            <Limit name="channel-count" max="2" />
+            <Limit name="sample-rate" ranges="8000,11025,12000,16000,22050,24000,32000,44100,48000" />
+            <Limit name="bitrate" range="8000-320000" />
+        </MediaCodec>
+        <MediaCodec name="OMX.google.amrnb.decoder" type="audio/3gpp">
+            <Limit name="channel-count" max="1" />
+            <Limit name="sample-rate" ranges="8000" />
+            <Limit name="bitrate" range="4750-12200" />
+        </MediaCodec>
+        <MediaCodec name="OMX.google.amrwb.decoder" type="audio/amr-wb">
+            <Limit name="channel-count" max="1" />
+            <Limit name="sample-rate" ranges="16000" />
+            <Limit name="bitrate" range="6600-23850" />
+        </MediaCodec>
+        <MediaCodec name="OMX.google.aac.decoder" type="audio/mp4a-latm">
+            <Limit name="channel-count" max="8" />
+            <Limit name="sample-rate" ranges="7350,8000,11025,12000,16000,22050,24000,32000,44100,48000" />
+            <Limit name="bitrate" range="8000-960000" />
+        </MediaCodec>
+        <MediaCodec name="OMX.google.g711.alaw.decoder" type="audio/g711-alaw">
+            <Limit name="channel-count" max="1" />
+            <Limit name="sample-rate" ranges="8000" />
+            <Limit name="bitrate" range="64000" />
+        </MediaCodec>
+        <MediaCodec name="OMX.google.g711.mlaw.decoder" type="audio/g711-mlaw">
+            <Limit name="channel-count" max="1" />
+            <Limit name="sample-rate" ranges="8000" />
+            <Limit name="bitrate" range="64000" />
+        </MediaCodec>
+        <MediaCodec name="OMX.google.vorbis.decoder" type="audio/vorbis">
+            <Limit name="channel-count" max="8" />
+            <Limit name="sample-rate" ranges="8000,11025,12000,16000,22050,24000,32000,44100,48000,96000" />
+            <Limit name="bitrate" range="32000-500000" />
+        </MediaCodec>
+        <MediaCodec name="OMX.google.opus.decoder" type="audio/opus">
+            <Limit name="channel-count" max="8" />
+            <Limit name="sample-rate" ranges="48000" />
+            <Limit name="bitrate" range="6000-510000" />
+        </MediaCodec>
+        <MediaCodec name="OMX.google.raw.decoder" type="audio/raw">
+            <Limit name="channel-count" max="8" />
+            <Limit name="sample-rate" ranges="8000-96000" />
+            <Limit name="bitrate" range="1-10000000" />
+        </MediaCodec>
     </Decoders>
-
     <Encoders>
-        <MediaCodec name="OMX.google.aac.encoder" type="audio/mp4a-latm" />
-        <MediaCodec name="OMX.google.amrnb.encoder" type="audio/3gpp" />
-        <MediaCodec name="OMX.google.amrwb.encoder" type="audio/amr-wb" />
-        <MediaCodec name="OMX.google.flac.encoder" type="audio/flac" />
+        <MediaCodec name="OMX.google.aac.encoder" type="audio/mp4a-latm">
+            <Limit name="channel-count" max="6" />
+            <Limit name="sample-rate" ranges="11025,12000,16000,22050,24000,32000,44100,48000" />
+            <Limit name="bitrate" range="8000-960000" />
+        </MediaCodec>
+        <MediaCodec name="OMX.google.amrnb.encoder" type="audio/3gpp">
+            <Limit name="channel-count" max="1" />
+            <Limit name="sample-rate" ranges="8000" />
+            <Limit name="bitrate" range="4750-12200" />
+            <Feature name="bitrate-modes" value="CBR" />
+        </MediaCodec>
+        <MediaCodec name="OMX.google.amrwb.encoder" type="audio/amr-wb">
+            <Limit name="channel-count" max="1" />
+            <Limit name="sample-rate" ranges="16000" />
+            <Limit name="bitrate" range="6600-23850" />
+            <Feature name="bitrate-modes" value="CBR" />
+        </MediaCodec>
+        <MediaCodec name="OMX.google.flac.encoder" type="audio/flac">
+            <Limit name="channel-count" max="2" />
+            <Limit name="sample-rate" ranges="1-655350" />
+            <Limit name="bitrate" range="1-21000000" />
+            <Limit name="complexity" range="0-8"  default="5" />
+            <Feature name="bitrate-modes" value="CQ" />
+        </MediaCodec>
     </Encoders>
 </Included>
diff --git a/media/libstagefright/data/media_codecs_google_telephony.xml b/media/libstagefright/data/media_codecs_google_telephony.xml
index 28f5ffc..5ad90d9 100644
--- a/media/libstagefright/data/media_codecs_google_telephony.xml
+++ b/media/libstagefright/data/media_codecs_google_telephony.xml
@@ -16,6 +16,10 @@
 
 <Included>
     <Decoders>
-        <MediaCodec name="OMX.google.gsm.decoder" type="audio/gsm" />
+        <MediaCodec name="OMX.google.gsm.decoder" type="audio/gsm">
+            <Limit name="channel-count" max="1" />
+            <Limit name="sample-rate" ranges="8000" />
+            <Limit name="bitrate" range="13000" />
+        </MediaCodec>
     </Decoders>
 </Included>
diff --git a/media/libstagefright/include/SoftwareRenderer.h b/media/libstagefright/include/SoftwareRenderer.h
index 0ba670c..fa3ea89 100644
--- a/media/libstagefright/include/SoftwareRenderer.h
+++ b/media/libstagefright/include/SoftwareRenderer.h
@@ -24,17 +24,17 @@
 
 namespace android {
 
-struct MetaData;
+struct AMessage;
 
 class SoftwareRenderer {
 public:
-    SoftwareRenderer(
-            const sp<ANativeWindow> &nativeWindow, const sp<MetaData> &meta);
+    explicit SoftwareRenderer(const sp<ANativeWindow> &nativeWindow);
 
     ~SoftwareRenderer();
 
     void render(
-            const void *data, size_t size, int64_t timestampNs, void *platformPrivate);
+            const void *data, size_t size, int64_t timestampNs,
+            void *platformPrivate, const sp<AMessage> &format);
 
 private:
     enum YUVMode {
@@ -51,6 +51,8 @@
 
     SoftwareRenderer(const SoftwareRenderer &);
     SoftwareRenderer &operator=(const SoftwareRenderer &);
+
+    void resetFormatIfChanged(const sp<AMessage> &format);
 };
 
 }  // namespace android