C++程序  |  1378行  |  49.13 KB

/*
* 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 <stdlib.h>
#include "VideoEncoderLog.h"
#include "VideoEncoderAVC.h"
#include <va/va_tpi.h>
#include <va/va_enc_h264.h>
#include <bitstream.h>

VideoEncoderAVC::VideoEncoderAVC()
    :VideoEncoderBase() {
    if(VideoEncoderBase::queryProfileLevelConfig(mVADisplay, VAProfileH264High) == ENCODE_SUCCESS){
        mComParams.profile = VAProfileH264High;
        mComParams.level = 42;
    }else if(VideoEncoderBase::queryProfileLevelConfig(mVADisplay, VAProfileH264Main) == ENCODE_SUCCESS){
        mComParams.profile = VAProfileH264Main;
        mComParams.level = 41;
    }
    mVideoParamsAVC.basicUnitSize = 0;
    mVideoParamsAVC.VUIFlag = 0;
    mVideoParamsAVC.sliceNum.iSliceNum = 2;
    mVideoParamsAVC.sliceNum.pSliceNum = 2;
    mVideoParamsAVC.idrInterval = 2;
    mVideoParamsAVC.ipPeriod = 1;
    mVideoParamsAVC.maxSliceSize = 0;
    mVideoParamsAVC.delimiterType = AVC_DELIMITER_ANNEXB;
    mSliceNum = 2;
    mVideoParamsAVC.crop.LeftOffset = 0;
    mVideoParamsAVC.crop.RightOffset = 0;
    mVideoParamsAVC.crop.TopOffset = 0;
    mVideoParamsAVC.crop.BottomOffset = 0;
    mVideoParamsAVC.SAR.SarWidth = 0;
    mVideoParamsAVC.SAR.SarHeight = 0;
    mVideoParamsAVC.bEntropyCodingCABAC = 0;
    mVideoParamsAVC.bWeightedPPrediction = 0;
    mVideoParamsAVC.bDirect8x8Inference = 0;
    mVideoParamsAVC.bConstIpred = 0;
    mAutoReferenceSurfaceNum = 4;

    packed_seq_header_param_buf_id = VA_INVALID_ID;
    packed_seq_buf_id = VA_INVALID_ID;
    packed_pic_header_param_buf_id = VA_INVALID_ID;
    packed_pic_buf_id = VA_INVALID_ID;
    packed_sei_header_param_buf_id = VA_INVALID_ID;   /* the SEI buffer */
    packed_sei_buf_id = VA_INVALID_ID;
}

Encode_Status VideoEncoderAVC::start() {

    Encode_Status ret = ENCODE_SUCCESS;
    LOG_V( "Begin\n");

    if (mComParams.rcMode == VA_RC_VCM) {
        // If we are in VCM, we will set slice num to max value
        // mVideoParamsAVC.sliceNum.iSliceNum = (mComParams.resolution.height + 15) / 16;
        // mVideoParamsAVC.sliceNum.pSliceNum = mVideoParamsAVC.sliceNum.iSliceNum;
    }

    ret = VideoEncoderBase::start ();
    CHECK_ENCODE_STATUS_RETURN("VideoEncoderBase::start");

    LOG_V( "end\n");
    return ret;
}

Encode_Status VideoEncoderAVC::derivedSetParams(VideoParamConfigSet *videoEncParams) {

    CHECK_NULL_RETURN_IFFAIL(videoEncParams);
    VideoParamsAVC *encParamsAVC = reinterpret_cast <VideoParamsAVC *> (videoEncParams);

    // AVC parames
    if (encParamsAVC->size != sizeof (VideoParamsAVC)) {
        return ENCODE_INVALID_PARAMS;
    }

    if(encParamsAVC->ipPeriod == 0 || encParamsAVC->ipPeriod >4)
        return ENCODE_INVALID_PARAMS;

    if((mComParams.intraPeriod >1)&&(mComParams.intraPeriod % encParamsAVC->ipPeriod !=0))
        return ENCODE_INVALID_PARAMS;

    mVideoParamsAVC = *encParamsAVC;
    if(mComParams.profile == VAProfileH264Baseline){
        mVideoParamsAVC.bEntropyCodingCABAC = 0;
        mVideoParamsAVC.bDirect8x8Inference = 0;
        mVideoParamsAVC.bWeightedPPrediction = 0;
    }
    return ENCODE_SUCCESS;
}

Encode_Status VideoEncoderAVC:: derivedGetParams(VideoParamConfigSet *videoEncParams) {

    CHECK_NULL_RETURN_IFFAIL(videoEncParams);
    VideoParamsAVC *encParamsAVC = reinterpret_cast <VideoParamsAVC *> (videoEncParams);

    // AVC parames
    if (encParamsAVC->size != sizeof (VideoParamsAVC)) {
        return ENCODE_INVALID_PARAMS;
    }

    *encParamsAVC = mVideoParamsAVC;
    return ENCODE_SUCCESS;

}

Encode_Status VideoEncoderAVC::derivedSetConfig(VideoParamConfigSet *videoEncConfig) {

    CHECK_NULL_RETURN_IFFAIL(videoEncConfig);
    LOG_V("Config type = %d\n", (int)videoEncConfig->type);

    switch (videoEncConfig->type) {
        case VideoConfigTypeAVCIntraPeriod: {

            VideoConfigAVCIntraPeriod *configAVCIntraPeriod =
                    reinterpret_cast <VideoConfigAVCIntraPeriod *> (videoEncConfig);
            // Config Intra Peroid
            if (configAVCIntraPeriod->size != sizeof (VideoConfigAVCIntraPeriod)) {
                return ENCODE_INVALID_PARAMS;
            }

            if(configAVCIntraPeriod->ipPeriod == 0 || configAVCIntraPeriod->ipPeriod >4)
                return ENCODE_INVALID_PARAMS;
            if((configAVCIntraPeriod->intraPeriod >1)&&(configAVCIntraPeriod->intraPeriod % configAVCIntraPeriod->ipPeriod !=0))
                return ENCODE_INVALID_PARAMS;

            mVideoParamsAVC.idrInterval = configAVCIntraPeriod->idrInterval;
            mVideoParamsAVC.ipPeriod = configAVCIntraPeriod->ipPeriod;
            mComParams.intraPeriod = configAVCIntraPeriod->intraPeriod;
            mNewHeader = true;
            break;
        }
        case VideoConfigTypeNALSize: {
            // Config MTU
            VideoConfigNALSize *configNALSize =
                    reinterpret_cast <VideoConfigNALSize *> (videoEncConfig);
            if (configNALSize->size != sizeof (VideoConfigNALSize)) {
                return ENCODE_INVALID_PARAMS;
            }

            mVideoParamsAVC.maxSliceSize = configNALSize->maxSliceSize;
            mRenderMaxSliceSize = true;
            break;
        }
        case VideoConfigTypeIDRRequest: {
            if(mVideoParamsAVC.ipPeriod >1)
                return ENCODE_FAIL;
            else
                mNewHeader = true;
            break;
        }
        case VideoConfigTypeSliceNum: {

            VideoConfigSliceNum *configSliceNum =
                    reinterpret_cast <VideoConfigSliceNum *> (videoEncConfig);
            // Config Slice size
            if (configSliceNum->size != sizeof (VideoConfigSliceNum)) {
                return ENCODE_INVALID_PARAMS;
            }

            mVideoParamsAVC.sliceNum = configSliceNum->sliceNum;
            break;
        }
        default: {
            LOG_E ("Invalid Config Type");
            break;
        }
    }

    return ENCODE_SUCCESS;
}

Encode_Status VideoEncoderAVC:: derivedGetConfig(
        VideoParamConfigSet *videoEncConfig) {

    CHECK_NULL_RETURN_IFFAIL(videoEncConfig);
    LOG_V("Config type = %d\n", (int)videoEncConfig->type);

    switch (videoEncConfig->type) {

        case VideoConfigTypeAVCIntraPeriod: {

            VideoConfigAVCIntraPeriod *configAVCIntraPeriod =
                    reinterpret_cast <VideoConfigAVCIntraPeriod *> (videoEncConfig);
            if (configAVCIntraPeriod->size != sizeof (VideoConfigAVCIntraPeriod)) {
                return ENCODE_INVALID_PARAMS;
            }

            configAVCIntraPeriod->idrInterval = mVideoParamsAVC.idrInterval;
            configAVCIntraPeriod->intraPeriod = mComParams.intraPeriod;
            configAVCIntraPeriod->ipPeriod = mVideoParamsAVC.ipPeriod;

            break;
        }
        case VideoConfigTypeNALSize: {

            VideoConfigNALSize *configNALSize =
                    reinterpret_cast <VideoConfigNALSize *> (videoEncConfig);
            if (configNALSize->size != sizeof (VideoConfigNALSize)) {
                return ENCODE_INVALID_PARAMS;
            }

            configNALSize->maxSliceSize = mVideoParamsAVC.maxSliceSize;
            break;
        }
        case VideoConfigTypeIDRRequest: {
            break;

        }
        case VideoConfigTypeSliceNum: {

            VideoConfigSliceNum *configSliceNum =
                    reinterpret_cast <VideoConfigSliceNum *> (videoEncConfig);
            if (configSliceNum->size != sizeof (VideoConfigSliceNum)) {
                return ENCODE_INVALID_PARAMS;
            }

            configSliceNum->sliceNum = mVideoParamsAVC.sliceNum;
            break;
        }
        default: {
            LOG_E ("Invalid Config Type");
            break;
        }
    }

    return ENCODE_SUCCESS;
}

Encode_Status VideoEncoderAVC::updateFrameInfo(EncodeTask* task) {
    uint32_t idrPeroid = mComParams.intraPeriod * mVideoParamsAVC.idrInterval;
    FrameType frametype;
    uint32_t frame_num = mFrameNum;
    uint32_t intraPeriod = mComParams.intraPeriod;

    if (idrPeroid != 0) {
        if(mVideoParamsAVC.ipPeriod > 1)
            frame_num = frame_num % (idrPeroid + 1);
        else
            frame_num = frame_num % idrPeroid ;
    }else{
        if (mComParams.intraPeriod == 0)
            intraPeriod = 0xFFFFFFFF;
    }


    if(frame_num ==0){
        frametype = FTYPE_IDR;
    }else if(intraPeriod ==1)
        // only I frame need intraPeriod=idrInterval=ipPeriod=0
        frametype = FTYPE_I;
    else if(mVideoParamsAVC.ipPeriod == 1){ // no B frame
        if((frame_num >  1) &&((frame_num -1)%intraPeriod == 0))
            frametype = FTYPE_I;
        else
            frametype = FTYPE_P;
    } else {
        if(((frame_num-1)%intraPeriod == 0)&&(frame_num >intraPeriod))
            frametype = FTYPE_I;
        else{
            frame_num = frame_num%intraPeriod;
            if(frame_num == 0)
                frametype = FTYPE_B;
            else if((frame_num-1)%mVideoParamsAVC.ipPeriod == 0)
                frametype = FTYPE_P;
            else
                frametype = FTYPE_B;
        }
    }

    if (frametype == FTYPE_IDR || frametype == FTYPE_I)
        task->flag |= ENCODE_BUFFERFLAG_SYNCFRAME;

    if (frametype != task->type) {
        const char* FrameTypeStr[10] = {"UNKNOWN", "I", "P", "B", "SI", "SP", "EI", "EP", "S", "IDR"};
        if ((uint32_t) task->type < 9)
            LOG_V("libMIX thinks it is %s Frame, the input is %s Frame", FrameTypeStr[frametype], FrameTypeStr[task->type]);
        else
            LOG_V("Wrong Frame type %d, type may not be initialized ?\n", task->type);
    }

//temparily comment out to avoid uninitialize error
//    if (task->type == FTYPE_UNKNOWN || (uint32_t) task->type > 9)
        task->type = frametype;

    return ENCODE_SUCCESS;
}

Encode_Status VideoEncoderAVC::getExtFormatOutput(VideoEncOutputBuffer *outBuffer) {

    Encode_Status ret = ENCODE_SUCCESS;

    LOG_V("Begin\n");

    switch (outBuffer->format) {
        case OUTPUT_CODEC_DATA: {
            // Output the codec data
            ret = outputCodecData(outBuffer);
            CHECK_ENCODE_STATUS_CLEANUP("outputCodecData");
            break;
        }

        case OUTPUT_ONE_NAL: {
            // Output only one NAL unit
            ret = outputOneNALU(outBuffer, true);
            CHECK_ENCODE_STATUS_CLEANUP("outputOneNALU");
            break;
        }

        case OUTPUT_ONE_NAL_WITHOUT_STARTCODE: {
            ret = outputOneNALU(outBuffer, false);
            CHECK_ENCODE_STATUS_CLEANUP("outputOneNALU");
            break;
        }

        case OUTPUT_LENGTH_PREFIXED: {
            // Output length prefixed
            ret = outputLengthPrefixed(outBuffer);
            CHECK_ENCODE_STATUS_CLEANUP("outputLengthPrefixed");
            break;
        }

        case OUTPUT_NALULENGTHS_PREFIXED: {
            // Output nalu lengths ahead of bitstream
            ret = outputNaluLengthsPrefixed(outBuffer);
            CHECK_ENCODE_STATUS_CLEANUP("outputNaluLengthsPrefixed");
            break;
        }

        default:
            LOG_E("Invalid buffer mode\n");
            ret = ENCODE_FAIL;
            break;
    }

    LOG_V("out size is = %d\n", outBuffer->dataSize);


CLEAN_UP:


    LOG_V("End\n");
    return ret;
}

Encode_Status VideoEncoderAVC::getOneNALUnit(
        uint8_t *inBuffer, uint32_t bufSize, uint32_t *nalSize,
        uint32_t *nalType, uint32_t *nalOffset, uint32_t status) {
    uint32_t pos = 0;
    uint32_t zeroByteCount = 0;
    uint32_t singleByteTable[3][2] = {{1,0},{2,0},{2,3}};
    uint32_t dataRemaining = 0;
    uint8_t *dataPtr;

    // Don't need to check parameters here as we just checked by caller
    while ((inBuffer[pos++] == 0x00)) {
        zeroByteCount ++;
        if (pos >= bufSize)  //to make sure the buffer to be accessed is valid
            break;
    }

    if (inBuffer[pos - 1] != 0x01 || zeroByteCount < 2) {
        LOG_E("The stream is not AnnexB format \n");
        LOG_E("segment status is %x \n", status);
        return ENCODE_FAIL; //not AnnexB, we won't process it
    }

    *nalType = (*(inBuffer + pos)) & 0x1F;
    LOG_V ("NAL type = 0x%x\n", *nalType);

    zeroByteCount = 0;
    *nalOffset = pos;

    if (status & VA_CODED_BUF_STATUS_SINGLE_NALU) {
        *nalSize = bufSize - pos;
        return ENCODE_SUCCESS;
    }

    dataPtr  = inBuffer + pos;
    dataRemaining = bufSize - pos + 1;

    while ((dataRemaining > 0) && (zeroByteCount < 3)) {
        if (((((intptr_t)dataPtr) & 0xF ) == 0) && (0 == zeroByteCount)
               && (dataRemaining > 0xF)) {

            __asm__  (
                //Data input
                "movl %1, %%ecx\n\t"//data_ptr=>ecx
                "movl %0, %%eax\n\t"//data_remaing=>eax
                //Main compare loop
                //
                "0:\n\t"   //MATCH_8_ZERO:
                "pxor %%xmm0,%%xmm0\n\t"//set 0=>xmm0
                "pcmpeqb (%%ecx),%%xmm0\n\t"//data_ptr=xmm0,(byte==0)?0xFF:0x00
                "pmovmskb %%xmm0, %%edx\n\t"//edx[0]=xmm0[7],edx[1]=xmm0[15],...,edx[15]=xmm0[127]
                "test $0xAAAA, %%edx\n\t"//edx& 1010 1010 1010 1010b
                "jnz 2f\n\t"//Not equal to zero means that at least one byte 0x00

                "1:\n\t"  //PREPARE_NEXT_MATCH:
                "sub $0x10, %%eax\n\t"//16 + ecx --> ecx
                "add $0x10, %%ecx\n\t"//eax-16 --> eax
                "cmp $0x10, %%eax\n\t"
                "jge 0b\n\t"//search next 16 bytes

                "2:\n\t"   //DATA_RET:
                "movl %%ecx, %1\n\t"//output ecx->data_ptr
                "movl %%eax, %0\n\t"//output eax->data_remaining
                : "+m"(dataRemaining), "+m"(dataPtr)
                :
                :"eax", "ecx", "edx", "xmm0"
                );
            if (0 >= dataRemaining) {
                break;
            }

        }
        //check the value of each byte
        if ((*dataPtr) >= 2) {

            zeroByteCount = 0;

        }
        else {
            zeroByteCount = singleByteTable[zeroByteCount][*dataPtr];
         }

        dataPtr ++;
        dataRemaining --;
    }

    if ((3 == zeroByteCount) && (dataRemaining > 0)) {

        *nalSize =  bufSize - dataRemaining - *nalOffset - 3;

    } else if (0 == dataRemaining) {

        *nalSize = bufSize - *nalOffset;
    }
    return ENCODE_SUCCESS;
}

Encode_Status VideoEncoderAVC::getHeader(
        uint8_t *inBuffer, uint32_t bufSize, uint32_t *headerSize, uint32_t status) {

    uint32_t nalType = 0;
    uint32_t nalSize = 0;
    uint32_t nalOffset = 0;
    uint32_t size = 0;
    uint8_t *buf = inBuffer;
    Encode_Status ret = ENCODE_SUCCESS;

    *headerSize = 0;
    CHECK_NULL_RETURN_IFFAIL(inBuffer);

    if (bufSize == 0) {
        //bufSize shoule not be 0, error happens
        LOG_E("Buffer size is 0\n");
        return ENCODE_FAIL;
    }

    while (1) {
        nalType = nalSize = nalOffset = 0;
        ret = getOneNALUnit(buf, bufSize, &nalSize, &nalType, &nalOffset, status);
        CHECK_ENCODE_STATUS_RETURN("getOneNALUnit");

        LOG_V("NAL type = %d, NAL size = %d, offset = %d\n", nalType, nalSize, nalOffset);
        size = nalSize + nalOffset;

        // Codec_data should be SPS or PPS
        if (nalType == 7 || nalType == 8) {
            *headerSize += size;
            buf += size;
            bufSize -= size;
        } else {
            LOG_V("No header found or no header anymore\n");
            break;
        }
    }

    return ENCODE_SUCCESS;
}

Encode_Status VideoEncoderAVC::outputCodecData(
        VideoEncOutputBuffer *outBuffer) {

    Encode_Status ret = ENCODE_SUCCESS;
    uint32_t headerSize = 0;

    ret = getHeader((uint8_t *)mCurSegment->buf + mOffsetInSeg,
            mCurSegment->size - mOffsetInSeg, &headerSize, mCurSegment->status);
    CHECK_ENCODE_STATUS_RETURN("getHeader");
    if (headerSize == 0) {
        outBuffer->dataSize = 0;
        mCurSegment = NULL;
        return ENCODE_NO_REQUEST_DATA;
    }

    if (headerSize <= outBuffer->bufferSize) {
        memcpy(outBuffer->data, (uint8_t *)mCurSegment->buf + mOffsetInSeg, headerSize);
        mTotalSizeCopied += headerSize;
        mOffsetInSeg += headerSize;
        outBuffer->dataSize = headerSize;
        outBuffer->remainingSize = 0;
        outBuffer->flag |= ENCODE_BUFFERFLAG_ENDOFFRAME;
        outBuffer->flag |= ENCODE_BUFFERFLAG_CODECCONFIG;
        outBuffer->flag |= ENCODE_BUFFERFLAG_SYNCFRAME;
    } else {
        // we need a big enough buffer, otherwise we won't output anything
        outBuffer->dataSize = 0;
        outBuffer->remainingSize = headerSize;
        outBuffer->flag |= ENCODE_BUFFERFLAG_DATAINVALID;
        LOG_E("Buffer size too small\n");
        return ENCODE_BUFFER_TOO_SMALL;
    }

    return ret;
}

Encode_Status VideoEncoderAVC::outputOneNALU(
        VideoEncOutputBuffer *outBuffer, bool startCode) {

    uint32_t nalType = 0;
    uint32_t nalSize = 0;
    uint32_t nalOffset = 0;
    uint32_t sizeToBeCopied = 0;

    Encode_Status ret = ENCODE_SUCCESS;
    CHECK_NULL_RETURN_IFFAIL(mCurSegment->buf);

    ret = getOneNALUnit((uint8_t *)mCurSegment->buf + mOffsetInSeg,
            mCurSegment->size - mOffsetInSeg, &nalSize, &nalType, &nalOffset, mCurSegment->status);
    CHECK_ENCODE_STATUS_RETURN("getOneNALUnit");

    // check if we need startcode along with the payload
    if (startCode) {
        sizeToBeCopied = nalSize + nalOffset;
    } else {
        sizeToBeCopied = nalSize;
    }

    if (sizeToBeCopied <= outBuffer->bufferSize) {
        if (startCode) {
            memcpy(outBuffer->data, (uint8_t *)mCurSegment->buf + mOffsetInSeg, sizeToBeCopied);
        } else {
            memcpy(outBuffer->data, (uint8_t *)mCurSegment->buf + mOffsetInSeg + nalOffset,
                   sizeToBeCopied);
        }
        mTotalSizeCopied += sizeToBeCopied;
        mOffsetInSeg += (nalSize + nalOffset);
        outBuffer->dataSize = sizeToBeCopied;
        outBuffer->flag |= ENCODE_BUFFERFLAG_PARTIALFRAME;
        outBuffer->remainingSize = 0;
    } else {
        // if nothing to be copied out, set flag to invalid
        outBuffer->dataSize = 0;
        outBuffer->flag |= ENCODE_BUFFERFLAG_DATAINVALID;
        outBuffer->remainingSize = sizeToBeCopied;
        LOG_W("Buffer size too small\n");
        return ENCODE_BUFFER_TOO_SMALL;
    }

    // check if all data in current segment has been copied out
    if (mCurSegment->size == mOffsetInSeg) {
        if (mCurSegment->next != NULL) {
            mCurSegment = (VACodedBufferSegment *)mCurSegment->next;
            mOffsetInSeg = 0;
        } else {
            LOG_V("End of stream\n");
            outBuffer->flag |= ENCODE_BUFFERFLAG_ENDOFFRAME;
            mCurSegment = NULL;
        }
    }

    return ENCODE_SUCCESS;
}

Encode_Status VideoEncoderAVC::outputLengthPrefixed(VideoEncOutputBuffer *outBuffer) {

    Encode_Status ret = ENCODE_SUCCESS;
    uint32_t nalType = 0;
    uint32_t nalSize = 0;
    uint32_t nalOffset = 0;
    uint32_t sizeCopiedHere = 0;

    CHECK_NULL_RETURN_IFFAIL(mCurSegment->buf);

    while (1) {

        if (mCurSegment->size < mOffsetInSeg || outBuffer->bufferSize < sizeCopiedHere) {
            LOG_E("mCurSegment->size < mOffsetInSeg  || outBuffer->bufferSize < sizeCopiedHere\n");
            return ENCODE_FAIL;
        }

        // we need to handle the whole bitstream NAL by NAL
        ret = getOneNALUnit(
                (uint8_t *)mCurSegment->buf + mOffsetInSeg,
                mCurSegment->size - mOffsetInSeg, &nalSize, &nalType, &nalOffset, mCurSegment->status);
        CHECK_ENCODE_STATUS_RETURN("getOneNALUnit");

        if (nalSize + 4 <= outBuffer->bufferSize - sizeCopiedHere) {
            // write the NAL length to bit stream
            outBuffer->data[sizeCopiedHere] = (nalSize >> 24) & 0xff;
            outBuffer->data[sizeCopiedHere + 1] = (nalSize >> 16) & 0xff;
            outBuffer->data[sizeCopiedHere + 2] = (nalSize >> 8)  & 0xff;
            outBuffer->data[sizeCopiedHere + 3] = nalSize   & 0xff;

            sizeCopiedHere += 4;
            mTotalSizeCopied += 4;

            memcpy(outBuffer->data + sizeCopiedHere,
                   (uint8_t *)mCurSegment->buf + mOffsetInSeg + nalOffset, nalSize);

            sizeCopiedHere += nalSize;
            mTotalSizeCopied += nalSize;
            mOffsetInSeg += (nalSize + nalOffset);

        } else {
            outBuffer->dataSize = sizeCopiedHere;
            // In case the start code is 3-byte length but we use 4-byte for length prefixed
            // so the remainingSize size may larger than the remaining data size
            outBuffer->remainingSize = mTotalSize - mTotalSizeCopied + 100;
            outBuffer->flag |= ENCODE_BUFFERFLAG_PARTIALFRAME;
            LOG_E("Buffer size too small\n");
            return ENCODE_BUFFER_TOO_SMALL;
        }

        // check if all data in current segment has been copied out
        if (mCurSegment->size == mOffsetInSeg) {
            if (mCurSegment->next != NULL) {
                mCurSegment = (VACodedBufferSegment *)mCurSegment->next;
                mOffsetInSeg = 0;
            } else {
                LOG_V("End of stream\n");
                outBuffer->dataSize = sizeCopiedHere;
                outBuffer->remainingSize = 0;
                outBuffer->flag |= ENCODE_BUFFERFLAG_ENDOFFRAME;
                mCurSegment = NULL;
                break;
            }
        }
    }

    return ENCODE_SUCCESS;
}

Encode_Status VideoEncoderAVC::outputNaluLengthsPrefixed(VideoEncOutputBuffer *outBuffer) {

    Encode_Status ret = ENCODE_SUCCESS;
    uint32_t nalType = 0;
    uint32_t nalSize = 0;
    uint32_t nalOffset = 0;
    uint32_t sizeCopiedHere = 0;
    const uint32_t NALUINFO_OFFSET = 256;
    uint32_t nalNum = 0;

    CHECK_NULL_RETURN_IFFAIL(mCurSegment->buf);

    while (1) {

        if (mCurSegment->size < mOffsetInSeg || outBuffer->bufferSize < sizeCopiedHere) {
            LOG_E("mCurSegment->size < mOffsetInSeg  || outBuffer->bufferSize < sizeCopiedHere\n");
            return ENCODE_FAIL;
        }

        // we need to handle the whole bitstream NAL by NAL
        ret = getOneNALUnit(
                (uint8_t *)mCurSegment->buf + mOffsetInSeg,
                mCurSegment->size - mOffsetInSeg, &nalSize, &nalType, &nalOffset, mCurSegment->status);
        CHECK_ENCODE_STATUS_RETURN("getOneNALUnit");

        if (nalSize + 4 <= outBuffer->bufferSize - NALUINFO_OFFSET - sizeCopiedHere) {

            memcpy(outBuffer->data + NALUINFO_OFFSET + sizeCopiedHere,
                   (uint8_t *)mCurSegment->buf + mOffsetInSeg, nalSize + nalOffset);

            sizeCopiedHere += nalSize + nalOffset;
            mTotalSizeCopied += nalSize + nalOffset;
            mOffsetInSeg += (nalSize + nalOffset);

        } else {
            outBuffer->dataSize = sizeCopiedHere;
            // In case the start code is 3-byte length but we use 4-byte for length prefixed
            // so the remainingSize size may larger than the remaining data size
            outBuffer->remainingSize = mTotalSize - mTotalSizeCopied + 100;
            outBuffer->flag |= ENCODE_BUFFERFLAG_PARTIALFRAME;
            LOG_E("Buffer size too small\n");
            return ENCODE_BUFFER_TOO_SMALL;
        }

        nalNum ++;
        uint32_t *nalLength = (uint32_t *) (outBuffer->data + (nalNum+1) * 4);

        *nalLength = nalSize + nalOffset;

        // check if all data in current segment has been copied out
        if (mCurSegment->size == mOffsetInSeg) {
            if (mCurSegment->next != NULL) {
                mCurSegment = (VACodedBufferSegment *)mCurSegment->next;
                mOffsetInSeg = 0;
            } else {
                LOG_V("End of stream\n");
                outBuffer->dataSize = sizeCopiedHere;
                outBuffer->remainingSize = 0;
                outBuffer->flag |= ENCODE_BUFFERFLAG_ENDOFFRAME;
                mCurSegment = NULL;
                break;
            }
        }
    }

    outBuffer->offset = NALUINFO_OFFSET;
    uint32_t *nalHead = (uint32_t *) outBuffer->data;
    *nalHead = 0x4E414C4C; //'nall'
    *(++nalHead) = nalNum;

    return ENCODE_SUCCESS;
}

Encode_Status VideoEncoderAVC::sendEncodeCommand(EncodeTask *task) {
    Encode_Status ret = ENCODE_SUCCESS;

    LOG_V( "Begin\n");

    if (mFrameNum == 0 || mNewHeader) {
        if (mRenderHrd) {
            ret = renderHrd();
            mRenderHrd = false;
            CHECK_ENCODE_STATUS_RETURN("renderHrd");
        }

        mFrameNum = 0;
        ret = renderSequenceParams(task);
        CHECK_ENCODE_STATUS_RETURN("renderSequenceParams");
        if (mNewHeader) {
            mNewHeader = false; //Set to require new header filed to false
            mFrameNum = 0; //reset mFrameNum to 0
            updateFrameInfo(task); //recalculate frame info if mNewHeader is set true after PrepareFrameInfo in encode()
        }
    }

    if (mRenderMaxSliceSize && mVideoParamsAVC.maxSliceSize != 0) {
        ret = renderMaxSliceSize();
        CHECK_ENCODE_STATUS_RETURN("renderMaxSliceSize");
        mRenderMaxSliceSize = false;
    }

    if (mComParams.rcParams.enableIntraFrameQPControl && (task->type == FTYPE_IDR || task->type == FTYPE_I))
        mRenderBitRate = true;

    if (mRenderBitRate) {
        ret = VideoEncoderBase::renderDynamicBitrate(task);
        CHECK_ENCODE_STATUS_RETURN("renderDynamicBitrate");
    }

    if (mRenderAIR &&
        (mComParams.refreshType == VIDEO_ENC_AIR ||
        mComParams.refreshType == VIDEO_ENC_BOTH)) {

        ret = renderAIR();
        CHECK_ENCODE_STATUS_RETURN("renderAIR");

        mRenderAIR = false;
    }
    
    if (mRenderCIR) {

        ret = renderCIR();
        CHECK_ENCODE_STATUS_RETURN("renderCIR");

        mRenderCIR = false;
    }

    if (mRenderFrameRate) {

        ret = VideoEncoderBase::renderDynamicFrameRate();
        CHECK_ENCODE_STATUS_RETURN("renderDynamicFrameRate");

        mRenderFrameRate = false;
    }

    ret = renderPictureParams(task);
    CHECK_ENCODE_STATUS_RETURN("renderPictureParams");

    if (mFrameNum == 0 && (mEncPackedHeaders != VA_ATTRIB_NOT_SUPPORTED)) {
        ret = renderPackedSequenceParams(task);
        CHECK_ENCODE_STATUS_RETURN("renderPackedSequenceParams");

        ret = renderPackedPictureParams(task);
        CHECK_ENCODE_STATUS_RETURN("renderPackedPictureParams");
    }

    ret = renderSliceParams(task);
    CHECK_ENCODE_STATUS_RETURN("renderSliceParams");

    LOG_V( "End\n");
    return ENCODE_SUCCESS;
}


Encode_Status VideoEncoderAVC::renderMaxSliceSize() {

    VAStatus vaStatus = VA_STATUS_SUCCESS;
    LOG_V( "Begin\n\n");

    if (mComParams.rcMode != RATE_CONTROL_VCM) {
        LOG_W ("Not in VCM mode, but call send_max_slice_size\n");
        return ENCODE_SUCCESS;
    }

    VAEncMiscParameterBuffer *miscEncParamBuf;
    VAEncMiscParameterMaxSliceSize *maxSliceSizeParam;
    VABufferID miscParamBufferID;

    vaStatus = vaCreateBuffer(
            mVADisplay, mVAContext,
            VAEncMiscParameterBufferType,
            sizeof(VAEncMiscParameterBuffer) + sizeof(VAEncMiscParameterMaxSliceSize),
            1, NULL, &miscParamBufferID);
    CHECK_VA_STATUS_RETURN("vaCreateBuffer");

    vaStatus = vaMapBuffer(mVADisplay, miscParamBufferID, (void **)&miscEncParamBuf);
    CHECK_VA_STATUS_RETURN("vaMapBuffer");

    miscEncParamBuf->type = VAEncMiscParameterTypeMaxSliceSize;
    maxSliceSizeParam = (VAEncMiscParameterMaxSliceSize *)miscEncParamBuf->data;

    maxSliceSizeParam->max_slice_size = mVideoParamsAVC.maxSliceSize;

    vaStatus = vaUnmapBuffer(mVADisplay, miscParamBufferID);
    CHECK_VA_STATUS_RETURN("vaUnmapBuffer");

    LOG_I( "max slice size = %d\n", maxSliceSizeParam->max_slice_size);

    vaStatus = vaRenderPicture(mVADisplay, mVAContext, &miscParamBufferID, 1);
    CHECK_VA_STATUS_RETURN("vaRenderPicture");

    return ENCODE_SUCCESS;
}

Encode_Status VideoEncoderAVC::renderCIR(){
    VAStatus vaStatus = VA_STATUS_SUCCESS;
    LOG_V( "%s Begin\n", __FUNCTION__);

    VABufferID miscParamBufferCIRid;
    VAEncMiscParameterBuffer *misc_param;
    VAEncMiscParameterCIR *misc_cir_param;

    vaStatus = vaCreateBuffer(mVADisplay, mVAContext,
            VAEncMiscParameterBufferType,
            sizeof(VAEncMiscParameterBuffer) + sizeof(VAEncMiscParameterCIR),
            1,
            NULL,
            &miscParamBufferCIRid);
    CHECK_VA_STATUS_RETURN("vaCreateBuffer");

    vaStatus = vaMapBuffer(mVADisplay, miscParamBufferCIRid,  (void **)&misc_param);
    CHECK_VA_STATUS_RETURN("vaMapBuffer");

    misc_param->type = VAEncMiscParameterTypeCIR;
    misc_cir_param = (VAEncMiscParameterCIR *)misc_param->data;
    misc_cir_param->cir_num_mbs = mComParams.cirParams.cir_num_mbs;
    LOG_I( "cir_num_mbs %d \n", misc_cir_param->cir_num_mbs);

    vaUnmapBuffer(mVADisplay, miscParamBufferCIRid);
    CHECK_VA_STATUS_RETURN("vaUnmapBuffer");

    vaStatus = vaRenderPicture(mVADisplay, mVAContext, &miscParamBufferCIRid, 1);
    CHECK_VA_STATUS_RETURN("vaRenderPicture");

    return ENCODE_SUCCESS;
}

Encode_Status VideoEncoderAVC::renderAIR() {
    VAStatus vaStatus = VA_STATUS_SUCCESS;
    LOG_V( "Begin\n\n");

    VAEncMiscParameterBuffer   *miscEncParamBuf;
    VAEncMiscParameterAIR *airParams;
    VABufferID miscParamBufferID;

    vaStatus = vaCreateBuffer(
            mVADisplay, mVAContext,
            VAEncMiscParameterBufferType,
            sizeof(miscEncParamBuf) + sizeof(VAEncMiscParameterAIR),
            1, NULL, &miscParamBufferID);
    CHECK_VA_STATUS_RETURN("vaCreateBuffer");

    vaStatus = vaMapBuffer(mVADisplay, miscParamBufferID, (void **)&miscEncParamBuf);
    CHECK_VA_STATUS_RETURN("vaMapBuffer");

    miscEncParamBuf->type = VAEncMiscParameterTypeAIR;
    airParams = (VAEncMiscParameterAIR *)miscEncParamBuf->data;

    airParams->air_num_mbs = mComParams.airParams.airMBs;
    airParams->air_threshold= mComParams.airParams.airThreshold;
    airParams->air_auto = mComParams.airParams.airAuto;

    vaStatus = vaUnmapBuffer(mVADisplay, miscParamBufferID);
    CHECK_VA_STATUS_RETURN("vaUnmapBuffer");

    vaStatus = vaRenderPicture(mVADisplay, mVAContext, &miscParamBufferID, 1);
    CHECK_VA_STATUS_RETURN("vaRenderPicture");

    LOG_I( "airThreshold = %d\n", airParams->air_threshold);
    return ENCODE_SUCCESS;
}

int VideoEncoderAVC::calcLevel(int numMbs) {
    int level = 30;

    if (numMbs < 1620) {
        level = 30;
    } else if (numMbs < 3600) {
        level = 31;
    } else if (numMbs < 5120) {
        level = 32;
    } else if (numMbs < 8192) {
        level = 41;
    } else if (numMbs < 8704) {
        level = 42;
    } else if (numMbs < 22080) {
        level = 50;
    } else if (numMbs < 36864) {
        level = 51;
    } else {
        LOG_W("No such level can support that resolution");
        level = 51;
    }
    return level;
}

Encode_Status VideoEncoderAVC::renderSequenceParams(EncodeTask *) {

    VAStatus vaStatus = VA_STATUS_SUCCESS;
    VAEncSequenceParameterBufferH264 avcSeqParams = VAEncSequenceParameterBufferH264();
    VAEncMiscParameterBuffer   *miscEncRCParamBuf;
    VAEncMiscParameterBuffer   *miscEncFrameRateParamBuf;
    VAEncMiscParameterRateControl *rcMiscParam;
    VAEncMiscParameterFrameRate *framerateParam;
    int level;
    uint32_t frameRateNum = mComParams.frameRate.frameRateNum;
    uint32_t frameRateDenom = mComParams.frameRate.frameRateDenom;

    LOG_V( "Begin\n\n");
    vaStatus = vaCreateBuffer(mVADisplay, mVAContext,
            VAEncMiscParameterBufferType,
            sizeof (VAEncMiscParameterBuffer) + sizeof (VAEncMiscParameterRateControl),
            1, NULL,
            &mRcParamBuf);
    CHECK_VA_STATUS_RETURN("vaCreateBuffer");
    vaStatus = vaMapBuffer(mVADisplay, mRcParamBuf, (void **)&miscEncRCParamBuf);
    CHECK_VA_STATUS_RETURN("vaMapBuffer");

    vaStatus = vaCreateBuffer(mVADisplay, mVAContext,
            VAEncMiscParameterBufferType,
            sizeof (VAEncMiscParameterBuffer) + sizeof (VAEncMiscParameterFrameRate),
            1, NULL,
            &mFrameRateParamBuf);
    CHECK_VA_STATUS_RETURN("vaCreateBuffer");
    vaStatus = vaMapBuffer(mVADisplay, mFrameRateParamBuf, (void **)&miscEncFrameRateParamBuf);
    CHECK_VA_STATUS_RETURN("vaMapBuffer");

    miscEncRCParamBuf->type = VAEncMiscParameterTypeRateControl;
    rcMiscParam = (VAEncMiscParameterRateControl  *)miscEncRCParamBuf->data;
    miscEncFrameRateParamBuf->type = VAEncMiscParameterTypeFrameRate;
    framerateParam = (VAEncMiscParameterFrameRate *)miscEncFrameRateParamBuf->data;
    // set up the sequence params for HW
    // avcSeqParams.level_idc = mLevel;
    avcSeqParams.intra_period = mComParams.intraPeriod;
    avcSeqParams.intra_idr_period = mVideoParamsAVC.idrInterval;
    avcSeqParams.ip_period = mVideoParamsAVC.ipPeriod;
    avcSeqParams.picture_width_in_mbs = (mComParams.resolution.width + 15) / 16;
    avcSeqParams.picture_height_in_mbs = (mComParams.resolution.height + 15) / 16;

    level = calcLevel (avcSeqParams.picture_width_in_mbs * avcSeqParams.picture_height_in_mbs);
    avcSeqParams.level_idc = level;
    avcSeqParams.bits_per_second = mComParams.rcParams.bitRate;
    framerateParam->framerate =
            (unsigned int) (frameRateNum + frameRateDenom /2 ) / frameRateDenom;
    rcMiscParam->initial_qp = mComParams.rcParams.initQP;
    rcMiscParam->min_qp = mComParams.rcParams.minQP;
    rcMiscParam->max_qp = mComParams.rcParams.maxQP;
    if (mComParams.rcParams.enableIntraFrameQPControl) {
        rcMiscParam->min_qp = mComParams.rcParams.I_minQP;
        rcMiscParam->max_qp = mComParams.rcParams.I_maxQP;
    }
    rcMiscParam->window_size = mComParams.rcParams.windowSize;
    //target bitrate is sent to libva through Sequence Parameter Buffer
    rcMiscParam->bits_per_second = 0;
    rcMiscParam->basic_unit_size = mVideoParamsAVC.basicUnitSize; //for rate control usage
    avcSeqParams.intra_period = mComParams.intraPeriod;
    //avcSeqParams.vui_flag = 248;
    avcSeqParams.vui_parameters_present_flag = mVideoParamsAVC.VUIFlag;
    avcSeqParams.num_units_in_tick = frameRateDenom;
    avcSeqParams.time_scale = 2 * frameRateNum;
    avcSeqParams.seq_parameter_set_id = 0;
    if (mVideoParamsAVC.crop.LeftOffset ||
            mVideoParamsAVC.crop.RightOffset ||
            mVideoParamsAVC.crop.TopOffset ||
            mVideoParamsAVC.crop.BottomOffset) {
        avcSeqParams.frame_cropping_flag = true;
        avcSeqParams.frame_crop_left_offset = mVideoParamsAVC.crop.LeftOffset;
        avcSeqParams.frame_crop_right_offset = mVideoParamsAVC.crop.RightOffset;
        avcSeqParams.frame_crop_top_offset = mVideoParamsAVC.crop.TopOffset;
        avcSeqParams.frame_crop_bottom_offset = mVideoParamsAVC.crop.BottomOffset;
    } else {
        avcSeqParams.frame_cropping_flag = false;

        if (mComParams.resolution.width & 0xf) {
            avcSeqParams.frame_cropping_flag = true;
            uint32_t AWidth = (mComParams.resolution.width + 0xf) & (~0xf);
            avcSeqParams.frame_crop_right_offset = ( AWidth - mComParams.resolution.width ) / 2;
        }

        if (mComParams.resolution.height & 0xf) {
            avcSeqParams.frame_cropping_flag = true;
            uint32_t AHeight = (mComParams.resolution.height + 0xf) & (~0xf);
            avcSeqParams.frame_crop_bottom_offset = ( AHeight - mComParams.resolution.height ) / 2;
        }
    }

    if(avcSeqParams.vui_parameters_present_flag && (mVideoParamsAVC.SAR.SarWidth || mVideoParamsAVC.SAR.SarHeight)) {
        avcSeqParams.vui_fields.bits.aspect_ratio_info_present_flag = true;
        avcSeqParams.aspect_ratio_idc = 0xff /* Extended_SAR */;
        avcSeqParams.sar_width = mVideoParamsAVC.SAR.SarWidth;
        avcSeqParams.sar_height = mVideoParamsAVC.SAR.SarHeight;
    }

    avcSeqParams.max_num_ref_frames = 1;

    if(avcSeqParams.ip_period > 1)
        avcSeqParams.max_num_ref_frames = 2;

    LOG_V("===h264 sequence params===\n");
    LOG_V( "seq_parameter_set_id = %d\n", (uint32_t)avcSeqParams.seq_parameter_set_id);
    LOG_V( "level_idc = %d\n", (uint32_t)avcSeqParams.level_idc);
    LOG_V( "intra_period = %d\n", avcSeqParams.intra_period);
    LOG_V( "idr_interval = %d\n", avcSeqParams.intra_idr_period);
    LOG_V( "picture_width_in_mbs = %d\n", avcSeqParams.picture_width_in_mbs);
    LOG_V( "picture_height_in_mbs = %d\n", avcSeqParams.picture_height_in_mbs);
    LOG_V( "bitrate = %d\n", rcMiscParam->bits_per_second);
    LOG_V( "frame_rate = %d\n", framerateParam->framerate);
    LOG_V( "initial_qp = %d\n", rcMiscParam->initial_qp);
    LOG_V( "min_qp = %d\n", rcMiscParam->min_qp);
    LOG_V( "basic_unit_size = %d\n", rcMiscParam->basic_unit_size);
    LOG_V( "bDirect8x8Inference = %d\n",mVideoParamsAVC.bDirect8x8Inference);

    // Not sure whether these settings work for all drivers
    avcSeqParams.seq_fields.bits.frame_mbs_only_flag = 1;
    avcSeqParams.seq_fields.bits.pic_order_cnt_type = 0;
    avcSeqParams.seq_fields.bits.direct_8x8_inference_flag = mVideoParamsAVC.bDirect8x8Inference;

    avcSeqParams.seq_fields.bits.log2_max_frame_num_minus4 = 0;
    avcSeqParams.seq_fields.bits.log2_max_pic_order_cnt_lsb_minus4 = 2;
//    avcSeqParams.time_scale = 900;
//    avcSeqParams.num_units_in_tick = 15;			/* Tc = num_units_in_tick / time_sacle */
    // Not sure whether these settings work for all drivers

    vaStatus = vaUnmapBuffer(mVADisplay, mRcParamBuf);
    CHECK_VA_STATUS_RETURN("vaUnmapBuffer");
    vaStatus = vaUnmapBuffer(mVADisplay, mFrameRateParamBuf);
    CHECK_VA_STATUS_RETURN("vaUnmapBuffer");
    vaStatus = vaCreateBuffer(
            mVADisplay, mVAContext,
            VAEncSequenceParameterBufferType,
            sizeof(avcSeqParams), 1, &avcSeqParams,
            &mSeqParamBuf);
    CHECK_VA_STATUS_RETURN("vaCreateBuffer");
    vaStatus = vaRenderPicture(mVADisplay, mVAContext, &mFrameRateParamBuf, 1);
    CHECK_VA_STATUS_RETURN("vaRenderPicture");
    vaStatus = vaRenderPicture(mVADisplay, mVAContext, &mSeqParamBuf, 1);
    CHECK_VA_STATUS_RETURN("vaRenderPicture");
    vaStatus = vaRenderPicture(mVADisplay, mVAContext, &mRcParamBuf, 1);
    CHECK_VA_STATUS_RETURN("vaRenderPicture");

    return ENCODE_SUCCESS;
}

Encode_Status VideoEncoderAVC::renderPackedSequenceParams(EncodeTask *) {

    VAStatus vaStatus = VA_STATUS_SUCCESS;
    VAEncSequenceParameterBufferH264 *avcSeqParams;
    VAEncPackedHeaderParameterBuffer packed_header_param_buffer;
    unsigned char *packed_seq_buffer = NULL;
    unsigned int length_in_bits;

    LOG_V("Begin\n");

    vaStatus = vaMapBuffer(mVADisplay, mSeqParamBuf, (void **)&avcSeqParams);
    CHECK_VA_STATUS_RETURN("vaMapBuffer");

    length_in_bits = build_packed_seq_buffer(&packed_seq_buffer, mComParams.profile, avcSeqParams);
    packed_header_param_buffer.type = VAEncPackedHeaderSequence;
    packed_header_param_buffer.bit_length = length_in_bits;
    packed_header_param_buffer.has_emulation_bytes = 0;
    vaStatus = vaCreateBuffer(mVADisplay, mVAContext,
            VAEncPackedHeaderParameterBufferType,
            sizeof(packed_header_param_buffer), 1, &packed_header_param_buffer,
            &packed_seq_header_param_buf_id);
    CHECK_VA_STATUS_RETURN("vaCreateBuffer");

    vaStatus = vaCreateBuffer(mVADisplay, mVAContext,
            VAEncPackedHeaderDataBufferType,
            (length_in_bits + 7) / 8, 1, packed_seq_buffer,
            &packed_seq_buf_id);
    CHECK_VA_STATUS_RETURN("vaCreateBuffer");

    vaStatus = vaRenderPicture(mVADisplay, mVAContext, &packed_seq_header_param_buf_id, 1);
    CHECK_VA_STATUS_RETURN("vaRenderPicture");

    vaStatus = vaRenderPicture(mVADisplay, mVAContext, &packed_seq_buf_id, 1);
    CHECK_VA_STATUS_RETURN("vaRenderPicture");

    vaStatus = vaUnmapBuffer(mVADisplay, mSeqParamBuf);
    CHECK_VA_STATUS_RETURN("vaUnmapBuffer");

    free(packed_seq_buffer);

    LOG_V("End\n");

    return vaStatus;
}

Encode_Status VideoEncoderAVC::renderPictureParams(EncodeTask *task) {

    VAStatus vaStatus = VA_STATUS_SUCCESS;
    VAEncPictureParameterBufferH264 avcPicParams = VAEncPictureParameterBufferH264();
    uint32_t RefFrmIdx;

    LOG_V( "Begin\n\n");
    // set picture params for HW
    if (mAutoReference == false) {
        for (RefFrmIdx = 0; RefFrmIdx < 16; RefFrmIdx++) {
            avcPicParams.ReferenceFrames[RefFrmIdx].picture_id = VA_INVALID_ID;
            avcPicParams.ReferenceFrames[RefFrmIdx].flags = VA_PICTURE_H264_INVALID;
        }
        avcPicParams.ReferenceFrames[0].picture_id= task->ref_surface;
        avcPicParams.ReferenceFrames[0].flags = VA_PICTURE_H264_SHORT_TERM_REFERENCE;
        avcPicParams.CurrPic.picture_id= task->rec_surface;
        // Not sure whether these settings work for all drivers
        avcPicParams.CurrPic.TopFieldOrderCnt = mFrameNum * 2;

        avcPicParams.pic_fields.bits.transform_8x8_mode_flag = 0;
        avcPicParams.seq_parameter_set_id = 0;
        avcPicParams.pic_parameter_set_id = 0;

        avcPicParams.last_picture = 0;
        avcPicParams.frame_num = 0;

        avcPicParams.pic_init_qp = 26;
        avcPicParams.num_ref_idx_l0_active_minus1 = 0;
        avcPicParams.num_ref_idx_l1_active_minus1 = 0;

        avcPicParams.pic_fields.bits.idr_pic_flag = 0;
        avcPicParams.pic_fields.bits.reference_pic_flag = 0;
        avcPicParams.pic_fields.bits.entropy_coding_mode_flag = 0;
        avcPicParams.pic_fields.bits.weighted_pred_flag = 0;
        avcPicParams.pic_fields.bits.weighted_bipred_idc = 0;
        avcPicParams.pic_fields.bits.transform_8x8_mode_flag = 0;
        avcPicParams.pic_fields.bits.deblocking_filter_control_present_flag = 1;

        avcPicParams.frame_num = mFrameNum;
        avcPicParams.pic_fields.bits.reference_pic_flag = 1;
        // Not sure whether these settings work for all drivers
    }else {
        avcPicParams.CurrPic.picture_id= VA_INVALID_SURFACE;
        for(uint32_t i =0; i< mAutoReferenceSurfaceNum; i++)
            avcPicParams.ReferenceFrames[i].picture_id = mAutoRefSurfaces[i];
    }

    avcPicParams.pic_fields.bits.idr_pic_flag = (mFrameNum == 0);
    avcPicParams.pic_fields.bits.entropy_coding_mode_flag = mVideoParamsAVC.bEntropyCodingCABAC;
    avcPicParams.coded_buf = task->coded_buffer;
    avcPicParams.last_picture = 0;

    LOG_V("======h264 picture params======\n");
    LOG_V( "reference_picture = 0x%08x\n", avcPicParams.ReferenceFrames[0].picture_id);
    LOG_V( "reconstructed_picture = 0x%08x\n", avcPicParams.CurrPic.picture_id);
    LOG_V( "coded_buf = 0x%08x\n", avcPicParams.coded_buf);
    //LOG_I( "picture_width = %d\n", avcPicParams.picture_width);
    //LOG_I( "picture_height = %d\n\n", avcPicParams.picture_height);

    vaStatus = vaCreateBuffer(
            mVADisplay, mVAContext,
            VAEncPictureParameterBufferType,
            sizeof(avcPicParams),
            1,&avcPicParams,
            &mPicParamBuf);
    CHECK_VA_STATUS_RETURN("vaCreateBuffer");

    vaStatus = vaRenderPicture(mVADisplay, mVAContext, &mPicParamBuf, 1);
    CHECK_VA_STATUS_RETURN("vaRenderPicture");

    LOG_V( "end\n");
    return ENCODE_SUCCESS;
}

Encode_Status VideoEncoderAVC::renderPackedPictureParams(EncodeTask *) {

    VAStatus vaStatus = VA_STATUS_SUCCESS;
    VAEncPictureParameterBufferH264 *avcPicParams;
    VAEncPackedHeaderParameterBuffer packed_header_param_buffer;
    unsigned char *packed_pic_buffer = NULL;
    unsigned int length_in_bits;

    LOG_V("Begin\n");

    vaStatus = vaMapBuffer(mVADisplay, mPicParamBuf, (void **)&avcPicParams);
    CHECK_VA_STATUS_RETURN("vaMapBuffer");

    length_in_bits = build_packed_pic_buffer(&packed_pic_buffer, avcPicParams);
    packed_header_param_buffer.type = VAEncPackedHeaderPicture;
    packed_header_param_buffer.bit_length = length_in_bits;
    packed_header_param_buffer.has_emulation_bytes = 0;
    vaStatus = vaCreateBuffer(mVADisplay, mVAContext,
            VAEncPackedHeaderParameterBufferType,
            sizeof(packed_header_param_buffer), 1, &packed_header_param_buffer,
            &packed_pic_header_param_buf_id);
    CHECK_VA_STATUS_RETURN("vaCreateBuffer");

    vaStatus = vaCreateBuffer(mVADisplay, mVAContext,
            VAEncPackedHeaderDataBufferType,
            (length_in_bits + 7) / 8, 1, packed_pic_buffer,
            &packed_pic_buf_id);
    CHECK_VA_STATUS_RETURN("vaCreateBuffer");

    vaStatus = vaRenderPicture(mVADisplay, mVAContext, &packed_pic_header_param_buf_id, 1);
    CHECK_VA_STATUS_RETURN("vaRenderPicture");

    vaStatus = vaRenderPicture(mVADisplay, mVAContext, &packed_pic_buf_id, 1);
    CHECK_VA_STATUS_RETURN("vaRenderPicture");

    vaStatus = vaUnmapBuffer(mVADisplay, mSeqParamBuf);
    CHECK_VA_STATUS_RETURN("vaUnmapBuffer");

    free(packed_pic_buffer);

    LOG_V("End\n");

    return vaStatus;
}

Encode_Status VideoEncoderAVC::renderSliceParams(EncodeTask *task) {

    VAStatus vaStatus = VA_STATUS_SUCCESS;

    uint32_t sliceNum = 0;
    uint32_t sliceIndex = 0;
    uint32_t sliceHeightInMB = 0;
    uint32_t maxSliceNum = 0;
    uint32_t minSliceNum = 0;
    uint32_t actualSliceHeightInMB = 0;
    uint32_t startRowInMB = 0;
    uint32_t modulus = 0;
    uint32_t RefFrmIdx;

    LOG_V( "Begin\n\n");

    maxSliceNum = (mComParams.resolution.height + 15) / 16;
    minSliceNum = 1;

    if (task->type == FTYPE_I || task->type == FTYPE_IDR) {
        sliceNum = mVideoParamsAVC.sliceNum.iSliceNum;
    } else {
        sliceNum = mVideoParamsAVC.sliceNum.pSliceNum;
    }

    if (sliceNum < minSliceNum) {
        LOG_W("Slice Number is too small");
        sliceNum = minSliceNum;
    }

    if (sliceNum > maxSliceNum) {
        LOG_W("Slice Number is too big");
        sliceNum = maxSliceNum;
    }

    mSliceNum= sliceNum;
    modulus = maxSliceNum % sliceNum;
    sliceHeightInMB = (maxSliceNum - modulus) / sliceNum ;

    vaStatus = vaCreateBuffer(
            mVADisplay, mVAContext,
            VAEncSliceParameterBufferType,
            sizeof(VAEncSliceParameterBufferH264),
            sliceNum, NULL,
            &mSliceParamBuf);
    CHECK_VA_STATUS_RETURN("vaCreateBuffer");

    VAEncSliceParameterBufferH264 *sliceParams, *currentSlice;

    vaStatus = vaMapBuffer(mVADisplay, mSliceParamBuf, (void **)&sliceParams);
    CHECK_VA_STATUS_RETURN("vaMapBuffer");
    if(!sliceParams)
        return ENCODE_NULL_PTR;
    memset(sliceParams, 0 , sizeof(VAEncSliceParameterBufferH264));
    if(!sliceParams)
        return ENCODE_NULL_PTR;

    currentSlice = sliceParams;
    startRowInMB = 0;
    for (sliceIndex = 0; sliceIndex < sliceNum; sliceIndex++) {
        currentSlice = sliceParams + sliceIndex;
        actualSliceHeightInMB = sliceHeightInMB;
        if (sliceIndex < modulus) {
            actualSliceHeightInMB ++;
        }

        // starting MB row number for this slice, suppose macroblock 16x16
        currentSlice->macroblock_address = startRowInMB * ((mComParams.resolution.width + 0xf) & ~0xf) / 16;
        // slice height measured in MB
        currentSlice->num_macroblocks = actualSliceHeightInMB * ((mComParams.resolution.width + 0xf) & ~0xf) / 16;
        if(task->type == FTYPE_I||task->type == FTYPE_IDR)
            currentSlice->slice_type = 2;
        else if(task->type == FTYPE_P)
            currentSlice->slice_type = 0;
        else if(task->type == FTYPE_B)
            currentSlice->slice_type = 1;
        currentSlice->disable_deblocking_filter_idc = mComParams.disableDeblocking;

        // This is a temporary fix suggested by Binglin for bad encoding quality issue
        // TODO: We need a long term design for this field
        //currentSlice->slice_flags.bits.uses_long_term_ref = 0;
        //currentSlice->slice_flags.bits.is_long_term_ref = 0;

        LOG_V("======AVC slice params======\n");
        LOG_V( "slice_index = %d\n", (int) sliceIndex);
        LOG_V( "macroblock_address = %d\n", (int) currentSlice->macroblock_address);
        LOG_V( "slice_height_in_mb = %d\n", (int) currentSlice->num_macroblocks);
        LOG_V( "slice.type = %d\n", (int) currentSlice->slice_type);
        LOG_V("disable_deblocking_filter_idc = %d\n\n", (int) currentSlice->disable_deblocking_filter_idc);

        // Not sure whether these settings work for all drivers
        currentSlice->pic_parameter_set_id = 0;
        currentSlice->pic_order_cnt_lsb = mFrameNum * 2;
        currentSlice->direct_spatial_mv_pred_flag = 0;
        currentSlice->num_ref_idx_l0_active_minus1 = 0;      /* FIXME: ??? */
        currentSlice->num_ref_idx_l1_active_minus1 = 0;
        currentSlice->cabac_init_idc = 0;
        currentSlice->slice_qp_delta = 0;
        currentSlice->disable_deblocking_filter_idc = 0;
        currentSlice->slice_alpha_c0_offset_div2 = 2;
        currentSlice->slice_beta_offset_div2 = 2;
        currentSlice->idr_pic_id = 0;
        for (RefFrmIdx = 0; RefFrmIdx < 32; RefFrmIdx++) {
            currentSlice->RefPicList0[RefFrmIdx].picture_id = VA_INVALID_ID;
            currentSlice->RefPicList0[RefFrmIdx].flags = VA_PICTURE_H264_INVALID;
        }
        currentSlice->RefPicList0[0].picture_id = task->ref_surface;
        currentSlice->RefPicList0[0].flags = VA_PICTURE_H264_SHORT_TERM_REFERENCE;
        // Not sure whether these settings work for all drivers

        startRowInMB += actualSliceHeightInMB;
    }

    vaStatus = vaUnmapBuffer(mVADisplay, mSliceParamBuf);
    CHECK_VA_STATUS_RETURN("vaUnmapBuffer");

    vaStatus = vaRenderPicture(mVADisplay, mVAContext, &mSliceParamBuf, 1);
    CHECK_VA_STATUS_RETURN("vaRenderPicture");
    LOG_V( "end\n");
    return ENCODE_SUCCESS;
}