Merge "stagefright: return encrypted input buffer for secure codecs" into lmp-dev
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 2ea12ae..ceedb40 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -64,16 +64,18 @@
 };
 
 struct NuPlayer::SeekAction : public Action {
-    SeekAction(int64_t seekTimeUs)
-        : mSeekTimeUs(seekTimeUs) {
+    SeekAction(int64_t seekTimeUs, bool needNotify)
+        : mSeekTimeUs(seekTimeUs),
+          mNeedNotify(needNotify) {
     }
 
     virtual void execute(NuPlayer *player) {
-        player->performSeek(mSeekTimeUs);
+        player->performSeek(mSeekTimeUs, mNeedNotify);
     }
 
 private:
     int64_t mSeekTimeUs;
+    bool mNeedNotify;
 
     DISALLOW_EVIL_CONSTRUCTORS(SeekAction);
 };
@@ -324,9 +326,10 @@
     (new AMessage(kWhatReset, id()))->post();
 }
 
-void NuPlayer::seekToAsync(int64_t seekTimeUs) {
+void NuPlayer::seekToAsync(int64_t seekTimeUs, bool needNotify) {
     sp<AMessage> msg = new AMessage(kWhatSeek, id());
     msg->setInt64("seekTimeUs", seekTimeUs);
+    msg->setInt32("needNotify", needNotify);
     msg->post();
 }
 
@@ -561,7 +564,8 @@
                     // the extractor may not yet be started and will assert.
                     // If the video decoder is not set (perhaps audio only in this case)
                     // do not perform a seek as it is not needed.
-                    mDeferredActions.push_back(new SeekAction(mCurrentPositionUs));
+                    mDeferredActions.push_back(
+                            new SeekAction(mCurrentPositionUs, false /* needNotify */));
                 }
 
                 // If there is a new surface texture, instantiate decoders
@@ -940,7 +944,7 @@
                 mRenderer->signalDisableOffloadAudio();
                 mOffloadAudio = false;
 
-                performSeek(positionUs);
+                performSeek(positionUs, false /* needNotify */);
                 instantiateDecoder(true /* audio */, &mAudioDecoder);
             }
             break;
@@ -969,14 +973,18 @@
         case kWhatSeek:
         {
             int64_t seekTimeUs;
+            int32_t needNotify;
             CHECK(msg->findInt64("seekTimeUs", &seekTimeUs));
+            CHECK(msg->findInt32("needNotify", &needNotify));
 
-            ALOGV("kWhatSeek seekTimeUs=%lld us", seekTimeUs);
+            ALOGV("kWhatSeek seekTimeUs=%lld us, needNotify=%d",
+                    seekTimeUs, needNotify);
 
             mDeferredActions.push_back(
                     new SimpleAction(&NuPlayer::performDecoderFlush));
 
-            mDeferredActions.push_back(new SeekAction(seekTimeUs));
+            mDeferredActions.push_back(
+                    new SeekAction(seekTimeUs, needNotify));
 
             processDeferredActions();
             break;
@@ -1802,10 +1810,11 @@
     }
 }
 
-void NuPlayer::performSeek(int64_t seekTimeUs) {
-    ALOGV("performSeek seekTimeUs=%lld us (%.2f secs)",
+void NuPlayer::performSeek(int64_t seekTimeUs, bool needNotify) {
+    ALOGV("performSeek seekTimeUs=%lld us (%.2f secs), needNotify(%d)",
           seekTimeUs,
-          seekTimeUs / 1E6);
+          seekTimeUs / 1E6,
+          needNotify);
 
     if (mSource == NULL) {
         // This happens when reset occurs right before the loop mode
@@ -1822,7 +1831,9 @@
         sp<NuPlayerDriver> driver = mDriver.promote();
         if (driver != NULL) {
             driver->notifyPosition(seekTimeUs);
-            driver->notifySeekComplete();
+            if (needNotify) {
+                driver->notifySeekComplete();
+            }
         }
     }
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index eee96ca..8fa7269 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -59,8 +59,9 @@
     // Will notify the driver through "notifyResetComplete" once finished.
     void resetAsync();
 
-    // Will notify the driver through "notifySeekComplete" once finished.
-    void seekToAsync(int64_t seekTimeUs);
+    // Will notify the driver through "notifySeekComplete" once finished
+    // and needNotify is true.
+    void seekToAsync(int64_t seekTimeUs, bool needNotify = false);
 
     status_t setVideoScalingMode(int32_t mode);
     status_t getTrackInfo(Parcel* reply) const;
@@ -215,7 +216,7 @@
 
     void processDeferredActions();
 
-    void performSeek(int64_t seekTimeUs);
+    void performSeek(int64_t seekTimeUs, bool needNotify);
     void performDecoderFlush();
     void performDecoderShutdown(bool audio, bool video);
     void performReset();
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index 7ec9876..a9bca49 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -240,9 +240,7 @@
             mPlayer->start();
 
             if (mStartupSeekTimeUs >= 0) {
-                if (mStartupSeekTimeUs == 0) {
-                    notifySeekComplete_l();
-                } else {
+                if (mStartupSeekTimeUs > 0) {
                     mPlayer->seekToAsync(mStartupSeekTimeUs);
                 }
 
@@ -369,7 +367,7 @@
             mAtEOS = false;
             // seeks can take a while, so we essentially paused
             notifyListener_l(MEDIA_PAUSED);
-            mPlayer->seekToAsync(seekTimeUs);
+            mPlayer->seekToAsync(seekTimeUs, true /* needNotify */);
             break;
         }
 
diff --git a/media/libstagefright/NuCachedSource2.cpp b/media/libstagefright/NuCachedSource2.cpp
index be2a873..f469d4d 100644
--- a/media/libstagefright/NuCachedSource2.cpp
+++ b/media/libstagefright/NuCachedSource2.cpp
@@ -254,6 +254,10 @@
             // set mDisconnecting to true, if a fetch returns after
             // this, the source will be marked as EOS.
             mDisconnecting = true;
+
+            // explicitly signal mCondition so that the pending readAt()
+            // will immediately return
+            mCondition.signal();
         }
 
         // explicitly disconnect from the source, to allow any
@@ -325,7 +329,11 @@
 
         Mutex::Autolock autoLock(mLock);
 
-        if (err == ERROR_UNSUPPORTED || err == -EPIPE) {
+        if (mDisconnecting) {
+            mNumRetriesLeft = 0;
+            mFinalStatus = ERROR_END_OF_STREAM;
+            return;
+        } else if (err == ERROR_UNSUPPORTED || err == -EPIPE) {
             // These are errors that are not likely to go away even if we
             // retry, i.e. the server doesn't support range requests or similar.
             mNumRetriesLeft = 0;
@@ -515,10 +523,14 @@
     CHECK(mAsyncResult == NULL);
     msg->post();
 
-    while (mAsyncResult == NULL) {
+    while (mAsyncResult == NULL && !mDisconnecting) {
         mCondition.wait(mLock);
     }
 
+    if (mDisconnecting) {
+        return ERROR_END_OF_STREAM;
+    }
+
     int32_t result;
     CHECK(mAsyncResult->findInt32("result", &result));
 
diff --git a/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp b/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp
index b0d0827..f4cba54 100644
--- a/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp
+++ b/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp
@@ -67,22 +67,16 @@
     : SoftVideoDecoderOMXComponent(name, componentName, codingType,
             kProfileLevels, ARRAY_SIZE(kProfileLevels),
             320 /* width */, 240 /* height */, callbacks,
-            appData, component) {
+            appData, component),
+      mMemRecords(NULL),
+      mFlushOutBuffer(NULL),
+      mOmxColorFormat(OMX_COLOR_FormatYUV420Planar),
+      mIvColorFormat(IV_YUV_420P),
+      mNewWidth(mWidth),
+      mNewHeight(mHeight),
+      mChangingResolution(false) {
     initPorts(kNumBuffers, INPUT_BUF_SIZE, kNumBuffers,
             CODEC_MIME_TYPE);
-
-    mOmxColorFormat = OMX_COLOR_FormatYUV420Planar;
-    mStride = mWidth;
-
-    if (OMX_COLOR_FormatYUV420Planar == mOmxColorFormat) {
-        mIvColorFormat = IV_YUV_420P;
-    } else if (OMX_COLOR_FormatYUV420SemiPlanar == mOmxColorFormat) {
-        mIvColorFormat = IV_YUV_420SP_UV;
-    }
-
-    mInitWidth = mWidth;
-    mInitHeight = mHeight;
-
     CHECK_EQ(initDecoder(), (status_t)OK);
 }
 
@@ -144,7 +138,7 @@
     s_ctl_ip.u4_size = sizeof(ivd_ctl_set_config_ip_t);
     s_ctl_op.u4_size = sizeof(ivd_ctl_set_config_op_t);
 
-    ALOGD("Set the run-time (dynamic) parameters");
+    ALOGV("Set the run-time (dynamic) parameters stride = %u", stride);
     status = ivdec_api_function(mCodecCtx, (void *)&s_ctl_ip,
             (void *)&s_ctl_op);
 
@@ -188,7 +182,7 @@
     }
 
     /* Set the run-time (dynamic) parameters */
-    setParams(0);
+    setParams(outputBufferWidth());
 
     /* Set number of cores/threads to be used by the codec */
     setNumCores();
@@ -250,23 +244,25 @@
     WORD32 i4_level;
 
     mNumCores = GetCPUCoreCount();
-    mMemRecords = NULL;
-    mFlushOutBuffer = NULL;
 
     /* Initialize number of ref and reorder modes (for HEVC) */
     u4_num_reorder_frames = 16;
     u4_num_ref_frames = 16;
     u4_share_disp_buf = 0;
 
-    if ((mWidth * mHeight) > (1920 * 1088)) {
+    uint32_t displayStride = outputBufferWidth();
+    uint32_t displayHeight = outputBufferHeight();
+    uint32_t displaySizeY = displayStride * displayHeight;
+
+    if (displaySizeY > (1920 * 1088)) {
         i4_level = 50;
-    } else if ((mWidth * mHeight) > (1280 * 720)) {
+    } else if (displaySizeY > (1280 * 720)) {
         i4_level = 40;
-    } else if ((mWidth * mHeight) > (960 * 540)) {
+    } else if (displaySizeY > (960 * 540)) {
         i4_level = 31;
-    } else if ((mWidth * mHeight) > (640 * 360)) {
+    } else if (displaySizeY > (640 * 360)) {
         i4_level = 30;
-    } else if ((mWidth * mHeight) > (352 * 288)) {
+    } else if (displaySizeY > (352 * 288)) {
         i4_level = 21;
     } else {
         i4_level = 20;
@@ -317,8 +313,8 @@
 
         s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.e_cmd = IV_CMD_FILL_NUM_MEM_REC;
         s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.pv_mem_rec_location = mMemRecords;
-        s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_wd = mWidth;
-        s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_ht = mHeight;
+        s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_wd = displayStride;
+        s_fill_mem_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_ht = displayHeight;
         s_fill_mem_op.s_ivd_fill_mem_rec_op_t.u4_size =
             sizeof(ivdext_fill_mem_rec_op_t);
 
@@ -363,8 +359,8 @@
         s_init_ip.s_ivd_init_ip_t.u4_size = sizeof(ivdext_init_ip_t);
         s_init_ip.s_ivd_init_ip_t.e_cmd = (IVD_API_COMMAND_TYPE_T)IV_CMD_INIT;
         s_init_ip.s_ivd_init_ip_t.pv_mem_rec_location = mMemRecords;
-        s_init_ip.s_ivd_init_ip_t.u4_frm_max_wd = mWidth;
-        s_init_ip.s_ivd_init_ip_t.u4_frm_max_ht = mHeight;
+        s_init_ip.s_ivd_init_ip_t.u4_frm_max_wd = displayStride;
+        s_init_ip.s_ivd_init_ip_t.u4_frm_max_ht = displayHeight;
 
         s_init_ip.i4_level = i4_level;
         s_init_ip.u4_num_reorder_frames = u4_num_reorder_frames;
@@ -395,7 +391,7 @@
     resetPlugin();
 
     /* Set the run time (dynamic) parameters */
-    setParams(0);
+    setParams(displayStride);
 
     /* Set number of cores/threads to be used by the codec */
     setNumCores();
@@ -404,12 +400,15 @@
     logVersion();
 
     /* Allocate internal picture buffer */
-    mFlushOutBuffer = (uint8_t *)ivd_aligned_malloc(128, mStride * mHeight * 3 / 2);
+    uint32_t bufferSize = displaySizeY * 3 / 2;
+    mFlushOutBuffer = (uint8_t *)ivd_aligned_malloc(128, bufferSize);
     if (NULL == mFlushOutBuffer) {
-        ALOGE("Could not allocate flushOutputBuffer of size %zu", mStride * mHeight * 3 / 2);
+        ALOGE("Could not allocate flushOutputBuffer of size %zu", bufferSize);
         return NO_MEMORY;
     }
 
+    mInitNeeded = false;
+    mFlushNeeded = false;
     return OK;
 }
 
@@ -428,11 +427,17 @@
             ps_mem_rec++;
         }
         ivd_aligned_free(mMemRecords);
+        mMemRecords = NULL;
     }
 
     if(mFlushOutBuffer) {
         ivd_aligned_free(mFlushOutBuffer);
+        mFlushOutBuffer = NULL;
     }
+
+    mInitNeeded = true;
+    mChangingResolution = false;
+
     return OK;
 }
 
@@ -449,6 +454,7 @@
     }
     return OK;
 }
+
 void SoftHEVC::onReset() {
     ALOGD("onReset called");
     SoftVideoDecoderOMXComponent::onReset();
@@ -457,12 +463,22 @@
     resetPlugin();
 }
 
+OMX_ERRORTYPE SoftHEVC::internalSetParameter(OMX_INDEXTYPE index, const OMX_PTR params) {
+    const uint32_t oldWidth = mWidth;
+    const uint32_t oldHeight = mHeight;
+    OMX_ERRORTYPE ret = SoftVideoDecoderOMXComponent::internalSetParameter(index, params);
+    if (mWidth != oldWidth || mHeight != oldHeight) {
+        reInitDecoder();
+    }
+    return ret;
+}
+
 void SoftHEVC::setDecodeArgs(ivd_video_decode_ip_t *ps_dec_ip,
         ivd_video_decode_op_t *ps_dec_op,
         OMX_BUFFERHEADERTYPE *inHeader,
         OMX_BUFFERHEADERTYPE *outHeader,
-        size_t sizeY,
         size_t timeStampIx) {
+    size_t sizeY = outputBufferWidth() * outputBufferHeight();
     size_t sizeUV;
     uint8_t *pBuf;
 
@@ -502,8 +518,6 @@
     return;
 }
 void SoftHEVC::onPortFlushCompleted(OMX_U32 portIndex) {
-    ALOGD("onPortFlushCompleted on port %d", portIndex);
-
     /* Once the output buffers are flushed, ignore any buffers that are held in decoder */
     if (kOutputPortIndex == portIndex) {
         setFlushMode();
@@ -514,7 +528,7 @@
             IV_API_CALL_STATUS_T status;
             size_t sizeY, sizeUV;
 
-            setDecodeArgs(&s_dec_ip, &s_dec_op, NULL, NULL, mStride * mHeight, 0);
+            setDecodeArgs(&s_dec_ip, &s_dec_op, NULL, NULL, 0);
 
             status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip,
                     (void *)&s_dec_op);
@@ -527,8 +541,6 @@
 }
 
 void SoftHEVC::onQueueFilled(OMX_U32 portIndex) {
-    IV_API_CALL_STATUS_T status;
-
     UNUSED(portIndex);
 
     if (mOutputPortSettingsChange != NONE) {
@@ -548,7 +560,7 @@
         setFlushMode();
     }
 
-    while (outQueue.size() == kNumBuffers) {
+    while (!outQueue.empty()) {
         BufferInfo *inInfo;
         OMX_BUFFERHEADERTYPE *inHeader;
 
@@ -586,6 +598,16 @@
             }
         }
 
+        // When there is an init required and the decoder is not in flush mode,
+        // update output port's definition and reinitialize decoder.
+        if (mInitNeeded && !mIsInFlush) {
+            bool portWillReset = false;
+            handlePortSettingsChange(&portWillReset, mNewWidth, mNewHeight);
+
+            CHECK_EQ(reInitDecoder(), (status_t)OK);
+            return;
+        }
+
         /* Get a free slot in timestamp array to hold input timestamp */
         {
             size_t i;
@@ -608,68 +630,91 @@
             WORD32 timeDelay, timeTaken;
             size_t sizeY, sizeUV;
 
-            setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader,
-                          mStride * mHeight, timeStampIx);
+            setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader, timeStampIx);
 
             GETTIME(&mTimeStart, NULL);
             /* Compute time elapsed between end of previous decode()
              * to start of current decode() */
             TIME_DIFF(mTimeEnd, mTimeStart, timeDelay);
 
-            status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip,
-                    (void *)&s_dec_op);
+            IV_API_CALL_STATUS_T status;
+            status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op);
+            // FIXME: Compare |status| to IHEVCD_UNSUPPORTED_DIMENSIONS, which is not one of the
+            // IV_API_CALL_STATUS_T, seems be wrong. But this is what the decoder returns right now.
+            // The decoder should be fixed so that |u4_error_code| instead of |status| returns
+            // IHEVCD_UNSUPPORTED_DIMENSIONS.
+            bool unsupportedDimensions =
+                ((IHEVCD_UNSUPPORTED_DIMENSIONS == status)
+                    || (IHEVCD_UNSUPPORTED_DIMENSIONS == s_dec_op.u4_error_code));
+            bool resChanged = (IVD_RES_CHANGED == (s_dec_op.u4_error_code & 0xFF));
 
             GETTIME(&mTimeEnd, NULL);
             /* Compute time taken for decode() */
             TIME_DIFF(mTimeStart, mTimeEnd, timeTaken);
 
-            ALOGD("timeTaken=%6d delay=%6d numBytes=%6d", timeTaken, timeDelay,
-                    s_dec_op.u4_num_bytes_consumed);
-
-            /* If width and height are greater than the
-             * the dimensions used during codec create, then
-             * delete the current instance and recreate an instance with
-             * new dimensions */
-
-            if(IHEVCD_UNSUPPORTED_DIMENSIONS == s_dec_op.u4_error_code) {
-                mInitWidth = s_dec_op.u4_pic_wd;
-                mInitHeight = s_dec_op.u4_pic_ht;
-                mStride = mInitWidth;
-                CHECK_EQ(reInitDecoder(), (status_t)OK);
-
-                setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader,
-                              mStride * mHeight, timeStampIx);
-
-                status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip,
-                        (void *)&s_dec_op);
+            ALOGV("timeTaken=%6d delay=%6d numBytes=%6d", timeTaken, timeDelay,
+                   s_dec_op.u4_num_bytes_consumed);
+            if (s_dec_op.u4_frame_decoded_flag && !mFlushNeeded) {
+                mFlushNeeded = true;
             }
+
             if ((inHeader != NULL) && (1 != s_dec_op.u4_frame_decoded_flag)) {
                 /* If the input did not contain picture data, then ignore
                  * the associated timestamp */
                 mTimeStampsValid[timeStampIx] = false;
             }
 
-            /* If valid height and width are decoded,
-             * then look at change in resolution */
+            // This is needed to handle CTS DecoderTest testCodecResetsHEVCWithoutSurface,
+            // which is not sending SPS/PPS after port reconfiguration and flush to the codec.
+            if (unsupportedDimensions && !mFlushNeeded) {
+                bool portWillReset = false;
+                handlePortSettingsChange(&portWillReset, s_dec_op.u4_pic_wd, s_dec_op.u4_pic_ht);
+
+                CHECK_EQ(reInitDecoder(), (status_t)OK);
+
+                setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader, timeStampIx);
+
+                ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op);
+                return;
+            }
+
+            // If the decoder is in the changing resolution mode and there is no output present,
+            // that means the switching is done and it's ready to reset the decoder and the plugin.
+            if (mChangingResolution && !s_dec_op.u4_output_present) {
+                mChangingResolution = false;
+                resetDecoder();
+                resetPlugin();
+                continue;
+            }
+
+            if (unsupportedDimensions || resChanged) {
+                mChangingResolution = true;
+                if (mFlushNeeded) {
+                    setFlushMode();
+                }
+
+                if (unsupportedDimensions) {
+                    mNewWidth = s_dec_op.u4_pic_wd;
+                    mNewHeight = s_dec_op.u4_pic_ht;
+                    mInitNeeded = true;
+                }
+                continue;
+            }
+
             if ((0 < s_dec_op.u4_pic_wd) && (0 < s_dec_op.u4_pic_ht)) {
                 uint32_t width = s_dec_op.u4_pic_wd;
                 uint32_t height = s_dec_op.u4_pic_ht;
+                bool portWillReset = false;
+                handlePortSettingsChange(&portWillReset, width, height);
 
-                if ((width != mWidth) || (height != mHeight)) {
-                    mWidth = width;
-                    mHeight = height;
-                    mStride = mWidth;
-
-                    updatePortDefinitions();
-
-                    notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
-                    mOutputPortSettingsChange = AWAITING_DISABLED;
+                if (portWillReset) {
+                    resetDecoder();
                     return;
                 }
             }
 
             if (s_dec_op.u4_output_present) {
-                outHeader->nFilledLen = (mStride * mHeight * 3) / 2;
+                outHeader->nFilledLen = (mWidth * mHeight * 3) / 2;
 
                 outHeader->nTimeStamp = mTimeStamps[s_dec_op.u4_ts];
                 mTimeStampsValid[s_dec_op.u4_ts] = false;
@@ -711,7 +756,7 @@
     }
 }
 
-} // namespace android
+}  // namespace android
 
 android::SoftOMXComponent *createSoftOMXComponent(const char *name,
         const OMX_CALLBACKTYPE *callbacks, OMX_PTR appData,
diff --git a/media/libstagefright/codecs/hevcdec/SoftHEVC.h b/media/libstagefright/codecs/hevcdec/SoftHEVC.h
index 233db0c..a91f528 100644
--- a/media/libstagefright/codecs/hevcdec/SoftHEVC.h
+++ b/media/libstagefright/codecs/hevcdec/SoftHEVC.h
@@ -62,6 +62,7 @@
     virtual void onQueueFilled(OMX_U32 portIndex);
     virtual void onPortFlushCompleted(OMX_U32 portIndex);
     virtual void onReset();
+    virtual OMX_ERRORTYPE internalSetParameter(OMX_INDEXTYPE index, const OMX_PTR params);
 private:
     // Number of input and output buffers
     enum {
@@ -72,12 +73,6 @@
     iv_mem_rec_t *mMemRecords;   // Memory records requested by the codec
     size_t mNumMemRecords;       // Number of memory records requested by the codec
 
-    uint32_t mNewWidth;          // New width after change in resolution
-    uint32_t mNewHeight;         // New height after change in resolution
-    uint32_t mInitWidth;         // Width used during codec creation
-    uint32_t mInitHeight;        // Height used during codec creation
-    size_t mStride;              // Stride to be used for display buffers
-
     size_t mNumCores;            // Number of cores to be uesd by the codec
 
     struct timeval mTimeStart;   // Time at the start of decode()
@@ -98,7 +93,13 @@
 
     bool mIsInFlush;        // codec is flush mode
     bool mReceivedEOS;      // EOS is receieved on input port
-    bool mIsAdapting;       // plugin in middle of change in resolution
+    bool mInitNeeded;
+    uint32_t mNewWidth;
+    uint32_t mNewHeight;
+    // The input stream has changed to a different resolution, which is still supported by the
+    // codec. So the codec is switching to decode the new resolution.
+    bool mChangingResolution;
+    bool mFlushNeeded;
 
     status_t initDecoder();
     status_t deInitDecoder();
@@ -114,7 +115,6 @@
         ivd_video_decode_op_t *ps_dec_op,
         OMX_BUFFERHEADERTYPE *inHeader,
         OMX_BUFFERHEADERTYPE *outHeader,
-        size_t sizeY,
         size_t timeStampIx);
 
     DISALLOW_EVIL_CONSTRUCTORS (SoftHEVC);
diff --git a/media/libstagefright/include/SoftVideoDecoderOMXComponent.h b/media/libstagefright/include/SoftVideoDecoderOMXComponent.h
index 8cb8ed7..37b1fe1 100644
--- a/media/libstagefright/include/SoftVideoDecoderOMXComponent.h
+++ b/media/libstagefright/include/SoftVideoDecoderOMXComponent.h
@@ -65,6 +65,9 @@
 
     virtual void updatePortDefinitions(bool updateCrop = true);
 
+    uint32_t outputBufferWidth();
+    uint32_t outputBufferHeight();
+
     void handlePortSettingsChange(
             bool *portWillReset, uint32_t width, uint32_t height,
             bool cropChanged = false, bool fakeStride = false);
diff --git a/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp b/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp
index 1cb1859..5853469 100644
--- a/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp
+++ b/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp
@@ -133,8 +133,8 @@
     def->nBufferSize = def->format.video.nFrameWidth * def->format.video.nFrameHeight * 3 / 2;
 
     def = &editPortInfo(kOutputPortIndex)->mDef;
-    def->format.video.nFrameWidth = mIsAdaptive ? mAdaptiveMaxWidth : mWidth;
-    def->format.video.nFrameHeight = mIsAdaptive ? mAdaptiveMaxHeight : mHeight;
+    def->format.video.nFrameWidth = outputBufferWidth();
+    def->format.video.nFrameHeight = outputBufferHeight();
     def->format.video.nStride = def->format.video.nFrameWidth;
     def->format.video.nSliceHeight = def->format.video.nFrameHeight;
 
@@ -150,6 +150,15 @@
     }
 }
 
+
+uint32_t SoftVideoDecoderOMXComponent::outputBufferWidth() {
+    return mIsAdaptive ? mAdaptiveMaxWidth : mWidth;
+}
+
+uint32_t SoftVideoDecoderOMXComponent::outputBufferHeight() {
+    return mIsAdaptive ? mAdaptiveMaxHeight : mHeight;
+}
+
 void SoftVideoDecoderOMXComponent::handlePortSettingsChange(
         bool *portWillReset, uint32_t width, uint32_t height, bool cropChanged, bool fakeStride) {
     *portWillReset = false;
@@ -199,9 +208,9 @@
 void SoftVideoDecoderOMXComponent::copyYV12FrameToOutputBuffer(
         uint8_t *dst, const uint8_t *srcY, const uint8_t *srcU, const uint8_t *srcV,
         size_t srcYStride, size_t srcUStride, size_t srcVStride) {
-    size_t dstYStride = mIsAdaptive ? mAdaptiveMaxWidth : mWidth;
+    size_t dstYStride = outputBufferWidth();
     size_t dstUVStride = dstYStride / 2;
-    size_t dstHeight = mIsAdaptive ? mAdaptiveMaxHeight : mHeight;
+    size_t dstHeight = outputBufferHeight();
     uint8_t *dstStart = dst;
 
     for (size_t i = 0; i < mHeight; ++i) {
diff --git a/services/audiopolicy/AudioPolicyManager.cpp b/services/audiopolicy/AudioPolicyManager.cpp
index 95ac070..d51ee8e 100644
--- a/services/audiopolicy/AudioPolicyManager.cpp
+++ b/services/audiopolicy/AudioPolicyManager.cpp
@@ -112,7 +112,7 @@
     STRING_TO_ENUM(AUDIO_DEVICE_IN_LOOPBACK),
 };
 
-const StringToEnum sFlagNameToEnumTable[] = {
+const StringToEnum sOutputFlagNameToEnumTable[] = {
     STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_DIRECT),
     STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_PRIMARY),
     STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_FAST),
@@ -122,6 +122,11 @@
     STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_HW_AV_SYNC),
 };
 
+const StringToEnum sInputFlagNameToEnumTable[] = {
+    STRING_TO_ENUM(AUDIO_INPUT_FLAG_FAST),
+    STRING_TO_ENUM(AUDIO_INPUT_FLAG_HW_HOTWORD),
+};
+
 const StringToEnum sFormatNameToEnumTable[] = {
     STRING_TO_ENUM(AUDIO_FORMAT_PCM_16_BIT),
     STRING_TO_ENUM(AUDIO_FORMAT_PCM_8_BIT),
@@ -1292,16 +1297,41 @@
         break;
     }
 
+    audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
+    bool isSoundTrigger = false;
+    audio_source_t halInputSource = inputSource;
+    if (inputSource == AUDIO_SOURCE_HOTWORD) {
+        ssize_t index = mSoundTriggerSessions.indexOfKey(session);
+        if (index >= 0) {
+            input = mSoundTriggerSessions.valueFor(session);
+            isSoundTrigger = true;
+            flags = (audio_input_flags_t)(flags | AUDIO_INPUT_FLAG_HW_HOTWORD);
+            ALOGV("SoundTrigger capture on session %d input %d", session, input);
+        } else {
+            halInputSource = AUDIO_SOURCE_VOICE_RECOGNITION;
+        }
+    }
+
     sp<IOProfile> profile = getInputProfile(device,
                                          samplingRate,
                                          format,
                                          channelMask,
                                          flags);
     if (profile == 0) {
-        ALOGW("getInput() could not find profile for device 0x%X, samplingRate %u, format %#x, "
-                "channelMask 0x%X, flags %#x",
-                device, samplingRate, format, channelMask, flags);
-        return AUDIO_IO_HANDLE_NONE;
+        //retry without flags
+        audio_input_flags_t log_flags = flags;
+        flags = AUDIO_INPUT_FLAG_NONE;
+        profile = getInputProfile(device,
+                                 samplingRate,
+                                 format,
+                                 channelMask,
+                                 flags);
+        if (profile == 0) {
+            ALOGW("getInput() could not find profile for device 0x%X, samplingRate %u, format %#x, "
+                    "channelMask 0x%X, flags %#x",
+                    device, samplingRate, format, channelMask, log_flags);
+            return AUDIO_IO_HANDLE_NONE;
+        }
     }
 
     if (profile->mModule->mHandle == 0) {
@@ -1313,20 +1343,7 @@
     config.sample_rate = samplingRate;
     config.channel_mask = channelMask;
     config.format = format;
-    audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
 
-    bool isSoundTrigger = false;
-    audio_source_t halInputSource = inputSource;
-    if (inputSource == AUDIO_SOURCE_HOTWORD) {
-        ssize_t index = mSoundTriggerSessions.indexOfKey(session);
-        if (index >= 0) {
-            input = mSoundTriggerSessions.valueFor(session);
-            isSoundTrigger = true;
-            ALOGV("SoundTrigger capture on session %d input %d", session, input);
-        } else {
-            halInputSource = AUDIO_SOURCE_VOICE_RECOGNITION;
-        }
-    }
     status_t status = mpClientInterface->openInput(profile->mModule->mHandle,
                                                    &input,
                                                    &config,
@@ -5220,7 +5237,7 @@
         mStrategyMutedByDevice[i] = false;
     }
     if (profile != NULL) {
-        mFlags = profile->mFlags;
+        mFlags = (audio_output_flags_t)profile->mFlags;
         mSamplingRate = profile->pickSamplingRate();
         mFormat = profile->pickFormat();
         mChannelMask = profile->pickChannelMask();
@@ -5568,6 +5585,8 @@
         } else if (strcmp(node->name, DEVICES_TAG) == 0) {
             profile->mSupportedDevices.loadDevicesFromName((char *)node->value,
                                                            mDeclaredDevices);
+        } else if (strcmp(node->name, FLAGS_TAG) == 0) {
+            profile->mFlags = parseInputFlagNames((char *)node->value);
         } else if (strcmp(node->name, GAINS_TAG) == 0) {
             profile->loadGains(node);
         }
@@ -5613,7 +5632,7 @@
             profile->mSupportedDevices.loadDevicesFromName((char *)node->value,
                                                            mDeclaredDevices);
         } else if (strcmp(node->name, FLAGS_TAG) == 0) {
-            profile->mFlags = parseFlagNames((char *)node->value);
+            profile->mFlags = parseOutputFlagNames((char *)node->value);
         } else if (strcmp(node->name, GAINS_TAG) == 0) {
             profile->loadGains(node);
         }
@@ -5728,7 +5747,7 @@
 
 AudioPolicyManager::AudioPort::AudioPort(const String8& name, audio_port_type_t type,
           audio_port_role_t role, const sp<HwModule>& module) :
-    mName(name), mType(type), mRole(role), mModule(module), mFlags((audio_output_flags_t)0)
+    mName(name), mType(type), mRole(role), mModule(module), mFlags(0)
 {
     mUseInChannelMask = ((type == AUDIO_PORT_TYPE_DEVICE) && (role == AUDIO_PORT_ROLE_SOURCE)) ||
                     ((type == AUDIO_PORT_TYPE_MIX) && (role == AUDIO_PORT_ROLE_SINK));
@@ -6560,7 +6579,7 @@
                                                             uint32_t *updatedSamplingRate,
                                                             audio_format_t format,
                                                             audio_channel_mask_t channelMask,
-                                                            audio_output_flags_t flags) const
+                                                            uint32_t flags) const
 {
     const bool isPlaybackThread = mType == AUDIO_PORT_TYPE_MIX && mRole == AUDIO_PORT_ROLE_SOURCE;
     const bool isRecordThread = mType == AUDIO_PORT_TYPE_MIX && mRole == AUDIO_PORT_ROLE_SINK;
@@ -6602,7 +6621,7 @@
     // An existing fast stream is compatible with a normal track request.
     // An existing normal stream is compatible with a fast track request,
     // but the fast request will be denied by AudioFlinger and converted to normal track.
-    if (isRecordThread && (((audio_input_flags_t) mFlags ^ (audio_input_flags_t) flags) &
+    if (isRecordThread && ((mFlags ^ flags) &
             ~AUDIO_INPUT_FLAG_FAST)) {
         return false;
     }
@@ -6958,7 +6977,7 @@
 
 // --- audio_policy.conf file parsing
 
-audio_output_flags_t AudioPolicyManager::parseFlagNames(char *name)
+uint32_t AudioPolicyManager::parseOutputFlagNames(char *name)
 {
     uint32_t flag = 0;
 
@@ -6967,8 +6986,8 @@
     char *flagName = strtok(name, "|");
     while (flagName != NULL) {
         if (strlen(flagName) != 0) {
-            flag |= stringToEnum(sFlagNameToEnumTable,
-                               ARRAY_SIZE(sFlagNameToEnumTable),
+            flag |= stringToEnum(sOutputFlagNameToEnumTable,
+                               ARRAY_SIZE(sOutputFlagNameToEnumTable),
                                flagName);
         }
         flagName = strtok(NULL, "|");
@@ -6980,7 +6999,25 @@
         flag |= AUDIO_OUTPUT_FLAG_DIRECT;
     }
 
-    return (audio_output_flags_t)flag;
+    return flag;
+}
+
+uint32_t AudioPolicyManager::parseInputFlagNames(char *name)
+{
+    uint32_t flag = 0;
+
+    // it is OK to cast name to non const here as we are not going to use it after
+    // strtok() modifies it
+    char *flagName = strtok(name, "|");
+    while (flagName != NULL) {
+        if (strlen(flagName) != 0) {
+            flag |= stringToEnum(sInputFlagNameToEnumTable,
+                               ARRAY_SIZE(sInputFlagNameToEnumTable),
+                               flagName);
+        }
+        flagName = strtok(NULL, "|");
+    }
+    return flag;
 }
 
 audio_devices_t AudioPolicyManager::parseDeviceNames(char *name)
diff --git a/services/audiopolicy/AudioPolicyManager.h b/services/audiopolicy/AudioPolicyManager.h
index da0d95d..0ea7b97 100644
--- a/services/audiopolicy/AudioPolicyManager.h
+++ b/services/audiopolicy/AudioPolicyManager.h
@@ -283,8 +283,8 @@
             Vector <audio_format_t> mFormats; // supported audio formats
             Vector < sp<AudioGain> > mGains; // gain controllers
             sp<HwModule> mModule;                 // audio HW module exposing this I/O stream
-            audio_output_flags_t mFlags; // attribute flags (e.g primary output,
-                                                // direct output...). For outputs only.
+            uint32_t mFlags; // attribute flags (e.g primary output,
+                                                // direct output...).
         };
 
         class AudioPortConfig: public virtual RefBase
@@ -387,7 +387,7 @@
                                      uint32_t *updatedSamplingRate,
                                      audio_format_t format,
                                      audio_channel_mask_t channelMask,
-                                     audio_output_flags_t flags) const;
+                                     uint32_t flags) const;
 
             void dump(int fd);
             void log();
@@ -754,7 +754,8 @@
                                       size_t size,
                                       uint32_t value);
         static bool stringToBool(const char *value);
-        static audio_output_flags_t parseFlagNames(char *name);
+        static uint32_t parseOutputFlagNames(char *name);
+        static uint32_t parseInputFlagNames(char *name);
         static audio_devices_t parseDeviceNames(char *name);
         void loadHwModule(cnode *root);
         void loadHwModules(cnode *root);