summaryrefslogtreecommitdiffstats
path: root/media/libstagefright/codecs/hevcdec/SoftHEVC.cpp
diff options
context:
space:
mode:
authorRonghua Wu <ronghuawu@google.com>2014-09-12 11:57:27 -0700
committerRonghua Wu <ronghuawu@google.com>2014-09-23 13:52:19 -0700
commit1aa26f787afc525e0deae31d856dce74a4b28a0f (patch)
treeb1722cd0ced9a000aa50e1b9fd33ca124fa9afb6 /media/libstagefright/codecs/hevcdec/SoftHEVC.cpp
parent2973994af39d55b58728df3dca067594e826ea2a (diff)
downloadframeworks_av-1aa26f787afc525e0deae31d856dce74a4b28a0f.zip
frameworks_av-1aa26f787afc525e0deae31d856dce74a4b28a0f.tar.gz
frameworks_av-1aa26f787afc525e0deae31d856dce74a4b28a0f.tar.bz2
stagefright: add adaptive playback support to SoftHEVC decoder.
Bug: 17326758 Change-Id: I245e2bd1490e810094ca550fdddfa87075bc2056
Diffstat (limited to 'media/libstagefright/codecs/hevcdec/SoftHEVC.cpp')
-rw-r--r--media/libstagefright/codecs/hevcdec/SoftHEVC.cpp189
1 files changed, 117 insertions, 72 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,