blob: f398467ee66ef567d078ca0c75e5225caec00189 [file] [log] [blame]
/*
* Copyright (c) 2017-2020, 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_avc.cpp
//! \brief Implements class for DDI media avc encode
//!
#include "media_libva.h"
#include "media_libva_encoder.h"
#include "media_libva_util.h"
#include "hwinfo_linux.h"
#include "media_ddi_encode_base.h"
#include "media_ddi_encode_avc.h"
#include "media_ddi_encode_const.h"
#include "media_ddi_factory.h"
#include "media_libva_caps.h"
// refer to spec section E.2.2, bit rate and cbp buffer size are shifted left with several bits, k is 1024
static const uint16_t vuiKbps = 1024;
static const uint8_t sliceTypeP = 0;
static const uint8_t sliceTypeB = 1;
static const uint8_t sliceTypeI = 2;
static const uint8_t maxPassesNum = 4;
//Inter MB partition 16x16 can't be disabled.
static const uint8_t disMbPartMask = 0x7E;
static const uint8_t subpelModeMask = 0x3;
static const uint8_t subpelModeQuant = 0x3;
static const uint8_t subpelModeReserved = 0x2;
static const uint8_t subpelModeHalf = 0x1;
extern template class MediaDdiFactoryNoArg<DdiEncodeBase>;
static bool isEncodeAvcRegistered =
MediaDdiFactoryNoArg<DdiEncodeBase>::RegisterCodec<DdiEncodeAvc>(ENCODE_ID_AVC);
DdiEncodeAvc::~DdiEncodeAvc()
{
if (nullptr == m_encodeCtx)
{
return;
}
MOS_FreeMemory(m_encodeCtx->pSeqParams);
m_encodeCtx->pSeqParams = nullptr;
MOS_FreeMemory(m_encodeCtx->pPicParams);
m_encodeCtx->pPicParams = nullptr;
if (nullptr != m_encodeCtx->ppNALUnitParams)
{
// Allocate one contiguous memory for the NALUnitParams buffers
// only need to free one time
MOS_FreeMemory(m_encodeCtx->ppNALUnitParams[0]);
m_encodeCtx->ppNALUnitParams[0] = nullptr;
MOS_FreeMemory(m_encodeCtx->ppNALUnitParams);
m_encodeCtx->ppNALUnitParams = nullptr;
}
MOS_FreeMemory(m_encodeCtx->pVuiParams);
m_encodeCtx->pVuiParams = nullptr;
MOS_FreeMemory(m_encodeCtx->pSliceParams);
m_encodeCtx->pSliceParams = nullptr;
MOS_FreeMemory(m_encodeCtx->pEncodeStatusReport);
m_encodeCtx->pEncodeStatusReport = nullptr;
if (m_encodeCtx->pSEIFromApp)
{
MOS_FreeMemory(m_encodeCtx->pSEIFromApp->pSEIBuffer);
m_encodeCtx->pSEIFromApp->pSEIBuffer = nullptr;
MOS_FreeMemory(m_encodeCtx->pSEIFromApp);
m_encodeCtx->pSEIFromApp = nullptr;
}
MOS_FreeMemory(m_encodeCtx->pSliceHeaderData);
m_encodeCtx->pSliceHeaderData = nullptr;
if (m_encodeCtx->pbsBuffer)
{
MOS_FreeMemory(m_encodeCtx->pbsBuffer->pBase);
m_encodeCtx->pbsBuffer->pBase = nullptr;
MOS_FreeMemory(m_encodeCtx->pbsBuffer);
m_encodeCtx->pbsBuffer = nullptr;
}
MOS_FreeMemory(m_qcParams);
m_qcParams = nullptr;
MOS_FreeMemory(m_roundingParams);
m_roundingParams = nullptr;
MOS_FreeMemory(iqMatrixParams);
iqMatrixParams = nullptr;
MOS_FreeMemory(iqWeightScaleLists);
iqWeightScaleLists = nullptr;
}
uint8_t DdiEncodeAvc::ConvertSliceStruct(uint32_t vaSliceStruct)
{
switch (vaSliceStruct)
{
case VA_ENC_SLICE_STRUCTURE_ARBITRARY_ROWS:
return CODECHAL_SLICE_STRUCT_ARBITRARYROWSLICE;
case VA_ENC_SLICE_STRUCTURE_POWER_OF_TWO_ROWS:
return CODECHAL_SLICE_STRUCT_POW2ROWS;
case VA_ENC_SLICE_STRUCTURE_ARBITRARY_MACROBLOCKS:
return CODECHAL_SLICE_STRUCT_ARBITRARYMBSLICE;
case VA_ENC_SLICE_STRUCTURE_EQUAL_MULTI_ROWS:
case VA_ENC_SLICE_STRUCTURE_EQUAL_ROWS:
return CODECHAL_SLICE_STRUCT_ROWSLICE;
default:
return CODECHAL_SLICE_STRUCT_ONESLICE;
}
}
CODEC_AVC_PROFILE_IDC DdiEncodeAvc::GetAVCProfileFromVAProfile()
{
switch (m_encodeCtx->vaProfile)
{
case VAProfileH264ConstrainedBaseline:
return CODEC_AVC_BASE_PROFILE;
case VAProfileH264Main:
return CODEC_AVC_MAIN_PROFILE;
case VAProfileH264High:
return CODEC_AVC_HIGH_PROFILE;
default:
return CODEC_AVC_MAIN_PROFILE;
}
}
uint8_t DdiEncodeAvc::CodechalPicTypeFromVaSlcType(uint8_t vaSliceType)
{
switch (vaSliceType)
{
case sliceTypeI:
case (sliceTypeI + 5):
return I_TYPE;
case sliceTypeP:
case (sliceTypeP + 5):
return P_TYPE;
case sliceTypeB:
case (sliceTypeB + 5):
return B_TYPE;
default:
return 0;
}
}
VAStatus DdiEncodeAvc::ParseMiscParamHRD(void *data)
{
DDI_CHK_NULL(data, "nullptr data", VA_STATUS_ERROR_INVALID_PARAMETER);
VAEncMiscParameterHRD *vaEncMiscParamHRD = (VAEncMiscParameterHRD *)data;
CODECHAL_ENCODE_AVC_VUI_PARAMS *vuiParam = (CODECHAL_ENCODE_AVC_VUI_PARAMS *)m_encodeCtx->pVuiParams;
// Assume only one SPS here, modify when enable multiple SPS support
PCODEC_AVC_ENCODE_SEQUENCE_PARAMS seqParams = (PCODEC_AVC_ENCODE_SEQUENCE_PARAMS)(m_encodeCtx->pSeqParams);
DDI_CHK_NULL(vuiParam, "nullptr vuiParam", VA_STATUS_ERROR_INVALID_PARAMETER);
DDI_CHK_NULL(seqParams, "nullptr seqParams", VA_STATUS_ERROR_INVALID_PARAMETER);
vuiParam->cbr_flag = 0x1;
seqParams->VBVBufferSizeInBit = vaEncMiscParamHRD->buffer_size;
seqParams->InitVBVBufferFullnessInBit = vaEncMiscParamHRD->initial_buffer_fullness;
vuiParam->cpb_size_value_minus1[0] = MOS_ROUNDUP_DIVIDE(seqParams->VBVBufferSizeInBit, vuiKbps) - 1;
return VA_STATUS_SUCCESS;
}
VAStatus DdiEncodeAvc::ParseMiscParamFR(void *data)
{
DDI_CHK_NULL(data, "nullptr data", VA_STATUS_ERROR_INVALID_PARAMETER);
// Assume only one SPS here, modify when enable multiple SPS support
PCODEC_AVC_ENCODE_SEQUENCE_PARAMS seqParams = (PCODEC_AVC_ENCODE_SEQUENCE_PARAMS)(m_encodeCtx->pSeqParams);
VAEncMiscParameterFrameRate *encMiscParamFR = (VAEncMiscParameterFrameRate *)data;
DDI_CHK_NULL(seqParams, "nullptr seqParams", VA_STATUS_ERROR_INVALID_PARAMETER);
uint32_t numerator = (encMiscParamFR->framerate & 0xffff) * 100; /** 100*/;
auto denominator = (encMiscParamFR->framerate >> 16)&0xfff;
if(denominator == 0)
{
denominator = 1;
}
// Pass frame rate value to seqParams and set BRC reset flag and bNewSeq to true while dynamic BRC occures
seqParams->FramesPer100Sec = (uint16_t)(numerator / denominator);
if(m_previousFRper100sec != 0)
{
if(m_previousFRper100sec != seqParams->FramesPer100Sec)
{
seqParams->bResetBRC = 0x1;
m_encodeCtx->bNewSeq = true;
}
}
m_previousFRper100sec = seqParams->FramesPer100Sec;
return VA_STATUS_SUCCESS;
}
VAStatus DdiEncodeAvc::ParseMiscParamRC(void *data)
{
DDI_CHK_NULL(data, "nullptr data", VA_STATUS_ERROR_INVALID_PARAMETER);
CODECHAL_ENCODE_AVC_VUI_PARAMS *vuiParam = (CODECHAL_ENCODE_AVC_VUI_PARAMS *)m_encodeCtx->pVuiParams;
// Assume only one SPS here, modify when enable multiple SPS support
PCODEC_AVC_ENCODE_SEQUENCE_PARAMS seqParams = (PCODEC_AVC_ENCODE_SEQUENCE_PARAMS)(m_encodeCtx->pSeqParams) + current_seq_parameter_set_id;
PCODEC_AVC_ENCODE_PIC_PARAMS picParams = (PCODEC_AVC_ENCODE_PIC_PARAMS)(m_encodeCtx->pPicParams) + current_pic_parameter_set_id;
VAEncMiscParameterRateControl *encMiscParamRC = (VAEncMiscParameterRateControl *)data;
DDI_CHK_NULL(vuiParam, "nullptr vuiParam", VA_STATUS_ERROR_INVALID_PARAMETER);
DDI_CHK_NULL(seqParams, "nullptr seqParams", VA_STATUS_ERROR_INVALID_PARAMETER);
DDI_CHK_NULL(picParams, "nullptr picParams", VA_STATUS_ERROR_INVALID_PARAMETER);
seqParams->TargetBitRate = encMiscParamRC->bits_per_second;
vuiParam->bit_rate_value_minus1[0] = MOS_ROUNDUP_SHIFT(encMiscParamRC->bits_per_second, 6 + vuiParam->bit_rate_scale) - 1;
seqParams->MBBRC = encMiscParamRC->rc_flags.bits.mb_rate_control;
// Assuming picParams are sent before MiscParams
picParams->ucMinimumQP = encMiscParamRC->min_qp;
picParams->ucMaximumQP = encMiscParamRC->max_qp;
if (picParams->ucMaximumQP == 0 && picParams->ucMinimumQP)
picParams->ucMaximumQP = 51;
#if VA_CHECK_VERSION(1, 10, 0)
picParams->TargetFrameSize = encMiscParamRC->target_frame_size;
#endif
if ((VA_RC_CBR == m_encodeCtx->uiRCMethod) || ((VA_RC_CBR | VA_RC_MB) == m_encodeCtx->uiRCMethod))
{
seqParams->MaxBitRate = seqParams->TargetBitRate;
seqParams->MinBitRate = seqParams->TargetBitRate;
vuiParam->cbr_flag = 0x1;
if (m_encodeCtx->uiTargetBitRate != seqParams->TargetBitRate)
{
if (m_encodeCtx->uiTargetBitRate)
{
seqParams->bResetBRC = 0x1;
m_encodeCtx->bNewSeq = true;
}
m_encodeCtx->uiTargetBitRate = seqParams->TargetBitRate;
m_encodeCtx->uiMaxBitRate = seqParams->TargetBitRate;
}
}
else if (VA_RC_ICQ == m_encodeCtx->uiRCMethod)
{
seqParams->ICQQualityFactor = encMiscParamRC->ICQ_quality_factor;
}
else if (VA_RC_AVBR == m_encodeCtx->uiRCMethod)
{
seqParams->AVBRAccuracy = encMiscParamRC->target_percentage;
seqParams->AVBRConvergence = encMiscParamRC->window_size;
}
else
{
seqParams->MaxBitRate = seqParams->TargetBitRate;
seqParams->MinBitRate = (uint32_t)((uint64_t)seqParams->TargetBitRate * (2 * encMiscParamRC->target_percentage - 100) / 100);
seqParams->TargetBitRate = (uint32_t)((uint64_t)seqParams->TargetBitRate * encMiscParamRC->target_percentage / 100);
vuiParam->cbr_flag = 0x0;
if (VA_RC_QVBR == m_encodeCtx->uiRCMethod)
{
seqParams->ICQQualityFactor = encMiscParamRC->quality_factor;
}
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->bNewSeq = true;
}
m_encodeCtx->uiTargetBitRate = seqParams->TargetBitRate;
m_encodeCtx->uiMaxBitRate = seqParams->MaxBitRate;
}
}
//if RateControl method is VBR/CBR, we can set MBBRC to enable or disable
if (VA_RC_CQP != m_encodeCtx->uiRCMethod)
{
if (encMiscParamRC->rc_flags.bits.mb_rate_control <= mbBrcDisabled)
seqParams->MBBRC = encMiscParamRC->rc_flags.bits.mb_rate_control;
}
#ifndef ANDROID
seqParams->FrameSizeTolerance = static_cast<ENCODE_FRAMESIZE_TOLERANCE>(encMiscParamRC->rc_flags.bits.frame_tolerance_mode);
#endif
return VA_STATUS_SUCCESS;
}
VAStatus DdiEncodeAvc::ParseMiscParamSkipFrame(void *data)
{
DDI_CHK_NULL(data, "nullptr data", VA_STATUS_ERROR_INVALID_PARAMETER);
// Assume only one PPS here, modify when enable multiple PPS support
PCODEC_AVC_ENCODE_PIC_PARAMS picParams = (PCODEC_AVC_ENCODE_PIC_PARAMS)(m_encodeCtx->pPicParams) + current_pic_parameter_set_id;
VAEncMiscParameterSkipFrame *vaEncMiscParamSkipFrame = (VAEncMiscParameterSkipFrame *)data;
DDI_CHK_NULL(picParams, "nullptr picParams", VA_STATUS_ERROR_INVALID_PARAMETER);
// populate skipped frame params from DDI
picParams->SkipFrameFlag = vaEncMiscParamSkipFrame->skip_frame_flag;
picParams->NumSkipFrames = vaEncMiscParamSkipFrame->num_skip_frames;
picParams->SizeSkipFrames = vaEncMiscParamSkipFrame->size_skip_frames;
if (FRAME_SKIP_NORMAL < picParams->SkipFrameFlag)
{
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
return VA_STATUS_SUCCESS;
}
VAStatus DdiEncodeAvc::ParseMiscParamMaxFrameSize(void *data)
{
DDI_CHK_NULL(data, "nullptr data", VA_STATUS_ERROR_INVALID_PARAMETER);
// Assume only one SPS here, modify when enable multiple SPS support
PCODEC_AVC_ENCODE_SEQUENCE_PARAMS seqParams = (PCODEC_AVC_ENCODE_SEQUENCE_PARAMS)(m_encodeCtx->pSeqParams);
VAEncMiscParameterBufferMaxFrameSize *vaEncMiscParamMaxFrameSize = (VAEncMiscParameterBufferMaxFrameSize *)data;
DDI_CHK_NULL(seqParams, "nullptr seqParams", VA_STATUS_ERROR_INVALID_PARAMETER);
if (seqParams->UserMaxFrameSize != vaEncMiscParamMaxFrameSize->max_frame_size >> 3)
{
seqParams->bResetBRC = 0x1;
}
// populate MaxFrameSize from DDI
seqParams->UserMaxFrameSize = vaEncMiscParamMaxFrameSize->max_frame_size >> 3; // convert to byte
return VA_STATUS_SUCCESS;
}
VAStatus DdiEncodeAvc::ParseMiscParamMultiPassFrameSize(void *data)
{
DDI_CHK_NULL(data, "nullptr data", VA_STATUS_ERROR_INVALID_PARAMETER);
PCODEC_AVC_ENCODE_PIC_PARAMS picParams = (PCODEC_AVC_ENCODE_PIC_PARAMS)(m_encodeCtx->pPicParams) + current_pic_parameter_set_id;
VAEncMiscParameterBufferMultiPassFrameSize *vaEncMiscParamMultiPassFrameSize = (VAEncMiscParameterBufferMultiPassFrameSize *)data;
DDI_CHK_NULL(picParams, "nullptr picParams", VA_STATUS_ERROR_INVALID_PARAMETER);
//add for multiple pass pak
picParams->dwMaxFrameSize = vaEncMiscParamMultiPassFrameSize->max_frame_size;
if (picParams->dwMaxFrameSize)
{
picParams->dwNumPasses = vaEncMiscParamMultiPassFrameSize->num_passes;
if ((picParams->dwNumPasses == 0) || (picParams->dwNumPasses > maxPassesNum))
{
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
if (picParams->pDeltaQp != nullptr)
{
MOS_FreeMemory(picParams->pDeltaQp);
}
picParams->pDeltaQp = (uint8_t *)MOS_AllocAndZeroMemory(sizeof(uint8_t) * picParams->dwNumPasses);
if (!picParams->pDeltaQp)
{
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
if (MOS_STATUS_SUCCESS != MOS_SecureMemcpy(picParams->pDeltaQp, picParams->dwNumPasses, vaEncMiscParamMultiPassFrameSize->delta_qp, picParams->dwNumPasses))
{
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
}
return VA_STATUS_SUCCESS;
}
VAStatus DdiEncodeAvc::ParseMiscParamEncQuality(void *data)
{
DDI_CHK_NULL(data, "nullptr data", VA_STATUS_ERROR_INVALID_PARAMETER);
// Assume only one SPS here, modify when enable multiple SPS support
PCODEC_AVC_ENCODE_SEQUENCE_PARAMS seqParams = (PCODEC_AVC_ENCODE_SEQUENCE_PARAMS)(m_encodeCtx->pSeqParams) + current_seq_parameter_set_id;
VAEncMiscParameterEncQuality *vaEncMiscParamEncQuality = (VAEncMiscParameterEncQuality *)data;
PCODEC_AVC_ENCODE_PIC_PARAMS picParams = (PCODEC_AVC_ENCODE_PIC_PARAMS)(m_encodeCtx->pPicParams) + current_pic_parameter_set_id;
DDI_CHK_NULL(seqParams, "nullptr seqParams", VA_STATUS_ERROR_INVALID_PARAMETER);
seqParams->bForcePanicModeControl = 1;
seqParams->bPanicModeDisable = (uint8_t)vaEncMiscParamEncQuality->PanicModeDisable;
picParams->UserFlags.bUseRawPicForRef = vaEncMiscParamEncQuality->useRawPicForRef;
m_qcParams->skipCheckDisable = vaEncMiscParamEncQuality->skipCheckDisable;
m_qcParams->FTQOverride = vaEncMiscParamEncQuality->FTQOverride;
if (m_qcParams->FTQOverride)
{
m_qcParams->FTQEnable = vaEncMiscParamEncQuality->FTQEnable;
}
m_qcParams->FTQSkipThresholdLUTInput = vaEncMiscParamEncQuality->FTQSkipThresholdLUTInput;
if (m_qcParams->FTQSkipThresholdLUTInput)
{
MOS_SecureMemcpy(m_qcParams->FTQSkipThresholdLUT, 52, vaEncMiscParamEncQuality->FTQSkipThresholdLUT, 52);
}
m_qcParams->NonFTQSkipThresholdLUTInput = vaEncMiscParamEncQuality->NonFTQSkipThresholdLUTInput;
if (m_qcParams->NonFTQSkipThresholdLUTInput)
{
MOS_SecureMemcpy(m_qcParams->NonFTQSkipThresholdLUT, 52, vaEncMiscParamEncQuality->NonFTQSkipThresholdLUT, 52);
}
m_qcParams->directBiasAdjustmentEnable = vaEncMiscParamEncQuality->directBiasAdjustmentEnable;
m_qcParams->globalMotionBiasAdjustmentEnable = vaEncMiscParamEncQuality->globalMotionBiasAdjustmentEnable;
m_qcParams->HMEMVCostScalingFactor = vaEncMiscParamEncQuality->HMEMVCostScalingFactor;
//disable HME
m_qcParams->HMEDisable = vaEncMiscParamEncQuality->HMEDisable;
//disable Super HME
m_qcParams->SuperHMEDisable = vaEncMiscParamEncQuality->SuperHMEDisable;
//disable Ultra HME
m_qcParams->UltraHMEDisable = vaEncMiscParamEncQuality->UltraHMEDisable;
// Force RepartitionCheck
m_qcParams->ForceRepartitionCheck = vaEncMiscParamEncQuality->ForceRepartitionCheck;
return VA_STATUS_SUCCESS;
}
VAStatus DdiEncodeAvc::ParseMiscParamQuantization(void *data)
{
DDI_CHK_NULL(data, "nullptr data", VA_STATUS_ERROR_INVALID_PARAMETER);
PCODEC_AVC_ENCODE_SEQUENCE_PARAMS seqParams = (PCODEC_AVC_ENCODE_SEQUENCE_PARAMS)(m_encodeCtx->pSeqParams);
VAEncMiscParameterQuantization *vaEncMiscParamQuantization = (VAEncMiscParameterQuantization *)data;
DDI_CHK_NULL(seqParams, "nullptr seqParams", VA_STATUS_ERROR_INVALID_PARAMETER);
seqParams->Trellis = trellisInternal;
if (vaEncMiscParamQuantization->quantization_flags.bits.disable_trellis)
{
seqParams->Trellis = trellisDisabled;
}
else
{
if (vaEncMiscParamQuantization->quantization_flags.bits.enable_trellis_I)
{
seqParams->Trellis |= trellisEnabledI;
}
if (vaEncMiscParamQuantization->quantization_flags.bits.enable_trellis_P)
{
seqParams->Trellis |= trellisEnabledP;
}
if (vaEncMiscParamQuantization->quantization_flags.bits.enable_trellis_B)
{
seqParams->Trellis |= trellisEnabledB;
}
if (!seqParams->Trellis)
{
DDI_ASSERTMESSAGE("trellis enabled, but the input parameters is invalided");
}
}
return VA_STATUS_SUCCESS;
}
VAStatus DdiEncodeAvc::ParseMiscParameterRIR(void *data)
{
DDI_CHK_NULL(data, "nullptr data", VA_STATUS_ERROR_INVALID_PARAMETER);
PCODEC_AVC_ENCODE_PIC_PARAMS picParams = (PCODEC_AVC_ENCODE_PIC_PARAMS)(m_encodeCtx->pPicParams) + current_pic_parameter_set_id;
PCODEC_AVC_ENCODE_SEQUENCE_PARAMS seqParams = (PCODEC_AVC_ENCODE_SEQUENCE_PARAMS)(m_encodeCtx->pSeqParams) + current_seq_parameter_set_id;
VAEncMiscParameterRIR *vaEncMiscParamRIR = (VAEncMiscParameterRIR *)data;
DDI_CHK_NULL(picParams, "nullptr picParams", VA_STATUS_ERROR_INVALID_PARAMETER);
DDI_CHK_NULL(seqParams, "nullptr seqParams", VA_STATUS_ERROR_INVALID_PARAMETER);
picParams->EnableRollingIntraRefresh = vaEncMiscParamRIR->rir_flags.value & 0x3; //only lower two bits are valid
#ifdef Android
//Convert row based rolling I to suqare region based rolling I before MSDK is ready to support square region based rolling I
if (ROLLING_I_ROW == picParams->EnableRollingIntraRefresh)
{
if (GFX_IS_PRODUCT(m_encodeCtx->pMediaCtx->platform, IGFX_BROADWELL))
{
picParams->EnableRollingIntraRefresh = ROLLING_I_SQUARE;
}
vaEncMiscParamRIR->intra_insert_size *= (seqParams->FrameWidth / CODECHAL_ENCODE_AVC_ROI_WIDTH_SCALE_FACTOR);
// From the experiment result, -6 could be the proper setting
vaEncMiscParamRIR->qp_delta_for_inserted_intra = -6;
}
#endif
// Set for all frames since pic type is not known yet. Disable in slice params if its I or B type.
switch (picParams->EnableRollingIntraRefresh)
{
case ROLLING_I_COLUMN:
picParams->IntraRefreshMBx = (uint8_t)vaEncMiscParamRIR->intra_insertion_location;
picParams->IntraRefreshMBNum = (uint8_t)vaEncMiscParamRIR->intra_insertion_location;
picParams->IntraRefreshUnitinMB = (uint8_t)vaEncMiscParamRIR->intra_insert_size;
break;
case ROLLING_I_ROW:
picParams->IntraRefreshMBy = (uint8_t)vaEncMiscParamRIR->intra_insertion_location;
picParams->IntraRefreshMBNum = (uint8_t)vaEncMiscParamRIR->intra_insertion_location;
picParams->IntraRefreshUnitinMB = (uint8_t)vaEncMiscParamRIR->intra_insert_size;
break;
case ROLLING_I_SQUARE:
picParams->IntraRefreshUnitinMB = (uint8_t)GFX_UF_ROUND(sqrt((double)vaEncMiscParamRIR->intra_insert_size));
break;
case ROLLING_I_DISABLED:
break;
default:
return MOS_STATUS_INVALID_PARAMETER;
}
picParams->IntraRefreshQPDelta = vaEncMiscParamRIR->qp_delta_for_inserted_intra;
// UMD tracks the MBx/MBy for the intra square
uint32_t rightBorder = ((seqParams->FrameWidth + CODECHAL_ENCODE_AVC_ROI_WIDTH_SCALE_FACTOR - 1) / CODECHAL_ENCODE_AVC_ROI_WIDTH_SCALE_FACTOR) - 1;
uint32_t bottomBorder = ((seqParams->FrameHeight + CODECHAL_ENCODE_AVC_ROI_FRAME_HEIGHT_SCALE_FACTOR - 1) / CODECHAL_ENCODE_AVC_ROI_FRAME_HEIGHT_SCALE_FACTOR) - 1;
if ((ROLLING_I_SQUARE == picParams->EnableRollingIntraRefresh))
{
if (m_encodeCtx->uiIntraRefreshFrameCnt == 0)
{
m_encodeCtx->uiIntraRefreshFrameCnt = 1;
m_encodeCtx->uiIntraRefreshMBx = 0;
m_encodeCtx->uiIntraRefreshMBy = 0;
}
else
{
m_encodeCtx->uiIntraRefreshMBx += picParams->IntraRefreshUnitinMB;
if (m_encodeCtx->uiIntraRefreshMBx >= rightBorder)
{
m_encodeCtx->uiIntraRefreshMBx = 0;
m_encodeCtx->uiIntraRefreshMBy += picParams->IntraRefreshUnitinMB;
if (m_encodeCtx->uiIntraRefreshMBy >= bottomBorder)
{
m_encodeCtx->uiIntraRefreshMBx = 0;
m_encodeCtx->uiIntraRefreshMBy = 0;
}
}
}
// set MBx/MBy to CODECHAL
picParams->IntraRefreshMBx = m_encodeCtx->uiIntraRefreshMBx;
picParams->IntraRefreshMBy = m_encodeCtx->uiIntraRefreshMBy;
}
return VA_STATUS_SUCCESS;
}
VAStatus DdiEncodeAvc::ParseMiscParamQualityLevel(void *data)
{
// Assume only one SPS here, modify when enable multiple SPS support
VAEncMiscParameterBufferQualityLevel *vaEncMiscParamQualityLevel = (VAEncMiscParameterBufferQualityLevel *)data;
m_encodeCtx->targetUsage = (uint8_t)vaEncMiscParamQualityLevel->quality_level;
// check if TU setting is valid, otherwise change to default
if ((m_encodeCtx->targetUsage > TARGETUSAGE_BEST_SPEED) || (0 == m_encodeCtx->targetUsage))
{
m_encodeCtx->targetUsage = TARGETUSAGE_RT_SPEED;
DDI_ASSERTMESSAGE("Quality Level setting from application is not correct, should be in (0,%d].", TARGETUSAGE_BEST_SPEED);
}
#ifdef _FULL_OPEN_SOURCE
if (!GFX_IS_PRODUCT(m_encodeCtx->pMediaCtx->platform, IGFX_ICELAKE_LP) && m_encodeCtx->targetUsage <= 3)
{
m_encodeCtx->targetUsage = 4;
}
#endif
return VA_STATUS_SUCCESS;
}
VAStatus DdiEncodeAvc::ParseMiscParamDirtyROI(void *data)
{
PCODEC_AVC_ENCODE_PIC_PARAMS picParams = (PCODEC_AVC_ENCODE_PIC_PARAMS)(m_encodeCtx->pPicParams) + current_pic_parameter_set_id;
PCODEC_AVC_ENCODE_SEQUENCE_PARAMS seqParams = (PCODEC_AVC_ENCODE_SEQUENCE_PARAMS)(m_encodeCtx->pSeqParams) + current_seq_parameter_set_id;
VAEncMiscParameterBufferDirtyRect *dirtyRect = (VAEncMiscParameterBufferDirtyRect *)data;
DDI_CHK_NULL(picParams, "nullptr picParams", VA_STATUS_ERROR_INVALID_PARAMETER);
DDI_CHK_NULL(seqParams, "nullptr seqParams", VA_STATUS_ERROR_INVALID_PARAMETER);
DDI_CHK_NULL(dirtyRect, "nullptr dirtyRect", VA_STATUS_ERROR_INVALID_PARAMETER);
DDI_CHK_NULL(dirtyRect->roi_rectangle, "nullptr dirtyRect->roi_rectangle", VA_STATUS_ERROR_INVALID_PARAMETER);
if (dirtyRect->num_roi_rectangle > 0)
{
uint16_t mbHeightScaleFactor = picParams->FieldCodingFlag ? CODECHAL_ENCODE_AVC_ROI_FIELD_HEIGHT_SCALE_FACTOR : CODECHAL_ENCODE_AVC_ROI_FRAME_HEIGHT_SCALE_FACTOR;
// Support upto 4 Dirty rectangles
int32_t maxDirtyRects = (dirtyRect->num_roi_rectangle > CODEC_AVC_NUM_MAX_DIRTY_RECT) ? CODEC_AVC_NUM_MAX_DIRTY_RECT : dirtyRect->num_roi_rectangle;
picParams->NumDirtyROI = 0;
MOS_ZeroMemory(picParams->DirtyROI, CODEC_AVC_NUM_MAX_DIRTY_RECT * sizeof(CODEC_ROI));
PCODEC_ROI roi;
for (int32_t i = 0; i < maxDirtyRects; i++)
{
if (nullptr != dirtyRect->roi_rectangle)
{
roi = &picParams->DirtyROI[picParams->NumDirtyROI];
roi->Left = MOS_MIN(MOS_MAX(dirtyRect->roi_rectangle->x, 0), seqParams->FrameWidth - 1);
roi->Top = MOS_MIN(MOS_MAX(dirtyRect->roi_rectangle->y, 0), seqParams->FrameHeight - 1);
roi->Right = MOS_MIN(dirtyRect->roi_rectangle->x + dirtyRect->roi_rectangle->width, seqParams->FrameWidth - 1);
roi->Bottom = MOS_MIN(dirtyRect->roi_rectangle->y + dirtyRect->roi_rectangle->height, seqParams->FrameHeight - 1);
// Check and adjust if ROI not within frame boundaries
roi->Left = MOS_MIN(roi->Left, seqParams->FrameWidth - 1);
roi->Top = MOS_MIN(roi->Top, seqParams->FrameHeight - 1);
roi->Right = MOS_MIN(roi->Right, seqParams->FrameWidth - 1);
roi->Bottom = MOS_MIN(roi->Bottom, seqParams->FrameHeight - 1);
roi->Right = MOS_ALIGN_CEIL(roi->Right, CODECHAL_ENCODE_AVC_ROI_WIDTH_SCALE_FACTOR);
roi->Bottom = MOS_ALIGN_CEIL(roi->Bottom, mbHeightScaleFactor);
// Convert from pixel units to MB units
roi->Left /= CODECHAL_ENCODE_AVC_ROI_WIDTH_SCALE_FACTOR;
roi->Right /= CODECHAL_ENCODE_AVC_ROI_WIDTH_SCALE_FACTOR;
roi->Top /= mbHeightScaleFactor;
roi->Bottom /= mbHeightScaleFactor;
dirtyRect->roi_rectangle++;
picParams->NumDirtyROI++;
}
else
{
continue;
}
}
}
return VA_STATUS_SUCCESS;
}
VAStatus DdiEncodeAvc::ParseMiscParamROI(void *data)
{
DDI_CHK_NULL(m_encodeCtx, "nullptr m_encodeCtx", VA_STATUS_ERROR_INVALID_PARAMETER);
DDI_CHK_NULL(data, "nullptr data", VA_STATUS_ERROR_INVALID_PARAMETER);
PCODEC_AVC_ENCODE_PIC_PARAMS picParams = (PCODEC_AVC_ENCODE_PIC_PARAMS)(m_encodeCtx->pPicParams) + current_pic_parameter_set_id;
PCODEC_AVC_ENCODE_SEQUENCE_PARAMS seqParams = (PCODEC_AVC_ENCODE_SEQUENCE_PARAMS)(m_encodeCtx->pSeqParams) + current_seq_parameter_set_id;
DDI_CHK_NULL(picParams, "nullptr picParams", VA_STATUS_ERROR_INVALID_PARAMETER);
DDI_CHK_NULL(seqParams, "nullptr seqParams", VA_STATUS_ERROR_INVALID_PARAMETER);
VAEncMiscParameterBufferROI *vaEncMiscParamROI = (VAEncMiscParameterBufferROI *)data;
PCODEC_ROI roi = &picParams->ROI[0];
DDI_CHK_NULL(m_encodeCtx->pMediaCtx, "nullptr pMediaCtx", VA_STATUS_ERROR_INVALID_PARAMETER);
DDI_CHK_NULL(m_encodeCtx->pMediaCtx->m_caps, "nullptr m_caps", VA_STATUS_ERROR_INVALID_PARAMETER);
uint32_t maxROIsupported = 0;
bool isROIValueInDeltaQP = false;
m_encodeCtx->pMediaCtx->m_caps->QueryAVCROIMaxNum(m_encodeCtx->uiRCMethod, m_encodeCtx->bVdencActive, &maxROIsupported, &isROIValueInDeltaQP);
if (maxROIsupported == 0)
{
return MOS_STATUS_INVALID_PARAMETER;
}
seqParams->ROIValueInDeltaQP = (isROIValueInDeltaQP ? 1 : 0);
picParams->NumROI = MOS_MIN(vaEncMiscParamROI->num_roi, maxROIsupported);
picParams->MaxDeltaQp = vaEncMiscParamROI->max_delta_qp;
picParams->MinDeltaQp = vaEncMiscParamROI->min_delta_qp;
uint8_t mbHeightScaleFactor = picParams->FieldCodingFlag ? CODECHAL_ENCODE_AVC_ROI_FIELD_HEIGHT_SCALE_FACTOR : CODECHAL_ENCODE_AVC_ROI_FRAME_HEIGHT_SCALE_FACTOR;
// Process information for all ROIs and pass to codecHAL
for (uint8_t i = 0; i < picParams->NumROI; i++)
{
DDI_CHK_NULL(vaEncMiscParamROI->roi, "nullptr vaEncMiscParamROI->roi", VA_STATUS_ERROR_INVALID_PARAMETER);
DDI_CHK_NULL(roi, "nullptr roi", VA_STATUS_ERROR_INVALID_PARAMETER);
// Check and adjust if ROI not within frame boundaries
roi->Left = MOS_MIN(MOS_MAX(vaEncMiscParamROI->roi->roi_rectangle.x, 0), seqParams->FrameWidth - 1);
roi->Top = MOS_MIN(MOS_MAX(vaEncMiscParamROI->roi->roi_rectangle.y, 0), seqParams->FrameHeight - 1);
roi->Right = MOS_MIN(roi->Left + vaEncMiscParamROI->roi->roi_rectangle.width, seqParams->FrameWidth - 1);
roi->Bottom = MOS_MIN(roi->Top + vaEncMiscParamROI->roi->roi_rectangle.height, seqParams->FrameHeight - 1);
// Convert from pixel units to MB units
roi->Left /= CODECHAL_ENCODE_AVC_ROI_WIDTH_SCALE_FACTOR;
roi->Top /= mbHeightScaleFactor;
roi->Right = (roi->Right + CODECHAL_ENCODE_AVC_ROI_WIDTH_SCALE_FACTOR - 1) / CODECHAL_ENCODE_AVC_ROI_WIDTH_SCALE_FACTOR;
roi->Bottom = (roi->Bottom + mbHeightScaleFactor - 1) / mbHeightScaleFactor;
roi->PriorityLevelOrDQp = vaEncMiscParamROI->roi->roi_value;
// Move to next ROI
vaEncMiscParamROI->roi++;
roi++;
}
#ifndef ANDROID
seqParams->ROIValueInDeltaQP = vaEncMiscParamROI->roi_flags.bits.roi_value_is_qp_delta;
if(picParams->NumROI != 0 && seqParams->ROIValueInDeltaQP == 0)
{
DDI_ASSERTMESSAGE("ROI does not support priority level now.");
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
#endif
return VA_STATUS_SUCCESS;
}
VAStatus DdiEncodeAvc::ParseMiscParamMaxSliceSize(void *data)
{
DDI_CHK_NULL(m_encodeCtx, "nullptr m_encodeCtx", VA_STATUS_ERROR_INVALID_PARAMETER);
DDI_CHK_NULL(data, "nullptr data", VA_STATUS_ERROR_INVALID_PARAMETER);
m_encodeCtx->EnableSliceLevelRateCtrl = true;
PCODEC_AVC_ENCODE_PIC_PARAMS picParams = (PCODEC_AVC_ENCODE_PIC_PARAMS)(m_encodeCtx->pPicParams) + current_pic_parameter_set_id;
PCODEC_AVC_ENCODE_SEQUENCE_PARAMS seqParams = (PCODEC_AVC_ENCODE_SEQUENCE_PARAMS)(m_encodeCtx->pSeqParams) + current_seq_parameter_set_id;
DDI_CHK_NULL(picParams, "nullptr picParams", VA_STATUS_ERROR_INVALID_PARAMETER);
DDI_CHK_NULL(seqParams, "nullptr seqParams", VA_STATUS_ERROR_INVALID_PARAMETER);
seqParams->EnableSliceLevelRateCtrl = m_encodeCtx->EnableSliceLevelRateCtrl;
VAEncMiscParameterMaxSliceSize *vaEncMiscParamMaxSliceSize = (VAEncMiscParameterMaxSliceSize *)data;
picParams->SliceSizeInBytes = vaEncMiscParamMaxSliceSize->max_slice_size;
return VA_STATUS_SUCCESS;
}
VAStatus DdiEncodeAvc::ParseMiscParamRounding(void *data)
{
DDI_CHK_NULL(m_encodeCtx, "nullptr m_encodeCtx", VA_STATUS_ERROR_INVALID_PARAMETER);
DDI_CHK_NULL(data, "nullptr data", VA_STATUS_ERROR_INVALID_PARAMETER);
VAEncMiscParameterCustomRoundingControl *vaEncMiscParamRounding = (VAEncMiscParameterCustomRoundingControl *)data;
if (vaEncMiscParamRounding->rounding_offset_setting.bits.enable_custom_rouding_intra)
{
m_roundingParams->bEnableCustomRoudingIntra = vaEncMiscParamRounding->rounding_offset_setting.bits.enable_custom_rouding_intra;
m_roundingParams->dwRoundingIntra = vaEncMiscParamRounding->rounding_offset_setting.bits.rounding_offset_intra;
}
if (vaEncMiscParamRounding->rounding_offset_setting.bits.enable_custom_rounding_inter)
{
m_roundingParams->bEnableCustomRoudingInter = vaEncMiscParamRounding->rounding_offset_setting.bits.enable_custom_rounding_inter;
m_roundingParams->dwRoundingInter = vaEncMiscParamRounding->rounding_offset_setting.bits.rounding_offset_inter;
}
return VA_STATUS_SUCCESS;
}
VAStatus DdiEncodeAvc::ParseMiscParamSubMbPartPel(void *data)
{
DDI_CHK_NULL(m_encodeCtx, "nullptr m_encodeCtx", VA_STATUS_ERROR_INVALID_PARAMETER);
DDI_CHK_NULL(data, "nullptr data", VA_STATUS_ERROR_INVALID_PARAMETER);
PCODEC_AVC_ENCODE_PIC_PARAMS picParams = (PCODEC_AVC_ENCODE_PIC_PARAMS)(m_encodeCtx->pPicParams) + current_pic_parameter_set_id;
DDI_CHK_NULL(picParams, "nullptr picParams", VA_STATUS_ERROR_INVALID_PARAMETER);
VAEncMiscParameterSubMbPartPelH264 *vaEncMiscParamSubMbPartPel = (VAEncMiscParameterSubMbPartPelH264*)data;
if (vaEncMiscParamSubMbPartPel->disable_inter_sub_mb_partition)
{
picParams->bEnableSubMbPartMask = true;
//Inter 16x16 can't be disabled
picParams->SubMbPartMask = vaEncMiscParamSubMbPartPel->inter_sub_mb_partition_mask.value & disMbPartMask;
}
if (vaEncMiscParamSubMbPartPel->enable_sub_pel_mode)
{
picParams->bEnableSubPelMode = true;
picParams->SubPelMode = vaEncMiscParamSubMbPartPel->sub_pel_mode & subpelModeMask;
if (picParams->SubPelMode == subpelModeReserved)
{
//When Quarter-pel mode is enabled, Half-pel must be enabled as well.
picParams->SubPelMode = subpelModeQuant;
}
}
return VA_STATUS_SUCCESS;
}
VAStatus DdiEncodeAvc::ContextInitialize(CodechalSetting * codecHalSettings)
{
DDI_CHK_NULL(m_encodeCtx, "nullptr m_encodeCtx.", VA_STATUS_ERROR_INVALID_CONTEXT);
DDI_CHK_NULL(m_encodeCtx->pCpDdiInterface, "nullptr m_encodeCtx->pCpDdiInterface.", VA_STATUS_ERROR_INVALID_CONTEXT);
DDI_CHK_NULL(codecHalSettings, "nullptr codecHalSettings.", VA_STATUS_ERROR_INVALID_CONTEXT);
if (m_encodeCtx->bVdencActive == true)
{
codecHalSettings->codecFunction = CODECHAL_FUNCTION_ENC_VDENC_PAK;
}
else
{
codecHalSettings->codecFunction = m_encodeCtx->codecFunction;
}
codecHalSettings->width = m_encodeCtx->dworiFrameWidth;
codecHalSettings->height = m_encodeCtx->dworiFrameHeight;
codecHalSettings->mode = m_encodeCtx->wModeType;
codecHalSettings->standard = CODECHAL_AVC;
m_encodeCtx->pSeqParams = (void *)MOS_AllocAndZeroMemory(CODEC_AVC_MAX_SPS_NUM * sizeof(CODEC_AVC_ENCODE_SEQUENCE_PARAMS));
DDI_CHK_NULL(m_encodeCtx->pSeqParams, "nullptr m_encodeCtx->pSeqParams", VA_STATUS_ERROR_ALLOCATION_FAILED);
m_encodeCtx->pPicParams = (void *)MOS_AllocAndZeroMemory(CODEC_AVC_MAX_PPS_NUM * sizeof(CODEC_AVC_ENCODE_PIC_PARAMS));
DDI_CHK_NULL(m_encodeCtx->pPicParams, "nullptr m_encodeCtx->pPicParams", VA_STATUS_ERROR_ALLOCATION_FAILED);
// Allocate NAL unit params
m_encodeCtx->ppNALUnitParams = (PCODECHAL_NAL_UNIT_PARAMS *)MOS_AllocAndZeroMemory(sizeof(PCODECHAL_NAL_UNIT_PARAMS) * CODECHAL_ENCODE_AVC_MAX_NAL_TYPE);
DDI_CHK_NULL(m_encodeCtx->ppNALUnitParams, "nullptr m_encodeCtx->ppNALUnitParams", VA_STATUS_ERROR_ALLOCATION_FAILED);
PCODECHAL_NAL_UNIT_PARAMS nalUnitParams = (PCODECHAL_NAL_UNIT_PARAMS)MOS_AllocAndZeroMemory(sizeof(CODECHAL_NAL_UNIT_PARAMS) * CODECHAL_ENCODE_AVC_MAX_NAL_TYPE);
DDI_CHK_NULL(nalUnitParams, "nullptr nalUnitParams", VA_STATUS_ERROR_ALLOCATION_FAILED);
for (int32_t i = 0; i < CODECHAL_ENCODE_AVC_MAX_NAL_TYPE; i++)
{
m_encodeCtx->ppNALUnitParams[i] = &(nalUnitParams[i]);
}
VAStatus status = m_encodeCtx->pCpDdiInterface->ParseCpParamsForEncode();
if (VA_STATUS_SUCCESS != status)
{
return status;
}
m_encodeCtx->pVuiParams = (void *)MOS_AllocAndZeroMemory(sizeof(CODECHAL_ENCODE_AVC_VUI_PARAMS));
DDI_CHK_NULL(m_encodeCtx->pVuiParams, "nullptr m_encodeCtx->pVuiParams", VA_STATUS_ERROR_ALLOCATION_FAILED);
// Allocate SliceParams
// Supports equal row slices.
m_encodeCtx->pSliceParams = (void *)MOS_AllocAndZeroMemory(ENCODE_AVC_MAX_SLICES_SUPPORTED * sizeof(CODEC_AVC_ENCODE_SLICE_PARAMS));
DDI_CHK_NULL(m_encodeCtx->pSliceParams, "nullptr m_encodeCtx->pSliceParams", VA_STATUS_ERROR_ALLOCATION_FAILED);
// Allocate Encode Status Report
m_encodeCtx->pEncodeStatusReport = (void *)MOS_AllocAndZeroMemory(CODECHAL_ENCODE_STATUS_NUM * sizeof(EncodeStatusReport));
DDI_CHK_NULL(m_encodeCtx->pEncodeStatusReport, "nullptr m_encodeCtx->pEncodeStatusReport", VA_STATUS_ERROR_ALLOCATION_FAILED);
// Allocate SEI structure
m_encodeCtx->pSEIFromApp = (CodechalEncodeSeiData*)MOS_AllocAndZeroMemory(sizeof(CodechalEncodeSeiData));
DDI_CHK_NULL(m_encodeCtx->pSEIFromApp, "nullptr m_encodeCtx->pSEIFromApp", VA_STATUS_ERROR_ALLOCATION_FAILED);
// for slice header from application
m_encodeCtx->pSliceHeaderData = (PCODEC_ENCODER_SLCDATA)MOS_AllocAndZeroMemory(ENCODE_AVC_MAX_SLICES_SUPPORTED *
sizeof(CODEC_ENCODER_SLCDATA));
DDI_CHK_NULL(m_encodeCtx->pSliceHeaderData, "nullptr m_encodeCtx->pSliceHeaderData", VA_STATUS_ERROR_ALLOCATION_FAILED);
// Create the bit stream buffer to hold the packed headers from application
m_encodeCtx->pbsBuffer = (PBSBuffer)MOS_AllocAndZeroMemory(sizeof(BSBuffer));
DDI_CHK_NULL(m_encodeCtx->pbsBuffer, "nullptr m_encodeCtx->pbsBuffer", VA_STATUS_ERROR_ALLOCATION_FAILED);
m_encodeCtx->pbsBuffer->pBase = (uint8_t *)MOS_AllocAndZeroMemory(ENCODE_AVC_MAX_SLICES_SUPPORTED * PACKED_HEADER_SIZE_PER_ROW);
DDI_CHK_NULL(m_encodeCtx->pbsBuffer->pBase, "nullptr m_encodeCtx->pbsBuffer->pBase", VA_STATUS_ERROR_ALLOCATION_FAILED);
m_encodeCtx->pbsBuffer->BufferSize = ENCODE_AVC_MAX_SLICES_SUPPORTED * PACKED_HEADER_SIZE_PER_ROW;
m_qcParams = (CODECHAL_ENCODE_AVC_QUALITY_CTRL_PARAMS *)MOS_AllocAndZeroMemory(sizeof(CODECHAL_ENCODE_AVC_QUALITY_CTRL_PARAMS));
DDI_CHK_NULL(m_qcParams, "nullptr m_qcParams", VA_STATUS_ERROR_ALLOCATION_FAILED);
m_roundingParams = (CODECHAL_ENCODE_AVC_ROUNDING_PARAMS *)MOS_AllocAndZeroMemory(sizeof(CODECHAL_ENCODE_AVC_ROUNDING_PARAMS));
DDI_CHK_NULL(m_roundingParams, "nullptr m_roundingParams", VA_STATUS_ERROR_ALLOCATION_FAILED);
iqMatrixParams = (PCODEC_AVC_IQ_MATRIX_PARAMS)MOS_AllocAndZeroMemory(sizeof(CODEC_AVC_IQ_MATRIX_PARAMS));
DDI_CHK_NULL(iqMatrixParams, "nullptr iqMatrixParams", VA_STATUS_ERROR_ALLOCATION_FAILED);
iqWeightScaleLists = (PCODEC_AVC_ENCODE_IQ_WEIGTHSCALE_LISTS)MOS_AllocAndZeroMemory(sizeof(CODEC_AVC_ENCODE_IQ_WEIGTHSCALE_LISTS));
DDI_CHK_NULL(iqWeightScaleLists, "nullptr iqWeightScaleLists", VA_STATUS_ERROR_ALLOCATION_FAILED);
return VA_STATUS_SUCCESS;
}
VAStatus DdiEncodeAvc::RenderPicture(
VADriverContextP ctx,
VAContextID context,
VABufferID *buffers,
int32_t numBuffers)
{
DDI_FUNCTION_ENTER();
DDI_CHK_NULL(ctx, "nullptr ctx", VA_STATUS_ERROR_INVALID_CONTEXT);
PDDI_MEDIA_CONTEXT mediaCtx = DdiMedia_GetMediaContext(ctx);
DDI_CHK_NULL(mediaCtx, "nullptr mediaCtx", VA_STATUS_ERROR_INVALID_CONTEXT);
// assume the VAContextID is encoder ID
DDI_CHK_NULL(m_encodeCtx, "nullptr m_encodeCtx", VA_STATUS_ERROR_INVALID_CONTEXT);
uint32_t numSlices = 0;
VAStatus vaStatus = VA_STATUS_SUCCESS;
DDI_MEDIA_BUFFER *buf;
void *data;
uint32_t dataSize;
for (int32_t i = 0; i < numBuffers; i++)
{
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;
}
dataSize = buf->iSize;
// can use internal function instead of DdiMedia_MapBuffer here?
DdiMedia_MapBuffer(ctx, buffers[i], &data);
DDI_CHK_NULL(data, "nullptr data", VA_STATUS_ERROR_INVALID_BUFFER);
switch (buf->uiType)
{
case VAIQMatrixBufferType:
case VAQMatrixBufferType:
DDI_CHK_STATUS(Qmatrix(data), VA_STATUS_ERROR_INVALID_BUFFER);
break;
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:
numSlices = buf->uiNumElements;
DDI_CHK_STATUS(ParseSlcParams(mediaCtx, data, numSlices), VA_STATUS_ERROR_INVALID_BUFFER);
break;
case VAEncPackedHeaderParameterBufferType:
DDI_CHK_STATUS(ParsePackedHeaderParams(data), VA_STATUS_ERROR_INVALID_BUFFER);
break;
case VAEncPackedHeaderDataBufferType:
DDI_CHK_STATUS(ParsePackedHeaderData(data), VA_STATUS_ERROR_INVALID_BUFFER);
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;
default:
if(m_encodeCtx->pCpDdiInterface)
{
vaStatus = m_encodeCtx->pCpDdiInterface->RenderCencPicture(ctx, context, buf, data);
}
else
{
vaStatus = VA_STATUS_ERROR_UNSUPPORTED_BUFFERTYPE;
}
break;
}
DdiMedia_UnmapBuffer(ctx, buffers[i]);
}
DDI_FUNCTION_EXIT(vaStatus);
return vaStatus;
}
VAStatus DdiEncodeAvc::EncodeInCodecHal(uint32_t numSlices)
{
uint8_t ppsIdx, spsIdx;
PCODEC_AVC_ENCODE_PIC_PARAMS picParams;
DDI_CHK_NULL(m_encodeCtx, "nullptr m_encodeCtx", VA_STATUS_ERROR_INVALID_PARAMETER);
DDI_CHK_NULL(m_encodeCtx->pMediaCtx, "nullptr m_encodeCtx->pMediaCtx", VA_STATUS_ERROR_INVALID_PARAMETER);
DDI_CHK_NULL(m_encodeCtx->pCpDdiInterface, "nullptr m_encodeCtx->pCpDdiInterface.", VA_STATUS_ERROR_INVALID_PARAMETER);
DDI_CODEC_RENDER_TARGET_TABLE *rtTbl = &(m_encodeCtx->RTtbl);
EncoderParams *encodeParams = &m_encodeCtx->EncodeParams;
MOS_ZeroMemory(encodeParams, sizeof(EncoderParams));
encodeParams->newSeqHeader = m_newSeqHeader;
encodeParams->newPpsHeader = m_newPpsHeader;
encodeParams->arbitraryNumMbsInSlice = m_arbitraryNumMbsInSlice;
if (m_encodeCtx->bVdencActive == true)
{
encodeParams->ExecCodecFunction = CODECHAL_FUNCTION_ENC_VDENC_PAK;
}
else
{
encodeParams->ExecCodecFunction = CODECHAL_FUNCTION_ENC_PAK;
}
// Raw Surface
PMOS_SURFACE rawSurface = &encodeParams->rawSurface;
rawSurface->Format = Format_NV12;
rawSurface->dwOffset = 0;
DdiMedia_MediaSurfaceToMosResource(rtTbl->pCurrentRT, &(rawSurface->OsResource));
PMOS_INTERFACE osInterface = m_encodeCtx->pCodecHal->GetOsInterface();
m_encodeCtx->pCpDdiInterface->SetInputResourceEncryption(osInterface, &(rawSurface->OsResource));
// Recon Surface
PMOS_SURFACE reconSurface = &encodeParams->reconSurface;
reconSurface->Format = Format_NV12;
reconSurface->dwOffset = 0;
DdiMedia_MediaSurfaceToMosResource(rtTbl->pCurrentReconTarget, &(reconSurface->OsResource));
//clear registered recon/ref surface flags
DDI_CHK_RET(ClearRefList(&m_encodeCtx->RTtbl, false), "ClearRefList failed!");
// Bitstream surface
PMOS_RESOURCE bitstreamSurface = &encodeParams->resBitstreamBuffer;
*bitstreamSurface = m_encodeCtx->resBitstreamBuffer; // in render picture
bitstreamSurface->Format = Format_Buffer;
encodeParams->psRawSurface = &encodeParams->rawSurface;
encodeParams->psReconSurface = &encodeParams->reconSurface;
encodeParams->presBitstreamBuffer = &encodeParams->resBitstreamBuffer;
PMOS_SURFACE mbQpSurface = &encodeParams->mbQpSurface;
if (m_encodeCtx->bMBQpEnable)
{
mbQpSurface->Format = Format_Buffer_2D;
mbQpSurface->dwOffset = 0;
mbQpSurface->OsResource = m_encodeCtx->resMBQpBuffer;
encodeParams->psMbQpDataSurface = &encodeParams->mbQpSurface;
encodeParams->bMbQpDataEnabled = true;
}
PMOS_SURFACE disableSkipMapSurface = &encodeParams->disableSkipMapSurface;
encodeParams->bMbDisableSkipMapEnabled = m_encodeCtx->bMbDisableSkipMapEnabled;
if (encodeParams->bMbDisableSkipMapEnabled)
{
disableSkipMapSurface->Format = Format_Buffer;
disableSkipMapSurface->dwOffset = 0;
disableSkipMapSurface->OsResource = m_encodeCtx->resPerMBSkipMapBuffer;
encodeParams->psMbDisableSkipMapSurface = &encodeParams->disableSkipMapSurface;
}
// correct some params
PCODEC_AVC_ENCODE_SEQUENCE_PARAMS seqParams;
CODECHAL_ENCODE_AVC_VUI_PARAMS *vuiParam;
vuiParam = (CODECHAL_ENCODE_AVC_VUI_PARAMS *)m_encodeCtx->pVuiParams;
seqParams = (PCODEC_AVC_ENCODE_SEQUENCE_PARAMS)(m_encodeCtx->pSeqParams);
seqParams->TargetUsage = m_encodeCtx->targetUsage;
if (VA_RC_CQP == m_encodeCtx->uiRCMethod)
{
vuiParam->bit_rate_value_minus1[0] = 0;
vuiParam->cpb_size_value_minus1[0] = 0;
seqParams->TargetBitRate = 0;
seqParams->MaxBitRate = 0;
seqParams->MinBitRate = 0;
seqParams->InitVBVBufferFullnessInBit = 0;
seqParams->VBVBufferSizeInBit = 0;
}
encodeParams->uiSlcStructCaps = CODECHAL_SLICE_STRUCT_ARBITRARYMBSLICE;
ppsIdx = ((PCODEC_AVC_ENCODE_SLICE_PARAMS)(m_encodeCtx->pSliceParams))->pic_parameter_set_id;
picParams = (PCODEC_AVC_ENCODE_PIC_PARAMS)m_encodeCtx->pPicParams + ppsIdx;
spsIdx = picParams->seq_parameter_set_id;
encodeParams->pSeqParams = (PCODEC_AVC_ENCODE_SEQUENCE_PARAMS)m_encodeCtx->pSeqParams + spsIdx;
encodeParams->pPicParams = picParams;
encodeParams->pVuiParams = m_encodeCtx->pVuiParams;
encodeParams->pSliceParams = m_encodeCtx->pSliceParams;
encodeParams->pAVCQCParams = m_qcParams;
encodeParams->pAVCRoundingParams = m_roundingParams;
// 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;
MOS_STATUS status = MOS_SecureMemcpy(&iqMatrixParams->ScalingList4x4,
6 * 16 * sizeof(uint8_t),
&m_scalingLists4x4,
6 * 16 * sizeof(uint8_t));
if (MOS_STATUS_SUCCESS != status)
{
DDI_ASSERTMESSAGE("DDI:Failed to copy scaling list 4x4!");
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
status = MOS_SecureMemcpy(&iqMatrixParams->ScalingList8x8,
2 * 64 * sizeof(uint8_t),
&m_scalingLists8x8,
2 * 64 * sizeof(uint8_t));
if (MOS_STATUS_SUCCESS != status)
{
DDI_ASSERTMESSAGE("DDI:Failed to copy scaling list 8x8!");
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
encodeParams->pIQMatrixBuffer = iqMatrixParams;
status = MOS_SecureMemcpy(&iqWeightScaleLists->WeightScale4x4,
(CODEC_AVC_WEIGHT_SCALE_4x4 * sizeof(uint32_t)),
&m_weightScale4x4,
(CODEC_AVC_WEIGHT_SCALE_4x4 * sizeof(uint32_t)));
if (MOS_STATUS_SUCCESS != status)
{
DDI_ASSERTMESSAGE("DDI:Failed to copy weight scale list 4x4!");
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
status = MOS_SecureMemcpy(&iqWeightScaleLists->WeightScale8x8,
(CODEC_AVC_WEIGHT_SCALE_8x8 * sizeof(uint32_t)),
&m_weightScale8x8,
(CODEC_AVC_WEIGHT_SCALE_8x8 * sizeof(uint32_t)));
if (MOS_STATUS_SUCCESS != status)
{
DDI_ASSERTMESSAGE("DDI:Failed to copy weight scale list 8x8!");
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
encodeParams->pIQWeightScaleLists = iqWeightScaleLists;
// whether driver need to pack slice header
if (true == m_encodeCtx->bHavePackedSliceHdr)
{
encodeParams->bAcceleratorHeaderPackingCaps = false;
}
else
{
encodeParams->bAcceleratorHeaderPackingCaps = true;
}
encodeParams->pBSBuffer = m_encodeCtx->pbsBuffer;
encodeParams->pSlcHeaderData = (void *)m_encodeCtx->pSliceHeaderData;
CodechalEncoderState *encoder = dynamic_cast<CodechalEncoderState *>(m_encodeCtx->pCodecHal);
DDI_CHK_NULL(encoder, "nullptr Codechal encode", VA_STATUS_ERROR_INVALID_PARAMETER);
if (!encoder->m_mfeEnabled)
{
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 DdiEncodeAvc::ResetAtFrameLevel()
{
DDI_CHK_NULL(m_encodeCtx, "nullptr m_encodeCtx", VA_STATUS_ERROR_INVALID_PARAMETER);
// Assume there is only one SPS parameter
PCODEC_AVC_ENCODE_SEQUENCE_PARAMS seqParams = (PCODEC_AVC_ENCODE_SEQUENCE_PARAMS)(m_encodeCtx->pSeqParams);
seqParams->bInitBRC = 0x0;
seqParams->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;
// clear the packed header information
if (nullptr != m_encodeCtx->ppNALUnitParams)
{
MOS_ZeroMemory(m_encodeCtx->ppNALUnitParams[0], sizeof(CODECHAL_NAL_UNIT_PARAMS) * CODECHAL_ENCODE_AVC_MAX_NAL_TYPE);
}
m_encodeCtx->bHavePackedSliceHdr = false;
m_encodeCtx->bLastPackedHdrIsSlice = false;
m_encodeCtx->bMbDisableSkipMapEnabled = false;
m_encodeCtx->bMBQpEnable = false;
if (nullptr != m_roundingParams)
{
MOS_ZeroMemory(m_roundingParams, sizeof(CODECHAL_ENCODE_AVC_ROUNDING_PARAMS));
}
return VA_STATUS_SUCCESS;
}
VAStatus DdiEncodeAvc::Qmatrix(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);
VAIQMatrixBufferH264 *qm = (VAIQMatrixBufferH264 *)ptr;
MOS_STATUS status = MOS_SecureMemcpy((void *)&m_scalingLists4x4,
6 * 16 * sizeof(uint8_t),
(void *)&qm->ScalingList4x4,
6 * 16 * sizeof(uint8_t));
if (MOS_STATUS_SUCCESS != status)
{
DDI_ASSERTMESSAGE("Failed to copy QM scaling list 4x4.");
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
MOS_SecureMemcpy((void *)&m_scalingLists8x8,
2 * 64 * sizeof(uint8_t),
(void *)&qm->ScalingList8x8,
2 * 64 * sizeof(uint8_t));
if (MOS_STATUS_SUCCESS != status)
{
DDI_ASSERTMESSAGE("Failed to copy QM scaling list 8x8.");
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
uint8_t idx1, idx2;
// 4x4 block
for (idx2 = 0; idx2 < 6; idx2++)
{
for (idx1 = 0; idx1 < 16; idx1++)
{
m_weightScale4x4[idx2][CODEC_AVC_Qmatrix_scan_4x4[idx1]] = qm->ScalingList4x4[idx2][idx1];
}
}
// 8x8 block
for (idx2 = 0; idx2 < 2; idx2++)
{
for (idx1 = 0; idx1 < 64; idx1++)
{
m_weightScale8x8[idx2][CODEC_AVC_Qmatrix_scan_8x8[idx1]] = qm->ScalingList8x8[idx2][idx1];
}
}
return VA_STATUS_SUCCESS;
}
VAStatus DdiEncodeAvc::ParseSeqParams(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);
VAEncSequenceParameterBufferH264 *seq = (VAEncSequenceParameterBufferH264 *)ptr;
PCODEC_AVC_ENCODE_SEQUENCE_PARAMS seqParams = (PCODEC_AVC_ENCODE_SEQUENCE_PARAMS)((uint8_t *)m_encodeCtx->pSeqParams + seq->seq_parameter_set_id * sizeof(CODEC_AVC_ENCODE_SEQUENCE_PARAMS));
if (seq->seq_parameter_set_id >= CODEC_AVC_MAX_SPS_NUM)
{
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
seqParams->FrameWidth = seq->picture_width_in_mbs * 16;
seqParams->FrameHeight = seq->picture_height_in_mbs * 16;
if ((seq->picture_width_in_mbs <= m_encodeCtx->wContextPicWidthInMB) && (seq->picture_height_in_mbs <= m_encodeCtx->wContextPicHeightInMB) && (seq->picture_width_in_mbs != m_encodeCtx->wOriPicWidthInMB) && (seq->picture_height_in_mbs != m_encodeCtx->wOriPicHeightInMB))
{
m_encodeCtx->wPicWidthInMB = seq->picture_width_in_mbs;
m_encodeCtx->wPicHeightInMB = seq->picture_height_in_mbs;
m_encodeCtx->wOriPicWidthInMB = m_encodeCtx->wPicWidthInMB;
m_encodeCtx->wOriPicHeightInMB = m_encodeCtx->wPicHeightInMB;
seqParams->bInitBRC = true;
}
else if ((seq->picture_width_in_mbs > m_encodeCtx->wContextPicWidthInMB) || (seq->picture_height_in_mbs > m_encodeCtx->wContextPicHeightInMB))
{
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
seqParams->Profile = GetAVCProfileFromVAProfile();
seqParams->Level = seq->level_idc;
seqParams->seq_parameter_set_id = seq->seq_parameter_set_id;
seqParams->chroma_format_idc = 1;
seqParams->bit_depth_luma_minus8 = seq->bit_depth_luma_minus8;
seqParams->bit_depth_chroma_minus8 = seq->bit_depth_chroma_minus8;
seqParams->GopPicSize = seq->intra_period;
seqParams->GopRefDist = seq->ip_period;
seqParams->RateControlMethod = VARC2HalRC(m_encodeCtx->uiRCMethod);
seqParams->TargetBitRate = seq->bits_per_second;
seqParams->MaxBitRate = seq->bits_per_second;
seqParams->MinBitRate = seq->bits_per_second;
// fps it set to 30 by default, can be overwritten by misc paramter
if(!seqParams->FramesPer100Sec)
{
seqParams->FramesPer100Sec = 3000;
}
// set default same as MSDK, can be overwritten by HRD params
seqParams->InitVBVBufferFullnessInBit = seq->bits_per_second;
seqParams->VBVBufferSizeInBit = seq->bits_per_second << 1;
seqParams->NumRefFrames = seq->max_num_ref_frames;
seqParams->log2_max_frame_num_minus4 = seq->seq_fields.bits.log2_max_frame_num_minus4;
seqParams->pic_order_cnt_type = seq->seq_fields.bits.pic_order_cnt_type;
seqParams->log2_max_pic_order_cnt_lsb_minus4 = seq->seq_fields.bits.log2_max_pic_order_cnt_lsb_minus4;
seqParams->num_ref_frames_in_pic_order_cnt_cycle = seq->num_ref_frames_in_pic_order_cnt_cycle;
seqParams->delta_pic_order_always_zero_flag = seq->seq_fields.bits.delta_pic_order_always_zero_flag;
seqParams->direct_8x8_inference_flag = seq->seq_fields.bits.direct_8x8_inference_flag;
seqParams->vui_parameters_present_flag = seq->vui_parameters_present_flag;
seqParams->frame_mbs_only_flag = seq->seq_fields.bits.frame_mbs_only_flag;
seqParams->offset_for_non_ref_pic = seq->offset_for_non_ref_pic;
seqParams->offset_for_top_to_bottom_field = seq->offset_for_top_to_bottom_field;
for (uint8_t i = 0; i < seqParams->num_ref_frames_in_pic_order_cnt_cycle; i++)
{
seqParams->offset_for_ref_frame[i] = seq->offset_for_ref_frame[i];
}
seqParams->frame_cropping_flag = seq->frame_cropping_flag;
seqParams->frame_crop_bottom_offset = seq->frame_crop_bottom_offset;
seqParams->frame_crop_left_offset = seq->frame_crop_left_offset;
seqParams->frame_crop_right_offset = seq->frame_crop_right_offset;
seqParams->frame_crop_top_offset = seq->frame_crop_top_offset;
// set up VUI parameter if rate control is enabled
if (seqParams->vui_parameters_present_flag)
{
CODECHAL_ENCODE_AVC_VUI_PARAMS *vuiParam;
vuiParam = (CODECHAL_ENCODE_AVC_VUI_PARAMS *)m_encodeCtx->pVuiParams;
vuiParam->nal_hrd_parameters_present_flag = 1;
vuiParam->cpb_cnt_minus1 = 0;
vuiParam->bit_rate_scale = 0;
vuiParam->cpb_size_scale = 6;
vuiParam->bit_rate_value_minus1[0] = MOS_ROUNDUP_SHIFT(seq->bits_per_second, 6 + vuiParam->bit_rate_scale) - 1;
vuiParam->cpb_size_value_minus1[0] = MOS_ROUNDUP_DIVIDE(seqParams->VBVBufferSizeInBit, vuiKbps) - 1;
vuiParam->cbr_flag = 0x0;
vuiParam->initial_cpb_removal_delay_length_minus1 = 23;
vuiParam->cpb_removal_delay_length_minus1 = 23;
vuiParam->dpb_output_delay_length_minus1 = 23;
vuiParam->time_offset_length = 24;
vuiParam->timing_info_present_flag = seq->vui_fields.bits.timing_info_present_flag;
vuiParam->num_units_in_tick = seq->num_units_in_tick;
vuiParam->time_scale = seq->time_scale;
vuiParam->fixed_frame_rate_flag = 1;
vuiParam->bitstream_restriction_flag = seq->vui_fields.bits.bitstream_restriction_flag;
vuiParam->motion_vectors_over_pic_boundaries_flag = 1;
vuiParam->max_bytes_per_pic_denom = 2;
vuiParam->max_bits_per_mb_denom = 1;
vuiParam->max_dec_frame_buffering = seq->max_num_ref_frames + 1;
vuiParam->num_reorder_frames = seq->max_num_ref_frames;
vuiParam->log2_max_mv_length_horizontal = seq->vui_fields.bits.log2_max_mv_length_horizontal;
vuiParam->log2_max_mv_length_vertical = seq->vui_fields.bits.log2_max_mv_length_vertical;
}
return VA_STATUS_SUCCESS;
}
VAStatus DdiEncodeAvc::ParsePicParams(
PDDI_MEDIA_CONTEXT mediaCtx,
void *ptr)
{
DDI_CHK_NULL(mediaCtx, "nullptr mediaCtx", VA_STATUS_ERROR_INVALID_PARAMETER);
DDI_CHK_NULL(m_encodeCtx, "nullptr m_encodeCtx", VA_STATUS_ERROR_INVALID_PARAMETER);
DDI_CHK_NULL(ptr, "nullptr ptr", VA_STATUS_ERROR_INVALID_PARAMETER);
VAEncPictureParameterBufferH264 *pic = (VAEncPictureParameterBufferH264 *)ptr;
PCODEC_AVC_ENCODE_PIC_PARAMS picParams = (PCODEC_AVC_ENCODE_PIC_PARAMS)((uint8_t *)m_encodeCtx->pPicParams + pic->pic_parameter_set_id * sizeof(CODEC_AVC_ENCODE_PIC_PARAMS));
DDI_CHK_NULL(picParams, "nullptr picParams", VA_STATUS_ERROR_INVALID_PARAMETER);
current_pic_parameter_set_id = pic->pic_parameter_set_id;
current_seq_parameter_set_id = pic->seq_parameter_set_id;
MOS_ZeroMemory(picParams, sizeof(CODEC_AVC_ENCODE_PIC_PARAMS));
PCODEC_AVC_ENCODE_SEQUENCE_PARAMS seqParams = (PCODEC_AVC_ENCODE_SEQUENCE_PARAMS)((uint8_t *)m_encodeCtx->pSeqParams + pic->seq_parameter_set_id * sizeof(CODEC_AVC_ENCODE_SEQUENCE_PARAMS));
if ((pic->seq_parameter_set_id >= CODEC_AVC_MAX_SPS_NUM) ||
(pic->pic_parameter_set_id >= CODEC_AVC_MAX_PPS_NUM))
{
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
if (pic->CurrPic.flags == VA_PICTURE_H264_TOP_FIELD ||
pic->CurrPic.flags == VA_PICTURE_H264_BOTTOM_FIELD)
{
picParams->FieldCodingFlag = 1;
}
if (pic->CurrPic.picture_id != VA_INVALID_SURFACE)
{
RegisterRTSurfaces(&(m_encodeCtx->RTtbl),
DdiMedia_GetSurfaceFromVASurfaceID(mediaCtx,
pic->CurrPic.picture_id));
}
// Curr Recon Pic
SetupCodecPicture(mediaCtx, &(m_encodeCtx->RTtbl), &picParams->CurrReconstructedPic,pic->CurrPic, picParams->FieldCodingFlag, false, false);
DDI_CODEC_RENDER_TARGET_TABLE *rtTbl = &(m_encodeCtx->RTtbl);
rtTbl->pCurrentReconTarget = DdiMedia_GetSurfaceFromVASurfaceID(mediaCtx, pic->CurrPic.picture_id);
// The surface for reconstructed frame is not registered, return error to app
if (nullptr == rtTbl->pCurrentReconTarget)
{
DDI_ASSERTMESSAGE("invalid surface for reconstructed frame");
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
// curr orig pic
// Hard to understand here!
picParams->CurrOriginalPic.FrameIdx = (uint8_t)GetRenderTargetID(rtTbl, rtTbl->pCurrentReconTarget);
picParams->CurrOriginalPic.PicFlags = picParams->CurrReconstructedPic.PicFlags;
// The surface for reconstructed frame is not registered, return error to app
if (picParams->CurrOriginalPic.FrameIdx == 0xFF)
{
DDI_ASSERTMESSAGE("unregistered surface for reconstructed frame");
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
// RefFrame List
for (uint32_t i = 0; i < DDI_CODEC_NUM_MAX_REF_FRAME; i++)
{
if(pic->ReferenceFrames[i].picture_id!= VA_INVALID_SURFACE)
{
UpdateRegisteredRTSurfaceFlag(&(m_encodeCtx->RTtbl),
DdiMedia_GetSurfaceFromVASurfaceID(mediaCtx,
pic->ReferenceFrames[i].picture_id));
}
SetupCodecPicture(mediaCtx, &(m_encodeCtx->RTtbl), &(picParams->RefFrameList[i]), pic->ReferenceFrames[i], picParams->FieldCodingFlag, true, false);
}
for (uint32_t i = 0; i < DDI_CODEC_NUM_MAX_REF_FRAME; i++)
{
picParams->FieldOrderCntList[i][0] = pic->ReferenceFrames[i].TopFieldOrderCnt;
picParams->FieldOrderCntList[i][1] = pic->ReferenceFrames[i].BottomFieldOrderCnt;
}
picParams->seq_parameter_set_id = pic->seq_parameter_set_id;
picParams->pic_parameter_set_id = pic->pic_parameter_set_id;
/* pic->coding_type; App is always setting this to 0 */
picParams->CodingType = I_TYPE;
picParams->second_chroma_qp_index_offset = pic->second_chroma_qp_index_offset;
picParams->num_ref_idx_l0_active_minus1 = pic->num_ref_idx_l0_active_minus1;
picParams->num_ref_idx_l1_active_minus1 = pic->num_ref_idx_l1_active_minus1;
picParams->QpY = pic->pic_init_qp;
if (pic->CurrPic.flags == VA_PICTURE_H264_SHORT_TERM_REFERENCE ||
pic->CurrPic.flags == VA_PICTURE_H264_LONG_TERM_REFERENCE)
{
picParams->UsedForReferenceFlags = 1;
}
picParams->CurrFieldOrderCnt[0] = pic->CurrPic.TopFieldOrderCnt;
picParams->CurrFieldOrderCnt[1] = pic->CurrPic.BottomFieldOrderCnt;
picParams->frame_num = pic->frame_num;
picParams->bLastPicInSeq = (pic->last_picture & H264_LAST_PICTURE_EOSEQ) ? 1 : 0;
picParams->bLastPicInStream = (pic->last_picture & H264_LAST_PICTURE_EOSTREAM) ? 1 : 0;
picParams->chroma_qp_index_offset = pic->chroma_qp_index_offset;
picParams->bIdrPic = pic->pic_fields.bits.idr_pic_flag;
picParams->RefPicFlag = pic->pic_fields.bits.reference_pic_flag;
picParams->entropy_coding_mode_flag = pic->pic_fields.bits.entropy_coding_mode_flag;
picParams->weighted_pred_flag = pic->pic_fields.bits.weighted_pred_flag;
picParams->weighted_bipred_idc = pic->pic_fields.bits.weighted_bipred_idc;
picParams->constrained_intra_pred_flag = pic->pic_fields.bits.constrained_intra_pred_flag;
picParams->transform_8x8_mode_flag = pic->pic_fields.bits.transform_8x8_mode_flag;
picParams->pic_order_present_flag = pic->pic_fields.bits.pic_order_present_flag;
picParams->pic_scaling_matrix_present_flag = pic->pic_fields.bits.pic_scaling_matrix_present_flag;
picParams->bDisplayFormatSwizzle = NeedDisplayFormatSwizzle(rtTbl->pCurrentRT);
for (uint32_t i = 0; i < 12; i++)
{
picParams->pic_scaling_list_present_flag[i] = pic->pic_fields.bits.pic_scaling_matrix_present_flag;
}
// pps, sps header packing in app
//Slice header packing will be done in app where bDisableAccelaratorHeaderPacking flag is defaulted to 0
//this flag shouldnt be true for slice header packing
picParams->UserFlags.bDisableAcceleratorHeaderPacking = true;
picParams->UserFlags.bUseRawPicForRef = false; //true;
//Reset it to zero now
picParams->NumSlice = 0;
//Hardcode SFD mvThreshold to 80.
picParams->dwZMvThreshold = 80;
DDI_MEDIA_BUFFER *buf = DdiMedia_GetBufferFromVABufferID(mediaCtx, pic->coded_buf);
DDI_CHK_NULL(buf, "nullptr buf", VA_STATUS_ERROR_INVALID_PARAMETER);
// MSDK will re-use the buffer so need to remove before adding to status report again
RemoveFromStatusReportQueue(buf);
DdiMedia_MediaBufferToMosResource(buf, &(m_encodeCtx->resBitstreamBuffer));
return VA_STATUS_SUCCESS;
}
VAStatus DdiEncodeAvc::ParseSlcParams(
PDDI_MEDIA_CONTEXT mediaCtx,
void *ptr,
uint32_t numSlices)
{
DDI_CHK_NULL(mediaCtx, "nullptr mediaCtx", VA_STATUS_ERROR_INVALID_PARAMETER);
DDI_CHK_NULL(m_encodeCtx, "nullptr m_encodeCtx", VA_STATUS_ERROR_INVALID_PARAMETER);
DDI_CHK_NULL(ptr, "nullptr ptr", VA_STATUS_ERROR_INVALID_PARAMETER);
CodechalEncoderState *encoder = dynamic_cast<CodechalEncoderState *>(m_encodeCtx->pCodecHal);
DDI_CHK_NULL(encoder, "nullptr codehal encoder", VA_STATUS_ERROR_INVALID_CONTEXT);
VAEncSliceParameterBufferH264 *slc = (VAEncSliceParameterBufferH264 *)ptr;
PCODEC_AVC_ENCODE_SLICE_PARAMS slcParams = (CODEC_AVC_ENCODE_SLICE_PARAMS *)m_encodeCtx->pSliceParams;
PCODEC_AVC_ENCODE_PIC_PARAMS picParams = (PCODEC_AVC_ENCODE_PIC_PARAMS)((uint8_t *)m_encodeCtx->pPicParams + slc->pic_parameter_set_id * sizeof(CODEC_AVC_ENCODE_PIC_PARAMS));
DDI_CHK_NULL(slcParams, "nullptr slcParams", VA_STATUS_ERROR_INVALID_PARAMETER);
DDI_CHK_NULL(picParams, "nullptr picParams", VA_STATUS_ERROR_INVALID_PARAMETER);
uint8_t numSlcs = 0;
uint32_t totalMBs = m_encodeCtx->wPicWidthInMB * m_encodeCtx->wPicHeightInMB;
uint32_t usedMBs = 0;
uint32_t mBScalerForField = 1; //related with frame/field coding
uint32_t sliceHeightInMB = 1;
uint32_t sliceActualMBs = 0;
if (slc->pic_parameter_set_id >= CODEC_AVC_MAX_PPS_NUM)
{
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
numSlcs = picParams->NumSlice;
if (numSlcs == 0)
{
picParams->CodingType = CodechalPicTypeFromVaSlcType(slc->slice_type);
}
// Disable rolling intra refresh if not a P-type picture
if ((picParams->EnableRollingIntraRefresh != ROLLING_I_DISABLED) && (picParams->CodingType != P_TYPE))
{
picParams->EnableRollingIntraRefresh = ROLLING_I_DISABLED;
m_encodeCtx->uiIntraRefreshFrameCnt = 0;
m_encodeCtx->uiIntraRefreshMBx = 0;
m_encodeCtx->uiIntraRefreshMBy = 0;
}
slcParams += numSlcs;
MOS_ZeroMemory(
slcParams,
numSlices * sizeof(CODEC_AVC_ENCODE_SLICE_PARAMS));
if (numSlcs != 0)
{
slcParams--;
usedMBs = (slcParams->NumMbsForSlice + slcParams->first_mb_in_slice) / mBScalerForField;
if (usedMBs >= totalMBs)
{
return VA_STATUS_SUCCESS;
}
slcParams++;
}
uint32_t slcCount;
uint32_t i;
for (slcCount = 0; slcCount < numSlices; slcCount++)
{
if (usedMBs >= totalMBs)
break;
sliceActualMBs = slc->num_macroblocks;
if (sliceActualMBs % m_encodeCtx->wPicWidthInMB) // If any slice is a partial row of macroblocks, then set flag to indicate sliceMapSurface is required.
{
m_arbitraryNumMbsInSlice = 1;
}
if (sliceActualMBs + usedMBs > totalMBs)
sliceActualMBs = totalMBs - usedMBs;
slcParams->NumMbsForSlice = sliceActualMBs * mBScalerForField;
slcParams->first_mb_in_slice = usedMBs * mBScalerForField;
usedMBs += sliceActualMBs;
slcParams->slice_type = slc->slice_type;
slcParams->pic_parameter_set_id = slc->pic_parameter_set_id;
slcParams->idr_pic_id = slc->idr_pic_id;
slcParams->pic_order_cnt_lsb = slc->pic_order_cnt_lsb;
slcParams->delta_pic_order_cnt_bottom = slc->delta_pic_order_cnt_bottom;
slcParams->delta_pic_order_cnt[0] = slc->delta_pic_order_cnt[0];
slcParams->delta_pic_order_cnt[1] = slc->delta_pic_order_cnt[1];
slcParams->direct_spatial_mv_pred_flag = slc->direct_spatial_mv_pred_flag;
slcParams->num_ref_idx_active_override_flag = slc->num_ref_idx_active_override_flag;
slcParams->num_ref_idx_l0_active_minus1 = slc->num_ref_idx_l0_active_minus1;
slcParams->num_ref_idx_l1_active_minus1 = slc->num_ref_idx_l1_active_minus1;
slcParams->luma_log2_weight_denom = slc->luma_log2_weight_denom;
slcParams->chroma_log2_weight_denom = slc->chroma_log2_weight_denom;
slcParams->cabac_init_idc = slc->cabac_init_idc;
slcParams->slice_qp_delta = slc->slice_qp_delta;
slcParams->disable_deblocking_filter_idc = slc->disable_deblocking_filter_idc;
slcParams->slice_alpha_c0_offset_div2 = slc->slice_alpha_c0_offset_div2;
slcParams->slice_beta_offset_div2 = slc->slice_beta_offset_div2;
slcParams->num_ref_idx_l0_active_minus1_from_DDI = slcParams->num_ref_idx_l0_active_minus1;
slcParams->num_ref_idx_l1_active_minus1_from_DDI = slcParams->num_ref_idx_l1_active_minus1;
slcParams->slice_id = numSlcs + slcCount;
slcParams->luma_weight_flag[0] = slc->luma_weight_l0_flag;
slcParams->chroma_weight_flag[0] = slc->chroma_weight_l0_flag;
slcParams->luma_weight_flag[1] = slc->luma_weight_l1_flag;
slcParams->chroma_weight_flag[1] = slc->chroma_weight_l1_flag;
for (i = 0; i < 32; i++)
{
// list 0
if ((slc->luma_weight_l0_flag) &&
((slc->luma_weight_l0[i] != 0) || (slc->luma_offset_l0[i] != 0)))
{
slcParams->Weights[0][i][0][0] = slc->luma_weight_l0[i]; // Y weight
slcParams->Weights[0][i][0][1] = slc->luma_offset_l0[i]; // Y offset
}
else
{
slcParams->Weights[0][i][0][0] = 1 << slcParams->luma_log2_weight_denom; // Y weight
slcParams->Weights[0][i][0][1] = 0; // Y offset
}
if ((slc->chroma_weight_l0_flag) &&
((slc->chroma_weight_l0[i][0] != 0) || (slc->chroma_offset_l0[i][0] != 0) ||
(slc->chroma_weight_l0[i][1] != 0) || (slc->chroma_offset_l0[i][1] != 0)))
{
slcParams->Weights[0][i][1][0] = slc->chroma_weight_l0[i][0]; // Cb weight
slcParams->Weights[0][i][1][1] = slc->chroma_offset_l0[i][0]; // Cb offset
slcParams->Weights[0][i][2][0] = slc->chroma_weight_l0[i][1]; // Cr weight
slcParams->Weights[0][i][2][1] = slc->chroma_offset_l0[i][1]; // Cr offset
}
else
{
slcParams->Weights[0][i][1][0] = 1; // Cb weight
slcParams->Weights[0][i][1][1] = 0; // Cb offset
slcParams->Weights[0][i][2][0] = 1; // Cr weight
slcParams->Weights[0][i][2][1] = 0; // Cr offset
}
// list 1
if ((slc->luma_weight_l1_flag) &&
((slc->luma_weight_l1[i] != 0) || (slc->luma_offset_l1[i] != 0)))
{
slcParams->Weights[1][i][0][0] = slc->luma_weight_l1[i]; // Y weight
slcParams->Weights[1][i][0][1] = slc->luma_offset_l1[i]; // Y offset
}
else
{
slcParams->Weights[1][i][0][0] = 1 << slcParams->luma_log2_weight_denom; // Y weight
slcParams->Weights[1][i][0][1] = 0; // Y offset
}
if ((slc->chroma_weight_l1_flag) &&
((slc->chroma_weight_l1[i][0] != 0) || (slc->chroma_offset_l1[i][0] != 0) ||
(slc->chroma_weight_l1[i][1] != 0) || (slc->chroma_offset_l1[i][1] != 0)))
{
slcParams->Weights[1][i][1][0] = slc->chroma_weight_l1[i][0]; // Cb weight
slcParams->Weights[1][i][1][1] = slc->chroma_offset_l1[i][0]; // Cb offset
slcParams->Weights[1][i][2][0] = slc->chroma_weight_l1[i][1]; // Cr weight
slcParams->Weights[1][i][2][1] = slc->chroma_offset_l1[i][1]; // Cr offset
}
else
{
slcParams->Weights[1][i][1][0] = 1; // Cb weight
slcParams->Weights[1][i][1][1] = 0; // Cb offset
slcParams->Weights[1][i][2][0] = 1; // Cr weight
slcParams->Weights[1][i][2][1] = 0; // Cr offset
}
}
for (i = 0; i < CODEC_MAX_NUM_REF_FIELD; i++)
{
SetupCodecPicture(mediaCtx, &(m_encodeCtx->RTtbl), &(slcParams->RefPicList[0][i]), slc->RefPicList0[i], picParams->FieldCodingFlag, false, true);
GetSlcRefIdx(&(picParams->RefFrameList[0]), &(slcParams->RefPicList[0][i]));
}
for (i = 0; i < CODEC_MAX_NUM_REF_FIELD; i++)
{
SetupCodecPicture(mediaCtx, &(m_encodeCtx->RTtbl), &(slcParams->RefPicList[1][i]), slc->RefPicList1[i], picParams->FieldCodingFlag, false, true);
GetSlcRefIdx(&(picParams->RefFrameList[0]), &(slcParams->RefPicList[1][i]));
}
slc++;
slcParams++;
}
picParams->NumSlice += slcCount;
if (picParams->NumSlice > ENCODE_AVC_MAX_SLICES_SUPPORTED)
{
DDI_ASSERTMESSAGE("Number of slices exceeds max supported");
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
m_encodeCtx->dwNumSlices = picParams->NumSlice;
return VA_STATUS_SUCCESS;
}
VAStatus DdiEncodeAvc::FindNalUnitStartCodes(
uint8_t * buf,
uint32_t size,
uint32_t * startCodesOffset,
uint32_t * startCodesLength)
{
uint8_t i = 0;
while (((i + 3) < size) &&
(buf[i] != 0 || buf[i+1] != 0 || buf[i+2] != 0x01) &&
(buf[i] != 0 || buf[i+1] != 0 || buf[i+2] != 0 || buf[i+3] != 0x01))
{
i++;
}
if ((i + 3) == size)
{
if (buf[i] != 0 || buf[i+1] != 0 || buf[i+2] != 0x01)
{
return VA_STATUS_ERROR_INVALID_BUFFER; //NALU start codes doesn't exit
}
else
{
*startCodesOffset = size - 3;
*startCodesLength = 3;
return VA_STATUS_SUCCESS;
}
}
if (buf[i] != 0 || buf[i+1] != 0 || buf[i+2] != 0x01)
{
*startCodesOffset = i;
*startCodesLength = 4;
}
else
{
*startCodesOffset = i;
*startCodesLength = 3;
}
return VA_STATUS_SUCCESS;
}
VAStatus DdiEncodeAvc::ParsePackedHeaderParams(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);
m_encodeCtx->bLastPackedHdrIsSlice = false;
VAEncPackedHeaderParameterBuffer *encPackedHeaderParamBuf = (VAEncPackedHeaderParameterBuffer *)ptr;
CODECHAL_ENCODE_AVC_NAL_UNIT_TYPE nalUnitType;
if (encPackedHeaderParamBuf->type == VAEncPackedHeaderH264_SPS)
{
nalUnitType = CODECHAL_ENCODE_AVC_NAL_UT_SPS;
m_newSeqHeader = 1;
}
else if (encPackedHeaderParamBuf->type == VAEncPackedHeaderH264_PPS)
{
nalUnitType = CODECHAL_ENCODE_AVC_NAL_UT_PPS;
m_newPpsHeader = 1;
}
else if (encPackedHeaderParamBuf->type == VAEncPackedHeaderH264_Slice)
{
nalUnitType = CODECHAL_ENCODE_AVC_NAL_UT_SLICE;
m_encodeCtx->bLastPackedHdrIsSlice = true;
m_encodeCtx->bHavePackedSliceHdr = true;
// check the slice header number. Max supported is AVC_ENCODE_MAX_SLICES_SUPPORTED
if (m_encodeCtx->uiSliceHeaderCnt >= ENCODE_AVC_MAX_SLICES_SUPPORTED)
{
DDI_ASSERTMESSAGE("Number of slices exceeds max supported");
return VA_STATUS_ERROR_MAX_NUM_EXCEEDED;
}
// get the packed header size
m_encodeCtx->pSliceHeaderData[m_encodeCtx->uiSliceHeaderCnt].BitSize = encPackedHeaderParamBuf->bit_length;
//don't know NALU start codes now, assign to 4 here when has_emulation_bytes is 0 and later will correct it
m_encodeCtx->pSliceHeaderData[m_encodeCtx->uiSliceHeaderCnt].SkipEmulationByteCount = (encPackedHeaderParamBuf->has_emulation_bytes) ? (encPackedHeaderParamBuf->bit_length + 7) / 8 : 4;
}
else if (encPackedHeaderParamBuf->type == VAEncPackedHeaderRawData)
{
// currently RawData is packed nal unit beside SPS,PPS,SLICE HEADER etc.
// use AUD just because we need a Type to distinguish with Slice header
nalUnitType = CODECHAL_ENCODE_AVC_NAL_UT_AUD;
}
else
{
nalUnitType = CODECHAL_ENCODE_AVC_MAX_NAL_TYPE;
}
if (encPackedHeaderParamBuf->type != VAEncPackedHeaderH264_Slice)
{
m_encodeCtx->ppNALUnitParams[m_encodeCtx->indexNALUnit]->uiNalUnitType = nalUnitType;
m_encodeCtx->ppNALUnitParams[m_encodeCtx->indexNALUnit]->bInsertEmulationBytes = (encPackedHeaderParamBuf->has_emulation_bytes) ? false : true;
//don't know NALU start codes now, assign to 4 here when has_emulation_bytes is 0 and later will correct it
m_encodeCtx->ppNALUnitParams[m_encodeCtx->indexNALUnit]->uiSkipEmulationCheckCount = (encPackedHeaderParamBuf->has_emulation_bytes) ? (encPackedHeaderParamBuf->bit_length + 7) / 8 : 4;
m_encodeCtx->ppNALUnitParams[m_encodeCtx->indexNALUnit]->uiSize = (encPackedHeaderParamBuf->bit_length + 7) / 8;
m_encodeCtx->ppNALUnitParams[m_encodeCtx->indexNALUnit]->uiOffset = 0;
}
return VA_STATUS_SUCCESS;
}
AvcOutBits::AvcOutBits(uint8_t *pOutBits, uint32_t BitSize)
{
m_pOutBits = pOutBits;
m_BitSize = BitSize;
m_BitOffset = 0;
}
inline uint32_t AvcOutBits::GetBitOffset()
{
return m_BitOffset;
}
void AvcOutBits::PutBit(uint32_t v)
{
DDI_ASSERT(m_BitOffset + 1 <= m_BitSize);
uint32_t LeftOffset = m_BitOffset % 8;
uint8_t *p = m_pOutBits + m_BitOffset / 8;
(*p) |= ((v & 1) << (7 - LeftOffset));
m_BitOffset++;
}
void AvcOutBits::PutBits(uint32_t v, uint32_t n)
{
DDI_ASSERT((n > 0) && (n <= 32));
uint32_t t = 0;
if (!(m_BitOffset % 8) && !(n % 8))
{
uint32_t nBytes = n / 8;
uint8_t *p = m_pOutBits + m_BitOffset / 8;
while (nBytes-- > 0)
(*p++) = (v >> nBytes) & 0xFF;
m_BitOffset += n;
return;
}
while (n-- > 0)
PutBit((v >> n) & 1);
}
AvcInBits::AvcInBits(uint8_t *pInBits, uint32_t BitSize)
{
m_pInBits = pInBits;
m_BitSize = BitSize;
m_BitOffset = 0;
}
void AvcInBits::SkipBits(uint32_t n)
{
DDI_ASSERT(n > 0);
DDI_ASSERT(m_BitOffset + n <= m_BitSize);
m_BitOffset += n;
}
uint32_t AvcInBits::GetBit()
{
DDI_ASSERT(m_BitOffset + 1 <= m_BitSize);
uint32_t LeftOffset = m_BitOffset % 8;
uint8_t const *p = m_pInBits + m_BitOffset / 8;
uint32_t v = (*p >> (7 - LeftOffset)) & 1;
m_BitOffset++;
return v;
}
uint32_t AvcInBits::GetBits(uint32_t n)
{
DDI_ASSERT((n > 0) && (n <= 32));
uint32_t v = 0;
if (!(m_BitOffset % 8) && !(n % 8))
{
uint32_t nBytes = n / 8;
uint8_t const *p = m_pInBits + m_BitOffset / 8;
while (nBytes-- > 0)
v = (v << 8) | (*p++);
m_BitOffset += n;
return v;
}
while (n-- > 0)
v = (v << 1) | GetBit();
return v;
}
uint32_t AvcInBits::AvcInBits::GetUE()
{
uint32_t nZero = 0;
while(!GetBit())
nZero++;
return nZero ? ((1 << nZero) | GetBits(nZero)) - 1 : 0;
}
inline uint32_t AvcInBits::GetBitOffset()
{
return m_BitOffset;
}
inline void AvcInBits::ResetBitOffset()
{
m_BitOffset = 0;
}
MOS_STATUS DdiEncodeAvc::CheckPackedSlcHeaderData(
void *pInSlcHdr,
uint32_t InBitSize,
void **ppOutSlcHdr,
uint32_t &OutBitSize)
{
MOS_STATUS status;
uint32_t HdrBitSize = 0;
*ppOutSlcHdr = NULL;
OutBitSize = 0;
if (VAEntrypointEncSliceLP != m_encodeCtx->vaEntrypoint)
return MOS_STATUS_SUCCESS;
if (0 == InBitSize || NULL == pInSlcHdr)
return MOS_STATUS_SUCCESS;
AvcInBits InBits((uint8_t*)pInSlcHdr, InBitSize);
// Skip start code
uint8_t StartCode = 0;
while (1 != StartCode) {
StartCode = InBits.GetBits(8);
HdrBitSize += 8;
}
uint32_t StartBitSize = HdrBitSize;
// Check NAL Unit type
HdrBitSize += 8;
InBits.SkipBits(1);
InBits.SkipBits(2);
uint32_t nalUnitType = InBits.GetBits(5);
if (20 == nalUnitType)
{
// MVC enxtension
InBits.SkipBits(24);
HdrBitSize += 24;
}
// find first_mb_in_slice
uint32_t first_mb_in_slice = InBits.GetUE();
if (0 == first_mb_in_slice)
return MOS_STATUS_SUCCESS;
// Force first_mb_in_slice to 0 for AVC VDENC
uint32_t LeftBitSize = InBitSize - InBits.GetBitOffset();
OutBitSize = LeftBitSize + HdrBitSize + 1;
*ppOutSlcHdr = MOS_AllocAndZeroMemory((OutBitSize + 7) / 8);
AvcOutBits OutBits((uint8_t*)(*ppOutSlcHdr), OutBitSize);
InBits.ResetBitOffset();
OutBits.PutBits(InBits.GetBits(StartBitSize), StartBitSize);
OutBits.PutBits(InBits.GetBits(8), 8);
if (20 == nalUnitType)
OutBits.PutBits(InBits.GetBits(24), 24);
// Replace first_mb_in_slice
first_mb_in_slice = InBits.GetUE();
OutBits.PutBit(0);
// Copy the left data
while (LeftBitSize >= 32)
{
OutBits.PutBits(InBits.GetBits(32), 32);
LeftBitSize -= 32;
}
if (LeftBitSize)
OutBits.PutBits(InBits.GetBits(LeftBitSize), LeftBitSize);
return MOS_STATUS_SUCCESS;
}
VAStatus DdiEncodeAvc::ParsePackedHeaderData(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);
BSBuffer *bsBuffer = m_encodeCtx->pbsBuffer;
DDI_CHK_NULL(bsBuffer, "nullptr bsBuffer", VA_STATUS_ERROR_INVALID_PARAMETER);
if ((m_encodeCtx->indexNALUnit == 0) && (m_encodeCtx->uiSliceHeaderCnt == 0))
{
*(bsBuffer->pBase) = 0;
bsBuffer->pCurrent = bsBuffer->pBase;
bsBuffer->SliceOffset = 0;
bsBuffer->BitOffset = 0;
bsBuffer->BitSize = 0;
}
uint32_t hdrDataSize;
if (true == m_encodeCtx->bLastPackedHdrIsSlice)
{
void *temp_ptr = NULL;
uint32_t temp_size = 0;
MOS_STATUS status = CheckPackedSlcHeaderData(ptr,
m_encodeCtx->pSliceHeaderData[m_encodeCtx->uiSliceHeaderCnt].BitSize,
&temp_ptr, temp_size);
if (MOS_STATUS_SUCCESS != status)
{
DDI_ASSERTMESSAGE("DDI:packed slice header is not supported!");
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
if (temp_size && temp_ptr)
{
m_encodeCtx->pSliceHeaderData[m_encodeCtx->uiSliceHeaderCnt].BitSize = temp_size;
}
hdrDataSize = (m_encodeCtx->pSliceHeaderData[m_encodeCtx->uiSliceHeaderCnt].BitSize + 7) / 8;
status = MOS_SecureMemcpy(bsBuffer->pCurrent,
bsBuffer->BufferSize - bsBuffer->SliceOffset,
(uint8_t *)(temp_ptr ? temp_ptr : ptr),
hdrDataSize);
if (MOS_STATUS_SUCCESS != status)
{
DDI_ASSERTMESSAGE("DDI:packed slice header size is too large to be supported!");
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
if (temp_size && temp_ptr)
{
MOS_FreeMemory(temp_ptr);
temp_size = 0;
temp_ptr = NULL;
}
m_encodeCtx->pSliceHeaderData[m_encodeCtx->uiSliceHeaderCnt].SliceOffset = bsBuffer->pCurrent - bsBuffer->pBase;
// correct SkipEmulationByteCount
// according to LibVA principle, one packed header buffer should only contain one NALU,
// so when has_emulation_bytes is 0, SkipEmulationByteCount only needs to skip the NALU start codes
if (m_encodeCtx->pSliceHeaderData[m_encodeCtx->uiSliceHeaderCnt].SkipEmulationByteCount != hdrDataSize)
{
uint32_t startCodesOffset = 0;
uint32_t startCodesLength = 0;
VAStatus vaSts = VA_STATUS_SUCCESS;
vaSts = FindNalUnitStartCodes((uint8_t *)ptr, hdrDataSize, &startCodesOffset, &startCodesLength);
if (VA_STATUS_SUCCESS != vaSts)
{
DDI_ASSERTMESSAGE("DDI: packed slice header doesn't include NAL unit start codes!");
return vaSts;
}
m_encodeCtx->pSliceHeaderData[m_encodeCtx->uiSliceHeaderCnt].SkipEmulationByteCount = MOS_MIN(15, (startCodesOffset + startCodesLength));
}
m_encodeCtx->uiSliceHeaderCnt++;
m_encodeCtx->bLastPackedHdrIsSlice = false;
}
else
{
// copy sps and pps header data
hdrDataSize = m_encodeCtx->ppNALUnitParams[m_encodeCtx->indexNALUnit]->uiSize;
MOS_STATUS status = MOS_SecureMemcpy(bsBuffer->pCurrent,
bsBuffer->BufferSize - bsBuffer->SliceOffset,
(uint8_t *)ptr,
hdrDataSize);
if (MOS_STATUS_SUCCESS != status)
{
DDI_ASSERTMESSAGE("DDI:packed header size is too large to be supported!");
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
// correct uiSkipEmulationCheckCount
// according to LibVA principle, one packed header buffer should only contain one NALU,
// so when has_emulation_bytes is 0, uiSkipEmulationCheckCount only needs to skip the NALU start codes
if (m_encodeCtx->ppNALUnitParams[m_encodeCtx->indexNALUnit]->uiSkipEmulationCheckCount != hdrDataSize)
{
uint32_t startCodesOffset = 0;
uint32_t startCodesLength = 0;
VAStatus vaSts = VA_STATUS_SUCCESS;
vaSts = FindNalUnitStartCodes((uint8_t *)ptr, hdrDataSize, &startCodesOffset, &startCodesLength);
if (VA_STATUS_SUCCESS != vaSts)
{
DDI_ASSERTMESSAGE("DDI: packed header doesn't include NAL unit start codes!");
return vaSts;
}
m_encodeCtx->ppNALUnitParams[m_encodeCtx->indexNALUnit]->uiSkipEmulationCheckCount = MOS_MIN(15, (startCodesOffset + startCodesLength));
}
m_encodeCtx->ppNALUnitParams[m_encodeCtx->indexNALUnit]->uiOffset = bsBuffer->pCurrent - bsBuffer->pBase;
m_encodeCtx->indexNALUnit++;
}
bsBuffer->pCurrent += hdrDataSize;
bsBuffer->SliceOffset += hdrDataSize;
bsBuffer->BitSize += hdrDataSize * 8;
return VA_STATUS_SUCCESS;
}
VAStatus DdiEncodeAvc::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);
VAEncMiscParameterBuffer *miscParamBuf = (VAEncMiscParameterBuffer *)ptr;
DDI_CHK_NULL(miscParamBuf->data, "nullptr miscParamBuf->data", VA_STATUS_ERROR_INVALID_PARAMETER);
VAStatus status = VA_STATUS_SUCCESS;
switch ((int32_t)(miscParamBuf->type))
{
case VAEncMiscParameterTypeHRD:
status = ParseMiscParamHRD((void *)miscParamBuf->data);
break;
case VAEncMiscParameterTypeFrameRate:
status = ParseMiscParamFR((void *)miscParamBuf->data);
break;
case VAEncMiscParameterTypeRateControl:
status = ParseMiscParamRC((void *)miscParamBuf->data);
break;
case VAEncMiscParameterTypeEncQuality:
status = ParseMiscParamEncQuality((void *)miscParamBuf->data);
break;
case VAEncMiscParameterTypeQuantization:
status = ParseMiscParamQuantization((void *)miscParamBuf->data);
break;
case VAEncMiscParameterTypeRIR:
status = ParseMiscParameterRIR((void *)miscParamBuf->data);
break;
case VAEncMiscParameterTypeSkipFrame:
status = ParseMiscParamSkipFrame((void *)miscParamBuf->data);
break;
case VAEncMiscParameterTypeMaxFrameSize:
status = ParseMiscParamMaxFrameSize((void *)miscParamBuf->data);
break;
case VAEncMiscParameterTypeMultiPassFrameSize:
status = ParseMiscParamMultiPassFrameSize((void *)miscParamBuf->data);
break;
case VAEncMiscParameterTypeQualityLevel:
status = ParseMiscParamQualityLevel((void *)miscParamBuf->data);
break;
case VAEncMiscParameterTypeMaxSliceSize:
status = ParseMiscParamMaxSliceSize((void *)miscParamBuf->data);
break;
case VAEncMiscParameterTypeROI:
status = ParseMiscParamROI((void *)miscParamBuf->data);
break;
case VAEncMiscParameterTypeDirtyRect:
status = ParseMiscParamDirtyROI((void *)miscParamBuf->data);
break;
case VAEncMiscParameterTypeCustomRoundingControl:
status = ParseMiscParamRounding((void *)miscParamBuf->data);
break;
case VAEncMiscParameterTypeSubMbPartPel:
status = ParseMiscParamSubMbPartPel((void *)miscParamBuf->data);
break;
default:
DDI_ASSERTMESSAGE("unsupported misc parameter type.");
status = VA_STATUS_ERROR_INVALID_PARAMETER;
break;
}
return status;
}
void DdiEncodeAvc::GetSlcRefIdx(CODEC_PICTURE *picReference, CODEC_PICTURE *slcReference)
{
if (nullptr == picReference || nullptr == slcReference)
{return;}
int32_t i = 0;
if (slcReference->FrameIdx != CODEC_AVC_NUM_UNCOMPRESSED_SURFACE)
{
for (i = 0; i < CODEC_MAX_NUM_REF_FRAME; i++)
{
if (slcReference->FrameIdx == picReference[i].FrameIdx)
{
slcReference->FrameIdx = i;
break;
}
}
if (i == CODEC_MAX_NUM_REF_FRAME)
{
slcReference->FrameIdx = CODEC_AVC_NUM_UNCOMPRESSED_SURFACE;
}
}
}
void DdiEncodeAvc::SetupCodecPicture(
DDI_MEDIA_CONTEXT *mediaCtx,
DDI_CODEC_RENDER_TARGET_TABLE *rtTbl,
CODEC_PICTURE *codecHalPic,
VAPictureH264 vaPic,
bool fieldPicFlag,
bool picReference,
bool sliceReference)
{
if(vaPic.picture_id != DDI_CODEC_INVALID_FRAME_INDEX)
{
DDI_MEDIA_SURFACE *surface = DdiMedia_GetSurfaceFromVASurfaceID(mediaCtx, vaPic.picture_id);
vaPic.frame_idx = GetRenderTargetID(rtTbl, surface);
codecHalPic->FrameIdx = (uint8_t)vaPic.frame_idx;
}
else
{
vaPic.frame_idx = DDI_CODEC_INVALID_FRAME_INDEX;
codecHalPic->FrameIdx = CODEC_AVC_NUM_UNCOMPRESSED_SURFACE - 1;
}
if (picReference)
{
if (vaPic.frame_idx == DDI_CODEC_INVALID_FRAME_INDEX)
{
codecHalPic->PicFlags = PICTURE_INVALID;
}
else if ((vaPic.flags&VA_PICTURE_H264_LONG_TERM_REFERENCE) == VA_PICTURE_H264_LONG_TERM_REFERENCE)
{
codecHalPic->PicFlags = PICTURE_LONG_TERM_REFERENCE;
}
else
{
codecHalPic->PicFlags = PICTURE_SHORT_TERM_REFERENCE;
}
}
else
{
if (fieldPicFlag)
{
if ((vaPic.flags&VA_PICTURE_H264_BOTTOM_FIELD) == VA_PICTURE_H264_BOTTOM_FIELD)
{
codecHalPic->PicFlags = PICTURE_BOTTOM_FIELD;
}
else
{
codecHalPic->PicFlags = PICTURE_TOP_FIELD;
}
}
else
{
codecHalPic->PicFlags = PICTURE_FRAME;
}
}
if (sliceReference && (vaPic.picture_id == VA_INVALID_ID))//VA_INVALID_ID is used to indicate invalide picture in LIBVA.
{
codecHalPic->PicFlags = PICTURE_INVALID;
}
}
uint32_t DdiEncodeAvc::getSliceParameterBufferSize()
{
return sizeof(VAEncSliceParameterBufferH264);
}
uint32_t DdiEncodeAvc::getSequenceParameterBufferSize()
{
return sizeof(VAEncSequenceParameterBufferH264);
}
uint32_t DdiEncodeAvc::getPictureParameterBufferSize()
{
return sizeof(VAEncPictureParameterBufferH264);
}
uint32_t DdiEncodeAvc::getQMatrixBufferSize()
{
return sizeof(VAIQMatrixBufferH264);
}
void DdiEncodeAvc::ClearPicParams()
{
uint8_t ppsIdx = ((PCODEC_AVC_ENCODE_SLICE_PARAMS)(m_encodeCtx->pSliceParams))->pic_parameter_set_id;
PCODEC_AVC_ENCODE_PIC_PARAMS picParams = (PCODEC_AVC_ENCODE_PIC_PARAMS)m_encodeCtx->pPicParams + ppsIdx;
if (picParams != nullptr && picParams->pDeltaQp != nullptr)
{
MOS_FreeMemory(picParams->pDeltaQp);
picParams->pDeltaQp = nullptr;
}
}