diff options
author | Zhao Liang <leo.zhao@intel.com> | 2012-09-24 16:08:15 +0800 |
---|---|---|
committer | Patrick Tjin <pattjin@google.com> | 2014-07-21 22:02:49 -0700 |
commit | 0d275ff362298b443c828f09f593bfb674112bbd (patch) | |
tree | f966f44e9ea31fe014b6dfbcfefd1897eae534b9 /videocodec/OMXVideoEncoderAVC.cpp | |
parent | ab82a0fd294f033d336bc53cdffe8d1708d947cc (diff) | |
download | android_hardware_intel_common_omx-components-0d275ff362298b443c828f09f593bfb674112bbd.tar.gz android_hardware_intel_common_omx-components-0d275ff362298b443c828f09f593bfb674112bbd.tar.bz2 android_hardware_intel_common_omx-components-0d275ff362298b443c828f09f593bfb674112bbd.zip |
MRFLD highprofile encoding support
BZ: 76824
enable HiP Video Encode support in omx-componment
1) infrastructure
2) Cache implementation / operation
3) EOS/EOE processing
4) Adapt with new encode/getOutput model
5) Frame status analysis / set according to parameters like Profile/B frame etc
6) Use pPlatformPrivate to store NSTOP info
7) add the unsupport setting return info
Change-Id: I8cc469dd7ea37b1c9989a55adec3b1834c4aa905
Signed-off-by: Zhao Liang <leo.zhao@intel.com>
Reviewed-on: http://android.intel.com:8080/67485
Reviewed-by: Yuan, Shengquan <shengquan.yuan@intel.com>
Reviewed-by: Shi, PingX <pingx.shi@intel.com>
Tested-by: Shi, PingX <pingx.shi@intel.com>
Reviewed-by: cactus <cactus@intel.com>
Tested-by: cactus <cactus@intel.com>
Diffstat (limited to 'videocodec/OMXVideoEncoderAVC.cpp')
-rw-r--r-- | videocodec/OMXVideoEncoderAVC.cpp | 600 |
1 files changed, 362 insertions, 238 deletions
diff --git a/videocodec/OMXVideoEncoderAVC.cpp b/videocodec/OMXVideoEncoderAVC.cpp index 9a59485..3d43526 100644 --- a/videocodec/OMXVideoEncoderAVC.cpp +++ b/videocodec/OMXVideoEncoderAVC.cpp @@ -14,8 +14,7 @@ * limitations under the License. */ - -//#define LOG_NDEBUG 0 +#define LOG_NDEBUG 0 #define LOG_TAG "OMXVideoEncoderAVC" #include <utils/Log.h> #include "OMXVideoEncoderAVC.h" @@ -46,6 +45,8 @@ OMX_ERRORTYPE OMXVideoEncoderAVC::InitOutputPortFormatSpecific(OMX_PARAM_PORTDEF mParamAvc.nPortIndex = OUTPORT_INDEX; mParamAvc.eProfile = OMX_VIDEO_AVCProfileBaseline; mParamAvc.eLevel = OMX_VIDEO_AVCLevel41; + mParamAvc.nPFrames = 30; + mParamAvc.nBFrames = 0; // OMX_NALSTREAMFORMATTYPE memset(&mNalStreamFormat, 0, sizeof(mNalStreamFormat)); @@ -60,7 +61,7 @@ OMX_ERRORTYPE OMXVideoEncoderAVC::InitOutputPortFormatSpecific(OMX_PARAM_PORTDEF mConfigAvcIntraPeriod.nPortIndex = OUTPORT_INDEX; // TODO: need to be populated from Video Encoder mConfigAvcIntraPeriod.nIDRPeriod = 1; - mConfigAvcIntraPeriod.nPFrames = 0; + mConfigAvcIntraPeriod.nPFrames = 30; // OMX_VIDEO_CONFIG_NALSIZE memset(&mConfigNalSize, 0, sizeof(mConfigNalSize)); @@ -113,12 +114,20 @@ OMX_ERRORTYPE OMXVideoEncoderAVC::SetVideoEncoderParam(void) { } mVideoEncoder->getParameters(mEncoderParams); - mEncoderParams->profile = (VAProfile)VAProfileH264Baseline; + if (mParamAvc.eProfile == OMX_VIDEO_AVCProfileBaseline) { + mEncoderParams->profile = (VAProfile)VAProfileH264Baseline; + mEncoderParams->intraPeriod = mParamAvc.nPFrames; //intraperiod + } else if (mParamAvc.eProfile == OMX_VIDEO_AVCProfileHigh) { + mEncoderParams->profile = (VAProfile)VAProfileH264High; + mEncoderParams->intraPeriod = mParamAvc.nPFrames + mParamAvc.nBFrames; //intraperiod + } // 0 - all luma and chroma block edges of the slice are filtered // 1 - deblocking is disabled for all block edges of the slice // 2 - all luma and chroma block edges of the slice are filtered // with exception of the block edges that coincide with slice boundaries mEncoderParams->disableDeblocking = 0; + + OMXVideoEncoderBase::SetVideoEncoderParam(); mVideoEncoder->getParameters(mAVCParams); @@ -132,33 +141,35 @@ OMX_ERRORTYPE OMXVideoEncoderAVC::SetVideoEncoderParam(void) { } mAVCParams->sliceNum.iSliceNum = mConfigIntelSliceNumbers.nISliceNumber; mAVCParams->sliceNum.pSliceNum = mConfigIntelSliceNumbers.nPSliceNumber; - mAVCParams->idrInterval = mConfigAvcIntraPeriod.nIDRPeriod; mAVCParams->maxSliceSize = mConfigNalSize.nNaluBytes * 8; - ret = mVideoEncoder ->setParameters(mAVCParams); - CHECK_ENCODE_STATUS("setParameters"); - - VideoConfigAVCIntraPeriod avcIntraPreriod; - avcIntraPreriod.idrInterval = mConfigAvcIntraPeriod.nIDRPeriod; - // hardcode intra period for AVC encoder, get value from OMX_VIDEO_PARAM_AVCTYPE.nPFrames or - // OMX_VIDEO_CONFIG_AVCINTRAPERIOD.nPFrames is a more flexible method - if (mParamAvc.nPFrames == 0) { - avcIntraPreriod.intraPeriod = 0; + if (mEncoderParams->intraPeriod == 0) { + mAVCParams->idrInterval = 0; + mAVCParams->ipPeriod = 0; } else { - avcIntraPreriod.intraPeriod = 30; + mAVCParams->idrInterval = mConfigAvcIntraPeriod.nIDRPeriod; //idrinterval + if (mParamAvc.eProfile == OMX_VIDEO_AVCProfileBaseline) { + mAVCParams->ipPeriod = 1; //ipperiod + } else if (mParamAvc.eProfile == OMX_VIDEO_AVCProfileHigh) { + mAVCParams->ipPeriod = mEncoderParams->intraPeriod / mParamAvc.nPFrames; //ipperiod + } } - ret = mVideoEncoder->setConfig(&avcIntraPreriod); - CHECK_ENCODE_STATUS("setConfig"); + ret = mVideoEncoder ->setParameters(mAVCParams); + CHECK_ENCODE_STATUS("setParameters"); LOGV("VUIFlag = %d\n", mAVCParams->VUIFlag); LOGV("sliceNum.iSliceNum = %d\n", mAVCParams->sliceNum.iSliceNum); LOGV("sliceNum.pSliceNum = %d\n", mAVCParams->sliceNum.pSliceNum); - LOGV("idrInterval = %d\n ", mAVCParams->idrInterval); LOGV("maxSliceSize = %d\n ", mAVCParams->maxSliceSize); + LOGV("intraPeriod = %d\n ", mEncoderParams->intraPeriod); + LOGV("idrInterval = %d\n ", mAVCParams->idrInterval); + LOGV("ipPeriod = %d\n ", mAVCParams->ipPeriod); return OMX_ErrorNone; } OMX_ERRORTYPE OMXVideoEncoderAVC::ProcessorInit(void) { mFirstFrame = OMX_TRUE; + mInputPictureCount = 0; + mFrameEncodedCount = 0; return OMXVideoEncoderBase::ProcessorInit(); } @@ -166,290 +177,376 @@ OMX_ERRORTYPE OMXVideoEncoderAVC::ProcessorDeinit(void) { return OMXVideoEncoderBase::ProcessorDeinit(); } -OMX_ERRORTYPE OMXVideoEncoderAVC::ProcessorProcess( - OMX_BUFFERHEADERTYPE **buffers, - buffer_retain_t *retains, - OMX_U32 numberBuffers) { +OMX_ERRORTYPE OMXVideoEncoderAVC::ProcessorStop(void) { + OMX_BUFFERHEADERTYPE *omxbuf = NULL; - OMX_U32 outfilledlen = 0; - OMX_S64 outtimestamp = 0; - OMX_U32 outflags = 0; - - OMX_ERRORTYPE oret = OMX_ErrorNone; - Encode_Status ret = ENCODE_SUCCESS; - - VideoEncOutputBuffer outBuf; - VideoEncRawBuffer inBuf; - - OMX_NALUFORMATSTYPE NaluFormat = mNalStreamFormat.eNaluFormat; - - LOGV_IF(buffers[INPORT_INDEX]->nFlags & OMX_BUFFERFLAG_EOS, - "%s(),%d: got OMX_BUFFERFLAG_EOS\n", __func__, __LINE__); - - if (!buffers[INPORT_INDEX]->nFilledLen) { - LOGE("%s(),%d: input buffer's nFilledLen is zero\n", __func__, __LINE__); - goto out; + while(!mBFrameList.empty()) { + omxbuf = * mBFrameList.begin(); + this->ports[INPORT_INDEX]->ReturnThisBuffer(omxbuf); + mBFrameList.erase(mBFrameList.begin()); } - if (bAndroidOpaqueFormat) { - mCurHandle = rgba2nv12conversion(buffers[INPORT_INDEX]); - } - - inBuf.data = buffers[INPORT_INDEX]->pBuffer + buffers[INPORT_INDEX]->nOffset; - inBuf.size = buffers[INPORT_INDEX]->nFilledLen; - - LOGV("inBuf.data=%x, size=%d",(unsigned)inBuf.data, inBuf.size); - - outBuf.data = buffers[OUTPORT_INDEX]->pBuffer + buffers[OUTPORT_INDEX]->nOffset; - outBuf.dataSize = 0; - outBuf.bufferSize = buffers[OUTPORT_INDEX]->nAllocLen - buffers[OUTPORT_INDEX]->nOffset; + return OMXVideoEncoderBase::ProcessorStop(); +} - if(inBuf.size<=0) { - LOGE("The Input buf size is 0\n"); - return OMX_ErrorBadParameter; +OMX_ERRORTYPE OMXVideoEncoderAVC::ProcessorPreEmptyBuffer(OMX_BUFFERHEADERTYPE* buffer) { + OMX_U32 EncodeInfo = 0; + OMX_U32 EncodeFrameType = 0; + + uint32_t poc = 0; + uint32_t idrPeriod = mAVCParams->idrInterval; + uint32_t IntraPeriod = mEncoderParams->intraPeriod; /*6*/ + uint32_t IpPeriod = mAVCParams->ipPeriod; /*3 */ + bool BFrameEnabled = IpPeriod > 1; + + LOGV("ProcessorPreEmptyBuffer idrPeriod=%d, IntraPeriod=%d, IpPeriod=%d, BFrameEnabled=%d\n", idrPeriod, IntraPeriod, IpPeriod, BFrameEnabled); + + //decide frame type, refer Merrifield Video Encoder Driver HLD Chapter 3.15 + if (idrPeriod == 0) + poc = mInputPictureCount; + else if (BFrameEnabled) + poc = mInputPictureCount % (IntraPeriod*idrPeriod + 1); + else + poc = mInputPictureCount % (IntraPeriod*idrPeriod); + + if (poc == 0 /*IDR*/) { + EncodeFrameType = F_IDR; + } else if (IntraPeriod == 0) { + EncodeFrameType = F_I; + }else if ((poc > IpPeriod) && ((poc - IpPeriod) % IntraPeriod == 0))/*I*/{ + EncodeFrameType = F_I; + if (BFrameEnabled) + SET_CO(EncodeInfo, CACHE_POP); + } else if ((poc % IpPeriod == 0) /*P*/ || (buffer->nFlags & OMX_BUFFERFLAG_EOS)/*EOS,always P*/) { + EncodeFrameType = F_P; + if (BFrameEnabled) + SET_CO(EncodeInfo, CACHE_POP); + } else { /*B*/ + EncodeFrameType = F_B; + SET_CO(EncodeInfo, CACHE_PUSH); } - LOGV("in buffer = 0x%x ts = %lld", - buffers[INPORT_INDEX]->pBuffer + buffers[INPORT_INDEX]->nOffset, - buffers[INPORT_INDEX]->nTimeStamp); + SET_FT(EncodeInfo, EncodeFrameType); + SET_FC(EncodeInfo, mInputPictureCount); - if(inBuf.data == NULL) { - LOGE("The Input buf is NULL\n"); - return OMX_ErrorBadParameter; - } + buffer->pPlatformPrivate = (OMX_PTR) EncodeInfo; - if(mFrameRetrieved) { - // encode and setConfig need to be thread safe - pthread_mutex_lock(&mSerializationLock); - ret = mVideoEncoder->encode(&inBuf); - pthread_mutex_unlock(&mSerializationLock); - CHECK_ENCODE_STATUS("encode"); - mFrameRetrieved = OMX_FALSE; + LOGV("ProcessorPreEmptyBuffer Frame %d, Type %s, EncodeInfo %x\n", mInputPictureCount, FrameTypeStr[EncodeFrameType], EncodeInfo); - // This is for buffer contention, we won't release current buffer - // but the last input buffer - ports[INPORT_INDEX]->ReturnAllRetainedBuffers(); - } + mInputPictureCount ++; + return OMX_ErrorNone; +} - if (mStoreMetaDataInBuffers) - NaluFormat = OMX_NaluFormatLengthPrefixedSeparateFirstHeader; +OMX_ERRORTYPE OMXVideoEncoderAVC::ProcessCacheOperation( + OMX_BUFFERHEADERTYPE **buffers, + buffer_retain_t *retains, + Encode_Info *pInfo) { - switch (NaluFormat) { - case OMX_NaluFormatStartCodes: + /* Check and do cache operation + */ + if (pInfo->CacheOperation == CACHE_NONE) { + if (buffers[INPORT_INDEX]->nFlags & OMX_BUFFERFLAG_EOS) + pInfo->EndOfEncode = true; - outBuf.format = OUTPUT_EVERYTHING; - ret = mVideoEncoder->getOutput(&outBuf); - CHECK_ENCODE_STATUS("encode"); + } else if (pInfo->CacheOperation == CACHE_PUSH) { + mBFrameList.push_front(buffers[INPORT_INDEX]); + retains[INPORT_INDEX] = BUFFER_RETAIN_CACHE; + retains[OUTPORT_INDEX] = BUFFER_RETAIN_GETAGAIN; - LOGV("output data size = %d", outBuf.dataSize); - outfilledlen = outBuf.dataSize; - outtimestamp = buffers[INPORT_INDEX]->nTimeStamp; + } else if (pInfo->CacheOperation == CACHE_POP) { + pInfo->NotStopFrame = true; //it is also a nstop frame + OMX_BUFFERHEADERTYPE *omxbuf = NULL; + uint32_t i = 0; - if (outBuf.flag & ENCODE_BUFFERFLAG_SYNCFRAME) { - outflags |= OMX_BUFFERFLAG_SYNCFRAME; - } + LOGV("BFrameList size = %d\n", mBFrameList.size()); - if(outBuf.flag & ENCODE_BUFFERFLAG_ENDOFFRAME) { - outflags |= OMX_BUFFERFLAG_ENDOFFRAME; - mFrameRetrieved = OMX_TRUE; - retains[INPORT_INDEX] = BUFFER_RETAIN_ACCUMULATE; + while(!mBFrameList.empty()) { + omxbuf = *mBFrameList.begin(); + if (buffers[INPORT_INDEX]->nFlags & OMX_BUFFERFLAG_EOS && i == 0 ) { + //this is final encode frame, make EOE + uint32_t tmp = (uint32_t) omxbuf->pPlatformPrivate; + tmp |= ENC_EOE; + omxbuf->pPlatformPrivate = (OMX_PTR) tmp; } else { - retains[INPORT_INDEX] = BUFFER_RETAIN_GETAGAIN; //get again - + //all these frames except final B frame in miniGOP can't be stopped at any time + //to avoid not breaking miniGOP integrity + if (i > 0) { + uint32_t tmp = (uint32_t) omxbuf->pPlatformPrivate; + tmp |= ENC_NSTOP; + omxbuf->pPlatformPrivate = (OMX_PTR) tmp; + } } + ports[INPORT_INDEX]->RetainThisBuffer(omxbuf, false); //push bufferq head - if (outfilledlen > 0) { - retains[OUTPORT_INDEX] = BUFFER_RETAIN_NOT_RETAIN; - } else { - retains[OUTPORT_INDEX] = BUFFER_RETAIN_GETAGAIN; - } + mBFrameList.erase(mBFrameList.begin()); //clear it from internal queue + i++; + } - break; - case OMX_NaluFormatOneNaluPerBuffer: + } else if (pInfo->CacheOperation == CACHE_RESET) { +// mBFrameList.clear(); + } - outBuf.format = OUTPUT_ONE_NAL; - ret = mVideoEncoder->getOutput(&outBuf); - CHECK_ENCODE_STATUS("getOutput"); - // Return code could not be ENCODE_BUFFER_TOO_SMALL - // If we don't return error, we will have dead lock issue - if (ret == ENCODE_BUFFER_TOO_SMALL) { - return OMX_ErrorUndefined; - } + pInfo->CacheOperation = CACHE_NONE; - LOGV("output codec data size = %d", outBuf.dataSize); + LOGV("ProcessCacheOperation OK\n"); + return OMX_ErrorNone; +} - outfilledlen = outBuf.dataSize; - outtimestamp = buffers[INPORT_INDEX]->nTimeStamp; +OMX_ERRORTYPE OMXVideoEncoderAVC::ProcessDataRetrieve( + OMX_BUFFERHEADERTYPE **buffers, + buffer_retain_t *retains, + Encode_Info *pInfo) { - if (outBuf.flag & ENCODE_BUFFERFLAG_SYNCFRAME) { - outflags |= OMX_BUFFERFLAG_SYNCFRAME; - } + OMX_NALUFORMATSTYPE NaluFormat = mNalStreamFormat.eNaluFormat; - if(outBuf.flag & ENCODE_BUFFERFLAG_ENDOFFRAME) { - outflags |= OMX_BUFFERFLAG_ENDOFFRAME; - mFrameRetrieved = OMX_TRUE; - retains[INPORT_INDEX] = BUFFER_RETAIN_ACCUMULATE; + if (mStoreMetaDataInBuffers) + NaluFormat = OMX_NaluFormatLengthPrefixedSeparateFirstHeader; - } else { - retains[INPORT_INDEX] = BUFFER_RETAIN_GETAGAIN; //get again - } + VideoEncOutputBuffer outBuf; + outBuf.data = buffers[OUTPORT_INDEX]->pBuffer + buffers[OUTPORT_INDEX]->nOffset; + outBuf.bufferSize = buffers[OUTPORT_INDEX]->nAllocLen - buffers[OUTPORT_INDEX]->nOffset; + outBuf.dataSize = 0; + outBuf.remainingSize = 0; + outBuf.flag = 0; + outBuf.timeStamp = 0; - if (outfilledlen > 0) { - retains[OUTPORT_INDEX] = BUFFER_RETAIN_NOT_RETAIN; - } else { - retains[OUTPORT_INDEX] = BUFFER_RETAIN_GETAGAIN; - } + switch (NaluFormat) { + case OMX_NaluFormatStartCodes: + outBuf.format = OUTPUT_EVERYTHING; + break; + case OMX_NaluFormatOneNaluPerBuffer: + outBuf.format = OUTPUT_ONE_NAL; break; - case OMX_NaluFormatStartCodesSeparateFirstHeader: + case OMX_NaluFormatStartCodesSeparateFirstHeader: + case OMX_NaluFormatLengthPrefixedSeparateFirstHeader: if(mFirstFrame) { - LOGV("mFirstFrame\n"); + LOGV("FirstFrame to output codec data\n"); outBuf.format = OUTPUT_CODEC_DATA; - ret = mVideoEncoder->getOutput(&outBuf); - CHECK_ENCODE_STATUS("getOutput"); + } else { + if (NaluFormat == OMX_NaluFormatStartCodesSeparateFirstHeader) + outBuf.format = OUTPUT_EVERYTHING; + else + outBuf.format = OUTPUT_LENGTH_PREFIXED; + } + break; - // Return code could not be ENCODE_BUFFER_TOO_SMALL - // If we don't return error, we will have dead lock issue - if (ret == ENCODE_BUFFER_TOO_SMALL) { - return OMX_ErrorUndefined; - } + default: + return OMX_ErrorUndefined; + } - LOGV("output codec data size = %d", outBuf.dataSize); + //start getOutput + Encode_Status ret = mVideoEncoder->getOutput(&outBuf); - outflags |= OMX_BUFFERFLAG_CODECCONFIG; - outflags |= OMX_BUFFERFLAG_ENDOFFRAME; - outflags |= OMX_BUFFERFLAG_SYNCFRAME; + if (ret < ENCODE_SUCCESS) { + LOGE("libMIX getOutput Failed. ret = 0x%08x, drop this frame\n", ret); + outBuf.dataSize = 0; + outBuf.flag |= ENCODE_BUFFERFLAG_ENDOFFRAME; +// return OMX_ErrorUndefined; - // This input buffer need to be gotten again - retains[INPORT_INDEX] = BUFFER_RETAIN_GETAGAIN; - outfilledlen = outBuf.dataSize; - mFirstFrame = OMX_FALSE; - } else { - outBuf.format = OUTPUT_EVERYTHING; - ret = mVideoEncoder->getOutput(&outBuf); - CHECK_ENCODE_STATUS("getOutput"); + } else if (ret == ENCODE_BUFFER_TOO_SMALL) + return OMX_ErrorUndefined; // Return code could not be ENCODE_BUFFER_TOO_SMALL, or we will have dead lock issue - LOGV("output data size = %d", outBuf.dataSize); + LOGV("libMIX getOutput data size= %d, flag=0x%08x", outBuf.dataSize, outBuf.flag); + OMX_U32 outfilledlen = outBuf.dataSize; + OMX_S64 outtimestamp = outBuf.timeStamp; + OMX_U32 outflags = 0; - outfilledlen = outBuf.dataSize; - outtimestamp = buffers[INPORT_INDEX]->nTimeStamp; + //if codecconfig + if (outBuf.flag & ENCODE_BUFFERFLAG_CODECCONFIG) + outflags |= OMX_BUFFERFLAG_CODECCONFIG; + + //if syncframe + if (outBuf.flag & ENCODE_BUFFERFLAG_SYNCFRAME) + outflags |= OMX_BUFFERFLAG_SYNCFRAME; + + //if eos + if (outBuf.flag & ENCODE_BUFFERFLAG_ENDOFSTREAM) + outflags |= OMX_BUFFERFLAG_EOS; + + //if full encoded data retrieved + if(outBuf.flag & ENCODE_BUFFERFLAG_ENDOFFRAME) { + LOGV("Output a complete Frame done\n"); + outflags |= OMX_BUFFERFLAG_ENDOFFRAME; + + if ((NaluFormat == OMX_NaluFormatStartCodesSeparateFirstHeader + || NaluFormat == OMX_NaluFormatLengthPrefixedSeparateFirstHeader ) && mFirstFrame ) { + // This input buffer need to be gotten again + retains[INPORT_INDEX] = BUFFER_RETAIN_GETAGAIN; + mFirstFrame = OMX_FALSE; + + } else { + pInfo->DataRetrieved = true; + ports[INPORT_INDEX]->ReturnAllRetainedBuffers(); //return last all retained frames + if (outBuf.flag & ENCODE_BUFFERFLAG_ENDOFSTREAM) + retains[INPORT_INDEX] = BUFFER_RETAIN_NOT_RETAIN; + else + retains[INPORT_INDEX] = BUFFER_RETAIN_ACCUMULATE; //retain current frame + + mFrameOutputCount ++; + } + } else //not complete output all encoded data, push again to continue output + retains[INPORT_INDEX] = BUFFER_RETAIN_GETAGAIN; - if (outBuf.flag & ENCODE_BUFFERFLAG_SYNCFRAME) { - outflags |= OMX_BUFFERFLAG_SYNCFRAME; - } - if(outBuf.flag & ENCODE_BUFFERFLAG_ENDOFFRAME) { - LOGV("Get buffer done\n"); - outflags |= OMX_BUFFERFLAG_ENDOFFRAME; - mFrameRetrieved = OMX_TRUE; - retains[INPORT_INDEX] = BUFFER_RETAIN_ACCUMULATE; + LOGV("OMX output buffer = %p:%d, flag = %x, ts=%lld", buffers[OUTPORT_INDEX]->pBuffer, outfilledlen, outflags, outtimestamp); - } else { - retains[INPORT_INDEX] = BUFFER_RETAIN_GETAGAIN; //get again + if (outfilledlen > 0) { + retains[OUTPORT_INDEX] = BUFFER_RETAIN_NOT_RETAIN; + buffers[OUTPORT_INDEX]->nFilledLen = outfilledlen; + buffers[OUTPORT_INDEX]->nTimeStamp = outtimestamp; + buffers[OUTPORT_INDEX]->nFlags = outflags; + if (outBuf.flag & ENCODE_BUFFERFLAG_NSTOPFRAME) + buffers[OUTPORT_INDEX]->pPlatformPrivate = (OMX_PTR) 0x00000001; //indicate it is nstop frame + } + else + retains[OUTPORT_INDEX] = BUFFER_RETAIN_GETAGAIN; - } - } + LOGV("ProcessDataRetrieve OK\n"); + return OMX_ErrorNone; +} - if (outfilledlen > 0) { - retains[OUTPORT_INDEX] = BUFFER_RETAIN_NOT_RETAIN; - } else { - retains[OUTPORT_INDEX] = BUFFER_RETAIN_GETAGAIN; - } - break; - case OMX_NaluFormatLengthPrefixedSeparateFirstHeader: +OMX_ERRORTYPE OMXVideoEncoderAVC::ProcessorProcess( + OMX_BUFFERHEADERTYPE **buffers, + buffer_retain_t *retains, + OMX_U32 numberBuffers) { - if(mFirstFrame) { - LOGV("mFirstFrame\n"); - outBuf.format = OUTPUT_CODEC_DATA; - ret = mVideoEncoder->getOutput(&outBuf); - CHECK_ENCODE_STATUS("getOutput"); - // Return code could not be ENCODE_BUFFER_TOO_SMALL - // If we don't return error, we will have dead lock issue - if (ret == ENCODE_BUFFER_TOO_SMALL) { - return OMX_ErrorUndefined; - } + OMX_ERRORTYPE oret = OMX_ErrorNone; + Encode_Status ret = ENCODE_SUCCESS; - LOGV("output codec data size = %d", outBuf.dataSize); + VideoEncRawBuffer inBuf; - outflags |= OMX_BUFFERFLAG_CODECCONFIG; - outflags |= OMX_BUFFERFLAG_ENDOFFRAME; - outflags |= OMX_BUFFERFLAG_SYNCFRAME; + inBuf.data = buffers[INPORT_INDEX]->pBuffer + buffers[INPORT_INDEX]->nOffset; + inBuf.size = buffers[INPORT_INDEX]->nFilledLen; + inBuf.flag = 0; + inBuf.timeStamp = buffers[INPORT_INDEX]->nTimeStamp; + + if (buffers[INPORT_INDEX]->nFlags & OMX_BUFFERFLAG_EOS) { + LOGV("%s(),%d: got OMX_BUFFERFLAG_EOS\n", __func__, __LINE__); + if(inBuf.size<=0 || inBuf.data == NULL) { + LOGE("The Input buf size is 0 or buf is NULL, return with no error\n"); + retains[INPORT_INDEX] = BUFFER_RETAIN_NOT_RETAIN; + return OMX_ErrorNone; + } + } - // This input buffer need to be gotten again - retains[INPORT_INDEX] = BUFFER_RETAIN_GETAGAIN; - outfilledlen = outBuf.dataSize; - mFirstFrame = OMX_FALSE; - } else { - outBuf.format = OUTPUT_LENGTH_PREFIXED; - ret = mVideoEncoder->getOutput(&outBuf); + if(inBuf.size<=0 || inBuf.data == NULL) { + LOGE("The Input buf size is 0 or buf is NULL, return with error\n"); + return OMX_ErrorBadParameter; + } - if (ret < ENCODE_SUCCESS) { \ - LOGE("getOutput Failed. ret = 0x%08x, drop this frame\n", ret); - outBuf.dataSize = 0; - outBuf.flag |= ENCODE_BUFFERFLAG_ENDOFFRAME; - } + LOGV("Input OMX Buffer = 0x%x, size=%d, ts = %lld", inBuf.data, inBuf.size, buffers[INPORT_INDEX]->nTimeStamp); + + //get frame encode info + Encode_Info eInfo; + uint32_t encodeInfo = (uint32_t) buffers[INPORT_INDEX]->pPlatformPrivate; + eInfo.FrameType = GET_FT(encodeInfo); + eInfo.EncodeComplete = encodeInfo & ENC_EC; + eInfo.DataRetrieved = encodeInfo & ENC_DR; + eInfo.CacheOperation = GET_CO(encodeInfo); + eInfo.EndOfEncode = encodeInfo & ENC_EOE; + eInfo.NotStopFrame = encodeInfo & ENC_NSTOP; + eInfo.FrameCount = GET_FC(encodeInfo); + + LOGV("ProcessorProcess Frame %d, type:%s, EC:%d, DR:%d, CO:%s, EOE=%d\n", + eInfo.FrameCount , FrameTypeStr[eInfo.FrameType], eInfo.EncodeComplete, + eInfo.DataRetrieved, CacheOperationStr[eInfo.CacheOperation], eInfo.EndOfEncode ); + + //for live effect + if (bAndroidOpaqueFormat) + mCurHandle = rgba2nv12conversion(buffers[INPORT_INDEX]); - LOGV("output data size = %d", outBuf.dataSize); + if (eInfo.CacheOperation == CACHE_PUSH) { + ProcessCacheOperation(buffers, retains, &eInfo); + //nothing should be done in this case, just store status and return + goto exit; + }else + ProcessCacheOperation(buffers, retains, &eInfo); - outfilledlen = outBuf.dataSize; - outtimestamp = buffers[INPORT_INDEX]->nTimeStamp; + /* Check encode state, if not, call libMIX encode() + */ + if(!eInfo.EncodeComplete) { + // encode and setConfig need to be thread safe + if (eInfo.EndOfEncode) + inBuf.flag |= ENCODE_BUFFERFLAG_ENDOFSTREAM; + if (eInfo.NotStopFrame) + inBuf.flag |= ENCODE_BUFFERFLAG_NSTOPFRAME; + inBuf.type = (FrameType) eInfo.FrameType; - if (outBuf.flag & ENCODE_BUFFERFLAG_SYNCFRAME) { - outflags |= OMX_BUFFERFLAG_SYNCFRAME; - } - if(outBuf.flag & ENCODE_BUFFERFLAG_ENDOFFRAME) { - LOGV("Get buffer done\n"); - outflags |= OMX_BUFFERFLAG_ENDOFFRAME; - mFrameRetrieved = OMX_TRUE; - retains[INPORT_INDEX] = BUFFER_RETAIN_ACCUMULATE; - - } else { - retains[INPORT_INDEX] = BUFFER_RETAIN_GETAGAIN; //get again - } - } + pthread_mutex_lock(&mSerializationLock); + ret = mVideoEncoder->encode(&inBuf); + pthread_mutex_unlock(&mSerializationLock); + CHECK_ENCODE_STATUS("encode"); + eInfo.EncodeComplete = true; - if (outfilledlen > 0) { - retains[OUTPORT_INDEX] = BUFFER_RETAIN_NOT_RETAIN; - } else { - retains[OUTPORT_INDEX] = BUFFER_RETAIN_GETAGAIN; - } - break; + mFrameEncodedCount ++; + if (mFrameEncodedCount == 2) {//not getoutput for second encode frame to keep in async mode + eInfo.DataRetrieved = true; + retains[INPORT_INDEX] = BUFFER_RETAIN_ACCUMULATE; + retains[OUTPORT_INDEX] = BUFFER_RETAIN_GETAGAIN; + } } -out: - LOGV("output buffers = %p:%d, flag = %x", buffers[OUTPORT_INDEX]->pBuffer, outfilledlen, outflags); - - if(retains[OUTPORT_INDEX] != BUFFER_RETAIN_GETAGAIN) { - buffers[OUTPORT_INDEX]->nFilledLen = outfilledlen; - buffers[OUTPORT_INDEX]->nTimeStamp = outtimestamp; - buffers[OUTPORT_INDEX]->nFlags = outflags; + /* Check encode data retrieve state, if not complete output, continue call libMIX getOutput() + */ + if (!eInfo.DataRetrieved) + oret = ProcessDataRetrieve(buffers, retains, &eInfo); + + /* Check EOE state, if yes, this is final encode frame, need to push this buffer again + to call getOutput again for final output + */ + if (eInfo.EndOfEncode && eInfo.EncodeComplete && eInfo.DataRetrieved) { + eInfo.DataRetrieved = false; + eInfo.EndOfEncode = false; + retains[INPORT_INDEX] = BUFFER_RETAIN_GETAGAIN; } - if (retains[INPORT_INDEX] == BUFFER_RETAIN_NOT_RETAIN || - retains[INPORT_INDEX] == BUFFER_RETAIN_ACCUMULATE ) { - mFrameInputCount ++; +#if 0 + if (avcEncParamIntelBitrateType.eControlRate != OMX_Video_Intel_ControlRateVideoConferencingMode) { + if (oret == (OMX_ERRORTYPE) OMX_ErrorIntelExtSliceSizeOverflow) { + oret = OMX_ErrorNone; + } } +#endif - if (retains[OUTPORT_INDEX] == BUFFER_RETAIN_NOT_RETAIN) mFrameOutputCount ++; +exit: if (bAndroidOpaqueFormat && buffers[INPORT_INDEX]->nFilledLen != 0) { // Restore input buffer's content + if (mCurHandle < 0) + return OMX_ErrorUndefined; + buffers[INPORT_INDEX]->nFilledLen = 4 + sizeof(buffer_handle_t); memcpy(buffers[INPORT_INDEX]->pBuffer, mBufferHandleMaps[mCurHandle].backBuffer, buffers[INPORT_INDEX]->nFilledLen); - } -#if 0 - if (avcEncParamIntelBitrateType.eControlRate != OMX_Video_Intel_ControlRateVideoConferencingMode) { - if (oret == (OMX_ERRORTYPE) OMX_ErrorIntelExtSliceSizeOverflow) { - oret = OMX_ErrorNone; - } - } -#endif - LOGV_IF(oret == OMX_ErrorNone, "%s(),%d: exit, encode is done\n", __func__, __LINE__); + /* restore all states into input OMX buffer + */ + if (eInfo.EncodeComplete) + encodeInfo |= ENC_EC; + else + encodeInfo &= ~ENC_EC; + + if (eInfo.DataRetrieved) + encodeInfo |= ENC_DR; + else + encodeInfo &= ~ENC_DR; + + if (eInfo.EndOfEncode) + encodeInfo |= ENC_EOE; + else + encodeInfo &= ~ENC_EOE; + + if (eInfo.NotStopFrame) + encodeInfo |= ENC_NSTOP; + else + encodeInfo &= ~ENC_NSTOP; + + SET_CO(encodeInfo, eInfo.CacheOperation); + buffers[INPORT_INDEX]->pPlatformPrivate = (OMX_PTR) encodeInfo; return oret; @@ -481,6 +578,7 @@ OMX_ERRORTYPE OMXVideoEncoderAVC::GetParamVideoProfileLevelQuerySupported(OMX_PT OMX_U32 level; } plTable[] = { {OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel41}, +// {OMX_VIDEO_AVCProfileHigh, OMX_VIDEO_AVCLevel41}, }; OMX_U32 count = sizeof(plTable)/sizeof(ProfileLevelTable); @@ -514,6 +612,18 @@ OMX_ERRORTYPE OMXVideoEncoderAVC::SetParamVideoAvc(OMX_PTR pStructure) { CHECK_PORT_INDEX(p, OUTPORT_INDEX); CHECK_SET_PARAM_STATE(); + if(p->bEnableASO == OMX_TRUE) + return OMX_ErrorUnsupportedSetting; + + if(p->bEnableFMO == OMX_TRUE) + return OMX_ErrorUnsupportedSetting; + + if(p->bEnableUEP == OMX_TRUE) + return OMX_ErrorUnsupportedSetting; + + if(p->bEnableRS == OMX_TRUE) + return OMX_ErrorUnsupportedSetting; + // TODO: do we need to check if port is enabled? // TODO: see SetPortAvcParam implementation - Can we make simple copy???? memcpy(&mParamAvc, p, sizeof(mParamAvc)); @@ -628,12 +738,26 @@ OMX_ERRORTYPE OMXVideoEncoderAVC::SetConfigVideoAVCIntraPeriod(OMX_PTR pStructur // TODO: apply AVC Intra Period configuration in Executing state VideoConfigAVCIntraPeriod avcIntraPreriod; - avcIntraPreriod.idrInterval = mConfigAvcIntraPeriod.nIDRPeriod; avcIntraPreriod.intraPeriod = mConfigAvcIntraPeriod.nPFrames; + if (avcIntraPreriod.intraPeriod == 0) { + avcIntraPreriod.idrInterval = 0; + avcIntraPreriod.ipPeriod = 0; + } else { + avcIntraPreriod.idrInterval = mConfigAvcIntraPeriod.nIDRPeriod; + if (mParamAvc.eProfile == OMX_VIDEO_AVCProfileBaseline) { + avcIntraPreriod.ipPeriod = 1; + } else if (mParamAvc.eProfile == OMX_VIDEO_AVCProfileHigh) { + avcIntraPreriod.ipPeriod = avcIntraPreriod.intraPeriod / mParamAvc.nPFrames; + } + } retStatus = mVideoEncoder->setConfig(&avcIntraPreriod); if(retStatus != ENCODE_SUCCESS) { - LOGW("set avc intra prerod config failed"); + LOGW("set avc intra period config failed"); } + + mEncoderParams->intraPeriod = avcIntraPreriod.intraPeriod; + mAVCParams->idrInterval = avcIntraPreriod.idrInterval; + mAVCParams->ipPeriod = avcIntraPreriod.ipPeriod; return OMX_ErrorNone; } |