| /* |
| * Copyright (c) 2009-2011 Intel Corporation. All rights reserved. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #define LOG_TAG "OMXVideoEncoderAVC" |
| #include "OMXVideoEncoderAVC.h" |
| #include "IntelMetadataBuffer.h" |
| |
| static const char *AVC_MIME_TYPE = "video/h264"; |
| |
| struct ProfileMap { |
| OMX_VIDEO_AVCPROFILETYPE key; |
| VAProfile value; |
| const char *name; |
| }; |
| |
| struct LevelMap { |
| OMX_VIDEO_AVCLEVELTYPE key; |
| uint32_t value; |
| const char *name; |
| }; |
| |
| static ProfileMap ProfileTable[] = { |
| { OMX_VIDEO_AVCProfileBaseline, VAProfileH264Baseline, "AVC Baseline" }, |
| { OMX_VIDEO_AVCProfileMain, VAProfileH264Main, "AVC Main" }, |
| { OMX_VIDEO_AVCProfileHigh, VAProfileH264High, "AVC High" }, |
| { (OMX_VIDEO_AVCPROFILETYPE) 0, (VAProfile) 0, "Not Supported" }, |
| }; |
| |
| static LevelMap LevelTable[] = { |
| { OMX_VIDEO_AVCLevel4, 40, "AVC Level4" }, |
| { OMX_VIDEO_AVCLevel41, 41, "AVC Level41" }, |
| { OMX_VIDEO_AVCLevel42, 42, "AVC Level42" }, |
| { OMX_VIDEO_AVCLevel5, 50, "AVC Level5" }, |
| { OMX_VIDEO_AVCLevel51, 51, "AVC Level51" }, |
| { (OMX_VIDEO_AVCLEVELTYPE) 0, 0, "Not Supported" }, |
| }; |
| |
| #define FIND_BYKEY(table, x, y) {\ |
| for(int ii = 0; ; ii++) { \ |
| if (table[ii].key == x || table[ii].key == 0) { \ |
| y = ii; \ |
| break; \ |
| } \ |
| } \ |
| }\ |
| |
| #define FIND_BYVALUE(table, x, y) {\ |
| for(int ii = 0; ; ii++) { \ |
| if (table[ii].value == x || table[ii].value == 0) { \ |
| y = ii; \ |
| break; \ |
| } \ |
| } \ |
| } \ |
| |
| OMXVideoEncoderAVC::OMXVideoEncoderAVC() { |
| BuildHandlerList(); |
| mVideoEncoder = createVideoEncoder(AVC_MIME_TYPE); |
| if (!mVideoEncoder) { |
| LOGE("OMX_ErrorInsufficientResources"); |
| return; |
| } |
| |
| mAVCParams = new VideoParamsAVC(); |
| if (!mAVCParams) { |
| LOGE("OMX_ErrorInsufficientResources"); |
| return; |
| } |
| |
| //Query supported Profile/Level |
| mPLTableCount = 0; |
| |
| VAProfile profiles[MAX_H264_PROFILE] = {VAProfileH264High, VAProfileH264Main, VAProfileH264Baseline}; |
| |
| VideoParamsProfileLevel pl; |
| for (int i=0; i < MAX_H264_PROFILE; i++) { |
| pl.profile = profiles[i]; |
| pl.level = 0; |
| pl.isSupported = false; |
| |
| mVideoEncoder->getParameters(&pl); |
| if (pl.isSupported) { |
| uint32_t profile_index; |
| uint32_t level_index; |
| |
| FIND_BYVALUE(ProfileTable, pl.profile, profile_index); |
| if (ProfileTable[profile_index].key == (OMX_VIDEO_AVCPROFILETYPE) 0) |
| continue; |
| |
| FIND_BYVALUE(LevelTable, pl.level, level_index); |
| if (LevelTable[level_index].key == (OMX_VIDEO_AVCLEVELTYPE) 0) |
| continue; |
| |
| mPLTable[mPLTableCount].profile = ProfileTable[profile_index].key; |
| mPLTable[mPLTableCount].level = LevelTable[level_index].key; |
| mPLTableCount ++; |
| LOGV("Support Profile:%s, Level:%s\n", ProfileTable[profile_index].name, LevelTable[level_index].name); |
| } |
| } |
| |
| mEmptyEOSBuf = OMX_FALSE; |
| } |
| |
| OMXVideoEncoderAVC::~OMXVideoEncoderAVC() { |
| if(mAVCParams) { |
| delete mAVCParams; |
| mAVCParams = NULL; |
| } |
| } |
| |
| OMX_ERRORTYPE OMXVideoEncoderAVC::InitOutputPortFormatSpecific(OMX_PARAM_PORTDEFINITIONTYPE *paramPortDefinitionOutput) { |
| // OMX_VIDEO_PARAM_AVCTYPE |
| memset(&mParamAvc, 0, sizeof(mParamAvc)); |
| SetTypeHeader(&mParamAvc, sizeof(mParamAvc)); |
| mParamAvc.nPortIndex = OUTPORT_INDEX; |
| |
| if (mPLTableCount > 0) { |
| mParamAvc.eProfile = (OMX_VIDEO_AVCPROFILETYPE) mPLTable[0].profile; |
| mParamAvc.eLevel = (OMX_VIDEO_AVCLEVELTYPE)mPLTable[0].level; |
| } else { |
| LOGE("No supported profile/level\n"); |
| return OMX_ErrorUndefined; |
| } |
| mParamAvc.nAllowedPictureTypes = OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP; |
| mParamAvc.nPFrames = 29; |
| mParamAvc.nBFrames = 0; |
| |
| // OMX_NALSTREAMFORMATTYPE |
| memset(&mNalStreamFormat, 0, sizeof(mNalStreamFormat)); |
| SetTypeHeader(&mNalStreamFormat, sizeof(mNalStreamFormat)); |
| mNalStreamFormat.nPortIndex = OUTPORT_INDEX; |
| // TODO: check if this is desired Nalu Format |
| //mNalStreamFormat.eNaluFormat = OMX_NaluFormatLengthPrefixedSeparateFirstHeader; |
| // OMX_VIDEO_CONFIG_AVCINTRAPERIOD |
| memset(&mConfigAvcIntraPeriod, 0, sizeof(mConfigAvcIntraPeriod)); |
| SetTypeHeader(&mConfigAvcIntraPeriod, sizeof(mConfigAvcIntraPeriod)); |
| mConfigAvcIntraPeriod.nPortIndex = OUTPORT_INDEX; |
| // TODO: need to be populated from Video Encoder |
| mConfigAvcIntraPeriod.nIDRPeriod = 1; |
| mConfigAvcIntraPeriod.nPFrames = 29; |
| |
| // OMX_VIDEO_CONFIG_NALSIZE |
| memset(&mConfigNalSize, 0, sizeof(mConfigNalSize)); |
| SetTypeHeader(&mConfigNalSize, sizeof(mConfigNalSize)); |
| mConfigNalSize.nPortIndex = OUTPORT_INDEX; |
| mConfigNalSize.nNaluBytes = 0; |
| |
| // OMX_VIDEO_PARAM_INTEL_AVCVUI |
| memset(&mParamIntelAvcVui, 0, sizeof(mParamIntelAvcVui)); |
| SetTypeHeader(&mParamIntelAvcVui, sizeof(mParamIntelAvcVui)); |
| mParamIntelAvcVui.nPortIndex = OUTPORT_INDEX; |
| mParamIntelAvcVui.bVuiGeneration = OMX_FALSE; |
| |
| // OMX_VIDEO_CONFIG_INTEL_SLICE_NUMBERS |
| memset(&mConfigIntelSliceNumbers, 0, sizeof(mConfigIntelSliceNumbers)); |
| SetTypeHeader(&mConfigIntelSliceNumbers, sizeof(mConfigIntelSliceNumbers)); |
| mConfigIntelSliceNumbers.nPortIndex = OUTPORT_INDEX; |
| mConfigIntelSliceNumbers.nISliceNumber = 1; |
| mConfigIntelSliceNumbers.nPSliceNumber = 1; |
| |
| // Override OMX_PARAM_PORTDEFINITIONTYPE |
| paramPortDefinitionOutput->nBufferCountActual = OUTPORT_ACTUAL_BUFFER_COUNT; |
| paramPortDefinitionOutput->nBufferCountMin = OUTPORT_MIN_BUFFER_COUNT; |
| paramPortDefinitionOutput->nBufferSize = OUTPORT_BUFFER_SIZE; |
| paramPortDefinitionOutput->format.video.cMIMEType = (OMX_STRING)AVC_MIME_TYPE; |
| paramPortDefinitionOutput->format.video.eCompressionFormat = OMX_VIDEO_CodingAVC; |
| |
| // Override OMX_VIDEO_PARAM_PROFILELEVELTYPE |
| // TODO: check if profile/level supported is correct |
| mParamProfileLevel.eProfile = mParamAvc.eProfile; |
| mParamProfileLevel.eLevel = mParamAvc.eLevel; |
| |
| // Override OMX_VIDEO_PARAM_BITRATETYPE |
| mParamBitrate.nTargetBitrate = 192000; |
| |
| // Override OMX_VIDEO_CONFIG_INTEL_BITRATETYPE |
| mConfigIntelBitrate.nInitialQP = 0; // Initial QP for I frames |
| |
| return OMX_ErrorNone; |
| } |
| |
| OMX_ERRORTYPE OMXVideoEncoderAVC::SetVideoEncoderParam(void) { |
| |
| Encode_Status ret = ENCODE_SUCCESS; |
| LOGV("OMXVideoEncoderAVC::SetVideoEncoderParam"); |
| |
| if (!mEncoderParams) { |
| LOGE("NULL pointer: mEncoderParams"); |
| return OMX_ErrorBadParameter; |
| } |
| |
| mVideoEncoder->getParameters(mEncoderParams); |
| uint32_t index; |
| FIND_BYKEY(ProfileTable, mParamAvc.eProfile, index); |
| if (ProfileTable[index].value != 0) |
| mEncoderParams->profile = ProfileTable[index].value; |
| |
| if (mParamAvc.nAllowedPictureTypes & OMX_VIDEO_PictureTypeB) |
| mEncoderParams->intraPeriod = mParamAvc.nPFrames + mParamAvc.nBFrames; |
| else |
| mEncoderParams->intraPeriod = mParamAvc.nPFrames + 1; |
| |
| // 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); |
| if(mParamIntelAvcVui.bVuiGeneration == OMX_TRUE) { |
| mAVCParams->VUIFlag = 1; |
| } |
| // For resolution below VGA, single core can hit the performance target and provide VQ gain |
| if (mEncoderParams->resolution.width <= 640 && mEncoderParams->resolution.height <= 480) { |
| mConfigIntelSliceNumbers.nISliceNumber = 1; |
| mConfigIntelSliceNumbers.nPSliceNumber = 1; |
| } |
| mAVCParams->sliceNum.iSliceNum = mConfigIntelSliceNumbers.nISliceNumber; |
| mAVCParams->sliceNum.pSliceNum = mConfigIntelSliceNumbers.nPSliceNumber; |
| mAVCParams->maxSliceSize = mConfigNalSize.nNaluBytes * 8; |
| |
| if (mEncoderParams->intraPeriod == 0) { |
| mAVCParams->idrInterval = 0; |
| mAVCParams->ipPeriod = 1; |
| } else { |
| mAVCParams->idrInterval = mConfigAvcIntraPeriod.nIDRPeriod; //idrinterval |
| if (mParamAvc.nAllowedPictureTypes & OMX_VIDEO_PictureTypeB) |
| mAVCParams->ipPeriod = mEncoderParams->intraPeriod / mParamAvc.nPFrames; |
| else |
| mAVCParams->ipPeriod = 1; |
| } |
| |
| 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("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) { |
| mCSDOutputted = OMX_FALSE; |
| mInputPictureCount = 0; |
| mFrameEncodedCount = 0; |
| return OMXVideoEncoderBase::ProcessorInit(); |
| } |
| |
| OMX_ERRORTYPE OMXVideoEncoderAVC::ProcessorDeinit(void) { |
| return OMXVideoEncoderBase::ProcessorDeinit(); |
| } |
| |
| OMX_ERRORTYPE OMXVideoEncoderAVC::ProcessorStop(void) { |
| OMX_BUFFERHEADERTYPE *omxbuf = NULL; |
| |
| while(!mBFrameList.empty()) { |
| omxbuf = * mBFrameList.begin(); |
| this->ports[INPORT_INDEX]->ReturnThisBuffer(omxbuf); |
| mBFrameList.erase(mBFrameList.begin()); |
| } |
| |
| mEmptyEOSBuf = OMX_FALSE; |
| return OMXVideoEncoderBase::ProcessorStop(); |
| } |
| |
| 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; |
| uint32_t IpPeriod = mAVCParams->ipPeriod; |
| bool BFrameEnabled = IpPeriod > 1; |
| uint32_t GOP = 0; |
| |
| if (idrPeriod == 0 || IntraPeriod == 0) { |
| GOP = 0xFFFFFFFF; |
| if (IntraPeriod == 0) |
| IntraPeriod = 0xFFFFFFFF; |
| } else if (BFrameEnabled) |
| GOP = IntraPeriod*idrPeriod + 1; |
| else |
| GOP = IntraPeriod*idrPeriod; |
| |
| 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.17 |
| poc = mInputPictureCount % GOP; |
| |
| if (poc == 0 /*IDR*/) { |
| EncodeFrameType = F_IDR; |
| } else if (IntraPeriod == 1) { |
| 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); |
| } |
| |
| SET_FT(EncodeInfo, EncodeFrameType); |
| SET_FC(EncodeInfo, mInputPictureCount); |
| |
| buffer->pPlatformPrivate = (OMX_PTR) EncodeInfo; |
| |
| LOGV("ProcessorPreEmptyBuffer Frame %d, Type %s, EncodeInfo %x\n", mInputPictureCount, FrameTypeStr[EncodeFrameType], EncodeInfo); |
| |
| mInputPictureCount ++; |
| return OMX_ErrorNone; |
| } |
| |
| OMX_BOOL OMXVideoEncoderAVC::ProcessCacheOperation(OMX_BUFFERHEADERTYPE **buffers) { |
| |
| OMX_BOOL Cached = OMX_FALSE; |
| |
| //get frame encode info |
| Encode_Info eInfo; |
| uint32_t encodeInfo = (uint32_t) buffers[INPORT_INDEX]->pPlatformPrivate; |
| eInfo.FrameType = GET_FT(encodeInfo); |
| |
| eInfo.CacheOperation = GET_CO(encodeInfo); |
| eInfo.NotStopFrame = encodeInfo & ENC_NSTOP; |
| eInfo.FrameCount = GET_FC(encodeInfo); |
| |
| LOGV("ProcessCacheOperation Frame %d, type:%s, CacheOps:%s, NoSTOP=%d, EOS=%d\n", |
| eInfo.FrameCount, FrameTypeStr[eInfo.FrameType], CacheOperationStr[eInfo.CacheOperation], |
| eInfo.NotStopFrame, buffers[INPORT_INDEX]->nFlags & OMX_BUFFERFLAG_EOS); |
| |
| OMX_BOOL emptyEOSBuf = OMX_FALSE; |
| if (buffers[INPORT_INDEX]->nFilledLen == 0 && buffers[INPORT_INDEX]->nFlags & OMX_BUFFERFLAG_EOS) { |
| //meet an empty EOS buffer |
| emptyEOSBuf = OMX_TRUE; |
| LOGV("ProcessCacheOperation: This frame is Empty EOS buffer\n"); |
| } |
| |
| if (eInfo.CacheOperation == CACHE_NONE) { |
| //nothing to do |
| } else if (eInfo.CacheOperation == CACHE_PUSH) { |
| mBFrameList.push_front(buffers[INPORT_INDEX]); |
| Cached = OMX_TRUE; |
| LOGV("ProcessCacheOperation: This B frame is cached\n"); |
| |
| } else if (eInfo.CacheOperation == CACHE_POP) { |
| eInfo.NotStopFrame = true; //it is also a nstop frame |
| |
| OMX_BUFFERHEADERTYPE *omxbuf = NULL; |
| uint32_t i = 0; |
| uint32_t bframecount = mBFrameList.size(); |
| |
| LOGV("BFrameList size = %d\n", bframecount); |
| |
| while(!mBFrameList.empty()) { |
| /*TODO: need to handle null data buffer with EOS |
| !NULL EOS case: B1 B2 P(EOS) -> P B1 B2(EOS) |
| NULL EOS case: B1 B2 NULL(EOS) -> B2 B1 NULL(EOS) |
| */ |
| |
| if (emptyEOSBuf) { |
| omxbuf = *mBFrameList.begin(); |
| ports[INPORT_INDEX]->PushThisBuffer(omxbuf); |
| mBFrameList.erase(mBFrameList.begin()); //clear it from internal queue |
| |
| } else { |
| omxbuf = *mBFrameList.begin(); |
| |
| if (buffers[INPORT_INDEX]->nFlags & OMX_BUFFERFLAG_EOS && i == 0 ) { |
| //this is final encode frame, mark it is new EOS and remove original EOS |
| omxbuf->nFlags |= OMX_BUFFERFLAG_EOS; |
| buffers[INPORT_INDEX]->nFlags &= ~OMX_BUFFERFLAG_EOS; |
| } else { |
| //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 |
| |
| mBFrameList.erase(mBFrameList.begin()); //clear it from internal queue |
| } |
| |
| i++; |
| } |
| |
| if (emptyEOSBuf) |
| ports[INPORT_INDEX]->PushThisBuffer(buffers[INPORT_INDEX]); //put it at the tail |
| |
| } else if (eInfo.CacheOperation == CACHE_RESET) { |
| // mBFrameList.clear(); |
| } |
| |
| eInfo.CacheOperation = CACHE_NONE; |
| |
| /* restore all states into input OMX buffer |
| */ |
| if (eInfo.NotStopFrame) |
| encodeInfo |= ENC_NSTOP; |
| else |
| encodeInfo &= ~ENC_NSTOP; |
| |
| SET_CO(encodeInfo, eInfo.CacheOperation); |
| buffers[INPORT_INDEX]->pPlatformPrivate = (OMX_PTR) encodeInfo; |
| |
| LOGV("ProcessCacheOperation Completed return %d\n", Cached); |
| return Cached; |
| } |
| |
| OMX_ERRORTYPE OMXVideoEncoderAVC::ProcessDataRetrieve( |
| OMX_BUFFERHEADERTYPE **buffers, OMX_BOOL *outBufReturned) { |
| |
| OMX_NALUFORMATSTYPE NaluFormat = mNalStreamFormat.eNaluFormat; |
| |
| // NaluFormat not set, setting default |
| if (NaluFormat == 0) { |
| NaluFormat = (OMX_NALUFORMATSTYPE)OMX_NaluFormatStartCodesSeparateFirstHeader; |
| mNalStreamFormat.eNaluFormat = NaluFormat; |
| } |
| |
| VideoEncOutputBuffer outBuf; |
| outBuf.data = buffers[OUTPORT_INDEX]->pBuffer; |
| outBuf.bufferSize = buffers[OUTPORT_INDEX]->nAllocLen; |
| outBuf.dataSize = 0; |
| outBuf.remainingSize = 0; |
| outBuf.flag = 0; |
| outBuf.timeStamp = 0; |
| outBuf.offset = 0; |
| |
| switch (NaluFormat) { |
| case OMX_NaluFormatStartCodes: |
| outBuf.format = OUTPUT_EVERYTHING; |
| break; |
| |
| case OMX_NaluFormatOneNaluPerBuffer: |
| outBuf.format = OUTPUT_ONE_NAL; |
| break; |
| |
| default: |
| if (NaluFormat == (OMX_NALUFORMATSTYPE)OMX_NaluFormatStartCodesSeparateFirstHeader|| |
| NaluFormat == (OMX_NALUFORMATSTYPE)OMX_NaluFormatLengthPrefixedSeparateFirstHeader){ |
| if(!mCSDOutputted) { |
| LOGV("Output codec data for first frame\n"); |
| outBuf.format = OUTPUT_CODEC_DATA; |
| } else { |
| if (NaluFormat == (OMX_NALUFORMATSTYPE)OMX_NaluFormatStartCodesSeparateFirstHeader) |
| outBuf.format = OUTPUT_EVERYTHING; |
| else |
| outBuf.format = OUTPUT_NALULENGTHS_PREFIXED; |
| } |
| break; |
| } else { |
| return OMX_ErrorUndefined; |
| } |
| } |
| |
| //start getOutput |
| Encode_Status ret = mVideoEncoder->getOutput(&outBuf, FUNC_NONBLOCK); |
| |
| if (ret < ENCODE_SUCCESS) { |
| LOGE("libMIX getOutput Failed. ret = 0x%08x\n", ret); |
| outBuf.dataSize = 0; |
| outBuf.flag |= ENCODE_BUFFERFLAG_ENDOFFRAME; |
| if (ret == ENCODE_NO_REQUEST_DATA) { |
| if (mEmptyEOSBuf) { |
| //make sure no data encoding in HW, then emit one empty out buffer with EOS |
| outBuf.flag |= ENCODE_BUFFERFLAG_ENDOFSTREAM; |
| LOGV("no more data encoding, will signal empty EOS output buf\n"); |
| } else { |
| //if not meet Empty EOS buffer, shouldn't get this error |
| LOGE("sever error, should not happend here\n"); |
| //return OMX_ErrorUndefined; //not return error here to avoid omxcodec crash |
| } |
| } |
| |
| } else if (ret == ENCODE_BUFFER_TOO_SMALL) { |
| LOGE("output buffer too small\n"); |
| // Return code could not be ENCODE_BUFFER_TOO_SMALL, or we will have dead lock issue |
| return OMX_ErrorUndefined; |
| } else if (ret == ENCODE_DATA_NOT_READY) { |
| LOGV("Call libMIX getOutput againe due to 'data not ready'\n"); |
| ret = mVideoEncoder->getOutput(&outBuf); |
| } |
| |
| LOGV("libMIX getOutput data size= %d, flag=0x%08x", outBuf.dataSize, outBuf.flag); |
| OMX_U32 outfilledlen = outBuf.dataSize; |
| OMX_U32 outoffset = outBuf.offset; |
| OMX_S64 outtimestamp = outBuf.timeStamp; |
| OMX_U32 outflags = 0; |
| |
| //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("got a complete libmix Frame\n"); |
| outflags |= OMX_BUFFERFLAG_ENDOFFRAME; |
| |
| if ((NaluFormat == (OMX_NALUFORMATSTYPE)OMX_NaluFormatStartCodesSeparateFirstHeader |
| || NaluFormat == (OMX_NALUFORMATSTYPE)OMX_NaluFormatLengthPrefixedSeparateFirstHeader ) |
| && !mCSDOutputted && outfilledlen > 0) { |
| mCSDOutputted = OMX_TRUE; |
| |
| } else { |
| ports[INPORT_INDEX]->ReturnOneRetainedBuffer(); //return one retained frame from head |
| mFrameOutputCount ++; |
| } |
| } |
| |
| if (outfilledlen == 0) { |
| if (mEmptyEOSBuf) { |
| //emit empty EOS out buf since meet empty EOS input buf |
| buffers[OUTPORT_INDEX]->nFilledLen = 0; |
| buffers[OUTPORT_INDEX]->nTimeStamp = 0; |
| buffers[OUTPORT_INDEX]->nFlags = outflags; |
| *outBufReturned = OMX_TRUE; |
| LOGV("emit one empty EOS OMX output buf = %p:%d, flag = 0x%08x, ts=%lld", buffers[OUTPORT_INDEX]->pBuffer, outfilledlen, outflags, outtimestamp); |
| } else |
| //not emit out buf since something wrong |
| *outBufReturned = OMX_FALSE; |
| |
| } else { |
| buffers[OUTPORT_INDEX]->nOffset = outoffset; |
| 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 |
| *outBufReturned = OMX_TRUE; |
| LOGV("emit one OMX output buf = %p:%d, flag = 0x%08x, ts=%lld", buffers[OUTPORT_INDEX]->pBuffer, outfilledlen, outflags, outtimestamp); |
| |
| } |
| |
| LOGV("ProcessDataRetrieve OK, mFrameEncodedCount=%d , mFrameOutputCount=%d\n", mFrameEncodedCount, mFrameOutputCount); |
| return OMX_ErrorNone; |
| } |
| |
| OMX_ERRORTYPE OMXVideoEncoderAVC::ProcessorProcess( |
| OMX_BUFFERHEADERTYPE **buffers, |
| buffer_retain_t *retains, |
| OMX_U32) { |
| |
| OMX_ERRORTYPE oret = OMX_ErrorNone; |
| Encode_Status ret = ENCODE_SUCCESS; |
| |
| bool FrameEncoded = false; |
| |
| if (buffers[INPORT_INDEX]) { |
| LOGV("input buffer has new frame\n"); |
| |
| //get frame encode info |
| Encode_Info eInfo; |
| uint32_t encodeInfo = (uint32_t) buffers[INPORT_INDEX]->pPlatformPrivate; |
| eInfo.FrameType = GET_FT(encodeInfo); |
| eInfo.CacheOperation = GET_CO(encodeInfo); |
| eInfo.NotStopFrame = encodeInfo & ENC_NSTOP; |
| eInfo.FrameCount = GET_FC(encodeInfo); |
| |
| //handle frame cache operation |
| if (ProcessCacheOperation(buffers)) { |
| //frame is cached, nothing should be done in this case, just store status and return |
| retains[INPORT_INDEX] = BUFFER_RETAIN_CACHE; |
| retains[OUTPORT_INDEX] = BUFFER_RETAIN_GETAGAIN; |
| return OMX_ErrorNone; |
| } |
| |
| //try encode if frame is not cached |
| VideoEncRawBuffer inBuf; |
| |
| 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 (inBuf.size == 0 && buffers[INPORT_INDEX]->nFlags & OMX_BUFFERFLAG_EOS) { |
| //meet an empty EOS buffer, retain it directly and return from here |
| retains[INPORT_INDEX] = BUFFER_RETAIN_ACCUMULATE; |
| retains[OUTPORT_INDEX] = BUFFER_RETAIN_GETAGAIN; |
| mEmptyEOSBuf = OMX_TRUE; |
| return OMX_ErrorNone; |
| } |
| |
| if (buffers[INPORT_INDEX]->nFlags & OMX_BUFFERFLAG_EOS) |
| inBuf.flag |= ENCODE_BUFFERFLAG_ENDOFSTREAM; |
| if (eInfo.NotStopFrame) |
| inBuf.flag |= ENCODE_BUFFERFLAG_NSTOPFRAME; |
| inBuf.type = (FrameType) eInfo.FrameType; |
| |
| LOGV("start libmix encoding\n"); |
| // encode and setConfig need to be thread safe |
| pthread_mutex_lock(&mSerializationLock); |
| ret = mVideoEncoder->encode(&inBuf, FUNC_NONBLOCK); |
| pthread_mutex_unlock(&mSerializationLock); |
| LOGV("end libmix encoding\n"); |
| |
| retains[INPORT_INDEX] = BUFFER_RETAIN_NOT_RETAIN; |
| if (ret == ENCODE_DEVICE_BUSY) { |
| //encoder is busy, put buf back and come again |
| LOGV("encoder is busy, push buffer back to get again\n"); |
| retains[INPORT_INDEX] = BUFFER_RETAIN_GETAGAIN; |
| } else { |
| //if error, this buf will be returned |
| CHECK_ENCODE_STATUS("encode"); |
| |
| LOGV("put buffer to encoder and retain this buffer\n"); |
| mFrameEncodedCount ++; |
| FrameEncoded = true; |
| retains[INPORT_INDEX] = BUFFER_RETAIN_ACCUMULATE; |
| } |
| |
| } else { |
| //no new coming frames, but maybe still have frames not outputted |
| LOGV("input buffer is null\n"); |
| } |
| |
| retains[OUTPORT_INDEX] = BUFFER_RETAIN_GETAGAIN; //set to default value |
| //just call getoutput if no frame encoded in this cycle to avoid retained buffer queue wrong state |
| if (!FrameEncoded) { |
| OMX_BOOL OutBufReturned = OMX_FALSE; |
| oret = ProcessDataRetrieve(buffers, &OutBufReturned); |
| if (OutBufReturned) |
| retains[OUTPORT_INDEX] = BUFFER_RETAIN_NOT_RETAIN; |
| } |
| |
| LOGV("ProcessorProcess ret=%x", oret); |
| return oret; |
| |
| } |
| |
| OMX_ERRORTYPE OMXVideoEncoderAVC::BuildHandlerList(void) { |
| OMXVideoEncoderBase::BuildHandlerList(); |
| AddHandler(OMX_IndexParamVideoAvc, GetParamVideoAvc, SetParamVideoAvc); |
| AddHandler((OMX_INDEXTYPE)OMX_IndexParamNalStreamFormat, GetParamNalStreamFormat, SetParamNalStreamFormat); |
| AddHandler((OMX_INDEXTYPE)OMX_IndexParamNalStreamFormatSupported, GetParamNalStreamFormatSupported, SetParamNalStreamFormatSupported); |
| AddHandler((OMX_INDEXTYPE)OMX_IndexParamNalStreamFormatSelect, GetParamNalStreamFormatSelect, SetParamNalStreamFormatSelect); |
| AddHandler(OMX_IndexConfigVideoAVCIntraPeriod, GetConfigVideoAVCIntraPeriod, SetConfigVideoAVCIntraPeriod); |
| AddHandler(OMX_IndexConfigVideoNalSize, GetConfigVideoNalSize, SetConfigVideoNalSize); |
| AddHandler((OMX_INDEXTYPE)OMX_IndexConfigIntelSliceNumbers, GetConfigIntelSliceNumbers, SetConfigIntelSliceNumbers); |
| AddHandler((OMX_INDEXTYPE)OMX_IndexParamIntelAVCVUI, GetParamIntelAVCVUI, SetParamIntelAVCVUI); |
| AddHandler((OMX_INDEXTYPE)OMX_IndexParamVideoBytestream, GetParamVideoBytestream, SetParamVideoBytestream); |
| AddHandler((OMX_INDEXTYPE)OMX_IndexParamVideoProfileLevelQuerySupported, GetParamVideoProfileLevelQuerySupported, SetParamVideoProfileLevelQuerySupported); |
| return OMX_ErrorNone; |
| } |
| |
| OMX_ERRORTYPE OMXVideoEncoderAVC::GetParamVideoProfileLevelQuerySupported(OMX_PTR pStructure) { |
| OMX_ERRORTYPE ret; |
| OMX_VIDEO_PARAM_PROFILELEVELTYPE *p = (OMX_VIDEO_PARAM_PROFILELEVELTYPE *)pStructure; |
| CHECK_TYPE_HEADER(p); |
| CHECK_PORT_INDEX(p, OUTPORT_INDEX); |
| |
| CHECK_ENUMERATION_RANGE(p->nProfileIndex,mPLTableCount); |
| |
| p->eProfile = mPLTable[p->nProfileIndex].profile; |
| p->eLevel = mPLTable[p->nProfileIndex].level; |
| |
| return OMX_ErrorNone; |
| } |
| |
| OMX_ERRORTYPE OMXVideoEncoderAVC::SetParamVideoProfileLevelQuerySupported(OMX_PTR) { |
| LOGW("SetParamVideoAVCProfileLevel is not supported."); |
| return OMX_ErrorUnsupportedSetting; |
| } |
| |
| OMX_ERRORTYPE OMXVideoEncoderAVC::GetParamVideoAvc(OMX_PTR pStructure) { |
| OMX_ERRORTYPE ret; |
| OMX_VIDEO_PARAM_AVCTYPE *p = (OMX_VIDEO_PARAM_AVCTYPE *)pStructure; |
| CHECK_TYPE_HEADER(p); |
| CHECK_PORT_INDEX(p, OUTPORT_INDEX); |
| |
| mVideoEncoder->getParameters(mAVCParams); |
| if(mParamAvc.eProfile == OMX_VIDEO_AVCProfileHigh) |
| { |
| mAVCParams->bEntropyCodingCABAC = 1; |
| mAVCParams->bDirect8x8Inference = 1; |
| } |
| mParamAvc.bEntropyCodingCABAC = (OMX_BOOL)mAVCParams->bEntropyCodingCABAC; |
| mParamAvc.bWeightedPPrediction = (OMX_BOOL)mAVCParams->bWeightedPPrediction; |
| mParamAvc.nRefIdx10ActiveMinus1 = mAVCParams->refIdx10ActiveMinus1; |
| mParamAvc.nRefIdx11ActiveMinus1 = mAVCParams->refIdx11ActiveMinus1; |
| mParamAvc.nWeightedBipredicitonMode = mAVCParams->weightedBipredicitonMode; |
| mParamAvc.bDirect8x8Inference = (OMX_BOOL)mAVCParams->bDirect8x8Inference; |
| mParamAvc.bDirectSpatialTemporal = (OMX_BOOL)mAVCParams->bDirectSpatialTemporal; |
| mParamAvc.nCabacInitIdc = mAVCParams->cabacInitIdc; |
| mParamAvc.bFrameMBsOnly = (OMX_BOOL)mAVCParams->bFrameMBsOnly; |
| mParamAvc.bconstIpred = (OMX_BOOL)mAVCParams->bConstIpred; |
| memcpy(p, &mParamAvc, sizeof(*p)); |
| return OMX_ErrorNone; |
| } |
| |
| OMX_ERRORTYPE OMXVideoEncoderAVC::SetParamVideoAvc(OMX_PTR pStructure) { |
| OMX_ERRORTYPE ret; |
| OMX_VIDEO_PARAM_AVCTYPE *p = (OMX_VIDEO_PARAM_AVCTYPE *)pStructure; |
| CHECK_TYPE_HEADER(p); |
| CHECK_PORT_INDEX(p, OUTPORT_INDEX); |
| CHECK_SET_PARAM_STATE(); |
| |
| //Check if parameters are valid |
| |
| 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; |
| |
| if (p->eProfile == OMX_VIDEO_AVCProfileBaseline && |
| (p->nAllowedPictureTypes & OMX_VIDEO_PictureTypeB) ) |
| return OMX_ErrorBadParameter; |
| |
| if (p->nAllowedPictureTypes & OMX_VIDEO_PictureTypeP && (p->nPFrames == 0)) |
| return OMX_ErrorBadParameter; |
| |
| if (p->nAllowedPictureTypes & OMX_VIDEO_PictureTypeB ) { |
| if (p->nBFrames == 0) |
| return OMX_ErrorBadParameter; |
| |
| //IpPeriod must be integer |
| uint32_t IntraPeriod = mParamAvc.nPFrames + mParamAvc.nBFrames ; |
| if (IntraPeriod % mParamAvc.nPFrames != 0) |
| return OMX_ErrorBadParameter; |
| |
| //IntraPeriod must be multipe of IpPeriod. |
| uint32_t IpPeriod = IntraPeriod /mParamAvc.nPFrames; |
| if (IntraPeriod % IpPeriod != 0) |
| return OMX_ErrorBadParameter; |
| } |
| |
| // TODO: do we need to check if port is enabled? |
| // TODO: see SetPortAvcParam implementation - Can we make simple copy???? |
| memcpy(&mParamAvc, p, sizeof(mParamAvc)); |
| mVideoEncoder->getParameters(mAVCParams); |
| mAVCParams->bEntropyCodingCABAC = mParamAvc.bEntropyCodingCABAC; |
| mAVCParams->bDirect8x8Inference = mParamAvc.bDirect8x8Inference; |
| if(mParamAvc.eProfile == OMX_VIDEO_AVCProfileBaseline){ |
| mAVCParams->bEntropyCodingCABAC = 0; |
| mAVCParams->bDirect8x8Inference = 0; |
| } |
| mVideoEncoder->setParameters(mAVCParams); |
| |
| |
| return OMX_ErrorNone; |
| } |
| |
| OMX_ERRORTYPE OMXVideoEncoderAVC::GetParamNalStreamFormat(OMX_PTR pStructure) { |
| OMX_ERRORTYPE ret; |
| OMX_NALSTREAMFORMATTYPE *p = (OMX_NALSTREAMFORMATTYPE *)pStructure; |
| |
| CHECK_TYPE_HEADER(p); |
| CHECK_PORT_INDEX(p, OUTPORT_INDEX); |
| // TODO: check if this is desired format |
| p->eNaluFormat = mNalStreamFormat.eNaluFormat; //OMX_NaluFormatStartCodes; |
| return OMX_ErrorNone; |
| } |
| |
| OMX_ERRORTYPE OMXVideoEncoderAVC::SetParamNalStreamFormat(OMX_PTR pStructure) { |
| OMX_ERRORTYPE ret; |
| OMX_NALSTREAMFORMATTYPE *p = (OMX_NALSTREAMFORMATTYPE *)pStructure; |
| |
| CHECK_TYPE_HEADER(p); |
| CHECK_PORT_INDEX(p, OUTPORT_INDEX); |
| LOGV("p->eNaluFormat =%d\n",p->eNaluFormat); |
| if(p->eNaluFormat != OMX_NaluFormatStartCodes && |
| p->eNaluFormat != (OMX_NALUFORMATSTYPE)OMX_NaluFormatStartCodesSeparateFirstHeader && |
| p->eNaluFormat != OMX_NaluFormatOneNaluPerBuffer && |
| p->eNaluFormat != (OMX_NALUFORMATSTYPE)OMX_NaluFormatLengthPrefixedSeparateFirstHeader) { |
| LOGE("Format not support\n"); |
| return OMX_ErrorUnsupportedSetting; |
| } |
| mNalStreamFormat.eNaluFormat = p->eNaluFormat; |
| return OMX_ErrorNone; |
| } |
| |
| OMX_ERRORTYPE OMXVideoEncoderAVC::GetParamNalStreamFormatSupported(OMX_PTR pStructure) { |
| OMX_ERRORTYPE ret; |
| OMX_NALSTREAMFORMATTYPE *p = (OMX_NALSTREAMFORMATTYPE *)pStructure; |
| |
| CHECK_TYPE_HEADER(p); |
| CHECK_PORT_INDEX(p, OUTPORT_INDEX); |
| p->eNaluFormat = (OMX_NALUFORMATSTYPE) |
| (OMX_NaluFormatStartCodes | |
| OMX_NaluFormatStartCodesSeparateFirstHeader | |
| OMX_NaluFormatOneNaluPerBuffer| |
| OMX_NaluFormatLengthPrefixedSeparateFirstHeader); |
| |
| // TODO: check if this is desired format |
| // OMX_NaluFormatFourByteInterleaveLength | |
| // OMX_NaluFormatZeroByteInterleaveLength); |
| return OMX_ErrorNone; |
| } |
| |
| OMX_ERRORTYPE OMXVideoEncoderAVC::SetParamNalStreamFormatSupported(OMX_PTR) { |
| LOGW("SetParamNalStreamFormatSupported is not supported."); |
| return OMX_ErrorUnsupportedSetting; |
| } |
| |
| OMX_ERRORTYPE OMXVideoEncoderAVC::GetParamNalStreamFormatSelect(OMX_PTR) { |
| LOGW("GetParamNalStreamFormatSelect is not supported."); |
| return OMX_ErrorUnsupportedSetting; |
| } |
| |
| OMX_ERRORTYPE OMXVideoEncoderAVC::SetParamNalStreamFormatSelect(OMX_PTR pStructure) { |
| OMX_ERRORTYPE ret; |
| OMX_NALSTREAMFORMATTYPE *p = (OMX_NALSTREAMFORMATTYPE *)pStructure; |
| CHECK_TYPE_HEADER(p); |
| CHECK_PORT_INDEX(p, OUTPORT_INDEX); |
| |
| // return OMX_ErrorIncorrectStateOperation if not in Loaded state |
| CHECK_SET_PARAM_STATE(); |
| |
| if (p->eNaluFormat != OMX_NaluFormatStartCodes && |
| p->eNaluFormat != (OMX_NALUFORMATSTYPE)OMX_NaluFormatStartCodesSeparateFirstHeader && |
| p->eNaluFormat != OMX_NaluFormatOneNaluPerBuffer&& |
| p->eNaluFormat != (OMX_NALUFORMATSTYPE)OMX_NaluFormatLengthPrefixedSeparateFirstHeader) { |
| //p->eNaluFormat != OMX_NaluFormatFourByteInterleaveLength && |
| //p->eNaluFormat != OMX_NaluFormatZeroByteInterleaveLength) { |
| // TODO: check if this is desried |
| return OMX_ErrorBadParameter; |
| } |
| |
| mNalStreamFormat = *p; |
| return OMX_ErrorNone; |
| } |
| |
| OMX_ERRORTYPE OMXVideoEncoderAVC::GetConfigVideoAVCIntraPeriod(OMX_PTR pStructure) { |
| OMX_ERRORTYPE ret; |
| OMX_VIDEO_CONFIG_AVCINTRAPERIOD *p = (OMX_VIDEO_CONFIG_AVCINTRAPERIOD *)pStructure; |
| |
| CHECK_TYPE_HEADER(p); |
| CHECK_PORT_INDEX(p, OUTPORT_INDEX); |
| // TODO: populate mConfigAvcIntraPeriod from VideoEncoder |
| // return OMX_ErrorNotReady if VideoEncoder is not created. |
| memcpy(p, &mConfigAvcIntraPeriod, sizeof(*p)); |
| return OMX_ErrorNone; |
| } |
| |
| OMX_ERRORTYPE OMXVideoEncoderAVC::SetConfigVideoAVCIntraPeriod(OMX_PTR pStructure) { |
| OMX_ERRORTYPE ret; |
| Encode_Status retStatus = ENCODE_SUCCESS; |
| OMX_VIDEO_CONFIG_AVCINTRAPERIOD *p = (OMX_VIDEO_CONFIG_AVCINTRAPERIOD *)pStructure; |
| CHECK_TYPE_HEADER(p); |
| CHECK_PORT_INDEX(p, OUTPORT_INDEX); |
| |
| // return OMX_ErrorNone if not in Executing state |
| // TODO: return OMX_ErrorIncorrectStateOperation? |
| CHECK_SET_CONFIG_STATE(); |
| |
| //check if parameters are valid |
| if ( ( (mParamAvc.nAllowedPictureTypes & OMX_VIDEO_PictureTypeP) || |
| (mParamAvc.nAllowedPictureTypes & OMX_VIDEO_PictureTypeB) ) && |
| p->nPFrames == 0 ) |
| return OMX_ErrorBadParameter; |
| |
| // TODO: apply AVC Intra Period configuration in Executing state |
| VideoConfigAVCIntraPeriod avcIntraPreriod; |
| |
| if (mParamAvc.nAllowedPictureTypes & OMX_VIDEO_PictureTypeB) { |
| avcIntraPreriod.intraPeriod = p->nPFrames; |
| if (p->nPFrames % mParamAvc.nBFrames != 0) |
| return OMX_ErrorBadParameter; |
| avcIntraPreriod.ipPeriod = p->nPFrames / mParamAvc.nBFrames; |
| |
| if (avcIntraPreriod.intraPeriod % avcIntraPreriod.ipPeriod != 0) |
| return OMX_ErrorBadParameter; |
| |
| avcIntraPreriod.idrInterval = p->nIDRPeriod; |
| } else { |
| avcIntraPreriod.intraPeriod = p->nPFrames + 1; |
| avcIntraPreriod.ipPeriod = 1; |
| if (avcIntraPreriod.intraPeriod == 0) |
| avcIntraPreriod.idrInterval = 0; |
| else |
| avcIntraPreriod.idrInterval = p->nIDRPeriod; |
| } |
| |
| retStatus = mVideoEncoder->setConfig(&avcIntraPreriod); |
| if(retStatus != ENCODE_SUCCESS) { |
| LOGW("set avc intra period config failed"); |
| } |
| |
| mEncoderParams->intraPeriod = avcIntraPreriod.intraPeriod; |
| mAVCParams->idrInterval = avcIntraPreriod.idrInterval; |
| mAVCParams->ipPeriod = avcIntraPreriod.ipPeriod; |
| |
| mConfigAvcIntraPeriod = *p; |
| mConfigAvcIntraPeriod.nIDRPeriod = avcIntraPreriod.idrInterval; |
| |
| return OMX_ErrorNone; |
| } |
| |
| OMX_ERRORTYPE OMXVideoEncoderAVC::GetConfigVideoNalSize(OMX_PTR pStructure) { |
| OMX_ERRORTYPE ret; |
| OMX_VIDEO_CONFIG_NALSIZE *p = (OMX_VIDEO_CONFIG_NALSIZE *)pStructure; |
| |
| CHECK_TYPE_HEADER(p); |
| CHECK_PORT_INDEX(p, OUTPORT_INDEX); |
| memcpy(p, &mConfigNalSize, sizeof(*p)); |
| return OMX_ErrorNone; |
| } |
| |
| OMX_ERRORTYPE OMXVideoEncoderAVC::SetConfigVideoNalSize(OMX_PTR pStructure) { |
| OMX_ERRORTYPE ret; |
| Encode_Status retStatus = ENCODE_SUCCESS; |
| if (mParamBitrate.eControlRate == OMX_Video_ControlRateMax) { |
| LOGE("SetConfigVideoNalSize failed. Feature is disabled."); |
| return OMX_ErrorUnsupportedIndex; |
| } |
| OMX_VIDEO_CONFIG_NALSIZE *p = (OMX_VIDEO_CONFIG_NALSIZE *)pStructure; |
| CHECK_TYPE_HEADER(p); |
| CHECK_PORT_INDEX(p, OUTPORT_INDEX); |
| |
| // set in either Loaded state (ComponentSetParam) or Executing state (ComponentSetConfig) |
| mConfigNalSize = *p; |
| |
| // return OMX_ErrorNone if not in Executing state |
| // TODO: return OMX_ErrorIncorrectStateOperation? |
| CHECK_SET_CONFIG_STATE(); |
| |
| if (mParamBitrate.eControlRate != (OMX_VIDEO_CONTROLRATETYPE)OMX_Video_Intel_ControlRateVideoConferencingMode) { |
| LOGE("SetConfigVideoNalSize failed. Feature is supported only in VCM."); |
| return OMX_ErrorUnsupportedSetting; |
| } |
| VideoConfigNALSize configNalSize; |
| configNalSize.maxSliceSize = mConfigNalSize.nNaluBytes * 8; |
| retStatus = mVideoEncoder->setConfig(&configNalSize); |
| if(retStatus != ENCODE_SUCCESS) { |
| LOGW("set NAL size config failed"); |
| } |
| return OMX_ErrorNone; |
| } |
| |
| OMX_ERRORTYPE OMXVideoEncoderAVC::GetConfigIntelSliceNumbers(OMX_PTR pStructure) { |
| OMX_ERRORTYPE ret; |
| OMX_VIDEO_CONFIG_INTEL_SLICE_NUMBERS *p = (OMX_VIDEO_CONFIG_INTEL_SLICE_NUMBERS *)pStructure; |
| |
| CHECK_TYPE_HEADER(p); |
| CHECK_PORT_INDEX(p, OUTPORT_INDEX); |
| memcpy(p, &mConfigIntelSliceNumbers, sizeof(*p)); |
| return OMX_ErrorNone; |
| } |
| |
| OMX_ERRORTYPE OMXVideoEncoderAVC::SetConfigIntelSliceNumbers(OMX_PTR pStructure) { |
| OMX_ERRORTYPE ret; |
| Encode_Status retStatus = ENCODE_SUCCESS; |
| if (mParamBitrate.eControlRate == OMX_Video_ControlRateMax) { |
| LOGE("SetConfigIntelSliceNumbers failed. Feature is disabled."); |
| return OMX_ErrorUnsupportedIndex; |
| } |
| OMX_VIDEO_CONFIG_INTEL_SLICE_NUMBERS *p = (OMX_VIDEO_CONFIG_INTEL_SLICE_NUMBERS *)pStructure; |
| CHECK_TYPE_HEADER(p); |
| CHECK_PORT_INDEX(p, OUTPORT_INDEX); |
| |
| // set in either Loaded state (ComponentSetParam) or Executing state (ComponentSetConfig) |
| mConfigIntelSliceNumbers = *p; |
| |
| // return OMX_ErrorNone if not in Executing state |
| // TODO: return OMX_ErrorIncorrectStateOperation? |
| CHECK_SET_CONFIG_STATE(); |
| |
| if (mParamBitrate.eControlRate != (OMX_VIDEO_CONTROLRATETYPE)OMX_Video_Intel_ControlRateVideoConferencingMode) { |
| LOGE("SetConfigIntelSliceNumbers failed. Feature is supported only in VCM."); |
| return OMX_ErrorUnsupportedSetting; |
| } |
| VideoConfigSliceNum sliceNum; |
| sliceNum.sliceNum.iSliceNum = mConfigIntelSliceNumbers.nISliceNumber; |
| sliceNum.sliceNum.pSliceNum = mConfigIntelSliceNumbers.nPSliceNumber; |
| retStatus = mVideoEncoder->setConfig(&sliceNum); |
| if(retStatus != ENCODE_SUCCESS) { |
| LOGW("set silce num config failed!\n"); |
| } |
| return OMX_ErrorNone; |
| } |
| |
| OMX_ERRORTYPE OMXVideoEncoderAVC::GetParamIntelAVCVUI(OMX_PTR pStructure) { |
| |
| OMX_ERRORTYPE ret; |
| OMX_VIDEO_PARAM_INTEL_AVCVUI *p = (OMX_VIDEO_PARAM_INTEL_AVCVUI *)pStructure; |
| |
| CHECK_TYPE_HEADER(p); |
| CHECK_PORT_INDEX(p, OUTPORT_INDEX); |
| memcpy(p, &mParamIntelAvcVui, sizeof(*p)); |
| |
| return OMX_ErrorNone; |
| } |
| |
| OMX_ERRORTYPE OMXVideoEncoderAVC::SetParamIntelAVCVUI(OMX_PTR pStructure) { |
| |
| OMX_ERRORTYPE ret; |
| OMX_VIDEO_PARAM_INTEL_AVCVUI *p = (OMX_VIDEO_PARAM_INTEL_AVCVUI *)pStructure; |
| CHECK_TYPE_HEADER(p); |
| CHECK_PORT_INDEX(p, OUTPORT_INDEX); |
| |
| // set only in Loaded state (ComponentSetParam) |
| CHECK_SET_PARAM_STATE(); |
| |
| mParamIntelAvcVui = *p; |
| return OMX_ErrorNone; |
| } |
| |
| OMX_ERRORTYPE OMXVideoEncoderAVC::GetParamVideoBytestream(OMX_PTR) { |
| return OMX_ErrorUnsupportedSetting; |
| } |
| |
| OMX_ERRORTYPE OMXVideoEncoderAVC::SetParamVideoBytestream(OMX_PTR pStructure) { |
| OMX_ERRORTYPE ret; |
| OMX_VIDEO_PARAM_BYTESTREAMTYPE *p = (OMX_VIDEO_PARAM_BYTESTREAMTYPE *)pStructure; |
| CHECK_TYPE_HEADER(p); |
| CHECK_PORT_INDEX(p, OUTPORT_INDEX); |
| |
| // set only in Loaded state (ComponentSetParam) |
| CHECK_SET_PARAM_STATE(); |
| |
| if (p->bBytestream == OMX_TRUE) { |
| mNalStreamFormat.eNaluFormat = OMX_NaluFormatStartCodes; |
| } else { |
| // TODO: do we need to override the Nalu format? |
| mNalStreamFormat.eNaluFormat = (OMX_NALUFORMATSTYPE)OMX_NaluFormatZeroByteInterleaveLength; |
| } |
| |
| return OMX_ErrorNone; |
| } |
| |
| |
| DECLARE_OMX_COMPONENT("OMX.Intel.VideoEncoder.AVC", "video_encoder.avc", OMXVideoEncoderAVC); |