diff options
author | Ronghua Wu <ronghuawu@google.com> | 2014-09-24 16:20:51 +0000 |
---|---|---|
committer | Android Git Automerger <android-git-automerger@android.com> | 2014-09-24 16:20:51 +0000 |
commit | 6f7851724bf938e98d3c253941f73118463d974b (patch) | |
tree | 08e836afee4107135c2d154792734cbba21e207f /media | |
parent | d996c4698bda072866d77bac9e9a7685a2c9349b (diff) | |
parent | 80ec934ae7d4e3a78af87554fdb77a58f6386ba0 (diff) | |
download | frameworks_av-6f7851724bf938e98d3c253941f73118463d974b.zip frameworks_av-6f7851724bf938e98d3c253941f73118463d974b.tar.gz frameworks_av-6f7851724bf938e98d3c253941f73118463d974b.tar.bz2 |
am 80ec934a: Merge "stagefright: add adaptive playback support to SoftHEVC decoder." into lmp-dev
* commit '80ec934ae7d4e3a78af87554fdb77a58f6386ba0':
stagefright: add adaptive playback support to SoftHEVC decoder.
Diffstat (limited to 'media')
4 files changed, 141 insertions, 84 deletions
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 @@ SoftHEVC::SoftHEVC( : 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 @@ status_t SoftHEVC::setParams(size_t stride) { 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 @@ status_t SoftHEVC::resetDecoder() { } /* 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 @@ status_t SoftHEVC::initDecoder() { 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 @@ status_t SoftHEVC::initDecoder() { 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 @@ status_t SoftHEVC::initDecoder() { 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 @@ status_t SoftHEVC::initDecoder() { 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 @@ status_t SoftHEVC::initDecoder() { 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 @@ status_t SoftHEVC::deInitDecoder() { 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 @@ status_t SoftHEVC::reInitDecoder() { } return OK; } + void SoftHEVC::onReset() { ALOGD("onReset called"); SoftVideoDecoderOMXComponent::onReset(); @@ -457,12 +463,22 @@ void SoftHEVC::onReset() { 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 @@ void SoftHEVC::setDecodeArgs(ivd_video_decode_ip_t *ps_dec_ip, 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 @@ void SoftHEVC::onPortFlushCompleted(OMX_U32 portIndex) { 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::onPortFlushCompleted(OMX_U32 portIndex) { } void SoftHEVC::onQueueFilled(OMX_U32 portIndex) { - IV_API_CALL_STATUS_T status; - UNUSED(portIndex); if (mOutputPortSettingsChange != NONE) { @@ -548,7 +560,7 @@ void SoftHEVC::onQueueFilled(OMX_U32 portIndex) { setFlushMode(); } - while (outQueue.size() == kNumBuffers) { + while (!outQueue.empty()) { BufferInfo *inInfo; OMX_BUFFERHEADERTYPE *inHeader; @@ -586,6 +598,16 @@ void SoftHEVC::onQueueFilled(OMX_U32 portIndex) { } } + // 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 @@ void SoftHEVC::onQueueFilled(OMX_U32 portIndex) { 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); + 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 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 */ + // 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); - 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); + setDecodeArgs(&s_dec_ip, &s_dec_op, inHeader, outHeader, timeStampIx); - status = ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, - (void *)&s_dec_op); + ivdec_api_function(mCodecCtx, (void *)&s_dec_ip, (void *)&s_dec_op); + return; } - 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 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 valid height and width are decoded, - * then look at change in resolution */ 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 @@ void SoftHEVC::onQueueFilled(OMX_U32 portIndex) { } } -} // 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 @@ protected: 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 @@ private: 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 @@ private: 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 @@ private: 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 @@ protected: 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 @@ void SoftVideoDecoderOMXComponent::updatePortDefinitions(bool updateCrop) { 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 @@ void SoftVideoDecoderOMXComponent::updatePortDefinitions(bool updateCrop) { } } + +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::handlePortSettingsChange( 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) { |