blob: a92bd148db1c776eb2522b2e2d84e560da10f367 [file] [log] [blame]
/*
* Copyright (c) 2018, Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
//!
//! \file media_ddi_encode_fei_hevc.cpp
//! \brief Implements class for DDI media hevc fei encode
//!
#include "media_libva.h"
#include "media_libva_encoder.h"
#include "media_libva_util.h"
#include "hwinfo_linux.h"
#include "codechal_encode_hevc_base.h"
#include "media_ddi_encode_base.h"
#include "media_ddi_encode_fei_hevc.h"
#include "media_ddi_encode_const.h"
#include "media_ddi_factory.h"
extern template class MediaDdiFactoryNoArg<DdiEncodeBase>;
static bool isEncodeHevcFeiRegistered =
MediaDdiFactoryNoArg<DdiEncodeBase>::RegisterCodec<DdiEncodeHevcFei>(ENCODE_ID_HEVCFEI);
DdiEncodeHevcFei::~DdiEncodeHevcFei()
{
if (nullptr == m_encodeCtx)
{
return;
}
MOS_FreeMemory(m_encodeCtx->pFeiPicParams);
m_encodeCtx->pFeiPicParams = nullptr;
}
VAStatus DdiEncodeHevcFei::ContextInitialize(CodechalSetting * codecHalSettings)
{
VAStatus status = DdiEncodeHevc::ContextInitialize(codecHalSettings);
if (VA_STATUS_SUCCESS != status)
{
return status;
}
codecHalSettings->codecFunction = m_encodeCtx->codecFunction;
m_encodeCtx->pFeiPicParams = (void *)MOS_AllocAndZeroMemory(CODECHAL_HEVC_MAX_PPS_NUM * sizeof(CodecEncodeHevcFeiPicParams));
DDI_CHK_NULL(m_encodeCtx->pFeiPicParams, "nullptr m_encodeCtx->pFeiPicParams", VA_STATUS_ERROR_ALLOCATION_FAILED);
return VA_STATUS_SUCCESS;
}
VAStatus DdiEncodeHevcFei::EncodeInCodecHal(uint32_t numSlices)
{
DDI_CHK_NULL(m_encodeCtx, "nullptr m_encodeCtx", VA_STATUS_ERROR_INVALID_PARAMETER);
DDI_CHK_NULL(m_encodeCtx->pCodecHal, "nullptr m_encodeCtx->pCodecHal", VA_STATUS_ERROR_INVALID_PARAMETER);
DDI_CODEC_RENDER_TARGET_TABLE *rtTbl = &(m_encodeCtx->RTtbl);
EncoderParams encodeParams;
MOS_ZeroMemory(&encodeParams, sizeof(encodeParams));
CodecEncodeHevcFeiPicParams *feiPicParams = (CodecEncodeHevcFeiPicParams *)(m_encodeCtx->pFeiPicParams);
if(CodecHalIsFeiEncode(m_encodeCtx->codecFunction))
{
encodeParams.ExecCodecFunction = m_encodeCtx->codecFunction;
}
else
{
DDI_ASSERTMESSAGE("DDI:Failed in HEVC FEI Function check!");
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
// Raw Surface
MOS_SURFACE rawSurface;
MOS_ZeroMemory(&rawSurface, sizeof(rawSurface));
rawSurface.dwOffset = 0;
if (m_encodeCtx->vaProfile == VAProfileHEVCMain10)
{
rawSurface.Format = Format_P010;
}
else //VAProfileHEVCMain
{
rawSurface.Format = Format_NV12;
}
DdiMedia_MediaSurfaceToMosResource(rtTbl->pCurrentRT, &(rawSurface.OsResource));
// Recon Surface
MOS_SURFACE reconSurface;
MOS_ZeroMemory(&reconSurface, sizeof(reconSurface));
reconSurface.dwOffset = 0;
if (m_encodeCtx->vaProfile == VAProfileHEVCMain10)
{
reconSurface.Format = Format_P010;
}
else //VAProfileHEVCMain
{
reconSurface.Format = Format_NV12;
}
DdiMedia_MediaSurfaceToMosResource(rtTbl->pCurrentReconTarget, &(reconSurface.OsResource));
//clear registered recon/ref surface flags
DDI_CHK_RET(ClearRefList(&m_encodeCtx->RTtbl, true), "ClearRefList failed!");
// Bitstream surface
MOS_RESOURCE bitstreamSurface;
MOS_ZeroMemory(&bitstreamSurface, sizeof(bitstreamSurface));
bitstreamSurface = m_encodeCtx->resBitstreamBuffer; // in render picture
bitstreamSurface.Format = Format_Buffer;
encodeParams.psRawSurface = &rawSurface;
encodeParams.psReconSurface = &reconSurface;
encodeParams.presBitstreamBuffer = &bitstreamSurface;
MOS_SURFACE mbQpSurface;
if(feiPicParams->bPerBlockQP)
{
// MBQp surface
MOS_ZeroMemory(&mbQpSurface, sizeof(mbQpSurface));
mbQpSurface.Format = Format_Buffer_2D;
mbQpSurface.dwOffset = 0;
mbQpSurface.OsResource = feiPicParams->resCTBQp;
encodeParams.psMbQpDataSurface = &mbQpSurface;
encodeParams.bMbQpDataEnabled = true;
}
encodeParams.pSeqParams = m_encodeCtx->pSeqParams;
encodeParams.pVuiParams = m_encodeCtx->pVuiParams;
encodeParams.pPicParams = m_encodeCtx->pPicParams;
encodeParams.pSliceParams = m_encodeCtx->pSliceParams;
encodeParams.pFeiPicParams = feiPicParams;
// Sequence data
encodeParams.bNewSeq = m_encodeCtx->bNewSeq;
// VUI
encodeParams.bNewVuiData = m_encodeCtx->bNewVuiData;
// Slice level data
encodeParams.dwNumSlices = numSlices;
// IQmatrix params
encodeParams.bNewQmatrixData = m_encodeCtx->bNewQmatrixData;
encodeParams.bPicQuant = m_encodeCtx->bPicQuant;
encodeParams.ppNALUnitParams = m_encodeCtx->ppNALUnitParams;
encodeParams.pSeiData = m_encodeCtx->pSEIFromApp;
encodeParams.pSeiParamBuffer = m_encodeCtx->pSEIFromApp->pSEIBuffer;
encodeParams.dwSEIDataOffset = 0;
CODECHAL_HEVC_IQ_MATRIX_PARAMS hevcIqMatrixParams;
encodeParams.pIQMatrixBuffer = &hevcIqMatrixParams;
// whether driver need to pack slice header
if (m_encodeCtx->bHavePackedSliceHdr)
{
encodeParams.bAcceleratorHeaderPackingCaps = false;
}
else
{
encodeParams.bAcceleratorHeaderPackingCaps = true;
}
encodeParams.pBSBuffer = m_encodeCtx->pbsBuffer;
encodeParams.pSlcHeaderData = (void *)m_encodeCtx->pSliceHeaderData;
MOS_STATUS status = m_encodeCtx->pCodecHal->Execute(&encodeParams);
if (MOS_STATUS_SUCCESS != status)
{
DDI_ASSERTMESSAGE("DDI:Failed in Codechal!");
return VA_STATUS_ERROR_ENCODING_ERROR;
}
return VA_STATUS_SUCCESS;
}
VAStatus DdiEncodeHevcFei::ResetAtFrameLevel()
{
DDI_CHK_NULL(m_encodeCtx, "nullptr m_encodeCtx", VA_STATUS_ERROR_INVALID_PARAMETER);
// Assume there is only one SPS parameter
PCODEC_HEVC_ENCODE_SEQUENCE_PARAMS hevcSeqParams = (PCODEC_HEVC_ENCODE_SEQUENCE_PARAMS)(m_encodeCtx->pSeqParams);
hevcSeqParams->bResetBRC = 0x0;
m_encodeCtx->dwNumSlices = 0x0;
m_encodeCtx->indexNALUnit = 0x0;
m_encodeCtx->uiSliceHeaderCnt = 0x0;
// reset bsbuffer every frame
m_encodeCtx->pbsBuffer->pCurrent = m_encodeCtx->pbsBuffer->pBase;
m_encodeCtx->pbsBuffer->SliceOffset = 0x0;
m_encodeCtx->pbsBuffer->BitOffset = 0x0;
m_encodeCtx->pbsBuffer->BitSize = 0x0;
CodecEncodeHevcFeiPicParams *feiPicParams = (CodecEncodeHevcFeiPicParams *)(m_encodeCtx->pFeiPicParams);
m_encodeCtx->codecFunction = CODECHAL_FUNCTION_FEI_ENC_PAK;
feiPicParams->NumMVPredictorsL0 = 0; // number of MV Predictors L0 provided, max is 4
feiPicParams->NumMVPredictorsL1 = 0; // number of MV Predictors L1 provided, max is 2
feiPicParams->SearchPath = 0; // search path, default is 0, 0 and 2 mean full search, 1 means diamond search
feiPicParams->LenSP = 57; // max number of SUs per reference which is evaluated by the predetermined SUs, range is [1, 63]
feiPicParams->MultiPredL0 = 0; // 000: no neighbor MVs will be used as predictor for L0, 001: spatial MVs, 010 temporal MVs, others: reserved.
feiPicParams->MultiPredL1 = 0; // 000: no neighbor MVs will be used as predictor for L1, 001: spatial MVs, 010 temporal MVs, others: reserved.
feiPicParams->SubPelMode = 3; // half/quater pixels mode, 00b integer mode search, 01b half mode search, 11b quater mode search
feiPicParams->AdaptiveSearch = true; // whether adaptive searching is enabled for IME
feiPicParams->MVPredictorInput = 0; // 000: disable MV Predictor input, 001: enabled per 16x16 block,
// 010: enabled per 32x32 block,
// 011: enabled per 64x64 block,
// 111: block size can vary and is determined by BlockSize in MVP
// others: reserved
feiPicParams->bPerBlockQP = false; // if enable per block QP input
feiPicParams->bPerCTBInput = false; // if enable per MB control/special input
feiPicParams->bForceLCUSplit = false; // specifies whether CTB should be forced to split to remove Inter big LCU
feiPicParams->bEnableCU64Check = true; // specifies whether 64x64 CB should be forced to split
feiPicParams->bEnableCU64AmpCheck = false; // specifies if 64x64 CB AMP should be checked, 0: No CU 64x64 AMP check, 1: check LCU64x64 AMP
feiPicParams->bCU64SkipCheckOnly = false; // specifies if check the 64x64 merge candidate, 0: after skip check, also run merge for TU1, 1: only skip check for 64x64 for TU4
feiPicParams->bColocatedCTBDistortion = false; // if enable, extra distortion between current CTB and co-located CTB is provided
feiPicParams->RefWidth = 48;
feiPicParams->RefHeight = 40;
feiPicParams->SearchWindow = 0;
feiPicParams->MaxNumIMESearchCenter = 6; // specifies number [1~6] of MV predictors for IME searches
feiPicParams->NumConcurrentEncFramePartition = 1; // specifies number [1, 2, 4] of splits that encoder could be run concurrently
feiPicParams->dwMaxFrameSize = 0; // specifies max frame size in bytes for multi-pass pak, 0 means disabling multi-pass pak
feiPicParams->bDistortionEnable = false;
feiPicParams->bCTBCmdCuRecordEnable = false;
// clear the packed header information
if (nullptr != m_encodeCtx->ppNALUnitParams)
{
MOS_ZeroMemory(m_encodeCtx->ppNALUnitParams[0], sizeof(CODECHAL_NAL_UNIT_PARAMS) * HEVC_MAX_NAL_UNIT_TYPE);
}
m_encodeCtx->bHavePackedSliceHdr = false;
m_encodeCtx->bLastPackedHdrIsSlice = false;
m_encodeCtx->bMBQpEnable = false;
return VA_STATUS_SUCCESS;
}
VAStatus DdiEncodeHevcFei::RenderPicture(VADriverContextP ctx, VAContextID context, VABufferID *buffers, int32_t numBuffers)
{
VAStatus vaStatus = VA_STATUS_SUCCESS;
DDI_FUNCTION_ENTER();
DDI_CHK_NULL(ctx, "nullptr context", VA_STATUS_ERROR_INVALID_CONTEXT);
DDI_MEDIA_CONTEXT *mediaCtx = DdiMedia_GetMediaContext(ctx);
DDI_CHK_NULL(mediaCtx, "Null mediaCtx", VA_STATUS_ERROR_INVALID_CONTEXT);
DDI_CHK_NULL(m_encodeCtx, "Null m_encodeCtx", VA_STATUS_ERROR_INVALID_CONTEXT);
for (int32_t i = 0; i < numBuffers; i++)
{
DDI_MEDIA_BUFFER *buf = DdiMedia_GetBufferFromVABufferID(mediaCtx, buffers[i]);
DDI_CHK_NULL(buf, "Invalid buffer.", VA_STATUS_ERROR_INVALID_BUFFER);
if (buf->uiType == VAEncMacroblockDisableSkipMapBufferType)
{
DdiMedia_MediaBufferToMosResource(buf, &(m_encodeCtx->resPerMBSkipMapBuffer));
m_encodeCtx->bMbDisableSkipMapEnabled = true;
continue;
}
uint32_t dataSize = buf->iSize;
// can use internal function instead of DdiMedia_MapBuffer here?
void *data = nullptr;
DdiMedia_MapBuffer(ctx, buffers[i], &data);
DDI_CHK_NULL(data, "Null data.", VA_STATUS_ERROR_INVALID_BUFFER);
switch (buf->uiType)
{
case VAEncSequenceParameterBufferType:
DDI_CHK_STATUS(ParseSeqParams(data), VA_STATUS_ERROR_INVALID_BUFFER);
m_encodeCtx->bNewSeq = true;
break;
case VAEncPictureParameterBufferType:
DDI_CHK_STATUS(ParsePicParams(mediaCtx, data), VA_STATUS_ERROR_INVALID_BUFFER);
DDI_CHK_STATUS(
AddToStatusReportQueue((void *)m_encodeCtx->resBitstreamBuffer.bo),
VA_STATUS_ERROR_INVALID_BUFFER);
break;
case VAEncSliceParameterBufferType:
{
uint32_t numSlices = buf->uiNumElements;
DDI_CHK_STATUS(ParseSlcParams(mediaCtx, data, numSlices), VA_STATUS_ERROR_INVALID_BUFFER);
break;
}
case VAEncPackedHeaderParameterBufferType:
vaStatus = ParsePackedHeaderParams(data);
break;
case VAEncPackedHeaderDataBufferType:
vaStatus = ParsePackedHeaderData(data);
break;
case VAEncMiscParameterBufferType:
DDI_CHK_STATUS(ParseMiscParams(data), VA_STATUS_ERROR_INVALID_BUFFER);
break;
case VAEncQPBufferType:
DdiMedia_MediaBufferToMosResource(buf, &m_encodeCtx->resMBQpBuffer);
m_encodeCtx->bMBQpEnable = true;
break;
case VAEncFEIMBControlBufferType:
case VAEncFEIMVPredictorBufferType:
case VAEncFEIMBCodeBufferType:
case VAEncFEICTBCmdBufferType:
case VAEncFEICURecordBufferType:
case VAEncFEIDistortionBufferType:
{
// handled in VAEncMiscParameterBufferType/VAEncMiscParameterTypeFEIFrameControlIntel case by vaBufferID
break;
}
default:
DDI_ASSERTMESSAGE("not supported buffer type.");
break;
}
DdiMedia_UnmapBuffer(ctx, buffers[i]);
}
DDI_FUNCTION_EXIT(vaStatus);
return vaStatus;
}
VAStatus DdiEncodeHevcFei::ParseMiscParamFeiPic(void *data)
{
DDI_CHK_NULL(data, "nullptr data", VA_STATUS_ERROR_INVALID_PARAMETER);
CodecEncodeHevcFeiPicParams *feiPicParams = (CodecEncodeHevcFeiPicParams *)(m_encodeCtx->pFeiPicParams);
DDI_CHK_NULL(feiPicParams, "nullptr feiPicParams", VA_STATUS_ERROR_INVALID_PARAMETER);
VAEncMiscParameterFEIFrameControlHEVC *vaEncMiscParamFeiPic = (VAEncMiscParameterFEIFrameControlHEVC *)data;
m_encodeCtx->codecFunction = CODECHAL_FUNCTION_INVALID;
if(vaEncMiscParamFeiPic->function & VA_FEI_FUNCTION_ENC_PAK)
m_encodeCtx->codecFunction = CODECHAL_FUNCTION_FEI_ENC_PAK;
if(vaEncMiscParamFeiPic->function == VA_FEI_FUNCTION_ENC)
m_encodeCtx->codecFunction = CODECHAL_FUNCTION_FEI_ENC;
if(vaEncMiscParamFeiPic->function == VA_FEI_FUNCTION_PAK)
m_encodeCtx->codecFunction = CODECHAL_FUNCTION_FEI_PAK;
feiPicParams->NumMVPredictorsL0 = vaEncMiscParamFeiPic->num_mv_predictors_l0;
feiPicParams->NumMVPredictorsL1 = vaEncMiscParamFeiPic->num_mv_predictors_l1;
feiPicParams->SearchPath = vaEncMiscParamFeiPic->search_path;
feiPicParams->LenSP = vaEncMiscParamFeiPic->len_sp;
feiPicParams->MultiPredL0 = vaEncMiscParamFeiPic->multi_pred_l0;
feiPicParams->MultiPredL1 = vaEncMiscParamFeiPic->multi_pred_l1;
feiPicParams->SubPelMode = vaEncMiscParamFeiPic->sub_pel_mode;
feiPicParams->AdaptiveSearch = vaEncMiscParamFeiPic->adaptive_search;
feiPicParams->MVPredictorInput = vaEncMiscParamFeiPic->mv_predictor_input;
feiPicParams->bPerBlockQP = vaEncMiscParamFeiPic->per_block_qp;
feiPicParams->bPerCTBInput = vaEncMiscParamFeiPic->per_ctb_input;
feiPicParams->bColocatedCTBDistortion = vaEncMiscParamFeiPic->colocated_ctb_distortion;
feiPicParams->bForceLCUSplit = vaEncMiscParamFeiPic->force_lcu_split;
feiPicParams->bEnableCU64Check = vaEncMiscParamFeiPic->enable_cu64_check;
feiPicParams->bEnableCU64AmpCheck = vaEncMiscParamFeiPic->enable_cu64_amp_check;
feiPicParams->bCU64SkipCheckOnly = vaEncMiscParamFeiPic->cu64_skip_check_only;
feiPicParams->RefWidth = vaEncMiscParamFeiPic->ref_width;
feiPicParams->RefHeight = vaEncMiscParamFeiPic->ref_height;
feiPicParams->SearchWindow = vaEncMiscParamFeiPic->search_window;
feiPicParams->MaxNumIMESearchCenter = vaEncMiscParamFeiPic->max_num_ime_search_center;
feiPicParams->FastIntraMode = vaEncMiscParamFeiPic->fast_intra_mode;
feiPicParams->NumConcurrentEncFramePartition = vaEncMiscParamFeiPic->num_concurrent_enc_frame_partition;
feiPicParams->dwMaxFrameSize = vaEncMiscParamFeiPic->max_frame_size;
DDI_MEDIA_BUFFER *mediaBuffer;
VAStatus status = VA_STATUS_SUCCESS;
if(feiPicParams->bPerCTBInput)
{
mediaBuffer = DdiMedia_GetBufferFromVABufferID(m_encodeCtx->pMediaCtx, vaEncMiscParamFeiPic->ctb_ctrl);
DDI_CHK_NULL(mediaBuffer, "nullptr mediaBuffer", VA_STATUS_ERROR_INVALID_PARAMETER);
DdiMedia_MediaBufferToMosResource(mediaBuffer, &(feiPicParams->resCTBCtrl));
}
if(feiPicParams->MVPredictorInput)
{
mediaBuffer = DdiMedia_GetBufferFromVABufferID(m_encodeCtx->pMediaCtx, vaEncMiscParamFeiPic->mv_predictor);
DDI_CHK_NULL(mediaBuffer, "nullptr mediaBuffer", VA_STATUS_ERROR_INVALID_PARAMETER);
DdiMedia_MediaBufferToMosResource(mediaBuffer, &(feiPicParams->resMVPredictor));
}
else if((feiPicParams->NumMVPredictorsL0 !=0) || (feiPicParams->NumMVPredictorsL1 != 0))
{
DDI_ASSERTMESSAGE("feiPicParams->NumMVPredictorsL0 and NumMVPredictorsL1 should be set to 0 when feiPicParams->MVPredictorInput is false!");
status = VA_STATUS_ERROR_INVALID_PARAMETER;
}
if(feiPicParams->bPerBlockQP)
{
mediaBuffer = DdiMedia_GetBufferFromVABufferID(m_encodeCtx->pMediaCtx, vaEncMiscParamFeiPic->qp);
DDI_CHK_NULL(mediaBuffer, "nullptr mediaBuffer", VA_STATUS_ERROR_INVALID_PARAMETER);
DdiMedia_MediaBufferToMosResource(mediaBuffer, &(feiPicParams->resCTBQp));
}
feiPicParams->bCTBCmdCuRecordEnable = false;
if(vaEncMiscParamFeiPic->ctb_cmd != VA_INVALID_ID)
{
feiPicParams->bCTBCmdCuRecordEnable = true;
mediaBuffer = DdiMedia_GetBufferFromVABufferID(m_encodeCtx->pMediaCtx, vaEncMiscParamFeiPic->ctb_cmd);
DDI_CHK_NULL(mediaBuffer, "nullptr mediaBuffer", VA_STATUS_ERROR_INVALID_PARAMETER);
DdiMedia_MediaBufferToMosResource(mediaBuffer, &(feiPicParams->resCTBCmd));
if(m_encodeCtx->codecFunction == CODECHAL_FUNCTION_FEI_ENC)
{
RemoveFromEncStatusReportQueue(mediaBuffer, FEI_ENC_BUFFER_TYPE_MVDATA);
if( VA_STATUS_SUCCESS != AddToEncStatusReportQueue( (void *)(feiPicParams->resCTBCmd.bo), FEI_ENC_BUFFER_TYPE_MVDATA) )
{
DDI_ASSERTMESSAGE("feiPicParams->resCTBCmd is invalid for FEI ENC only");
status = VA_STATUS_ERROR_INVALID_PARAMETER;
}
}
}
if(vaEncMiscParamFeiPic->cu_record != VA_INVALID_ID)
{
if(feiPicParams->bCTBCmdCuRecordEnable == false)
{
DDI_ASSERTMESSAGE("CTB cmd and CU record should be enabled or disabled together!");
status = VA_STATUS_ERROR_INVALID_PARAMETER;
}
mediaBuffer = DdiMedia_GetBufferFromVABufferID(m_encodeCtx->pMediaCtx, vaEncMiscParamFeiPic->cu_record);
DDI_CHK_NULL(mediaBuffer, "nullptr mediaBuffer", VA_STATUS_ERROR_INVALID_PARAMETER);
DdiMedia_MediaBufferToMosResource(mediaBuffer, &(feiPicParams->resCURecord));
if(m_encodeCtx->codecFunction == CODECHAL_FUNCTION_FEI_ENC)
{
RemoveFromEncStatusReportQueue(mediaBuffer, FEI_ENC_BUFFER_TYPE_MBCODE);
if( VA_STATUS_SUCCESS != AddToEncStatusReportQueue((void *)(feiPicParams->resCURecord.bo), FEI_ENC_BUFFER_TYPE_MBCODE) )
{
DDI_ASSERTMESSAGE("feiPicParams->resCURecord is invalid for FEI ENC only");
status = VA_STATUS_ERROR_INVALID_PARAMETER;
}
}
}
if(vaEncMiscParamFeiPic->distortion != VA_INVALID_ID)
{
feiPicParams->bDistortionEnable = true;
mediaBuffer = DdiMedia_GetBufferFromVABufferID(m_encodeCtx->pMediaCtx, vaEncMiscParamFeiPic->distortion);
DDI_CHK_NULL(mediaBuffer, "nullptr mediaBuffer", VA_STATUS_ERROR_INVALID_PARAMETER);
DdiMedia_MediaBufferToMosResource(mediaBuffer, &(feiPicParams->resDistortion));
if(m_encodeCtx->codecFunction == CODECHAL_FUNCTION_FEI_ENC)
{
RemoveFromEncStatusReportQueue(mediaBuffer, FEI_ENC_BUFFER_TYPE_DISTORTION);
if( VA_STATUS_SUCCESS != AddToEncStatusReportQueue((void *)(feiPicParams->resDistortion.bo), FEI_ENC_BUFFER_TYPE_DISTORTION) )
{
DDI_ASSERTMESSAGE("feiPicParams->resDistortion is invalid for FEI ENC only");
status = VA_STATUS_ERROR_INVALID_PARAMETER;
}
}
}
if(m_encodeCtx->codecFunction == CODECHAL_FUNCTION_FEI_ENC)
{
AddToEncStatusReportQueueUpdatePos();
}
//add for mutlple pass pak
feiPicParams->dwMaxFrameSize = vaEncMiscParamFeiPic->max_frame_size;
if (feiPicParams->dwMaxFrameSize)
{
feiPicParams->dwNumPasses = vaEncMiscParamFeiPic->num_passes;
if ((feiPicParams->dwNumPasses == 0) || (feiPicParams->dwNumPasses > feiHevcMaxPassesNum))
{
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
if (feiPicParams->pDeltaQp != nullptr)
{
MOS_FreeMemory(feiPicParams->pDeltaQp);
}
feiPicParams->pDeltaQp = (uint8_t *)MOS_AllocAndZeroMemory(sizeof(uint8_t) * feiPicParams->dwNumPasses);
if (!feiPicParams->pDeltaQp)
{
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
if (MOS_STATUS_SUCCESS != MOS_SecureMemcpy(feiPicParams->pDeltaQp, feiPicParams->dwNumPasses, vaEncMiscParamFeiPic->delta_qp, feiPicParams->dwNumPasses))
{
status = VA_STATUS_ERROR_INVALID_PARAMETER;
}
}
finish:
return status;
}
VAStatus DdiEncodeHevcFei::AddToEncStatusReportQueue(
void *encBuf,
DDI_ENCODE_FEI_ENC_BUFFER_TYPE typeIdx)
{
DDI_CHK_NULL(encBuf, "nullptr encBuf", VA_STATUS_ERROR_INVALID_PARAMETER);
CodecEncodeHevcFeiPicParams *feiPicParams = (CodecEncodeHevcFeiPicParams *)(m_encodeCtx->pFeiPicParams);
DDI_CHK_NULL(feiPicParams, "nullptr feiPicParams", VA_STATUS_ERROR_INVALID_PARAMETER);
if (m_encodeCtx->codecFunction != CODECHAL_FUNCTION_FEI_ENC)
{
DDI_ASSERTMESSAGE("ENC output buffers status checking is not allowed for non-FEI_ENC case! .");
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
if ((typeIdx < 0) || (typeIdx >= FEI_ENC_BUFFER_TYPE_MAX))
{
DDI_ASSERTMESSAGE("ENC output buffers status checking, gets invalid buffer type index! .");
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
int32_t idx = m_encodeCtx->statusReportBuf.ulHeadPosition;
m_encodeCtx->statusReportBuf.encInfos[idx].pEncBuf[typeIdx] = encBuf;
m_encodeCtx->statusReportBuf.encInfos[idx].uiStatus = 0;
m_encodeCtx->statusReportBuf.encInfos[idx].uiBuffers++;
return VA_STATUS_SUCCESS;
}
VAStatus DdiEncodeHevcFei::AddToEncStatusReportQueueUpdatePos()
{
CodecEncodeHevcFeiPicParams *feiPicParams = (CodecEncodeHevcFeiPicParams *)(m_encodeCtx->pFeiPicParams);
DDI_CHK_NULL(feiPicParams, "nullptr feiPicParams", VA_STATUS_ERROR_INVALID_PARAMETER);
if(m_encodeCtx->codecFunction != CODECHAL_FUNCTION_FEI_ENC)
{
DDI_ASSERTMESSAGE("ENC output buffers status checking is not allowed for non-FEI_ENC case! .");
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
int32_t i = m_encodeCtx->statusReportBuf.ulHeadPosition;
if((m_encodeCtx->statusReportBuf.encInfos[i].uiBuffers == (feiPicParams->bCTBCmdCuRecordEnable * 2 + feiPicParams->bDistortionEnable)) && m_encodeCtx->statusReportBuf.encInfos[i].uiBuffers != 0)
{
m_encodeCtx->statusReportBuf.ulHeadPosition = (m_encodeCtx->statusReportBuf.ulHeadPosition + 1) % DDI_ENCODE_MAX_STATUS_REPORT_BUFFER;
}
finish:
return VA_STATUS_SUCCESS;
}
VAStatus DdiEncodeHevcFei::ParseMiscParams(void *ptr)
{
DDI_CHK_NULL(m_encodeCtx, "nullptr m_encodeCtx", VA_STATUS_ERROR_INVALID_PARAMETER);
DDI_CHK_NULL(ptr, "nullptr ptr", VA_STATUS_ERROR_INVALID_PARAMETER);
DDI_CHK_NULL(m_encodeCtx->pSeqParams, "nullptr m_encodeCtx->pSeqParams", VA_STATUS_ERROR_INVALID_PARAMETER);
DDI_CHK_NULL(m_encodeCtx->pPicParams, "nullptr m_encodeCtx->pPicParams", VA_STATUS_ERROR_INVALID_PARAMETER);
PCODEC_HEVC_ENCODE_SEQUENCE_PARAMS seqParams = (PCODEC_HEVC_ENCODE_SEQUENCE_PARAMS)(m_encodeCtx->pSeqParams);
PCODEC_HEVC_ENCODE_PICTURE_PARAMS picParams = (PCODEC_HEVC_ENCODE_PICTURE_PARAMS)(m_encodeCtx->pPicParams);
VAEncMiscParameterBuffer *miscParamBuf = (VAEncMiscParameterBuffer *)ptr;
DDI_CHK_NULL(miscParamBuf->data, "nullptr miscParamBuf->data", VA_STATUS_ERROR_INVALID_PARAMETER);
switch ((int32_t)(miscParamBuf->type))
{
case VAEncMiscParameterTypeQualityLevel:
{
VAEncMiscParameterBufferQualityLevel *vaEncMiscParamQualityLevel = (VAEncMiscParameterBufferQualityLevel *)miscParamBuf->data;
seqParams->TargetUsage = (uint8_t)vaEncMiscParamQualityLevel->quality_level;
// HEVC only supports TU=1, 4, and 7
if (1 != seqParams->TargetUsage && 4 != seqParams->TargetUsage && 7 != seqParams->TargetUsage)
{
DDI_ASSERTMESSAGE("unsupported target usage in HEVC encoder.");
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
break;
}
case VAEncMiscParameterTypeHRD:
{
VAEncMiscParameterHRD *vaEncMiscParamHRD = (VAEncMiscParameterHRD *)miscParamBuf->data;
seqParams->VBVBufferSizeInBit = vaEncMiscParamHRD->buffer_size;
seqParams->InitVBVBufferFullnessInBit = vaEncMiscParamHRD->initial_buffer_fullness;
seqParams->RateControlMethod = RATECONTROL_CBR;
break;
}
case VAEncMiscParameterTypeFrameRate:
{
VAEncMiscParameterFrameRate *vaEncMiscParamFR = (VAEncMiscParameterFrameRate *)miscParamBuf->data;
seqParams->FrameRate.Numerator = vaEncMiscParamFR->framerate & 0xffff;
seqParams->FrameRate.Denominator = (vaEncMiscParamFR->framerate >> 16 ) & 0xffff;
if(seqParams->FrameRate.Denominator == 0)
{
seqParams->FrameRate.Denominator = 1;
}
break;
}
case VAEncMiscParameterTypeRateControl:
{
// Assume only one SPS here, modify when enable multiple SPS support
VAEncMiscParameterRateControl *vaEncMiscParamRC = (VAEncMiscParameterRateControl *)miscParamBuf->data;
seqParams->TargetBitRate = MOS_ROUNDUP_DIVIDE(vaEncMiscParamRC->bits_per_second, CODECHAL_ENCODE_BRC_KBPS);
seqParams->MBBRC = (vaEncMiscParamRC->rc_flags.bits.mb_rate_control <= mbBrcDisabled) ? vaEncMiscParamRC->rc_flags.bits.mb_rate_control : 0;
//enable parallelBRC for Android and Linux
seqParams->ParallelBRC = vaEncMiscParamRC->rc_flags.bits.enable_parallel_brc;
// Assuming picParams are sent before MiscParams
picParams->BRCMinQp = vaEncMiscParamRC->min_qp;
picParams->BRCMaxQp = vaEncMiscParamRC->max_qp;
if (VA_RC_NONE == m_encodeCtx->uiRCMethod || VA_RC_CQP == m_encodeCtx->uiRCMethod)
{
seqParams->RateControlMethod = RATECONTROL_CQP;
seqParams->MBBRC = 0;
}
else if ((VA_RC_CBR | VA_RC_MB) == m_encodeCtx->uiRCMethod || (VA_RC_CBR | VA_RC_MB | VA_RC_PARALLEL) == m_encodeCtx->uiRCMethod)
{
seqParams->MaxBitRate = seqParams->TargetBitRate;
seqParams->MinBitRate = seqParams->TargetBitRate;
seqParams->RateControlMethod = RATECONTROL_CBR;
}
else if (VA_RC_ICQ == m_encodeCtx->uiRCMethod || (VA_RC_ICQ | VA_RC_PARALLEL) == m_encodeCtx->uiRCMethod)
{
seqParams->ICQQualityFactor = vaEncMiscParamRC->ICQ_quality_factor;
seqParams->RateControlMethod = RATECONTROL_ICQ;
seqParams->MBBRC = 1;
}
else
{
switch (m_encodeCtx->uiRCMethod)
{
case (VA_RC_VCM | VA_RC_PARALLEL):
case VA_RC_VCM:
seqParams->RateControlMethod = RATECONTROL_VCM;
seqParams->MBBRC = 0;
break;
case (VA_RC_VBR | VA_RC_MB | VA_RC_PARALLEL):
case (VA_RC_VBR | VA_RC_MB):
seqParams->RateControlMethod = RATECONTROL_VBR;
break;
default:
DDI_ASSERTMESSAGE("invalid RC method.");
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
seqParams->MaxBitRate = seqParams->TargetBitRate;
seqParams->MinBitRate = seqParams->TargetBitRate * (2 * vaEncMiscParamRC->target_percentage - 100) / 100;
seqParams->TargetBitRate = seqParams->TargetBitRate * vaEncMiscParamRC->target_percentage / 100;
if ((m_encodeCtx->uiTargetBitRate != seqParams->TargetBitRate) ||
(m_encodeCtx->uiMaxBitRate != seqParams->MaxBitRate))
{
if ((m_encodeCtx->uiTargetBitRate != 0) && (m_encodeCtx->uiMaxBitRate != 0))
{
seqParams->bResetBRC = 0x1;
}
m_encodeCtx->uiTargetBitRate = seqParams->TargetBitRate;
m_encodeCtx->uiMaxBitRate = seqParams->MaxBitRate;
}
}
break;
}
case VAEncMiscParameterTypeParallelBRC:
{
VAEncMiscParameterParallelRateControl *vaEncMiscParameterParallel = (VAEncMiscParameterParallelRateControl *)miscParamBuf->data;
seqParams->NumOfBInGop[0] = vaEncMiscParameterParallel->num_b_in_gop[0];
seqParams->NumOfBInGop[1] = vaEncMiscParameterParallel->num_b_in_gop[1];
seqParams->NumOfBInGop[2] = vaEncMiscParameterParallel->num_b_in_gop[2];
break;
}
case VAEncMiscParameterTypeRIR:
{
VAEncMiscParameterRIR *vaEncMiscParamRIR = (VAEncMiscParameterRIR *)miscParamBuf->data;
picParams->bEnableRollingIntraRefresh = vaEncMiscParamRIR->rir_flags.value & 0x3; //only lower two bits are valid
// Set for all frames since pic type is not known yet. Disable in slice params if its I or B type.
if ((ROLLING_I_COLUMN == picParams->bEnableRollingIntraRefresh) || (ROLLING_I_ROW == picParams->bEnableRollingIntraRefresh))
{
picParams->IntraInsertionLocation = (uint16_t)vaEncMiscParamRIR->intra_insertion_location;
picParams->IntraInsertionSize = (uint8_t)vaEncMiscParamRIR->intra_insert_size;
picParams->QpDeltaForInsertedIntra = vaEncMiscParamRIR->qp_delta_for_inserted_intra;
}
else if ((ROLLING_I_ROW | ROLLING_I_COLUMN) == picParams->bEnableRollingIntraRefresh) // cannot have row and column rolling
{
picParams->bEnableRollingIntraRefresh = ROLLING_I_DISABLED;
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
break;
}
case VAEncMiscParameterTypeROI:
{
VAEncMiscParameterBufferROI *vaEncMiscParamROI = (VAEncMiscParameterBufferROI *)miscParamBuf->data;
uint32_t maxROIsupported = CODECHAL_ENCODE_HEVC_MAX_NUM_ROI;
uint8_t blockSize = (m_encodeCtx->bVdencActive) ? vdencRoiBlockSize : CODECHAL_MACROBLOCK_WIDTH;
if (vaEncMiscParamROI->num_roi)
{
for (uint32_t i = 0; i < vaEncMiscParamROI->num_roi; ++i)
{
picParams->ROI[i].PriorityLevelOrDQp = vaEncMiscParamROI->roi[i].roi_value;
picParams->ROI[i].Top = vaEncMiscParamROI->roi[i].roi_rectangle.y;
picParams->ROI[i].Left = vaEncMiscParamROI->roi[i].roi_rectangle.x;
picParams->ROI[i].Bottom = vaEncMiscParamROI->roi[i].roi_rectangle.y +
vaEncMiscParamROI->roi[i].roi_rectangle.height - 1;
picParams->ROI[i].Right = vaEncMiscParamROI->roi[i].roi_rectangle.x +
vaEncMiscParamROI->roi[i].roi_rectangle.width - 1;
if (m_encodeCtx->bVdencActive == false)
{
// align to CTB edge (32 on Gen9) to avoid QP average issue
picParams->ROI[i].Left = MOS_ALIGN_FLOOR(picParams->ROI[i].Left, 32);
picParams->ROI[i].Right = MOS_ALIGN_CEIL(picParams->ROI[i].Right, 32);
picParams->ROI[i].Top = MOS_ALIGN_FLOOR(picParams->ROI[i].Top, 32);
picParams->ROI[i].Bottom = MOS_ALIGN_CEIL(picParams->ROI[i].Bottom, 32);
}
// Convert from pixel units to block size units
picParams->ROI[i].Left /= blockSize;
picParams->ROI[i].Right /= blockSize;
picParams->ROI[i].Top /= blockSize;
picParams->ROI[i].Bottom /= blockSize;
}
picParams->NumROI = MOS_MIN(vaEncMiscParamROI->num_roi, maxROIsupported);
}
#ifndef ANDROID
// support DeltaQP based ROI by default
seqParams->ROIValueInDeltaQP = vaEncMiscParamROI->roi_flags.bits.roi_value_is_qp_delta;
#endif
break;
}
case VAEncMiscParameterTypeSkipFrame:
{
VAEncMiscParameterSkipFrame *vaEncMiscParamSkipFrame = (VAEncMiscParameterSkipFrame *)miscParamBuf->data;
// populate skipped frame params from DDI
if (FRAME_SKIP_NORMAL != vaEncMiscParamSkipFrame->skip_frame_flag)
{
DDI_ASSERTMESSAGE("unsupported misc parameter type.");
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
picParams->SkipFrameFlag = vaEncMiscParamSkipFrame->skip_frame_flag;
picParams->NumSkipFrames = vaEncMiscParamSkipFrame->num_skip_frames;
picParams->SizeSkipFrames = vaEncMiscParamSkipFrame->size_skip_frames;
break;
}
case VAEncMiscParameterTypeMaxSliceSize:
{
VAEncMiscParameterMaxSliceSize *vaEncMiscParamMaxSliceSize = (VAEncMiscParameterMaxSliceSize *)miscParamBuf->data;
m_encodeCtx->EnableSliceLevelRateCtrl = true;
seqParams->SliceSizeControl = true;
picParams->MaxSliceSizeInBytes = vaEncMiscParamMaxSliceSize->max_slice_size;
break;
}
case VAEncMiscParameterTypeEncQuality:
{
VAEncMiscParameterEncQuality *vaEncMiscParamEncQuality = (VAEncMiscParameterEncQuality *)miscParamBuf->data;
picParams->bUseRawPicForRef = vaEncMiscParamEncQuality->useRawPicForRef;
break;
}
case VAEncMiscParameterTypeFEIFrameControl:
{
if (VA_STATUS_SUCCESS != ParseMiscParamFeiPic((void *)miscParamBuf->data))
{
DDI_ASSERTMESSAGE("parse misc FEI picture parameters error.");
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
break;
}
default:
DDI_ASSERTMESSAGE("unsupported misc parameter type.");
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
return VA_STATUS_SUCCESS;
}