Initial libmix commit
Change-Id: I7a0b9afdc83a3274189cef0788c7296a871a3d98
Signed-off-by: Guilhem IMBERTON <guilhem.imberton@intel.com>
diff --git a/videoencoder/VideoEncoderBase.cpp b/videoencoder/VideoEncoderBase.cpp
new file mode 100644
index 0000000..b3fd3c2
--- /dev/null
+++ b/videoencoder/VideoEncoderBase.cpp
@@ -0,0 +1,1928 @@
+/*
+* 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.
+*/
+
+#include <string.h>
+#include "VideoEncoderLog.h"
+#include "VideoEncoderBase.h"
+#include "IntelMetadataBuffer.h"
+#include <va/va_tpi.h>
+#include <va/va_android.h>
+
+VideoEncoderBase::VideoEncoderBase()
+ :mInitialized(true)
+ ,mStarted(false)
+ ,mVADisplay(NULL)
+ ,mVAContext(VA_INVALID_ID)
+ ,mVAConfig(VA_INVALID_ID)
+ ,mVAEntrypoint(VAEntrypointEncSlice)
+ ,mNewHeader(false)
+ ,mRenderMaxSliceSize(false)
+ ,mRenderQP (false)
+ ,mRenderAIR(false)
+ ,mRenderCIR(false)
+ ,mRenderFrameRate(false)
+ ,mRenderBitRate(false)
+ ,mRenderHrd(false)
+ ,mRenderMultiTemporal(false)
+ ,mForceKFrame(false)
+ ,mSeqParamBuf(0)
+ ,mPicParamBuf(0)
+ ,mSliceParamBuf(0)
+ ,mAutoRefSurfaces(NULL)
+ ,mRefSurface(VA_INVALID_SURFACE)
+ ,mRecSurface(VA_INVALID_SURFACE)
+ ,mFrameNum(0)
+ ,mCodedBufSize(0)
+ ,mAutoReference(false)
+ ,mAutoReferenceSurfaceNum(4)
+ ,mEncPackedHeaders(VA_ATTRIB_NOT_SUPPORTED)
+ ,mSliceSizeOverflow(false)
+ ,mCurOutputTask(NULL)
+ ,mOutCodedBuffer(0)
+ ,mOutCodedBufferPtr(NULL)
+ ,mCurSegment(NULL)
+ ,mOffsetInSeg(0)
+ ,mTotalSize(0)
+ ,mTotalSizeCopied(0)
+ ,mFrameSkipped(false)
+ ,mSupportedSurfaceMemType(0)
+ ,mVASurfaceMappingAction(0)
+#ifdef INTEL_VIDEO_XPROC_SHARING
+ ,mSessionFlag(0)
+#endif
+ {
+
+ VAStatus vaStatus = VA_STATUS_SUCCESS;
+ // here the display can be any value, use following one
+ // just for consistence purpose, so don't define it
+ unsigned int display = 0x18C34078;
+ int majorVersion = -1;
+ int minorVersion = -1;
+
+ setDefaultParams();
+
+ LOG_V("vaGetDisplay \n");
+ mVADisplay = vaGetDisplay(&display);
+ if (mVADisplay == NULL) {
+ LOG_E("vaGetDisplay failed.");
+ }
+
+ vaStatus = vaInitialize(mVADisplay, &majorVersion, &minorVersion);
+ LOG_V("vaInitialize \n");
+ if (vaStatus != VA_STATUS_SUCCESS) {
+ LOG_E( "Failed vaInitialize, vaStatus = %d\n", vaStatus);
+ mInitialized = false;
+ }
+}
+
+VideoEncoderBase::~VideoEncoderBase() {
+
+ VAStatus vaStatus = VA_STATUS_SUCCESS;
+
+ stop();
+
+ vaStatus = vaTerminate(mVADisplay);
+ LOG_V( "vaTerminate\n");
+ if (vaStatus != VA_STATUS_SUCCESS) {
+ LOG_W( "Failed vaTerminate, vaStatus = %d\n", vaStatus);
+ } else {
+ mVADisplay = NULL;
+ }
+
+#ifdef INTEL_VIDEO_XPROC_SHARING
+ IntelMetadataBuffer::ClearContext(mSessionFlag, false);
+#endif
+}
+
+Encode_Status VideoEncoderBase::start() {
+
+ Encode_Status ret = ENCODE_SUCCESS;
+ VAStatus vaStatus = VA_STATUS_SUCCESS;
+
+ if (!mInitialized) {
+ LOGE("Encoder Initialize fail can not start");
+ return ENCODE_DRIVER_FAIL;
+ }
+
+ if (mStarted) {
+ LOG_V("Encoder has been started\n");
+ return ENCODE_ALREADY_INIT;
+ }
+
+ if (mComParams.rawFormat != RAW_FORMAT_NV12)
+#ifdef IMG_GFX
+ mVASurfaceMappingAction |= MAP_ACTION_COLORCONVERT;
+#else
+ return ENCODE_NOT_SUPPORTED;
+#endif
+
+ if (mComParams.resolution.width > 2048 || mComParams.resolution.height > 2048){
+ LOGE("Unsupported resolution width %d, height %d\n",
+ mComParams.resolution.width, mComParams.resolution.height);
+ return ENCODE_NOT_SUPPORTED;
+ }
+ queryAutoReferenceConfig(mComParams.profile);
+
+ VAConfigAttrib vaAttrib_tmp[6],vaAttrib[VAConfigAttribTypeMax];
+ int vaAttribNumber = 0;
+ vaAttrib_tmp[0].type = VAConfigAttribRTFormat;
+ vaAttrib_tmp[1].type = VAConfigAttribRateControl;
+ vaAttrib_tmp[2].type = VAConfigAttribEncAutoReference;
+ vaAttrib_tmp[3].type = VAConfigAttribEncPackedHeaders;
+ vaAttrib_tmp[4].type = VAConfigAttribEncMaxRefFrames;
+ vaAttrib_tmp[5].type = VAConfigAttribEncRateControlExt;
+
+ vaStatus = vaGetConfigAttributes(mVADisplay, mComParams.profile,
+ VAEntrypointEncSlice, &vaAttrib_tmp[0], 6);
+ CHECK_VA_STATUS_RETURN("vaGetConfigAttributes");
+
+ if((vaAttrib_tmp[0].value & VA_RT_FORMAT_YUV420) != 0)
+ {
+ vaAttrib[vaAttribNumber].type = VAConfigAttribRTFormat;
+ vaAttrib[vaAttribNumber].value = VA_RT_FORMAT_YUV420;
+ vaAttribNumber++;
+ }
+
+ vaAttrib[vaAttribNumber].type = VAConfigAttribRateControl;
+ vaAttrib[vaAttribNumber].value = mComParams.rcMode;
+ vaAttribNumber++;
+
+ vaAttrib[vaAttribNumber].type = VAConfigAttribEncAutoReference;
+ vaAttrib[vaAttribNumber].value = mAutoReference ? 1 : VA_ATTRIB_NOT_SUPPORTED;
+ vaAttribNumber++;
+
+ if(vaAttrib_tmp[3].value != VA_ATTRIB_NOT_SUPPORTED)
+ {
+ vaAttrib[vaAttribNumber].type = VAConfigAttribEncPackedHeaders;
+ vaAttrib[vaAttribNumber].value = vaAttrib[3].value;
+ vaAttribNumber++;
+ mEncPackedHeaders = vaAttrib[3].value;
+ }
+
+ if(vaAttrib_tmp[4].value != VA_ATTRIB_NOT_SUPPORTED)
+ {
+ vaAttrib[vaAttribNumber].type = VAConfigAttribEncMaxRefFrames;
+ vaAttrib[vaAttribNumber].value = vaAttrib[4].value;
+ vaAttribNumber++;
+ mEncMaxRefFrames = vaAttrib[4].value;
+ }
+
+ if(vaAttrib_tmp[5].value != VA_ATTRIB_NOT_SUPPORTED)
+ {
+ vaAttrib[vaAttribNumber].type = VAConfigAttribEncRateControlExt;
+ vaAttrib[vaAttribNumber].value = mComParams.numberOfLayer;
+ vaAttribNumber++;
+ }
+
+ LOG_V( "======VA Configuration======\n");
+ LOG_I( "profile = %d\n", mComParams.profile);
+ LOG_I( "mVAEntrypoint = %d\n", mVAEntrypoint);
+ LOG_I( "vaAttrib[0].type = %d\n", vaAttrib[0].type);
+ LOG_I( "vaAttrib[1].type = %d\n", vaAttrib[1].type);
+ LOG_I( "vaAttrib[2].type = %d\n", vaAttrib[2].type);
+ LOG_I( "vaAttrib[0].value (Format) = %d\n", vaAttrib[0].value);
+ LOG_I( "vaAttrib[1].value (RC mode) = %d\n", vaAttrib[1].value);
+ LOG_I( "vaAttrib[2].value (AutoReference) = %d\n", vaAttrib[2].value);
+ LOG_I( "vaAttribNumber is %d\n", vaAttribNumber);
+ LOG_I( "mComParams.numberOfLayer is %d\n", mComParams.numberOfLayer);
+
+ LOG_V( "vaCreateConfig\n");
+
+ vaStatus = vaCreateConfig(
+ mVADisplay, mComParams.profile, mVAEntrypoint,
+ &vaAttrib[0], vaAttribNumber, &(mVAConfig));
+// &vaAttrib[0], 3, &(mVAConfig)); //uncomment this after psb_video supports
+ CHECK_VA_STATUS_RETURN("vaCreateConfig");
+
+ querySupportedSurfaceMemTypes();
+
+ if (mComParams.rcMode == VA_RC_VCM) {
+ // Following three features are only enabled in VCM mode
+ mRenderMaxSliceSize = true;
+ mRenderAIR = true;
+ mRenderBitRate = true;
+ }
+
+ LOG_V( "======VA Create Surfaces for Rec/Ref frames ======\n");
+
+ uint32_t stride_aligned, height_aligned;
+ if(mAutoReference == false){
+ stride_aligned = (mComParams.resolution.width + 15) & ~15;
+ height_aligned = (mComParams.resolution.height + 15) & ~15;
+ }else{
+ // this alignment is used for AVC. For vp8 encode, driver will handle the alignment
+ if(mComParams.profile == VAProfileVP8Version0_3)
+ {
+ stride_aligned = mComParams.resolution.width;
+ height_aligned = mComParams.resolution.height;
+ mVASurfaceMappingAction |= MAP_ACTION_COPY;
+ }
+ else
+ {
+ stride_aligned = (mComParams.resolution.width + 63) & ~63; //on Merr, stride must be 64 aligned.
+ height_aligned = (mComParams.resolution.height + 31) & ~31;
+ mVASurfaceMappingAction |= MAP_ACTION_ALIGN64;
+ }
+ }
+
+ if(mAutoReference == false){
+ mRefSurface = CreateNewVASurface(mVADisplay, stride_aligned, height_aligned);
+ mRecSurface = CreateNewVASurface(mVADisplay, stride_aligned, height_aligned);
+
+ }else {
+ mAutoRefSurfaces = new VASurfaceID [mAutoReferenceSurfaceNum];
+ for(uint32_t i = 0; i < mAutoReferenceSurfaceNum; i ++)
+ mAutoRefSurfaces[i] = CreateNewVASurface(mVADisplay, stride_aligned, height_aligned);
+ }
+ CHECK_VA_STATUS_RETURN("vaCreateSurfaces");
+
+ //Prepare all Surfaces to be added into Context
+ uint32_t contextSurfaceCnt;
+ if(mAutoReference == false )
+ contextSurfaceCnt = 2 + mSrcSurfaceMapList.size();
+ else
+ contextSurfaceCnt = mAutoReferenceSurfaceNum + mSrcSurfaceMapList.size();
+
+ VASurfaceID *contextSurfaces = new VASurfaceID[contextSurfaceCnt];
+ int32_t index = -1;
+ android::List<VASurfaceMap *>::iterator map_node;
+
+ for(map_node = mSrcSurfaceMapList.begin(); map_node != mSrcSurfaceMapList.end(); map_node++)
+ {
+ contextSurfaces[++index] = (*map_node)->getVASurface();
+ (*map_node)->setTracked();
+ }
+
+ if(mAutoReference == false){
+ contextSurfaces[++index] = mRefSurface;
+ contextSurfaces[++index] = mRecSurface;
+ } else {
+ for (uint32_t i=0; i < mAutoReferenceSurfaceNum; i++)
+ contextSurfaces[++index] = mAutoRefSurfaces[i];
+ }
+
+ //Initialize and save the VA context ID
+ LOG_V( "vaCreateContext\n");
+ vaStatus = vaCreateContext(mVADisplay, mVAConfig,
+#ifdef IMG_GFX
+ mComParams.resolution.width,
+ mComParams.resolution.height,
+#else
+ stride_aligned,
+ height_aligned,
+#endif
+ VA_PROGRESSIVE, contextSurfaces, contextSurfaceCnt,
+ &(mVAContext));
+ CHECK_VA_STATUS_RETURN("vaCreateContext");
+
+ delete [] contextSurfaces;
+
+ LOG_I("Success to create libva context width %d, height %d\n",
+ mComParams.resolution.width, mComParams.resolution.height);
+
+ uint32_t maxSize = 0;
+ ret = getMaxOutSize(&maxSize);
+ CHECK_ENCODE_STATUS_RETURN("getMaxOutSize");
+
+ // Create CodedBuffer for output
+ VABufferID VACodedBuffer;
+
+ for(uint32_t i = 0; i <mComParams.codedBufNum; i++) {
+ vaStatus = vaCreateBuffer(mVADisplay, mVAContext,
+ VAEncCodedBufferType,
+ mCodedBufSize,
+ 1, NULL,
+ &VACodedBuffer);
+ CHECK_VA_STATUS_RETURN("vaCreateBuffer::VAEncCodedBufferType");
+
+ mVACodedBufferList.push_back(VACodedBuffer);
+ }
+
+ if (ret == ENCODE_SUCCESS)
+ mStarted = true;
+
+ LOG_V( "end\n");
+ return ret;
+}
+
+Encode_Status VideoEncoderBase::encode(VideoEncRawBuffer *inBuffer, uint32_t timeout) {
+
+ Encode_Status ret = ENCODE_SUCCESS;
+ VAStatus vaStatus = VA_STATUS_SUCCESS;
+
+ if (!mStarted) {
+ LOG_E("Encoder has not initialized yet\n");
+ return ENCODE_NOT_INIT;
+ }
+
+ CHECK_NULL_RETURN_IFFAIL(inBuffer);
+
+ //======Prepare all resources encoder needed=====.
+
+ //Prepare encode vaSurface
+ VASurfaceID sid = VA_INVALID_SURFACE;
+ ret = manageSrcSurface(inBuffer, &sid);
+ CHECK_ENCODE_STATUS_RETURN("manageSrcSurface");
+
+ //Prepare CodedBuffer
+ mCodedBuffer_Lock.lock();
+ if(mVACodedBufferList.empty()){
+ if(timeout == FUNC_BLOCK)
+ mCodedBuffer_Cond.wait(mCodedBuffer_Lock);
+ else if (timeout > 0) {
+ if(NO_ERROR != mEncodeTask_Cond.waitRelative(mCodedBuffer_Lock, 1000000*timeout)){
+ mCodedBuffer_Lock.unlock();
+ LOG_E("Time out wait for Coded buffer.\n");
+ return ENCODE_DEVICE_BUSY;
+ }
+ }
+ else {//Nonblock
+ mCodedBuffer_Lock.unlock();
+ LOG_E("Coded buffer is not ready now.\n");
+ return ENCODE_DEVICE_BUSY;
+ }
+ }
+
+ if(mVACodedBufferList.empty()){
+ mCodedBuffer_Lock.unlock();
+ return ENCODE_DEVICE_BUSY;
+ }
+ VABufferID coded_buf = (VABufferID) *(mVACodedBufferList.begin());
+ mVACodedBufferList.erase(mVACodedBufferList.begin());
+ mCodedBuffer_Lock.unlock();
+
+ LOG_V("CodedBuffer ID 0x%08x\n", coded_buf);
+
+ //All resources are ready, start to assemble EncodeTask
+ EncodeTask* task = new EncodeTask();
+
+ task->completed = false;
+ task->enc_surface = sid;
+ task->coded_buffer = coded_buf;
+ task->timestamp = inBuffer->timeStamp;
+ task->priv = inBuffer->priv;
+
+ //Setup frame info, like flag ( SYNCFRAME), frame number, type etc
+ task->type = inBuffer->type;
+ task->flag = inBuffer->flag;
+ PrepareFrameInfo(task);
+
+ if(mAutoReference == false){
+ //Setup ref /rec frames
+ //TODO: B frame support, temporary use same logic
+ switch (inBuffer->type) {
+ case FTYPE_UNKNOWN:
+ case FTYPE_IDR:
+ case FTYPE_I:
+ case FTYPE_P:
+ {
+ if(!mFrameSkipped) {
+ VASurfaceID tmpSurface = mRecSurface;
+ mRecSurface = mRefSurface;
+ mRefSurface = tmpSurface;
+ }
+
+ task->ref_surface = mRefSurface;
+ task->rec_surface = mRecSurface;
+
+ break;
+ }
+ case FTYPE_B:
+ default:
+ LOG_V("Something wrong, B frame may not be supported in this mode\n");
+ ret = ENCODE_NOT_SUPPORTED;
+ goto CLEAN_UP;
+ }
+ }else {
+ task->ref_surface = VA_INVALID_SURFACE;
+ task->rec_surface = VA_INVALID_SURFACE;
+ }
+ //======Start Encoding, add task to list======
+ LOG_V("Start Encoding vaSurface=0x%08x\n", task->enc_surface);
+
+ vaStatus = vaBeginPicture(mVADisplay, mVAContext, task->enc_surface);
+ CHECK_VA_STATUS_GOTO_CLEANUP("vaBeginPicture");
+
+ ret = sendEncodeCommand(task);
+ CHECK_ENCODE_STATUS_CLEANUP("sendEncodeCommand");
+
+ vaStatus = vaEndPicture(mVADisplay, mVAContext);
+ CHECK_VA_STATUS_GOTO_CLEANUP("vaEndPicture");
+
+ LOG_V("Add Task %p into Encode Task list\n", task);
+ mEncodeTask_Lock.lock();
+ mEncodeTaskList.push_back(task);
+ mEncodeTask_Cond.signal();
+ mEncodeTask_Lock.unlock();
+
+ mFrameNum ++;
+
+ LOG_V("encode return Success\n");
+
+ return ENCODE_SUCCESS;
+
+CLEAN_UP:
+
+ delete task;
+ mCodedBuffer_Lock.lock();
+ mVACodedBufferList.push_back(coded_buf); //push to CodedBuffer pool again since it is not used
+ mCodedBuffer_Cond.signal();
+ mCodedBuffer_Lock.unlock();
+
+ LOG_V("encode return error=%x\n", ret);
+
+ return ret;
+}
+
+/*
+ 1. Firstly check if one task is outputting data, if yes, continue outputting, if not try to get one from list.
+ 2. Due to block/non-block/block with timeout 3 modes, if task is not completed, then sync surface, if yes,
+ start output data
+ 3. Use variable curoutputtask to record task which is getOutput() working on to avoid push again when get failure
+ on non-block/block with timeout modes.
+ 4. if complete all output data, curoutputtask should be set NULL
+*/
+Encode_Status VideoEncoderBase::getOutput(VideoEncOutputBuffer *outBuffer, uint32_t timeout) {
+
+ Encode_Status ret = ENCODE_SUCCESS;
+ VAStatus vaStatus = VA_STATUS_SUCCESS;
+ bool useLocalBuffer = false;
+
+ CHECK_NULL_RETURN_IFFAIL(outBuffer);
+
+ if (mCurOutputTask == NULL) {
+ mEncodeTask_Lock.lock();
+ if(mEncodeTaskList.empty()) {
+ LOG_V("getOutput CurrentTask is NULL\n");
+ if(timeout == FUNC_BLOCK) {
+ LOG_V("waiting for task....\n");
+ mEncodeTask_Cond.wait(mEncodeTask_Lock);
+ } else if (timeout > 0) {
+ LOG_V("waiting for task in %i ms....\n", timeout);
+ if(NO_ERROR != mEncodeTask_Cond.waitRelative(mEncodeTask_Lock, 1000000*timeout)) {
+ mEncodeTask_Lock.unlock();
+ LOG_E("Time out wait for encode task.\n");
+ return ENCODE_NO_REQUEST_DATA;
+ }
+ } else {//Nonblock
+ mEncodeTask_Lock.unlock();
+ return ENCODE_NO_REQUEST_DATA;
+ }
+ }
+
+ if(mEncodeTaskList.empty()){
+ mEncodeTask_Lock.unlock();
+ return ENCODE_DATA_NOT_READY;
+ }
+ mCurOutputTask = *(mEncodeTaskList.begin());
+ mEncodeTaskList.erase(mEncodeTaskList.begin());
+ mEncodeTask_Lock.unlock();
+ }
+
+ //sync/query/wait task if not completed
+ if (mCurOutputTask->completed == false) {
+ VASurfaceStatus vaSurfaceStatus;
+
+ if (timeout == FUNC_BLOCK) {
+ //block mode, direct sync surface to output data
+
+ mOutCodedBuffer = mCurOutputTask->coded_buffer;
+
+ // Check frame skip
+ // Need encoding to be completed before calling query surface below to
+ // get the right skip frame flag for current frame
+ // It is a requirement of video driver
+ // vaSyncSurface syncs the wrong frame when rendering the same surface multiple times,
+ // so use vaMapbuffer instead
+ LOG_I ("block mode, vaMapBuffer ID = 0x%08x\n", mOutCodedBuffer);
+ if (mOutCodedBufferPtr == NULL) {
+ vaStatus = vaMapBuffer (mVADisplay, mOutCodedBuffer, (void **)&mOutCodedBufferPtr);
+ CHECK_VA_STATUS_GOTO_CLEANUP("vaMapBuffer");
+ CHECK_NULL_RETURN_IFFAIL(mOutCodedBufferPtr);
+ }
+
+ vaStatus = vaQuerySurfaceStatus(mVADisplay, mCurOutputTask->enc_surface, &vaSurfaceStatus);
+ CHECK_VA_STATUS_RETURN("vaQuerySurfaceStatus");
+ mFrameSkipped = vaSurfaceStatus & VASurfaceSkipped;
+
+ mCurOutputTask->completed = true;
+
+ } else {
+ //For both block with timeout and non-block mode, query surface, if ready, output data
+ LOG_I ("non-block mode, vaQuerySurfaceStatus ID = 0x%08x\n", mCurOutputTask->enc_surface);
+
+ vaStatus = vaQuerySurfaceStatus(mVADisplay, mCurOutputTask->enc_surface, &vaSurfaceStatus);
+ if (vaSurfaceStatus & VASurfaceReady) {
+ mOutCodedBuffer = mCurOutputTask->coded_buffer;
+ mFrameSkipped = vaSurfaceStatus & VASurfaceSkipped;
+ mCurOutputTask->completed = true;
+ //if need to call SyncSurface again ?
+
+ } else {//not encode complet yet, but keep all context and return directly
+ return ENCODE_DATA_NOT_READY;
+ }
+
+ }
+
+ }
+
+ //start to output data
+ ret = prepareForOutput(outBuffer, &useLocalBuffer);
+ CHECK_ENCODE_STATUS_CLEANUP("prepareForOutput");
+
+ //copy all flags to outBuffer
+ outBuffer->offset = 0;
+ outBuffer->flag = mCurOutputTask->flag;
+ outBuffer->type = mCurOutputTask->type;
+ outBuffer->timeStamp = mCurOutputTask->timestamp;
+ outBuffer->priv = mCurOutputTask->priv;
+
+ if (outBuffer->format == OUTPUT_EVERYTHING || outBuffer->format == OUTPUT_FRAME_DATA) {
+ ret = outputAllData(outBuffer);
+ CHECK_ENCODE_STATUS_CLEANUP("outputAllData");
+ }else {
+ ret = getExtFormatOutput(outBuffer);
+ CHECK_ENCODE_STATUS_CLEANUP("getExtFormatOutput");
+ }
+
+ LOG_I("out size for this getOutput call = %d\n", outBuffer->dataSize);
+
+ ret = cleanupForOutput();
+ CHECK_ENCODE_STATUS_CLEANUP("cleanupForOutput");
+
+ LOG_V("getOutput return Success, Frame skip is %d\n", mFrameSkipped);
+
+ return ENCODE_SUCCESS;
+
+CLEAN_UP:
+
+ if (outBuffer->data && (useLocalBuffer == true)) {
+ delete[] outBuffer->data;
+ outBuffer->data = NULL;
+ useLocalBuffer = false;
+ }
+
+ if (mOutCodedBufferPtr != NULL) {
+ vaStatus = vaUnmapBuffer(mVADisplay, mOutCodedBuffer);
+ mOutCodedBufferPtr = NULL;
+ mCurSegment = NULL;
+ }
+
+ delete mCurOutputTask;
+ mCurOutputTask = NULL;
+ mCodedBuffer_Lock.lock();
+ mVACodedBufferList.push_back(mOutCodedBuffer);
+ mCodedBuffer_Cond.signal();
+ mCodedBuffer_Lock.unlock();
+
+ LOG_V("getOutput return error=%x\n", ret);
+ return ret;
+}
+
+void VideoEncoderBase::flush() {
+
+ LOG_V( "Begin\n");
+
+ // reset the properities
+ mFrameNum = 0;
+
+ LOG_V( "end\n");
+}
+
+Encode_Status VideoEncoderBase::stop() {
+
+ VAStatus vaStatus = VA_STATUS_SUCCESS;
+ Encode_Status ret = ENCODE_SUCCESS;
+
+ LOG_V( "Begin\n");
+
+ // It is possible that above pointers have been allocated
+ // before we set mStarted to true
+ if (!mStarted) {
+ LOG_V("Encoder has been stopped\n");
+ return ENCODE_SUCCESS;
+ }
+ if (mAutoRefSurfaces) {
+ delete[] mAutoRefSurfaces;
+ mAutoRefSurfaces = NULL;
+ }
+
+ mCodedBuffer_Lock.lock();
+ mVACodedBufferList.clear();
+ mCodedBuffer_Lock.unlock();
+ mCodedBuffer_Cond.broadcast();
+
+ //Delete all uncompleted tasks
+ mEncodeTask_Lock.lock();
+ while(! mEncodeTaskList.empty())
+ {
+ delete *mEncodeTaskList.begin();
+ mEncodeTaskList.erase(mEncodeTaskList.begin());
+ }
+ mEncodeTask_Lock.unlock();
+ mEncodeTask_Cond.broadcast();
+
+ //Release Src Surface Buffer Map, destroy surface manually since it is not added into context
+ LOG_V( "Rlease Src Surface Map\n");
+ while(! mSrcSurfaceMapList.empty())
+ {
+ delete (*mSrcSurfaceMapList.begin());
+ mSrcSurfaceMapList.erase(mSrcSurfaceMapList.begin());
+ }
+
+ LOG_V( "vaDestroyContext\n");
+ if (mVAContext != VA_INVALID_ID) {
+ vaStatus = vaDestroyContext(mVADisplay, mVAContext);
+ CHECK_VA_STATUS_GOTO_CLEANUP("vaDestroyContext");
+ }
+
+ LOG_V( "vaDestroyConfig\n");
+ if (mVAConfig != VA_INVALID_ID) {
+ vaStatus = vaDestroyConfig(mVADisplay, mVAConfig);
+ CHECK_VA_STATUS_GOTO_CLEANUP("vaDestroyConfig");
+ }
+
+CLEAN_UP:
+
+ mStarted = false;
+ mSliceSizeOverflow = false;
+ mCurOutputTask= NULL;
+ mOutCodedBuffer = 0;
+ mCurSegment = NULL;
+ mOffsetInSeg =0;
+ mTotalSize = 0;
+ mTotalSizeCopied = 0;
+ mFrameSkipped = false;
+ mSupportedSurfaceMemType = 0;
+
+ LOG_V( "end\n");
+ return ret;
+}
+
+Encode_Status VideoEncoderBase::prepareForOutput(
+ VideoEncOutputBuffer *outBuffer, bool *useLocalBuffer) {
+
+ VAStatus vaStatus = VA_STATUS_SUCCESS;
+ VACodedBufferSegment *vaCodedSeg = NULL;
+ uint32_t status = 0;
+
+ LOG_V( "begin\n");
+ // Won't check parameters here as the caller already checked them
+ // mCurSegment is NULL means it is first time to be here after finishing encoding a frame
+ if (mCurSegment == NULL) {
+ if (mOutCodedBufferPtr == NULL) {
+ vaStatus = vaMapBuffer (mVADisplay, mOutCodedBuffer, (void **)&mOutCodedBufferPtr);
+ CHECK_VA_STATUS_RETURN("vaMapBuffer");
+ CHECK_NULL_RETURN_IFFAIL(mOutCodedBufferPtr);
+ }
+
+ LOG_I ("Coded Buffer ID been mapped = 0x%08x\n", mOutCodedBuffer);
+
+ mTotalSize = 0;
+ mOffsetInSeg = 0;
+ mTotalSizeCopied = 0;
+ vaCodedSeg = (VACodedBufferSegment *)mOutCodedBufferPtr;
+ mCurSegment = (VACodedBufferSegment *)mOutCodedBufferPtr;
+
+ while (1) {
+
+ mTotalSize += vaCodedSeg->size;
+ status = vaCodedSeg->status;
+#ifndef IMG_GFX
+ uint8_t *pTemp;
+ uint32_t ii;
+ pTemp = (uint8_t*)vaCodedSeg->buf;
+ for(ii = 0; ii < 16;){
+ if (*(pTemp + ii) == 0xFF)
+ ii++;
+ else
+ break;
+ }
+ if (ii > 0) {
+ mOffsetInSeg = ii;
+ }
+#endif
+ if (!mSliceSizeOverflow) {
+ mSliceSizeOverflow = status & VA_CODED_BUF_STATUS_SLICE_OVERFLOW_MASK;
+ }
+
+ if (vaCodedSeg->next == NULL)
+ break;
+
+ vaCodedSeg = (VACodedBufferSegment *)vaCodedSeg->next;
+ }
+ }
+
+ // We will support two buffer allocation mode,
+ // one is application allocates the buffer and passes to encode,
+ // the other is encode allocate memory
+
+ //means app doesn't allocate the buffer, so _encode will allocate it.
+ if (outBuffer->data == NULL) {
+ *useLocalBuffer = true;
+ outBuffer->data = new uint8_t[mTotalSize - mTotalSizeCopied + 100];
+ if (outBuffer->data == NULL) {
+ LOG_E( "outBuffer->data == NULL\n");
+ return ENCODE_NO_MEMORY;
+ }
+ outBuffer->bufferSize = mTotalSize + 100;
+ outBuffer->dataSize = 0;
+ }
+
+ // Clear all flag for every call
+ outBuffer->flag = 0;
+ if (mSliceSizeOverflow) outBuffer->flag |= ENCODE_BUFFERFLAG_SLICEOVERFOLOW;
+
+ if (!mCurSegment)
+ return ENCODE_FAIL;
+
+ if (mCurSegment->size < mOffsetInSeg) {
+ LOG_E("mCurSegment->size < mOffsetInSeg\n");
+ return ENCODE_FAIL;
+ }
+
+ // Make sure we have data in current segment
+ if (mCurSegment->size == mOffsetInSeg) {
+ if (mCurSegment->next != NULL) {
+ mCurSegment = (VACodedBufferSegment *)mCurSegment->next;
+ mOffsetInSeg = 0;
+ } else {
+ LOG_V("No more data available\n");
+ outBuffer->flag |= ENCODE_BUFFERFLAG_DATAINVALID;
+ outBuffer->dataSize = 0;
+ mCurSegment = NULL;
+ return ENCODE_NO_REQUEST_DATA;
+ }
+ }
+
+ LOG_V( "end\n");
+ return ENCODE_SUCCESS;
+}
+
+Encode_Status VideoEncoderBase::cleanupForOutput() {
+
+ VAStatus vaStatus = VA_STATUS_SUCCESS;
+
+ //mCurSegment is NULL means all data has been copied out
+ if (mCurSegment == NULL && mOutCodedBufferPtr) {
+ vaStatus = vaUnmapBuffer(mVADisplay, mOutCodedBuffer);
+ CHECK_VA_STATUS_RETURN("vaUnmapBuffer");
+ mOutCodedBufferPtr = NULL;
+ mTotalSize = 0;
+ mOffsetInSeg = 0;
+ mTotalSizeCopied = 0;
+
+ delete mCurOutputTask;
+ mCurOutputTask = NULL;
+ mCodedBuffer_Lock.lock();
+ mVACodedBufferList.push_back(mOutCodedBuffer);
+ mCodedBuffer_Cond.signal();
+ mCodedBuffer_Lock.unlock();
+
+ LOG_V("All data has been outputted, return CodedBuffer 0x%08x to pool\n", mOutCodedBuffer);
+ }
+ return ENCODE_SUCCESS;
+}
+
+Encode_Status VideoEncoderBase::queryProfileLevelConfig(VADisplay dpy, VAProfile profile) {
+
+ VAStatus vaStatus = VA_STATUS_SUCCESS;
+ VAEntrypoint entryPtr[8];
+ int i, entryPtrNum;
+
+ if(profile == VAProfileH264Main) //need to be fixed
+ return ENCODE_NOT_SUPPORTED;
+
+ vaStatus = vaQueryConfigEntrypoints(dpy, profile, entryPtr, &entryPtrNum);
+ CHECK_VA_STATUS_RETURN("vaQueryConfigEntrypoints");
+
+ for(i=0; i<entryPtrNum; i++){
+ if(entryPtr[i] == VAEntrypointEncSlice)
+ return ENCODE_SUCCESS;
+ }
+
+ return ENCODE_NOT_SUPPORTED;
+}
+
+Encode_Status VideoEncoderBase::queryAutoReferenceConfig(VAProfile profile) {
+
+ VAStatus vaStatus = VA_STATUS_SUCCESS;
+ VAConfigAttrib attrib_list;
+ attrib_list.type = VAConfigAttribEncAutoReference;
+ attrib_list.value = VA_ATTRIB_NOT_SUPPORTED;
+
+ vaStatus = vaGetConfigAttributes(mVADisplay, profile, VAEntrypointEncSlice, &attrib_list, 1);
+ if(attrib_list.value == VA_ATTRIB_NOT_SUPPORTED )
+ mAutoReference = false;
+ else
+ mAutoReference = true;
+
+ return ENCODE_SUCCESS;
+}
+
+Encode_Status VideoEncoderBase::querySupportedSurfaceMemTypes() {
+
+ VAStatus vaStatus = VA_STATUS_SUCCESS;
+
+ unsigned int num = 0;
+
+ VASurfaceAttrib* attribs = NULL;
+
+ //get attribs number
+ vaStatus = vaQuerySurfaceAttributes(mVADisplay, mVAConfig, attribs, &num);
+ CHECK_VA_STATUS_RETURN("vaGetSurfaceAttributes");
+
+ if (num == 0)
+ return ENCODE_SUCCESS;
+
+ attribs = new VASurfaceAttrib[num];
+
+ vaStatus = vaQuerySurfaceAttributes(mVADisplay, mVAConfig, attribs, &num);
+ CHECK_VA_STATUS_RETURN("vaGetSurfaceAttributes");
+
+ for(uint32_t i = 0; i < num; i ++) {
+ if (attribs[i].type == VASurfaceAttribMemoryType) {
+ mSupportedSurfaceMemType = attribs[i].value.value.i;
+ break;
+ }
+ else
+ continue;
+ }
+
+ delete attribs;
+
+ return ENCODE_SUCCESS;
+}
+
+Encode_Status VideoEncoderBase::outputAllData(VideoEncOutputBuffer *outBuffer) {
+
+ // Data size been copied for every single call
+ uint32_t sizeCopiedHere = 0;
+ uint32_t sizeToBeCopied = 0;
+
+ CHECK_NULL_RETURN_IFFAIL(outBuffer->data);
+
+ while (1) {
+
+ LOG_I("mCurSegment->size = %d, mOffsetInSeg = %d\n", mCurSegment->size, mOffsetInSeg);
+ LOG_I("outBuffer->bufferSize = %d, sizeCopiedHere = %d, mTotalSizeCopied = %d\n",
+ outBuffer->bufferSize, sizeCopiedHere, mTotalSizeCopied);
+
+ if (mCurSegment->size < mOffsetInSeg || outBuffer->bufferSize < sizeCopiedHere) {
+ LOG_E("mCurSegment->size < mOffsetInSeg || outBuffer->bufferSize < sizeCopiedHere\n");
+ return ENCODE_FAIL;
+ }
+
+ if ((mCurSegment->size - mOffsetInSeg) <= outBuffer->bufferSize - sizeCopiedHere) {
+ sizeToBeCopied = mCurSegment->size - mOffsetInSeg;
+ memcpy(outBuffer->data + sizeCopiedHere,
+ (uint8_t *)mCurSegment->buf + mOffsetInSeg, sizeToBeCopied);
+ sizeCopiedHere += sizeToBeCopied;
+ mTotalSizeCopied += sizeToBeCopied;
+ mOffsetInSeg = 0;
+ } else {
+ sizeToBeCopied = outBuffer->bufferSize - sizeCopiedHere;
+ memcpy(outBuffer->data + sizeCopiedHere,
+ (uint8_t *)mCurSegment->buf + mOffsetInSeg, outBuffer->bufferSize - sizeCopiedHere);
+ mTotalSizeCopied += sizeToBeCopied;
+ mOffsetInSeg += sizeToBeCopied;
+ outBuffer->dataSize = outBuffer->bufferSize;
+ outBuffer->remainingSize = mTotalSize - mTotalSizeCopied;
+ outBuffer->flag |= ENCODE_BUFFERFLAG_PARTIALFRAME;
+ return ENCODE_BUFFER_TOO_SMALL;
+ }
+
+ if (mCurSegment->next == NULL) {
+ outBuffer->dataSize = sizeCopiedHere;
+ outBuffer->remainingSize = 0;
+ outBuffer->flag |= ENCODE_BUFFERFLAG_ENDOFFRAME;
+ mCurSegment = NULL;
+ return ENCODE_SUCCESS;
+ }
+
+ mCurSegment = (VACodedBufferSegment *)mCurSegment->next;
+ mOffsetInSeg = 0;
+ }
+}
+
+void VideoEncoderBase::setDefaultParams() {
+
+ // Set default value for input parameters
+ mComParams.profile = VAProfileH264Baseline;
+ mComParams.level = 41;
+ mComParams.rawFormat = RAW_FORMAT_NV12;
+ mComParams.frameRate.frameRateNum = 30;
+ mComParams.frameRate.frameRateDenom = 1;
+ mComParams.resolution.width = 0;
+ mComParams.resolution.height = 0;
+ mComParams.intraPeriod = 30;
+ mComParams.rcMode = RATE_CONTROL_NONE;
+ mComParams.rcParams.initQP = 15;
+ mComParams.rcParams.minQP = 0;
+ mComParams.rcParams.maxQP = 0;
+ mComParams.rcParams.I_minQP = 0;
+ mComParams.rcParams.I_maxQP = 0;
+ mComParams.rcParams.bitRate = 640000;
+ mComParams.rcParams.targetPercentage= 0;
+ mComParams.rcParams.windowSize = 0;
+ mComParams.rcParams.disableFrameSkip = 0;
+ mComParams.rcParams.disableBitsStuffing = 1;
+ mComParams.rcParams.enableIntraFrameQPControl = 0;
+ mComParams.rcParams.temporalFrameRate = 0;
+ mComParams.rcParams.temporalID = 0;
+ mComParams.cyclicFrameInterval = 30;
+ mComParams.refreshType = VIDEO_ENC_NONIR;
+ mComParams.airParams.airMBs = 0;
+ mComParams.airParams.airThreshold = 0;
+ mComParams.airParams.airAuto = 1;
+ mComParams.disableDeblocking = 2;
+ mComParams.syncEncMode = false;
+ mComParams.codedBufNum = 2;
+ mComParams.numberOfLayer = 1;
+ mComParams.nPeriodicity = 0;
+ memset(mComParams.nLayerID,0,32*sizeof(uint32_t));
+
+ mHrdParam.bufferSize = 0;
+ mHrdParam.initBufferFullness = 0;
+
+ mStoreMetaDataInBuffers.isEnabled = false;
+}
+
+Encode_Status VideoEncoderBase::setParameters(
+ VideoParamConfigSet *videoEncParams) {
+
+ Encode_Status ret = ENCODE_SUCCESS;
+ CHECK_NULL_RETURN_IFFAIL(videoEncParams);
+ LOG_I("Config type = %x\n", (int)videoEncParams->type);
+
+ if (mStarted) {
+ LOG_E("Encoder has been initialized, should use setConfig to change configurations\n");
+ return ENCODE_ALREADY_INIT;
+ }
+
+ switch (videoEncParams->type) {
+ case VideoParamsTypeCommon: {
+
+ VideoParamsCommon *paramsCommon =
+ reinterpret_cast <VideoParamsCommon *> (videoEncParams);
+ if (paramsCommon->size != sizeof (VideoParamsCommon)) {
+ return ENCODE_INVALID_PARAMS;
+ }
+ if(paramsCommon->codedBufNum < 2)
+ paramsCommon->codedBufNum =2;
+ mComParams = *paramsCommon;
+ break;
+ }
+
+ case VideoParamsTypeUpSteamBuffer: {
+
+ VideoParamsUpstreamBuffer *upStreamBuffer =
+ reinterpret_cast <VideoParamsUpstreamBuffer *> (videoEncParams);
+
+ if (upStreamBuffer->size != sizeof (VideoParamsUpstreamBuffer)) {
+ return ENCODE_INVALID_PARAMS;
+ }
+
+ ret = setUpstreamBuffer(upStreamBuffer);
+ break;
+ }
+
+ case VideoParamsTypeUsrptrBuffer: {
+
+ // usrptr only can be get
+ // this case should not happen
+ break;
+ }
+
+ case VideoParamsTypeHRD: {
+ VideoParamsHRD *hrd =
+ reinterpret_cast <VideoParamsHRD *> (videoEncParams);
+
+ if (hrd->size != sizeof (VideoParamsHRD)) {
+ return ENCODE_INVALID_PARAMS;
+ }
+
+ mHrdParam.bufferSize = hrd->bufferSize;
+ mHrdParam.initBufferFullness = hrd->initBufferFullness;
+ mRenderHrd = true;
+
+ break;
+ }
+
+ case VideoParamsTypeStoreMetaDataInBuffers: {
+ VideoParamsStoreMetaDataInBuffers *metadata =
+ reinterpret_cast <VideoParamsStoreMetaDataInBuffers *> (videoEncParams);
+
+ if (metadata->size != sizeof (VideoParamsStoreMetaDataInBuffers)) {
+ return ENCODE_INVALID_PARAMS;
+ }
+
+ mStoreMetaDataInBuffers.isEnabled = metadata->isEnabled;
+
+ break;
+ }
+
+ case VideoParamsTypeTemporalLayer:{
+ VideoParamsTemporalLayer *temporallayer =
+ reinterpret_cast <VideoParamsTemporalLayer *> (videoEncParams);
+
+ if (temporallayer->size != sizeof(VideoParamsTemporalLayer)) {
+ return ENCODE_INVALID_PARAMS;
+ }
+
+ mComParams.numberOfLayer = temporallayer->numberOfLayer;
+ mComParams.nPeriodicity = temporallayer->nPeriodicity;
+ for(uint32_t i=0;i<temporallayer->nPeriodicity;i++)
+ mComParams.nLayerID[i] = temporallayer->nLayerID[i];
+ mRenderMultiTemporal = true;
+ break;
+ }
+
+ case VideoParamsTypeAVC:
+ case VideoParamsTypeH263:
+ case VideoParamsTypeMP4:
+ case VideoParamsTypeVC1:
+ case VideoParamsTypeVP8: {
+ ret = derivedSetParams(videoEncParams);
+ break;
+ }
+
+ default: {
+ LOG_E ("Wrong ParamType here\n");
+ return ENCODE_INVALID_PARAMS;
+ }
+ }
+ return ret;
+}
+
+Encode_Status VideoEncoderBase::getParameters(
+ VideoParamConfigSet *videoEncParams) {
+
+ Encode_Status ret = ENCODE_SUCCESS;
+ CHECK_NULL_RETURN_IFFAIL(videoEncParams);
+ LOG_I("Config type = %d\n", (int)videoEncParams->type);
+
+ switch (videoEncParams->type) {
+ case VideoParamsTypeCommon: {
+
+ VideoParamsCommon *paramsCommon =
+ reinterpret_cast <VideoParamsCommon *> (videoEncParams);
+
+ if (paramsCommon->size != sizeof (VideoParamsCommon)) {
+ return ENCODE_INVALID_PARAMS;
+ }
+ *paramsCommon = mComParams;
+ break;
+ }
+
+ case VideoParamsTypeUpSteamBuffer: {
+
+ // Get upstream buffer could happen
+ // but not meaningful a lot
+ break;
+ }
+
+ case VideoParamsTypeUsrptrBuffer: {
+ VideoParamsUsrptrBuffer *usrptrBuffer =
+ reinterpret_cast <VideoParamsUsrptrBuffer *> (videoEncParams);
+
+ if (usrptrBuffer->size != sizeof (VideoParamsUsrptrBuffer)) {
+ return ENCODE_INVALID_PARAMS;
+ }
+
+ ret = getNewUsrptrFromSurface(
+ usrptrBuffer->width, usrptrBuffer->height, usrptrBuffer->format,
+ usrptrBuffer->expectedSize, &(usrptrBuffer->actualSize),
+ &(usrptrBuffer->stride), &(usrptrBuffer->usrPtr));
+
+ break;
+ }
+
+ case VideoParamsTypeHRD: {
+ VideoParamsHRD *hrd =
+ reinterpret_cast <VideoParamsHRD *> (videoEncParams);
+
+ if (hrd->size != sizeof (VideoParamsHRD)) {
+ return ENCODE_INVALID_PARAMS;
+ }
+
+ hrd->bufferSize = mHrdParam.bufferSize;
+ hrd->initBufferFullness = mHrdParam.initBufferFullness;
+
+ break;
+ }
+
+ case VideoParamsTypeStoreMetaDataInBuffers: {
+ VideoParamsStoreMetaDataInBuffers *metadata =
+ reinterpret_cast <VideoParamsStoreMetaDataInBuffers *> (videoEncParams);
+
+ if (metadata->size != sizeof (VideoParamsStoreMetaDataInBuffers)) {
+ return ENCODE_INVALID_PARAMS;
+ }
+
+ metadata->isEnabled = mStoreMetaDataInBuffers.isEnabled;
+
+ break;
+ }
+
+ case VideoParamsTypeProfileLevel: {
+ VideoParamsProfileLevel *profilelevel =
+ reinterpret_cast <VideoParamsProfileLevel *> (videoEncParams);
+
+ if (profilelevel->size != sizeof (VideoParamsProfileLevel)) {
+ return ENCODE_INVALID_PARAMS;
+ }
+
+ profilelevel->level = 0;
+ if(queryProfileLevelConfig(mVADisplay, profilelevel->profile) == ENCODE_SUCCESS){
+ profilelevel->isSupported = true;
+ if(profilelevel->profile == VAProfileH264High)
+ profilelevel->level = 42;
+ else if(profilelevel->profile == VAProfileH264Main)
+ profilelevel->level = 42;
+ else if(profilelevel->profile == VAProfileH264Baseline)
+ profilelevel->level = 41;
+ else{
+ profilelevel->level = 0;
+ profilelevel->isSupported = false;
+ }
+ }
+ }
+
+ case VideoParamsTypeTemporalLayer:{
+ VideoParamsTemporalLayer *temporallayer =
+ reinterpret_cast <VideoParamsTemporalLayer *> (videoEncParams);
+
+ if(temporallayer->size != sizeof(VideoParamsTemporalLayer)) {
+ return ENCODE_INVALID_PARAMS;
+ }
+
+ temporallayer->numberOfLayer = mComParams.numberOfLayer;
+
+ break;
+ }
+
+ case VideoParamsTypeAVC:
+ case VideoParamsTypeH263:
+ case VideoParamsTypeMP4:
+ case VideoParamsTypeVC1:
+ case VideoParamsTypeVP8: {
+ derivedGetParams(videoEncParams);
+ break;
+ }
+
+ default: {
+ LOG_E ("Wrong ParamType here\n");
+ break;
+ }
+
+ }
+ return ENCODE_SUCCESS;
+}
+
+Encode_Status VideoEncoderBase::setConfig(VideoParamConfigSet *videoEncConfig) {
+
+ Encode_Status ret = ENCODE_SUCCESS;
+ CHECK_NULL_RETURN_IFFAIL(videoEncConfig);
+ LOG_I("Config type = %d\n", (int)videoEncConfig->type);
+
+ // workaround
+#if 0
+ if (!mStarted) {
+ LOG_E("Encoder has not initialized yet, can't call setConfig\n");
+ return ENCODE_NOT_INIT;
+ }
+#endif
+
+ switch (videoEncConfig->type) {
+ case VideoConfigTypeFrameRate: {
+ VideoConfigFrameRate *configFrameRate =
+ reinterpret_cast <VideoConfigFrameRate *> (videoEncConfig);
+
+ if (configFrameRate->size != sizeof (VideoConfigFrameRate)) {
+ return ENCODE_INVALID_PARAMS;
+ }
+ mComParams.frameRate = configFrameRate->frameRate;
+ mRenderFrameRate = true;
+ break;
+ }
+
+ case VideoConfigTypeBitRate: {
+ VideoConfigBitRate *configBitRate =
+ reinterpret_cast <VideoConfigBitRate *> (videoEncConfig);
+
+ if (configBitRate->size != sizeof (VideoConfigBitRate)) {
+ return ENCODE_INVALID_PARAMS;
+ }
+
+ if(mComParams.numberOfLayer == 1)
+ {
+ mComParams.rcParams = configBitRate->rcParams;
+ mRenderBitRate = true;
+ }
+ else
+ {
+ mTemporalLayerBitrateFramerate[configBitRate->rcParams.temporalID].nLayerID = configBitRate->rcParams.temporalID;
+ mTemporalLayerBitrateFramerate[configBitRate->rcParams.temporalID].bitRate = configBitRate->rcParams.bitRate;
+ mTemporalLayerBitrateFramerate[configBitRate->rcParams.temporalID].frameRate = configBitRate->rcParams.temporalFrameRate;
+ }
+ break;
+ }
+
+ case VideoConfigTypeResolution: {
+
+ // Not Implemented
+ break;
+ }
+ case VideoConfigTypeIntraRefreshType: {
+
+ VideoConfigIntraRefreshType *configIntraRefreshType =
+ reinterpret_cast <VideoConfigIntraRefreshType *> (videoEncConfig);
+
+ if (configIntraRefreshType->size != sizeof (VideoConfigIntraRefreshType)) {
+ return ENCODE_INVALID_PARAMS;
+ }
+ mComParams.refreshType = configIntraRefreshType->refreshType;
+ break;
+ }
+
+ case VideoConfigTypeCyclicFrameInterval: {
+ VideoConfigCyclicFrameInterval *configCyclicFrameInterval =
+ reinterpret_cast <VideoConfigCyclicFrameInterval *> (videoEncConfig);
+ if (configCyclicFrameInterval->size != sizeof (VideoConfigCyclicFrameInterval)) {
+ return ENCODE_INVALID_PARAMS;
+ }
+
+ mComParams.cyclicFrameInterval = configCyclicFrameInterval->cyclicFrameInterval;
+ break;
+ }
+
+ case VideoConfigTypeAIR: {
+
+ VideoConfigAIR *configAIR = reinterpret_cast <VideoConfigAIR *> (videoEncConfig);
+
+ if (configAIR->size != sizeof (VideoConfigAIR)) {
+ return ENCODE_INVALID_PARAMS;
+ }
+
+ mComParams.airParams = configAIR->airParams;
+ mRenderAIR = true;
+ break;
+ }
+ case VideoConfigTypeCIR: {
+
+ VideoConfigCIR *configCIR = reinterpret_cast <VideoConfigCIR *> (videoEncConfig);
+
+ if (configCIR->size != sizeof (VideoConfigCIR)) {
+ return ENCODE_INVALID_PARAMS;
+ }
+
+ mComParams.cirParams = configCIR->cirParams;
+ mRenderCIR = true;
+ break;
+ }
+ case VideoConfigTypeAVCIntraPeriod:
+ case VideoConfigTypeNALSize:
+ case VideoConfigTypeIDRRequest:
+ case VideoConfigTypeSliceNum:
+ case VideoConfigTypeVP8:
+ case VideoConfigTypeVP8ReferenceFrame:
+ case VideoConfigTypeVP8MaxFrameSizeRatio:{
+ ret = derivedSetConfig(videoEncConfig);
+ break;
+ }
+ default: {
+ LOG_E ("Wrong Config Type here\n");
+ break;
+ }
+ }
+ return ret;
+}
+
+Encode_Status VideoEncoderBase::getConfig(VideoParamConfigSet *videoEncConfig) {
+
+ Encode_Status ret = ENCODE_SUCCESS;
+ CHECK_NULL_RETURN_IFFAIL(videoEncConfig);
+ LOG_I("Config type = %d\n", (int)videoEncConfig->type);
+
+ switch (videoEncConfig->type) {
+ case VideoConfigTypeFrameRate: {
+ VideoConfigFrameRate *configFrameRate =
+ reinterpret_cast <VideoConfigFrameRate *> (videoEncConfig);
+
+ if (configFrameRate->size != sizeof (VideoConfigFrameRate)) {
+ return ENCODE_INVALID_PARAMS;
+ }
+
+ configFrameRate->frameRate = mComParams.frameRate;
+ break;
+ }
+
+ case VideoConfigTypeBitRate: {
+ VideoConfigBitRate *configBitRate =
+ reinterpret_cast <VideoConfigBitRate *> (videoEncConfig);
+
+ if (configBitRate->size != sizeof (VideoConfigBitRate)) {
+ return ENCODE_INVALID_PARAMS;
+ }
+ configBitRate->rcParams = mComParams.rcParams;
+
+
+ break;
+ }
+ case VideoConfigTypeResolution: {
+ // Not Implemented
+ break;
+ }
+ case VideoConfigTypeIntraRefreshType: {
+
+ VideoConfigIntraRefreshType *configIntraRefreshType =
+ reinterpret_cast <VideoConfigIntraRefreshType *> (videoEncConfig);
+
+ if (configIntraRefreshType->size != sizeof (VideoConfigIntraRefreshType)) {
+ return ENCODE_INVALID_PARAMS;
+ }
+ configIntraRefreshType->refreshType = mComParams.refreshType;
+ break;
+ }
+
+ case VideoConfigTypeCyclicFrameInterval: {
+ VideoConfigCyclicFrameInterval *configCyclicFrameInterval =
+ reinterpret_cast <VideoConfigCyclicFrameInterval *> (videoEncConfig);
+ if (configCyclicFrameInterval->size != sizeof (VideoConfigCyclicFrameInterval)) {
+ return ENCODE_INVALID_PARAMS;
+ }
+
+ configCyclicFrameInterval->cyclicFrameInterval = mComParams.cyclicFrameInterval;
+ break;
+ }
+
+ case VideoConfigTypeAIR: {
+
+ VideoConfigAIR *configAIR = reinterpret_cast <VideoConfigAIR *> (videoEncConfig);
+
+ if (configAIR->size != sizeof (VideoConfigAIR)) {
+ return ENCODE_INVALID_PARAMS;
+ }
+
+ configAIR->airParams = mComParams.airParams;
+ break;
+ }
+ case VideoConfigTypeCIR: {
+
+ VideoConfigCIR *configCIR = reinterpret_cast <VideoConfigCIR *> (videoEncConfig);
+
+ if (configCIR->size != sizeof (VideoConfigCIR)) {
+ return ENCODE_INVALID_PARAMS;
+ }
+
+ configCIR->cirParams = mComParams.cirParams;
+ break;
+ }
+ case VideoConfigTypeAVCIntraPeriod:
+ case VideoConfigTypeNALSize:
+ case VideoConfigTypeIDRRequest:
+ case VideoConfigTypeSliceNum:
+ case VideoConfigTypeVP8: {
+
+ ret = derivedGetConfig(videoEncConfig);
+ break;
+ }
+ default: {
+ LOG_E ("Wrong ParamType here\n");
+ break;
+ }
+ }
+ return ret;
+}
+
+void VideoEncoderBase:: PrepareFrameInfo (EncodeTask* task) {
+ if (mNewHeader) mFrameNum = 0;
+ LOG_I( "mFrameNum = %d ", mFrameNum);
+
+ updateFrameInfo(task) ;
+}
+
+Encode_Status VideoEncoderBase:: updateFrameInfo (EncodeTask* task) {
+
+ task->type = FTYPE_P;
+
+ // determine the picture type
+ if (mFrameNum == 0)
+ task->type = FTYPE_I;
+ if (mComParams.intraPeriod != 0 && ((mFrameNum % mComParams.intraPeriod) == 0))
+ task->type = FTYPE_I;
+
+ if (task->type == FTYPE_I)
+ task->flag |= ENCODE_BUFFERFLAG_SYNCFRAME;
+
+ return ENCODE_SUCCESS;
+}
+
+Encode_Status VideoEncoderBase::getMaxOutSize (uint32_t *maxSize) {
+
+ uint32_t size = mComParams.resolution.width * mComParams.resolution.height;
+
+ if (maxSize == NULL) {
+ LOG_E("maxSize == NULL\n");
+ return ENCODE_NULL_PTR;
+ }
+
+ LOG_V( "Begin\n");
+
+ if (mCodedBufSize > 0) {
+ *maxSize = mCodedBufSize;
+ LOG_V ("Already calculate the max encoded size, get the value directly");
+ return ENCODE_SUCCESS;
+ }
+
+ // here, VP8 is different from AVC/H263
+ if(mComParams.profile == VAProfileVP8Version0_3) // for VP8 encode
+ {
+ // According to VIED suggestions, in CBR mode, coded buffer should be the size of 3 bytes per luma pixel
+ // in CBR_HRD mode, coded buffer size should be 5 * rc_buf_sz * rc_target_bitrate;
+ // now we just hardcode mCodedBufSize as 2M to walk round coded buffer size issue;
+ /*
+ if(mComParams.rcMode == VA_RC_CBR) // CBR_HRD mode
+ mCodedBufSize = 5 * mComParams.rcParams.bitRate * 6000;
+ else // CBR mode
+ mCodedBufSize = 3 * mComParams.resolution.width * mComParams.resolution.height;
+ */
+ mCodedBufSize = (2 * 1024 * 1024 + 31) & (~31);
+ }
+ else // for AVC/H263/MPEG4 encode
+ {
+ // base on the rate control mode to calculate the defaule encoded buffer size
+ if (mComParams.rcMode == VA_RC_NONE) {
+ mCodedBufSize = (size * 400) / (16 * 16);
+ // set to value according to QP
+ } else {
+ mCodedBufSize = mComParams.rcParams.bitRate / 4;
+ }
+
+ mCodedBufSize = max (mCodedBufSize , (size * 400) / (16 * 16));
+
+ // in case got a very large user input bit rate value
+ mCodedBufSize = min(mCodedBufSize, (size * 1.5 * 8));
+ mCodedBufSize = (mCodedBufSize + 15) &(~15);
+ }
+
+ *maxSize = mCodedBufSize;
+ return ENCODE_SUCCESS;
+}
+
+Encode_Status VideoEncoderBase::getNewUsrptrFromSurface(
+ uint32_t width, uint32_t height, uint32_t format,
+ uint32_t expectedSize, uint32_t *outsize, uint32_t *stride, uint8_t **usrptr) {
+
+ Encode_Status ret = ENCODE_FAIL;
+ VAStatus vaStatus = VA_STATUS_SUCCESS;
+
+ VASurfaceID surface = VA_INVALID_SURFACE;
+ VAImage image;
+ uint32_t index = 0;
+
+ LOG_V( "Begin\n");
+ // If encode session has been configured, we can not request surface creation anymore
+ if (mStarted) {
+ LOG_E( "Already Initialized, can not request VA surface anymore\n");
+ return ENCODE_WRONG_STATE;
+ }
+ if (width<=0 || height<=0 ||outsize == NULL ||stride == NULL || usrptr == NULL) {
+ LOG_E("width<=0 || height<=0 || outsize == NULL || stride == NULL ||usrptr == NULL\n");
+ return ENCODE_NULL_PTR;
+ }
+
+ // Current only NV12 is supported in VA API
+ // Through format we can get known the number of planes
+ if (format != STRING_TO_FOURCC("NV12")) {
+ LOG_W ("Format is not supported\n");
+ return ENCODE_NOT_SUPPORTED;
+ }
+
+ surface = CreateNewVASurface(mVADisplay, width, height);
+ if (surface == VA_INVALID_SURFACE)
+ return ENCODE_DRIVER_FAIL;
+
+ vaStatus = vaDeriveImage(mVADisplay, surface, &image);
+ CHECK_VA_STATUS_RETURN("vaDeriveImage");
+ LOG_V( "vaDeriveImage Done\n");
+ vaStatus = vaMapBuffer(mVADisplay, image.buf, (void **) usrptr);
+ CHECK_VA_STATUS_RETURN("vaMapBuffer");
+
+ // make sure the physical page been allocated
+ for (index = 0; index < image.data_size; index = index + 4096) {
+ unsigned char tmp = *(*usrptr + index);
+ if (tmp == 0)
+ *(*usrptr + index) = 0;
+ }
+
+ *outsize = image.data_size;
+ *stride = image.pitches[0];
+
+ LOG_I( "surface = 0x%08x\n",(uint32_t)surface);
+ LOG_I("image->pitches[0] = %d\n", image.pitches[0]);
+ LOG_I("image->pitches[1] = %d\n", image.pitches[1]);
+ LOG_I("image->offsets[0] = %d\n", image.offsets[0]);
+ LOG_I("image->offsets[1] = %d\n", image.offsets[1]);
+ LOG_I("image->num_planes = %d\n", image.num_planes);
+ LOG_I("image->width = %d\n", image.width);
+ LOG_I("image->height = %d\n", image.height);
+ LOG_I ("data_size = %d\n", image.data_size);
+ LOG_I ("usrptr = 0x%p\n", *usrptr);
+
+ vaStatus = vaUnmapBuffer(mVADisplay, image.buf);
+ CHECK_VA_STATUS_RETURN("vaUnmapBuffer");
+ vaStatus = vaDestroyImage(mVADisplay, image.image_id);
+ CHECK_VA_STATUS_RETURN("vaDestroyImage");
+
+ if (*outsize < expectedSize) {
+ LOG_E ("Allocated buffer size is small than the expected size, destroy the surface");
+ LOG_I ("Allocated size is %d, expected size is %d\n", *outsize, expectedSize);
+ vaStatus = vaDestroySurfaces(mVADisplay, &surface, 1);
+ CHECK_VA_STATUS_RETURN("vaDestroySurfaces");
+ return ENCODE_FAIL;
+ }
+
+ VASurfaceMap *map = new VASurfaceMap(mVADisplay, mSupportedSurfaceMemType);
+ if (map == NULL) {
+ LOG_E( "new VASurfaceMap failed\n");
+ return ENCODE_NO_MEMORY;
+ }
+
+ map->setVASurface(surface); //special case, vasuface is set, so nothing do in doMapping
+// map->setType(MetadataBufferTypeEncoder);
+ map->setValue((intptr_t)*usrptr);
+ ValueInfo vinfo;
+ memset(&vinfo, 0, sizeof(ValueInfo));
+ vinfo.mode = (MemMode)MEM_MODE_USRPTR;
+ vinfo.handle = 0;
+ vinfo.size = 0;
+ vinfo.width = width;
+ vinfo.height = height;
+ vinfo.lumaStride = width;
+ vinfo.chromStride = width;
+ vinfo.format = VA_FOURCC_NV12;
+ vinfo.s3dformat = 0xffffffff;
+ map->setValueInfo(vinfo);
+ map->doMapping();
+
+ mSrcSurfaceMapList.push_back(map);
+
+ ret = ENCODE_SUCCESS;
+
+ return ret;
+}
+
+Encode_Status VideoEncoderBase::setUpstreamBuffer(VideoParamsUpstreamBuffer *upStreamBuffer) {
+
+ Encode_Status status = ENCODE_SUCCESS;
+
+ CHECK_NULL_RETURN_IFFAIL(upStreamBuffer);
+ if (upStreamBuffer->bufCnt == 0) {
+ LOG_E("bufCnt == 0\n");
+ return ENCODE_FAIL;
+ }
+
+ for(unsigned int i=0; i < upStreamBuffer->bufCnt; i++) {
+ if (findSurfaceMapByValue(upStreamBuffer->bufList[i]) != NULL) //already mapped
+ continue;
+
+ //wrap upstream buffer into vaSurface
+ VASurfaceMap *map = new VASurfaceMap(mVADisplay, mSupportedSurfaceMemType);
+
+// map->setType(MetadataBufferTypeUser);
+ map->setValue(upStreamBuffer->bufList[i]);
+ ValueInfo vinfo;
+ memset(&vinfo, 0, sizeof(ValueInfo));
+ vinfo.mode = (MemMode)upStreamBuffer->bufferMode;
+ vinfo.handle = (intptr_t)upStreamBuffer->display;
+ vinfo.size = 0;
+ if (upStreamBuffer->bufAttrib) {
+ vinfo.width = upStreamBuffer->bufAttrib->realWidth;
+ vinfo.height = upStreamBuffer->bufAttrib->realHeight;
+ vinfo.lumaStride = upStreamBuffer->bufAttrib->lumaStride;
+ vinfo.chromStride = upStreamBuffer->bufAttrib->chromStride;
+ vinfo.format = upStreamBuffer->bufAttrib->format;
+ }
+ vinfo.s3dformat = 0xFFFFFFFF;
+ map->setValueInfo(vinfo);
+ status = map->doMapping();
+
+ if (status == ENCODE_SUCCESS)
+ mSrcSurfaceMapList.push_back(map);
+ else
+ delete map;
+ }
+
+ return status;
+}
+
+Encode_Status VideoEncoderBase::manageSrcSurface(VideoEncRawBuffer *inBuffer, VASurfaceID *sid) {
+
+ Encode_Status ret = ENCODE_SUCCESS;
+ IntelMetadataBufferType type;
+ intptr_t value;
+ ValueInfo vinfo;
+ ValueInfo *pvinfo = &vinfo;
+ intptr_t *extravalues = NULL;
+ unsigned int extravalues_count = 0;
+
+ IntelMetadataBuffer imb;
+ VASurfaceMap *map = NULL;
+
+ memset(&vinfo, 0, sizeof(ValueInfo));
+ if (mStoreMetaDataInBuffers.isEnabled) {
+ //metadatabuffer mode
+ LOG_I("in metadata mode, data=%p, size=%d\n", inBuffer->data, inBuffer->size);
+ if (imb.UnSerialize(inBuffer->data, inBuffer->size) != IMB_SUCCESS) {
+ //fail to parse buffer
+ return ENCODE_NO_REQUEST_DATA;
+ }
+
+ imb.GetType(type);
+ imb.GetValue(value);
+ } else {
+ //raw mode
+ LOG_I("in raw mode, data=%p, size=%d\n", inBuffer->data, inBuffer->size);
+ if (! inBuffer->data || inBuffer->size == 0) {
+ return ENCODE_NULL_PTR;
+ }
+
+ type = IntelMetadataBufferTypeUser;
+ value = (intptr_t)inBuffer->data;
+ }
+
+#ifdef INTEL_VIDEO_XPROC_SHARING
+ uint32_t sflag = mSessionFlag;
+ imb.GetSessionFlag(mSessionFlag);
+ if (mSessionFlag != sflag) {
+ //new sharing session, flush buffer sharing cache
+ IntelMetadataBuffer::ClearContext(sflag, false);
+ //flush surfacemap cache
+ LOG_V( "Flush Src Surface Map\n");
+ while(! mSrcSurfaceMapList.empty())
+ {
+ delete (*mSrcSurfaceMapList.begin());
+ mSrcSurfaceMapList.erase(mSrcSurfaceMapList.begin());
+ }
+ }
+#endif
+
+ //find if mapped
+ map = (VASurfaceMap*) findSurfaceMapByValue(value);
+
+ if (map) {
+ //has mapped, get surfaceID directly and do all necessary actions
+ LOG_I("direct find surface %d from value %i\n", map->getVASurface(), value);
+ *sid = map->getVASurface();
+ map->doMapping();
+ return ret;
+ }
+
+ //if no found from list, then try to map value with parameters
+ LOG_I("not find surface from cache with value %i, start mapping if enough information\n", value);
+
+ if (mStoreMetaDataInBuffers.isEnabled) {
+
+ //if type is IntelMetadataBufferTypeGrallocSource, use default parameters since no ValueInfo
+ if (type == IntelMetadataBufferTypeGrallocSource) {
+ vinfo.mode = MEM_MODE_GFXHANDLE;
+ vinfo.handle = 0;
+ vinfo.size = 0;
+ vinfo.width = mComParams.resolution.width;
+ vinfo.height = mComParams.resolution.height;
+ vinfo.lumaStride = mComParams.resolution.width;
+ vinfo.chromStride = mComParams.resolution.width;
+ vinfo.format = VA_FOURCC_NV12;
+ vinfo.s3dformat = 0xFFFFFFFF;
+ } else {
+ //get all info mapping needs
+ imb.GetValueInfo(pvinfo);
+ imb.GetExtraValues(extravalues, extravalues_count);
+ }
+
+ } else {
+
+ //raw mode
+ vinfo.mode = MEM_MODE_MALLOC;
+ vinfo.handle = 0;
+ vinfo.size = inBuffer->size;
+ vinfo.width = mComParams.resolution.width;
+ vinfo.height = mComParams.resolution.height;
+ vinfo.lumaStride = mComParams.resolution.width;
+ vinfo.chromStride = mComParams.resolution.width;
+ vinfo.format = VA_FOURCC_NV12;
+ vinfo.s3dformat = 0xFFFFFFFF;
+ }
+
+ /* Start mapping, if pvinfo is not NULL, then have enough info to map;
+ * if extravalues is not NULL, then need to do more times mapping
+ */
+ if (pvinfo){
+ //map according info, and add to surfacemap list
+ map = new VASurfaceMap(mVADisplay, mSupportedSurfaceMemType);
+ map->setValue(value);
+ map->setValueInfo(*pvinfo);
+ map->setAction(mVASurfaceMappingAction);
+
+ ret = map->doMapping();
+ if (ret == ENCODE_SUCCESS) {
+ LOG_I("surface mapping success, map value %i into surface %d\n", value, map->getVASurface());
+ mSrcSurfaceMapList.push_back(map);
+ } else {
+ delete map;
+ LOG_E("surface mapping failed, wrong info or meet serious error\n");
+ return ret;
+ }
+
+ *sid = map->getVASurface();
+
+ } else {
+ //can't map due to no info
+ LOG_E("surface mapping failed, missing information\n");
+ return ENCODE_NO_REQUEST_DATA;
+ }
+
+ if (extravalues) {
+ //map more using same ValueInfo
+ for(unsigned int i=0; i<extravalues_count; i++) {
+ map = new VASurfaceMap(mVADisplay, mSupportedSurfaceMemType);
+ map->setValue(extravalues[i]);
+ map->setValueInfo(vinfo);
+
+ ret = map->doMapping();
+ if (ret == ENCODE_SUCCESS) {
+ LOG_I("surface mapping extravalue success, map value %i into surface %d\n", extravalues[i], map->getVASurface());
+ mSrcSurfaceMapList.push_back(map);
+ } else {
+ delete map;
+ map = NULL;
+ LOG_E( "surface mapping extravalue failed, extravalue is %i\n", extravalues[i]);
+ }
+ }
+ }
+
+ return ret;
+}
+
+Encode_Status VideoEncoderBase::renderDynamicBitrate(EncodeTask* task) {
+ VAStatus vaStatus = VA_STATUS_SUCCESS;
+
+ LOG_V( "Begin\n\n");
+ // disable bits stuffing and skip frame apply to all rate control mode
+
+ VAEncMiscParameterBuffer *miscEncParamBuf;
+ VAEncMiscParameterRateControl *bitrateControlParam;
+ VABufferID miscParamBufferID;
+
+ vaStatus = vaCreateBuffer(mVADisplay, mVAContext,
+ VAEncMiscParameterBufferType,
+ sizeof (VAEncMiscParameterBuffer) + sizeof (VAEncMiscParameterRateControl),
+ 1, NULL,
+ &miscParamBufferID);
+
+ CHECK_VA_STATUS_RETURN("vaCreateBuffer");
+
+ vaStatus = vaMapBuffer(mVADisplay, miscParamBufferID, (void **)&miscEncParamBuf);
+ CHECK_VA_STATUS_RETURN("vaMapBuffer");
+
+ miscEncParamBuf->type = VAEncMiscParameterTypeRateControl;
+ bitrateControlParam = (VAEncMiscParameterRateControl *)miscEncParamBuf->data;
+
+ bitrateControlParam->bits_per_second = mComParams.rcParams.bitRate;
+ bitrateControlParam->initial_qp = mComParams.rcParams.initQP;
+ if(mComParams.rcParams.enableIntraFrameQPControl && (task->type == FTYPE_IDR || task->type == FTYPE_I)) {
+ bitrateControlParam->min_qp = mComParams.rcParams.I_minQP;
+ bitrateControlParam->max_qp = mComParams.rcParams.I_maxQP;
+ mRenderBitRate = true;
+ LOG_I("apply I min/max qp for IDR or I frame\n");
+ } else {
+ bitrateControlParam->min_qp = mComParams.rcParams.minQP;
+ bitrateControlParam->max_qp = mComParams.rcParams.maxQP;
+ mRenderBitRate = false;
+ LOG_I("revert to original min/max qp after IDR or I frame\n");
+ }
+ bitrateControlParam->target_percentage = mComParams.rcParams.targetPercentage;
+ bitrateControlParam->window_size = mComParams.rcParams.windowSize;
+ bitrateControlParam->rc_flags.bits.disable_frame_skip = mComParams.rcParams.disableFrameSkip;
+ bitrateControlParam->rc_flags.bits.disable_bit_stuffing = mComParams.rcParams.disableBitsStuffing;
+ bitrateControlParam->basic_unit_size = 0;
+
+ LOG_I("bits_per_second = %d\n", bitrateControlParam->bits_per_second);
+ LOG_I("initial_qp = %d\n", bitrateControlParam->initial_qp);
+ LOG_I("min_qp = %d\n", bitrateControlParam->min_qp);
+ LOG_I("max_qp = %d\n", bitrateControlParam->max_qp);
+ LOG_I("target_percentage = %d\n", bitrateControlParam->target_percentage);
+ LOG_I("window_size = %d\n", bitrateControlParam->window_size);
+ LOG_I("disable_frame_skip = %d\n", bitrateControlParam->rc_flags.bits.disable_frame_skip);
+ LOG_I("disable_bit_stuffing = %d\n", bitrateControlParam->rc_flags.bits.disable_bit_stuffing);
+
+ vaStatus = vaUnmapBuffer(mVADisplay, miscParamBufferID);
+ CHECK_VA_STATUS_RETURN("vaUnmapBuffer");
+
+ vaStatus = vaRenderPicture(mVADisplay, mVAContext,
+ &miscParamBufferID, 1);
+ CHECK_VA_STATUS_RETURN("vaRenderPicture");
+
+ return ENCODE_SUCCESS;
+}
+
+
+Encode_Status VideoEncoderBase::renderDynamicFrameRate() {
+
+ VAStatus vaStatus = VA_STATUS_SUCCESS;
+
+ if (mComParams.rcMode != RATE_CONTROL_VCM) {
+
+ LOG_W("Not in VCM mode, but call SendDynamicFramerate\n");
+ return ENCODE_SUCCESS;
+ }
+
+ VAEncMiscParameterBuffer *miscEncParamBuf;
+ VAEncMiscParameterFrameRate *frameRateParam;
+ VABufferID miscParamBufferID;
+
+ vaStatus = vaCreateBuffer(mVADisplay, mVAContext,
+ VAEncMiscParameterBufferType,
+ sizeof(miscEncParamBuf) + sizeof(VAEncMiscParameterFrameRate),
+ 1, NULL, &miscParamBufferID);
+ CHECK_VA_STATUS_RETURN("vaCreateBuffer");
+
+ vaStatus = vaMapBuffer(mVADisplay, miscParamBufferID, (void **)&miscEncParamBuf);
+ CHECK_VA_STATUS_RETURN("vaMapBuffer");
+
+ miscEncParamBuf->type = VAEncMiscParameterTypeFrameRate;
+ frameRateParam = (VAEncMiscParameterFrameRate *)miscEncParamBuf->data;
+ frameRateParam->framerate =
+ (unsigned int) (mComParams.frameRate.frameRateNum + mComParams.frameRate.frameRateDenom/2)
+ / mComParams.frameRate.frameRateDenom;
+
+ vaStatus = vaUnmapBuffer(mVADisplay, miscParamBufferID);
+ CHECK_VA_STATUS_RETURN("vaUnmapBuffer");
+
+ vaStatus = vaRenderPicture(mVADisplay, mVAContext, &miscParamBufferID, 1);
+ CHECK_VA_STATUS_RETURN("vaRenderPicture");
+
+ LOG_I( "frame rate = %d\n", frameRateParam->framerate);
+ return ENCODE_SUCCESS;
+}
+
+Encode_Status VideoEncoderBase::renderHrd() {
+
+ VAStatus vaStatus = VA_STATUS_SUCCESS;
+
+ VAEncMiscParameterBuffer *miscEncParamBuf;
+ VAEncMiscParameterHRD *hrdParam;
+ VABufferID miscParamBufferID;
+
+ vaStatus = vaCreateBuffer(mVADisplay, mVAContext,
+ VAEncMiscParameterBufferType,
+ sizeof(miscEncParamBuf) + sizeof(VAEncMiscParameterHRD),
+ 1, NULL, &miscParamBufferID);
+ CHECK_VA_STATUS_RETURN("vaCreateBuffer");
+
+ vaStatus = vaMapBuffer(mVADisplay, miscParamBufferID, (void **)&miscEncParamBuf);
+ CHECK_VA_STATUS_RETURN("vaMapBuffer");
+
+ miscEncParamBuf->type = VAEncMiscParameterTypeHRD;
+ hrdParam = (VAEncMiscParameterHRD *)miscEncParamBuf->data;
+
+ hrdParam->buffer_size = mHrdParam.bufferSize;
+ hrdParam->initial_buffer_fullness = mHrdParam.initBufferFullness;
+
+ vaStatus = vaUnmapBuffer(mVADisplay, miscParamBufferID);
+ CHECK_VA_STATUS_RETURN("vaUnmapBuffer");
+
+ vaStatus = vaRenderPicture(mVADisplay, mVAContext, &miscParamBufferID, 1);
+ CHECK_VA_STATUS_RETURN("vaRenderPicture");
+
+ return ENCODE_SUCCESS;
+}
+
+VASurfaceMap *VideoEncoderBase::findSurfaceMapByValue(intptr_t value) {
+ android::List<VASurfaceMap *>::iterator node;
+
+ for(node = mSrcSurfaceMapList.begin(); node != mSrcSurfaceMapList.end(); node++)
+ {
+ if ((*node)->getValue() == value)
+ return *node;
+ else
+ continue;
+ }
+
+ return NULL;
+}