blob: 6a8cc0c69df0694c7ca4292fdb1558d89cc4098a [file] [log] [blame]
/*
* Copyright (c) 2017, 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_hevc.cpp
//! \brief HEVC class definition for DDI media encoder.
//!
#include "media_ddi_base.h"
#include "media_ddi_encode_base.h"
#include "media_ddi_encode_hevc.h"
#include "media_libva_util.h"
#include "media_ddi_encode_const.h"
#include "media_ddi_factory.h"
#include "codechal_encoder_base.h"
extern template class MediaDdiFactoryNoArg<DdiEncodeBase>;
static bool isEncodeHevcRegistered =
MediaDdiFactoryNoArg<DdiEncodeBase>::RegisterCodec<DdiEncodeHevc>(ENCODE_ID_HEVC);
DdiEncodeHevc::~DdiEncodeHevc()
{
if (m_encodeCtx == nullptr)
{
return;
}
MOS_FreeMemory(m_encodeCtx->pSeqParams);
m_encodeCtx->pSeqParams = nullptr;
MOS_FreeMemory(((PCODEC_HEVC_ENCODE_PICTURE_PARAMS)m_encodeCtx->pPicParams)->pDirtyRect);
((PCODEC_HEVC_ENCODE_PICTURE_PARAMS)m_encodeCtx->pPicParams)->pDirtyRect = nullptr;
MOS_FreeMemory(m_encodeCtx->pPicParams);
m_encodeCtx->pPicParams = nullptr;
if (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->pSliceParams);
m_encodeCtx->pSliceParams = nullptr;
MOS_FreeMemory(m_encodeCtx->pEncodeStatusReport);
m_encodeCtx->pEncodeStatusReport = nullptr;
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;
}
}
VAStatus DdiEncodeHevc::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 (true == m_encodeCtx->bVdencActive)
{
codecHalSettings->codecFunction = CODECHAL_FUNCTION_ENC_VDENC_PAK;
codecHalSettings->disableUltraHME = false;
codecHalSettings->disableSuperHME = false;
}
else
{
codecHalSettings->codecFunction = CODECHAL_FUNCTION_ENC_PAK;
}
codecHalSettings->height = m_encodeCtx->dworiFrameHeight;
codecHalSettings->width = m_encodeCtx->dworiFrameWidth;
codecHalSettings->mode = m_encodeCtx->wModeType;
codecHalSettings->standard = CODECHAL_HEVC;
if(m_encodeCtx->vaProfile==VAProfileHEVCMain || m_encodeCtx->vaProfile==VAProfileHEVCSccMain)
{
codecHalSettings->chromaFormat = HCP_CHROMA_FORMAT_YUV420;
codecHalSettings->lumaChromaDepth = CODECHAL_LUMA_CHROMA_DEPTH_8_BITS;
}
else if(m_encodeCtx->vaProfile==VAProfileHEVCMain10 || m_encodeCtx->vaProfile==VAProfileHEVCSccMain10)
{
codecHalSettings->chromaFormat = HCP_CHROMA_FORMAT_YUV420;
codecHalSettings->lumaChromaDepth = CODECHAL_LUMA_CHROMA_DEPTH_10_BITS;
}
else if(m_encodeCtx->vaProfile == VAProfileHEVCMain12)
{
codecHalSettings->chromaFormat = HCP_CHROMA_FORMAT_YUV420;
codecHalSettings->lumaChromaDepth = CODECHAL_LUMA_CHROMA_DEPTH_12_BITS;
}
else if(m_encodeCtx->vaProfile == VAProfileHEVCMain422_10)
{
codecHalSettings->chromaFormat = HCP_CHROMA_FORMAT_YUV422;
codecHalSettings->lumaChromaDepth = CODECHAL_LUMA_CHROMA_DEPTH_10_BITS;
}
else if(m_encodeCtx->vaProfile == VAProfileHEVCMain422_12)
{
codecHalSettings->chromaFormat = HCP_CHROMA_FORMAT_YUV422;
codecHalSettings->lumaChromaDepth = CODECHAL_LUMA_CHROMA_DEPTH_12_BITS;
}
else if (m_encodeCtx->vaProfile == VAProfileHEVCMain444 || m_encodeCtx->vaProfile==VAProfileHEVCSccMain444)
{
codecHalSettings->chromaFormat = HCP_CHROMA_FORMAT_YUV444;
codecHalSettings->lumaChromaDepth = CODECHAL_LUMA_CHROMA_DEPTH_8_BITS;
}
else if (m_encodeCtx->vaProfile == VAProfileHEVCMain444_10 || m_encodeCtx->vaProfile==VAProfileHEVCSccMain444_10)
{
codecHalSettings->chromaFormat = HCP_CHROMA_FORMAT_YUV444;
codecHalSettings->lumaChromaDepth = CODECHAL_LUMA_CHROMA_DEPTH_10_BITS;
}
else if (m_encodeCtx->vaProfile == VAProfileHEVCMain444_12)
{
codecHalSettings->chromaFormat = HCP_CHROMA_FORMAT_YUV444;
codecHalSettings->lumaChromaDepth = CODECHAL_LUMA_CHROMA_DEPTH_12_BITS;
}
codecHalSettings->isSCCEnabled = IsSccProfile();
VAStatus eStatus = VA_STATUS_SUCCESS;
// Allocate sequence params
m_encodeCtx->pSeqParams = (void *)MOS_AllocAndZeroMemory(sizeof(CODEC_HEVC_ENCODE_SEQUENCE_PARAMS));
DDI_CHK_NULL(m_encodeCtx->pSeqParams, "nullptr m_encodeCtx->pSeqParams.", VA_STATUS_ERROR_ALLOCATION_FAILED);
// Allocate picture params
m_encodeCtx->pPicParams = (void *)MOS_AllocAndZeroMemory(sizeof(CODEC_HEVC_ENCODE_PICTURE_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) * HEVC_MAX_NAL_UNIT_TYPE);
DDI_CHK_NULL(m_encodeCtx->ppNALUnitParams, "nullptr m_encodeCtx->ppNALUnitParams.", VA_STATUS_ERROR_ALLOCATION_FAILED);
PCODECHAL_NAL_UNIT_PARAMS nalUnitParams = (CODECHAL_NAL_UNIT_PARAMS *)MOS_AllocAndZeroMemory(sizeof(CODECHAL_NAL_UNIT_PARAMS) * HEVC_MAX_NAL_UNIT_TYPE);
DDI_CHK_NULL(nalUnitParams, "nullptr nalUnitParams.", VA_STATUS_ERROR_ALLOCATION_FAILED);
for (uint32_t i = 0; i < HEVC_MAX_NAL_UNIT_TYPE; i++)
{
m_encodeCtx->ppNALUnitParams[i] = &(nalUnitParams[i]);
}
// Allocate SliceParams
// Supports one LCU per slice, with minimum LCU size of 16x16
m_encodeCtx->pSliceParams = (void *)MOS_AllocAndZeroMemory(m_encodeCtx->wPicHeightInMB * m_encodeCtx->wPicWidthInMB * sizeof(CODEC_HEVC_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 = (CODEC_ENCODER_SLCDATA *)MOS_AllocAndZeroMemory(m_encodeCtx->wPicHeightInMB * m_encodeCtx->wPicWidthInMB * 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 = (BSBuffer *)MOS_AllocAndZeroMemory(sizeof(BSBuffer));
DDI_CHK_NULL(m_encodeCtx->pbsBuffer, "nullptr m_encodeCtx->pbsBuffer.", VA_STATUS_ERROR_ALLOCATION_FAILED);
m_encodeCtx->pbsBuffer->BufferSize = m_encodeCtx->wPicHeightInMB * m_encodeCtx->wPicWidthInMB * PACKED_HEADER_SIZE_PER_ROW;
m_encodeCtx->pbsBuffer->pBase = (uint8_t *)MOS_AllocAndZeroMemory(m_encodeCtx->pbsBuffer->BufferSize);
DDI_CHK_NULL(m_encodeCtx->pbsBuffer->pBase, "nullptr m_encodeCtx->pbsBuffer->pBase.", VA_STATUS_ERROR_ALLOCATION_FAILED);
return eStatus;
}
VAStatus DdiEncodeHevc::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, "nullptr mediaCtx", VA_STATUS_ERROR_INVALID_CONTEXT);
DDI_CHK_NULL(m_encodeCtx, "nullptr 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, "nullptr 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;
default:
DDI_ASSERTMESSAGE("not supported buffer type.");
break;
}
DdiMedia_UnmapBuffer(ctx, buffers[i]);
}
DDI_FUNCTION_EXIT(vaStatus);
return vaStatus;
}
VAStatus DdiEncodeHevc::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));
if (m_encodeCtx->bVdencActive)
{
encodeParams.ExecCodecFunction = CODECHAL_FUNCTION_ENC_VDENC_PAK;
}
else
{
encodeParams.ExecCodecFunction = CODECHAL_FUNCTION_ENC_PAK;
}
// Raw Surface
MOS_SURFACE rawSurface;
MOS_ZeroMemory(&rawSurface, sizeof(rawSurface));
rawSurface.dwOffset = 0;
DdiMedia_MediaSurfaceToMosResource(rtTbl->pCurrentRT, &(rawSurface.OsResource));
// Recon Surface
MOS_SURFACE reconSurface;
MOS_ZeroMemory(&reconSurface, sizeof(reconSurface));
reconSurface.dwOffset = 0;
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 (m_encodeCtx->bMBQpEnable)
{
// MBQp surface
MOS_ZeroMemory(&mbQpSurface, sizeof(mbQpSurface));
mbQpSurface.Format = Format_Buffer_2D;
mbQpSurface.dwOffset = 0;
mbQpSurface.OsResource = m_encodeCtx->resMBQpBuffer;
encodeParams.psMbQpDataSurface = &mbQpSurface;
encodeParams.bMbQpDataEnabled = true;
}
PCODEC_HEVC_ENCODE_SEQUENCE_PARAMS hevcSeqParams = (PCODEC_HEVC_ENCODE_SEQUENCE_PARAMS)((uint8_t *)m_encodeCtx->pSeqParams);
if (m_encodeCtx->bNewSeq)
{
hevcSeqParams->TargetUsage = m_encodeCtx->targetUsage;
}
encodeParams.pSeqParams = m_encodeCtx->pSeqParams;
encodeParams.pVuiParams = m_encodeCtx->pVuiParams;
encodeParams.pPicParams = m_encodeCtx->pPicParams;
encodeParams.pSliceParams = m_encodeCtx->pSliceParams;
// 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;
CodechalEncoderState *encoder = dynamic_cast<CodechalEncoderState *>(m_encodeCtx->pCodecHal);
if(encoder != nullptr)
{
encoder->m_mfeEncodeParams.submitIndex = 0;
encoder->m_mfeEncodeParams.submitNumber = 1; //By default we only use one stream
encoder->m_mfeEncodeParams.streamId = 0;
}
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 DdiEncodeHevc::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;
// 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 DdiEncodeHevc::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);
VAEncSequenceParameterBufferHEVC *seqParams = (VAEncSequenceParameterBufferHEVC *)ptr;
PCODEC_HEVC_ENCODE_SEQUENCE_PARAMS hevcSeqParams = (PCODEC_HEVC_ENCODE_SEQUENCE_PARAMS)((uint8_t *)m_encodeCtx->pSeqParams);
DDI_CHK_NULL(hevcSeqParams, "nullptr hevcSeqParams", VA_STATUS_ERROR_INVALID_PARAMETER);
//MOS_ZeroMemory(hevcSeqParams, sizeof(CODEC_HEVC_ENCODE_SEQUENCE_PARAMS));
uint8_t log2MinCUSize = seqParams->log2_min_luma_coding_block_size_minus3 + 3;
hevcSeqParams->wFrameWidthInMinCbMinus1 = (seqParams->pic_width_in_luma_samples >> log2MinCUSize) - 1;
hevcSeqParams->wFrameHeightInMinCbMinus1 = (seqParams->pic_height_in_luma_samples >> log2MinCUSize) - 1;
hevcSeqParams->general_profile_idc = seqParams->general_profile_idc;
hevcSeqParams->Level = seqParams->general_level_idc / 3; // App sends (30*level), we track as (10*level)
hevcSeqParams->general_tier_flag = seqParams->general_tier_flag;
hevcSeqParams->GopPicSize = seqParams->intra_period;
hevcSeqParams->GopRefDist = seqParams->ip_period;
hevcSeqParams->chroma_format_idc = seqParams->seq_fields.bits.chroma_format_idc;
hevcSeqParams->RateControlMethod = VARC2HalRC(m_encodeCtx->uiRCMethod);
hevcSeqParams->TargetBitRate = MOS_ROUNDUP_DIVIDE(seqParams->bits_per_second, CODECHAL_ENCODE_BRC_KBPS);
hevcSeqParams->MaxBitRate = MOS_ROUNDUP_DIVIDE(seqParams->bits_per_second, CODECHAL_ENCODE_BRC_KBPS);
hevcSeqParams->MinBitRate = MOS_ROUNDUP_DIVIDE(seqParams->bits_per_second, CODECHAL_ENCODE_BRC_KBPS);
// if didn't setting FrameRate, set to 30 by default, can be overwritten by misc paramter
if (!hevcSeqParams->FrameRate.Numerator) {
hevcSeqParams->FrameRate.Numerator = 3000;
hevcSeqParams->FrameRate.Denominator = 100;
}
// set default same as application, can be overwritten by HRD params
hevcSeqParams->InitVBVBufferFullnessInBit = (uint32_t)seqParams->bits_per_second;
hevcSeqParams->VBVBufferSizeInBit = (uint32_t)seqParams->bits_per_second << 1;
hevcSeqParams->scaling_list_enable_flag = seqParams->seq_fields.bits.scaling_list_enabled_flag;
hevcSeqParams->sps_temporal_mvp_enable_flag = seqParams->seq_fields.bits.sps_temporal_mvp_enabled_flag;
hevcSeqParams->strong_intra_smoothing_enable_flag = seqParams->seq_fields.bits.strong_intra_smoothing_enabled_flag;
hevcSeqParams->amp_enabled_flag = seqParams->seq_fields.bits.amp_enabled_flag;
hevcSeqParams->SAO_enabled_flag = seqParams->seq_fields.bits.sample_adaptive_offset_enabled_flag;
hevcSeqParams->pcm_enabled_flag = seqParams->seq_fields.bits.pcm_enabled_flag;
hevcSeqParams->pcm_loop_filter_disable_flag = seqParams->seq_fields.bits.pcm_loop_filter_disabled_flag;
hevcSeqParams->LowDelayMode = seqParams->seq_fields.bits.low_delay_seq;
hevcSeqParams->HierarchicalFlag = seqParams->seq_fields.bits.hierachical_flag;
hevcSeqParams->log2_max_coding_block_size_minus3 = seqParams->log2_diff_max_min_luma_coding_block_size +
seqParams->log2_min_luma_coding_block_size_minus3;
hevcSeqParams->log2_min_coding_block_size_minus3 = seqParams->log2_min_luma_coding_block_size_minus3;
hevcSeqParams->log2_max_transform_block_size_minus2 = seqParams->log2_diff_max_min_transform_block_size +
seqParams->log2_min_transform_block_size_minus2;
hevcSeqParams->log2_min_transform_block_size_minus2 = seqParams->log2_min_transform_block_size_minus2;
hevcSeqParams->max_transform_hierarchy_depth_intra = seqParams->max_transform_hierarchy_depth_intra;
hevcSeqParams->max_transform_hierarchy_depth_inter = seqParams->max_transform_hierarchy_depth_inter;
hevcSeqParams->log2_min_PCM_cb_size_minus3 = seqParams->log2_min_pcm_luma_coding_block_size_minus3;
hevcSeqParams->log2_max_PCM_cb_size_minus3 = seqParams->log2_max_pcm_luma_coding_block_size_minus3;
hevcSeqParams->bit_depth_luma_minus8 = seqParams->seq_fields.bits.bit_depth_luma_minus8;
hevcSeqParams->bit_depth_chroma_minus8 = seqParams->seq_fields.bits.bit_depth_chroma_minus8;
if (m_codechalSettings->isSCCEnabled)
{
hevcSeqParams->palette_mode_enabled_flag = seqParams->scc_fields.bits.palette_mode_enabled_flag;
hevcSeqParams->motion_vector_resolution_control_idc = 0;
}
return VA_STATUS_SUCCESS;
}
VAStatus DdiEncodeHevc::ParsePicParams(
DDI_MEDIA_CONTEXT *mediaCtx,
void *ptr)
{
DDI_CHK_NULL(mediaCtx, "nullptr mediaCtx", VA_STATUS_ERROR_INVALID_PARAMETER);
DDI_CHK_NULL(ptr, "nullptr ptr", VA_STATUS_ERROR_INVALID_PARAMETER);
DDI_CHK_NULL(m_encodeCtx, "nullptr m_encodeCtx", VA_STATUS_ERROR_INVALID_PARAMETER);
VAEncPictureParameterBufferHEVC *picParams = (VAEncPictureParameterBufferHEVC *)ptr;
PCODEC_HEVC_ENCODE_PICTURE_PARAMS hevcPicParams = (PCODEC_HEVC_ENCODE_PICTURE_PARAMS)((uint8_t *)m_encodeCtx->pPicParams);
DDI_CHK_NULL(hevcPicParams, "nullptr hevcPicParams", VA_STATUS_ERROR_INVALID_PARAMETER);
MOS_ZeroMemory(hevcPicParams, sizeof(CODEC_HEVC_ENCODE_PICTURE_PARAMS));
PCODEC_HEVC_ENCODE_SEQUENCE_PARAMS hevcSeqParams = (PCODEC_HEVC_ENCODE_SEQUENCE_PARAMS)((uint8_t *)m_encodeCtx->pSeqParams);
DDI_MEDIA_SURFACE *surface;
if(picParams->decoded_curr_pic.picture_id != VA_INVALID_SURFACE)
{
surface = DdiMedia_GetSurfaceFromVASurfaceID(mediaCtx, picParams->decoded_curr_pic.picture_id);
if(m_encodeCtx->vaProfile == VAProfileHEVCMain444
|| m_encodeCtx->vaProfile == VAProfileHEVCMain444_10
|| m_encodeCtx->vaProfile == VAProfileHEVCMain444_12
|| m_encodeCtx->vaProfile == VAProfileHEVCMain422_10
|| m_encodeCtx->vaProfile == VAProfileHEVCMain422_12
|| m_encodeCtx->vaProfile == VAProfileHEVCMain10
|| m_encodeCtx->vaProfile == VAProfileHEVCMain12
|| m_encodeCtx->vaProfile == VAProfileHEVCSccMain10
|| m_encodeCtx->vaProfile == VAProfileHEVCSccMain444
|| m_encodeCtx->vaProfile == VAProfileHEVCSccMain444_10)
{
surface = DdiMedia_ReplaceSurfaceWithVariant(surface, m_encodeCtx->vaEntrypoint);
}
DDI_CHK_RET(RegisterRTSurfaces(&(m_encodeCtx->RTtbl),surface), "RegisterRTSurfaces failed!");
}
// Curr Recon Pic
SetupCodecPicture(
mediaCtx,
&(m_encodeCtx->RTtbl),
&hevcPicParams->CurrReconstructedPic,
picParams->decoded_curr_pic,
false,
false);
DDI_CODEC_RENDER_TARGET_TABLE *rtTbl = &(m_encodeCtx->RTtbl);
rtTbl->pCurrentReconTarget = DdiMedia_GetSurfaceFromVASurfaceID(mediaCtx, picParams->decoded_curr_pic.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
hevcPicParams->CurrOriginalPic.FrameIdx = (uint8_t)GetRenderTargetID(rtTbl, rtTbl->pCurrentReconTarget);
hevcPicParams->CurrOriginalPic.PicFlags = hevcPicParams->CurrReconstructedPic.PicFlags;
hevcPicParams->CurrOriginalPic.PicEntry = hevcPicParams->CurrReconstructedPic.PicEntry;
hevcPicParams->CollocatedRefPicIndex = picParams->collocated_ref_pic_index;
// RefFrame List
for (uint32_t i = 0; i < numMaxRefFrame; i++)
{
if(picParams->reference_frames[i].picture_id != VA_INVALID_SURFACE)
{
DDI_CHK_RET(UpdateRegisteredRTSurfaceFlag(&(m_encodeCtx->RTtbl), DdiMedia_GetSurfaceFromVASurfaceID(mediaCtx, picParams->reference_frames[i].picture_id)), "RegisterRTSurfaces failed!");
}
SetupCodecPicture(
mediaCtx,
&(m_encodeCtx->RTtbl),
&(hevcPicParams->RefFrameList[i]),
picParams->reference_frames[i],
true,
false);
hevcPicParams->RefFramePOCList[i] = picParams->reference_frames[i].pic_order_cnt;
}
hevcPicParams->CurrPicOrderCnt = picParams->decoded_curr_pic.pic_order_cnt;
/* picParams->coding_type; App is always setting this to 0 */
hevcPicParams->CodingType = picParams->pic_fields.bits.coding_type;
/* CodingType may be updated in slice processing. Do below to save pyramid level info */
hevcPicParams->ppsCodingType = picParams->pic_fields.bits.coding_type;
hevcPicParams->HierarchLevelPlus1 = picParams->hierarchical_level_plus1;
/* Reset it to zero now */
hevcPicParams->NumSlices = 0;
hevcPicParams->sign_data_hiding_flag = picParams->pic_fields.bits.sign_data_hiding_enabled_flag;
hevcPicParams->constrained_intra_pred_flag = picParams->pic_fields.bits.constrained_intra_pred_flag;
hevcPicParams->transform_skip_enabled_flag = picParams->pic_fields.bits.transform_skip_enabled_flag;
hevcPicParams->transquant_bypass_enabled_flag = picParams->pic_fields.bits.transquant_bypass_enabled_flag;
hevcPicParams->tiles_enabled_flag = picParams->pic_fields.bits.tiles_enabled_flag;
hevcPicParams->cu_qp_delta_enabled_flag = picParams->pic_fields.bits.cu_qp_delta_enabled_flag;
hevcPicParams->weighted_pred_flag = picParams->pic_fields.bits.weighted_pred_flag;
hevcPicParams->weighted_bipred_flag = picParams->pic_fields.bits.weighted_bipred_flag;
hevcPicParams->loop_filter_across_slices_flag = picParams->pic_fields.bits.pps_loop_filter_across_slices_enabled_flag;
hevcPicParams->loop_filter_across_tiles_flag = picParams->pic_fields.bits.loop_filter_across_tiles_enabled_flag;
hevcPicParams->bLastPicInSeq = (picParams->last_picture & HEVC_LAST_PICTURE_EOSEQ) ? 1 : 0;
hevcPicParams->bLastPicInStream = (picParams->last_picture & HEVC_LAST_PICTURE_EOSTREAM) ? 1 : 0;
hevcPicParams->bUseRawPicForRef = false;
hevcPicParams->bScreenContent = picParams->pic_fields.bits.screen_content_flag;
hevcPicParams->bEmulationByteInsertion = true;
hevcPicParams->QpY = picParams->pic_init_qp;
hevcPicParams->diff_cu_qp_delta_depth = picParams->diff_cu_qp_delta_depth;
hevcPicParams->pps_cb_qp_offset = picParams->pps_cb_qp_offset;
hevcPicParams->pps_cr_qp_offset = picParams->pps_cr_qp_offset;
hevcPicParams->num_tile_columns_minus1 = picParams->num_tile_columns_minus1;
hevcPicParams->num_tile_rows_minus1 = picParams->num_tile_rows_minus1;
hevcPicParams->log2_parallel_merge_level_minus2 = picParams->log2_parallel_merge_level_minus2;
hevcPicParams->LcuMaxBitsizeAllowed = picParams->ctu_max_bitsize_allowed;
hevcPicParams->bUsedAsRef = picParams->pic_fields.bits.reference_pic_flag;
hevcPicParams->slice_pic_parameter_set_id = picParams->slice_pic_parameter_set_id;
hevcPicParams->nal_unit_type = picParams->nal_unit_type;
hevcPicParams->no_output_of_prior_pics_flag = picParams->pic_fields.bits.no_output_of_prior_pics_flag;
hevcPicParams->bDisplayFormatSwizzle = NeedDisapayFormatSwizzle(rtTbl->pCurrentRT, rtTbl->pCurrentReconTarget);
// Correct Input color space of Sequence parameter here
hevcSeqParams->InputColorSpace = hevcPicParams->bDisplayFormatSwizzle ? ECOLORSPACE_P601 : ECOLORSPACE_P709;
if (hevcPicParams->tiles_enabled_flag)
{
uint16_t shift = hevcSeqParams->log2_max_coding_block_size_minus3 -
hevcSeqParams->log2_min_coding_block_size_minus3;
uint16_t frameWidthAligedInLCU = MOS_ROUNDUP_SHIFT((hevcSeqParams->wFrameWidthInMinCbMinus1 + 1), shift);
uint16_t frameHeightAligedInLCU = MOS_ROUNDUP_SHIFT((hevcSeqParams->wFrameHeightInMinCbMinus1 + 1), shift);
if(hevcPicParams->num_tile_columns_minus1 > CODECHAL_GET_ARRAY_LENGTH(picParams->column_width_minus1) ||
hevcPicParams->num_tile_rows_minus1 > CODECHAL_GET_ARRAY_LENGTH(picParams->row_height_minus1))
{
// app passed wrong parameters
DDI_ASSERTMESSAGE("invalid tile parameters!");
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
for(uint32_t i = 0; i < (uint32_t)(hevcPicParams->num_tile_columns_minus1); i++)
{
hevcPicParams->tile_column_width[i] = picParams->column_width_minus1[i] + 1;
frameWidthAligedInLCU -= hevcPicParams->tile_column_width[i];
}
if(frameWidthAligedInLCU > 0)
{
hevcPicParams->tile_column_width[hevcPicParams->num_tile_columns_minus1] = frameWidthAligedInLCU;
}
else
{
// app passed wrong parameters
DDI_ASSERTMESSAGE("invalid tile parameters!");
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
for(uint32_t i = 0; i < (uint32_t)(hevcPicParams->num_tile_rows_minus1); i++)
{
hevcPicParams->tile_row_height[i] = picParams->row_height_minus1[i] + 1;
frameHeightAligedInLCU -= hevcPicParams->tile_row_height[i];
}
if(frameHeightAligedInLCU > 0)
{
hevcPicParams->tile_row_height[hevcPicParams->num_tile_rows_minus1] = frameHeightAligedInLCU;
}
else
{
// app passed wrong parameters
DDI_ASSERTMESSAGE("invalid tile parameters!");
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
}
if (m_codechalSettings->isSCCEnabled)
{
// SCC
hevcPicParams->pps_curr_pic_ref_enabled_flag = picParams->scc_fields.bits.pps_curr_pic_ref_enabled_flag;
hevcPicParams->residual_adaptive_colour_transform_enabled_flag = 0;
hevcPicParams->pps_slice_act_qp_offsets_present_flag = 0;
// GEN12 HW only can support the initial palette size 0
hevcPicParams->PredictorPaletteSize = 0;
}
DDI_MEDIA_BUFFER *buf = DdiMedia_GetBufferFromVABufferID(mediaCtx, picParams->coded_buf);
if (nullptr == buf)
{
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
//Application may 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 DdiEncodeHevc::ParseSlcParams(
DDI_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);
VAEncSliceParameterBufferHEVC *vaEncSlcParamsHEVC = (VAEncSliceParameterBufferHEVC *)ptr;
PCODEC_HEVC_ENCODE_SLICE_PARAMS hevcSlcParams = (PCODEC_HEVC_ENCODE_SLICE_PARAMS)m_encodeCtx->pSliceParams;
DDI_CHK_NULL(hevcSlcParams, "nullptr hevcSlcParams", VA_STATUS_ERROR_INVALID_PARAMETER);
PCODEC_HEVC_ENCODE_PICTURE_PARAMS hevcPicParams = (PCODEC_HEVC_ENCODE_PICTURE_PARAMS)(m_encodeCtx->pPicParams);
DDI_CHK_NULL(hevcPicParams, "nullptr hevcPicParams", VA_STATUS_ERROR_INVALID_PARAMETER);
hevcPicParams->CodingType = CodechalPicTypeFromVaSlcType(vaEncSlcParamsHEVC->slice_type);
if (vaEncSlcParamsHEVC->slice_segment_address == 0)
{
hevcPicParams->NumSlices = 0;
}
else
{
hevcSlcParams += hevcPicParams->NumSlices;
}
MOS_ZeroMemory(
hevcSlcParams,
numSlices * sizeof(CODEC_HEVC_ENCODE_SLICE_PARAMS));
for (uint32_t slcCount = 0; slcCount < numSlices; slcCount++, hevcSlcParams++)
{
hevcSlcParams->slice_segment_address = vaEncSlcParamsHEVC->slice_segment_address;
hevcSlcParams->NumLCUsInSlice = vaEncSlcParamsHEVC->num_ctu_in_slice;
hevcSlcParams->num_ref_idx_l0_active_minus1 = vaEncSlcParamsHEVC->num_ref_idx_l0_active_minus1;
hevcSlcParams->num_ref_idx_l1_active_minus1 = vaEncSlcParamsHEVC->num_ref_idx_l1_active_minus1;
hevcSlcParams->bLastSliceOfPic = vaEncSlcParamsHEVC->slice_fields.bits.last_slice_of_pic_flag;
hevcSlcParams->dependent_slice_segment_flag = vaEncSlcParamsHEVC->slice_fields.bits.dependent_slice_segment_flag;
hevcSlcParams->slice_temporal_mvp_enable_flag = vaEncSlcParamsHEVC->slice_fields.bits.slice_temporal_mvp_enabled_flag;
hevcSlcParams->slice_type = vaEncSlcParamsHEVC->slice_type;
hevcSlcParams->slice_sao_luma_flag = vaEncSlcParamsHEVC->slice_fields.bits.slice_sao_luma_flag;
hevcSlcParams->slice_sao_chroma_flag = vaEncSlcParamsHEVC->slice_fields.bits.slice_sao_chroma_flag;
hevcSlcParams->mvd_l1_zero_flag = vaEncSlcParamsHEVC->slice_fields.bits.mvd_l1_zero_flag;
hevcSlcParams->cabac_init_flag = vaEncSlcParamsHEVC->slice_fields.bits.cabac_init_flag;
hevcSlcParams->slice_deblocking_filter_disable_flag = vaEncSlcParamsHEVC->slice_fields.bits.slice_deblocking_filter_disabled_flag;
hevcSlcParams->collocated_from_l0_flag = vaEncSlcParamsHEVC->slice_fields.bits.collocated_from_l0_flag;
hevcSlcParams->slice_qp_delta = vaEncSlcParamsHEVC->slice_qp_delta;
hevcSlcParams->slice_cb_qp_offset = vaEncSlcParamsHEVC->slice_cb_qp_offset;
hevcSlcParams->slice_cr_qp_offset = vaEncSlcParamsHEVC->slice_cr_qp_offset;
hevcSlcParams->beta_offset_div2 = vaEncSlcParamsHEVC->slice_beta_offset_div2;
hevcSlcParams->tc_offset_div2 = vaEncSlcParamsHEVC->slice_tc_offset_div2;
hevcSlcParams->MaxNumMergeCand = vaEncSlcParamsHEVC->max_num_merge_cand;
hevcSlcParams->luma_log2_weight_denom = vaEncSlcParamsHEVC->luma_log2_weight_denom;
hevcSlcParams->delta_chroma_log2_weight_denom = vaEncSlcParamsHEVC->delta_chroma_log2_weight_denom;
hevcSlcParams->slice_id = hevcPicParams->NumSlices + slcCount;
hevcSlcParams->BitLengthSliceHeaderStartingPortion = 40;
hevcSlcParams->bLastSliceOfPic = (slcCount == numSlices - 1) ? 1 : 0;
// If either stored slice count or current count in this buffer are non-zero, then verify
// that previous slice is not marked as last slice (it will be marked as last if it was last
// slice in previous buffer, which is not necessarily last slice in picture).
if (slcCount || hevcPicParams->NumSlices)
{
hevcSlcParams--;
hevcSlcParams->bLastSliceOfPic = false;
hevcSlcParams++;
}
for (uint32_t i = 0; i < numMaxRefFrame; i++)
{
// list 0
hevcSlcParams->luma_offset[0][i] = vaEncSlcParamsHEVC->luma_offset_l0[i];
hevcSlcParams->delta_luma_weight[0][i] = vaEncSlcParamsHEVC->delta_luma_weight_l0[i];
hevcSlcParams->chroma_offset[0][i][0] = MOS_CLAMP_MIN_MAX(vaEncSlcParamsHEVC->chroma_offset_l0[i][0], minChromaOffset, maxChromaOffset);
hevcSlcParams->delta_chroma_weight[0][i][0] = vaEncSlcParamsHEVC->delta_chroma_weight_l0[i][0];
hevcSlcParams->chroma_offset[0][i][1] = MOS_CLAMP_MIN_MAX(vaEncSlcParamsHEVC->chroma_offset_l0[i][1], minChromaOffset, maxChromaOffset);
hevcSlcParams->delta_chroma_weight[0][i][1] = vaEncSlcParamsHEVC->delta_chroma_weight_l0[i][1];
// list 1
hevcSlcParams->luma_offset[1][i] = vaEncSlcParamsHEVC->luma_offset_l1[i];
hevcSlcParams->delta_luma_weight[1][i] = vaEncSlcParamsHEVC->delta_luma_weight_l1[i];
hevcSlcParams->chroma_offset[1][i][0] = MOS_CLAMP_MIN_MAX(vaEncSlcParamsHEVC->chroma_offset_l1[i][0], minChromaOffset, maxChromaOffset);
hevcSlcParams->delta_chroma_weight[1][i][0] = vaEncSlcParamsHEVC->delta_chroma_weight_l1[i][0];
hevcSlcParams->chroma_offset[1][i][1] = MOS_CLAMP_MIN_MAX(vaEncSlcParamsHEVC->chroma_offset_l1[i][1], minChromaOffset, maxChromaOffset);
hevcSlcParams->delta_chroma_weight[1][i][1] = vaEncSlcParamsHEVC->delta_chroma_weight_l1[i][1];
}
for (uint32_t i = 0; i < numMaxRefFrame; i++)
{
if(i > hevcSlcParams->num_ref_idx_l0_active_minus1)
{
hevcSlcParams->RefPicList[0][i].FrameIdx = CODECHAL_NUM_UNCOMPRESSED_SURFACE_HEVC;
hevcSlcParams->RefPicList[0][i].PicFlags = PICTURE_INVALID;
hevcSlcParams->RefPicList[0][i].PicEntry = 0xFF;
}
else
{
SetupCodecPicture(
mediaCtx,
&(m_encodeCtx->RTtbl),
&(hevcSlcParams->RefPicList[0][i]),
vaEncSlcParamsHEVC->ref_pic_list0[i],
false,
true);
GetSlcRefIdx(&(hevcPicParams->RefFrameList[0]), &(hevcSlcParams->RefPicList[0][i]));
}
}
for (uint32_t i = 0; i < numMaxRefFrame; i++)
{
if(i > hevcSlcParams->num_ref_idx_l1_active_minus1)
{
hevcSlcParams->RefPicList[1][i].FrameIdx = CODECHAL_NUM_UNCOMPRESSED_SURFACE_HEVC;
hevcSlcParams->RefPicList[1][i].PicFlags = PICTURE_INVALID;
hevcSlcParams->RefPicList[1][i].PicEntry = 0xFF;
}
else
{
SetupCodecPicture(
mediaCtx,
&(m_encodeCtx->RTtbl),
&(hevcSlcParams->RefPicList[1][i]),
vaEncSlcParamsHEVC->ref_pic_list1[i],
false,
true);
GetSlcRefIdx(&(hevcPicParams->RefFrameList[0]), &(hevcSlcParams->RefPicList[1][i]));
}
}
vaEncSlcParamsHEVC++;
}
hevcPicParams->NumSlices += numSlices;
m_encodeCtx->dwNumSlices = hevcPicParams->NumSlices;
return VA_STATUS_SUCCESS;
}
VAStatus DdiEncodeHevc::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 DdiEncodeHevc::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);
VAEncPackedHeaderParameterBuffer *encPackedHeaderParamBuf = (VAEncPackedHeaderParameterBuffer *)ptr;
m_encodeCtx->bLastPackedHdrIsSlice = false;
if (encPackedHeaderParamBuf->type == VAEncPackedHeaderHEVC_Slice)
{
m_encodeCtx->bLastPackedHdrIsSlice = true;
m_encodeCtx->bHavePackedSliceHdr = true;
// Current minimum LCU size for HEVC is 16x16. Minimum 1 LCU per slice.
if (m_encodeCtx->uiSliceHeaderCnt >= m_encodeCtx->wPicHeightInMB * m_encodeCtx->wPicWidthInMB)
{
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
{
/* App does not indicate the type, using PPS in general for headers */
m_encodeCtx->ppNALUnitParams[m_encodeCtx->indexNALUnit]->uiNalUnitType = HEVC_NAL_UT_PPS;
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;
}
VAStatus DdiEncodeHevc::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->pCurrent = bsBuffer->pBase;
bsBuffer->SliceOffset = 0;
bsBuffer->BitOffset = 0;
bsBuffer->BitSize = 0;
}
uint32_t hdrDataSize = 0;
MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
if (true == m_encodeCtx->bLastPackedHdrIsSlice)
{
hdrDataSize = (m_encodeCtx->pSliceHeaderData[m_encodeCtx->uiSliceHeaderCnt].BitSize + 7) / 8;
eStatus = MOS_SecureMemcpy(bsBuffer->pCurrent, bsBuffer->BufferSize - bsBuffer->SliceOffset, (uint8_t *)ptr, hdrDataSize);
if (MOS_STATUS_SUCCESS != eStatus)
{
DDI_ASSERTMESSAGE("DDI:packed slice header size is too large to be supported!");
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
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;
eStatus = MOS_SecureMemcpy(bsBuffer->pCurrent, bsBuffer->BufferSize - bsBuffer->SliceOffset, (uint8_t *)ptr, hdrDataSize);
if (MOS_STATUS_SUCCESS != eStatus)
{
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 DdiEncodeHevc::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;
m_encodeCtx->targetUsage = (uint8_t)vaEncMiscParamQualityLevel->quality_level;
#ifdef _FULL_OPEN_SOURCE
if(seqParams->TargetUsage >= 1 && seqParams->TargetUsage <= 2)
{
seqParams->TargetUsage = 4;
}
else if(seqParams->TargetUsage >= 3 && seqParams->TargetUsage <= 5)
{
seqParams->TargetUsage = 7;
}
else
{
DDI_ASSERTMESSAGE("unsupported target usage in HEVC encoder.");
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
#endif
// HEVC only supports TU=1, 4, and 7
if (1 != m_encodeCtx->targetUsage && 4 != m_encodeCtx->targetUsage && 7 != m_encodeCtx->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;
break;
}
case VAEncMiscParameterTypeFrameRate:
{
VAEncMiscParameterFrameRate *vaEncMiscParamFR = (VAEncMiscParameterFrameRate *)miscParamBuf->data;
uint32_t vaFRnumerator = vaEncMiscParamFR->framerate & 0xffff;
#if (VA_MAJOR_VERSION < 1)
uint32_t vaFRDenominator = 100;
#else
uint32_t vaFRDenominator = (vaEncMiscParamFR->framerate >> 16) & 0xffff;
#endif
if(vaFRDenominator == 0)
{
vaFRDenominator = 1;
}
// Pass frame rate value to seqParams and set BRC reset flag and bNewSeq to true while dynamic BRC occures
seqParams->FrameRate.Numerator = vaFRnumerator;
seqParams->FrameRate.Denominator = vaFRDenominator;
if(m_previousFRvalue != 0)
{
uint16_t seqFRvalue = (uint16_t)(seqParams->FrameRate.Numerator / seqParams->FrameRate.Denominator);
if(m_previousFRvalue != seqFRvalue)
{
seqParams->bResetBRC = 0x1;
m_encodeCtx->bNewSeq = true;
}
}
m_previousFRvalue = (uint16_t)(vaFRnumerator / vaFRDenominator);
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;
if (true == m_encodeCtx->bVdencActive)
{
picParams->BRCMaxQp = (vaEncMiscParamRC->max_qp == 0) ? 51 : (uint8_t)CodecHal_Clip3(1, 51, (int8_t)vaEncMiscParamRC->max_qp);
picParams->BRCMinQp = (vaEncMiscParamRC->min_qp == 0) ? 1 : (uint8_t)CodecHal_Clip3(1, picParams->BRCMaxQp, (int8_t)vaEncMiscParamRC->min_qp);
#if VA_CHECK_VERSION(1, 10, 0)
picParams->TargetFrameSize = vaEncMiscParamRC->target_frame_size;
#endif
}
else
{
picParams->BRCMaxQp = (uint8_t)CodecHal_Clip3(0, 51, (int8_t)vaEncMiscParamRC->max_qp); //use 0 to ignore
picParams->BRCMinQp = (uint8_t)CodecHal_Clip3(0, picParams->BRCMaxQp, (int8_t)vaEncMiscParamRC->min_qp); //use 0 to ignore
}
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 & m_encodeCtx->uiRCMethod )
{
seqParams->MaxBitRate = seqParams->TargetBitRate;
seqParams->MinBitRate = seqParams->TargetBitRate;
seqParams->RateControlMethod = RATECONTROL_CBR;
}
else if (VA_RC_ICQ & m_encodeCtx->uiRCMethod)
{
seqParams->ICQQualityFactor = vaEncMiscParamRC->ICQ_quality_factor;
seqParams->RateControlMethod = RATECONTROL_ICQ;
seqParams->MBBRC = 1;
}
else if(VA_RC_VCM & m_encodeCtx->uiRCMethod)
{
seqParams->RateControlMethod = RATECONTROL_VCM;
seqParams->MBBRC = 0;
}
else if(VA_RC_VBR & m_encodeCtx->uiRCMethod)
{
seqParams->RateControlMethod = RATECONTROL_VBR;
}
else if (VA_RC_QVBR & m_encodeCtx->uiRCMethod)
{
seqParams->RateControlMethod = RATECONTROL_QVBR;
seqParams->ICQQualityFactor = vaEncMiscParamRC->quality_factor;
}
else
{
DDI_ASSERTMESSAGE("invalid RC method.");
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
if((RATECONTROL_VCM == seqParams->RateControlMethod)
|| (RATECONTROL_VBR == seqParams->RateControlMethod)
|| (RATECONTROL_CBR == seqParams->RateControlMethod)
|| (RATECONTROL_QVBR == seqParams->RateControlMethod))
{
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->bNewSeq = true;
}
m_encodeCtx->uiTargetBitRate = seqParams->TargetBitRate;
m_encodeCtx->uiMaxBitRate = seqParams->MaxBitRate;
}
}
#ifndef ANDROID
seqParams->FrameSizeTolerance = static_cast<ENCODE_FRAMESIZE_TOLERANCE>(vaEncMiscParamRC->rc_flags.bits.frame_tolerance_mode);
#endif
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;
uint8_t blockSize = (m_encodeCtx->bVdencActive) ? vdencRoiBlockSize : CODECHAL_MACROBLOCK_WIDTH;
uint32_t frameWidth = (seqParams->wFrameWidthInMinCbMinus1 + 1) << (seqParams->log2_min_coding_block_size_minus3 + 3);
uint32_t frameHeight = (seqParams->wFrameHeightInMinCbMinus1 + 1) << (seqParams->log2_min_coding_block_size_minus3 + 3);
uint16_t rightBorder = (uint16_t)CODECHAL_GET_WIDTH_IN_BLOCKS(frameWidth, blockSize) - 1;
uint16_t bottomBorder = (uint16_t)CODECHAL_GET_HEIGHT_IN_BLOCKS(frameHeight, blockSize) - 1;
if(vaEncMiscParamROI->num_roi > CODECHAL_ENCODE_HEVC_MAX_NUM_ROI)
{
DDI_ASSERTMESSAGE("The number of ROI rect is greater than %d", CODECHAL_ENCODE_HEVC_MAX_NUM_ROI);
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
if (vaEncMiscParamROI->num_roi)
{
for (uint32_t i = 0; i < vaEncMiscParamROI->num_roi; ++i)
{
auto &pic_param_roi = picParams->ROI[i];
auto &va_roi = vaEncMiscParamROI->roi[i];
pic_param_roi.Top = va_roi.roi_rectangle.y;
pic_param_roi.Left = va_roi.roi_rectangle.x;
pic_param_roi.Right = va_roi.roi_rectangle.x + va_roi.roi_rectangle.width - 1;
pic_param_roi.Bottom = va_roi.roi_rectangle.y+va_roi.roi_rectangle.height - 1;
pic_param_roi.PriorityLevelOrDQp = va_roi.roi_value;
if( pic_param_roi.Left > pic_param_roi.Right){
DDI_ASSERTMESSAGE("ROI left > ROI Right.");
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
// check frame boundary
if( pic_param_roi.Top > pic_param_roi.Bottom){
DDI_ASSERTMESSAGE("ROI Top > ROI Bottom.");
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
// Convert from pixel units to block size units
pic_param_roi.Left /= blockSize;
pic_param_roi.Right /= blockSize;
pic_param_roi.Top /= blockSize;
pic_param_roi.Bottom /= blockSize;
// check frame boundary
pic_param_roi.Left = pic_param_roi.Left > rightBorder ? rightBorder : pic_param_roi.Left;
pic_param_roi.Right = pic_param_roi.Right > rightBorder ? rightBorder : pic_param_roi.Right;
pic_param_roi.Top = pic_param_roi.Top > bottomBorder ? bottomBorder : pic_param_roi.Top;
pic_param_roi.Bottom = pic_param_roi.Bottom > bottomBorder ? bottomBorder : pic_param_roi.Bottom;
// DDI defination for right and bottom parameters is inclusive whereas
// the defination in BRC kernel input is exclusive. So adding 1 to right & bottom.
pic_param_roi.Right += 1;
pic_param_roi.Bottom += 1;
}
picParams->NumROI = vaEncMiscParamROI->num_roi;
}
#ifndef ANDROID
// support DeltaQP based ROI by default
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
break;
}
case VAEncMiscParameterTypeDirtyRect:
{
VAEncMiscParameterBufferDirtyRect *vaEncMiscDirtyRect = (VAEncMiscParameterBufferDirtyRect *)miscParamBuf->data;
uint8_t blockSize = (m_encodeCtx->bVdencActive) ? vdencRoiBlockSize : CODECHAL_MACROBLOCK_WIDTH;
uint32_t rightBorder = CODECHAL_GET_WIDTH_IN_BLOCKS(m_encodeCtx->dwFrameWidth, blockSize) - 1;
uint32_t bottomBorder = CODECHAL_GET_HEIGHT_IN_BLOCKS(m_encodeCtx->dwFrameHeight, blockSize) - 1;
DDI_CHK_NULL(vaEncMiscDirtyRect->roi_rectangle, "nullptr dirty rect", VA_STATUS_ERROR_INVALID_PARAMETER);
if(vaEncMiscDirtyRect->num_roi_rectangle > ENCODE_VDENC_HEVC_MAX_DIRTYRECT_G10)
{
DDI_ASSERTMESSAGE("The number of dirty rect is greater than %d", ENCODE_VDENC_HEVC_MAX_DIRTYRECT_G10);
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
picParams->pDirtyRect = m_pDirtyRect;
if (vaEncMiscDirtyRect->num_roi_rectangle > m_numDirtyRects)
{
picParams->pDirtyRect = (PCODEC_ROI)MOS_ReallocMemory(picParams->pDirtyRect, vaEncMiscDirtyRect->num_roi_rectangle * sizeof(CODEC_ROI));
if (!picParams->pDirtyRect)
{
picParams->NumDirtyRects = 0;
DDI_ASSERTMESSAGE("Allocation of pDirtyRect failed!");
return VA_STATUS_ERROR_ALLOCATION_FAILED;
}
m_pDirtyRect = picParams->pDirtyRect;
m_numDirtyRects = vaEncMiscDirtyRect->num_roi_rectangle;
}
if(vaEncMiscDirtyRect->num_roi_rectangle > 0)
{
MOS_ZeroMemory(picParams->pDirtyRect, vaEncMiscDirtyRect->num_roi_rectangle * sizeof(CODEC_ROI));
picParams->NumDirtyRects = 0;
for (int32_t i = 0; i < vaEncMiscDirtyRect->num_roi_rectangle; i++)
{
auto &rect = picParams->pDirtyRect[i];
auto &va_rect = vaEncMiscDirtyRect->roi_rectangle[i];
rect.Left = va_rect.x;
rect.Top = va_rect.y;
rect.Right = va_rect.x + va_rect.width - 1;
rect.Bottom = va_rect.y + va_rect.height - 1;
// Convert from pixel units to block units
rect.Left /= blockSize;
rect.Right /= blockSize;
rect.Top /= blockSize;
rect.Bottom /= blockSize;
// Check and adjust if rect not within frame boundaries
rect.Left = MOS_MIN(rect.Left, rightBorder);
rect.Right = MOS_MIN(rect.Right, rightBorder);
rect.Top = MOS_MIN(rect.Top, bottomBorder);
rect.Bottom = MOS_MIN(rect.Bottom, bottomBorder);
if (rect.Left > rect.Right || rect.Top > rect.Bottom)
{
DDI_ASSERTMESSAGE("Invalid rect region parameter.");
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
picParams->NumDirtyRects ++;
}
}
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 = (vaEncMiscParamMaxSliceSize->max_slice_size > 0) ? true : false;;
picParams->MaxSliceSizeInBytes = vaEncMiscParamMaxSliceSize->max_slice_size;
break;
}
case VAEncMiscParameterTypeEncQuality:
{
VAEncMiscParameterEncQuality *vaEncMiscParamPrivate = (VAEncMiscParameterEncQuality *)miscParamBuf->data;
picParams->bUseRawPicForRef = vaEncMiscParamPrivate->useRawPicForRef;
break;
}
case VAEncMiscParameterTypeMaxFrameSize:
{
VAEncMiscParameterBufferMaxFrameSize *vaEncData = (VAEncMiscParameterBufferMaxFrameSize *)miscParamBuf->data;
seqParams->UserMaxIFrameSize = vaEncData->max_frame_size>>3; // convert to bytes
seqParams->UserMaxPBFrameSize = vaEncData->max_frame_size>>3; // convert to bytes
break;
}
default:
DDI_ASSERTMESSAGE("unsupported misc parameter type.");
return VA_STATUS_ERROR_INVALID_PARAMETER;
}
return VA_STATUS_SUCCESS;
}
uint8_t DdiEncodeHevc::CodechalPicTypeFromVaSlcType(uint8_t vaSliceType)
{
switch (vaSliceType)
{
case sliceTypeI:
return I_TYPE;
case sliceTypeP:
if (m_codechalSettings->isSCCEnabled)
{
PCODEC_HEVC_ENCODE_PICTURE_PARAMS hevcPicParams = (PCODEC_HEVC_ENCODE_PICTURE_PARAMS)((uint8_t *)m_encodeCtx->pPicParams);
if (hevcPicParams->CodingType == I_TYPE && hevcPicParams->pps_curr_pic_ref_enabled_flag)
{
return I_TYPE;
}
}
return P_TYPE;
case sliceTypeB:
return B_TYPE;
default:
return 0;
}
}
void DdiEncodeHevc::GetSlcRefIdx(CODEC_PICTURE *picReference, CODEC_PICTURE *slcReference)
{
if (nullptr == picReference || nullptr == slcReference)
{
return;
}
int32_t i = 0;
if (CODECHAL_NUM_UNCOMPRESSED_SURFACE_HEVC != slcReference->FrameIdx)
{
for (i = 0; i < numMaxRefFrame; i++)
{
if (slcReference->FrameIdx == picReference[i].FrameIdx)
{
slcReference->FrameIdx = i;
slcReference->PicEntry = i;
break;
}
}
if (numMaxRefFrame == i)
{
slcReference->FrameIdx = CODECHAL_NUM_UNCOMPRESSED_SURFACE_HEVC;
slcReference->PicEntry = 0xFF;
}
}
}
void DdiEncodeHevc::SetupCodecPicture(
DDI_MEDIA_CONTEXT *mediaCtx,
DDI_CODEC_RENDER_TARGET_TABLE *rtTbl,
CODEC_PICTURE *codecHalPic,
VAPictureHEVC vaPicHEVC,
bool picReference,
bool sliceReference)
{
DDI_UNUSED(sliceReference);
if (DDI_CODEC_INVALID_FRAME_INDEX != vaPicHEVC.picture_id)
{
codecHalPic->FrameIdx = GetRenderTargetID(rtTbl, DdiMedia_GetSurfaceFromVASurfaceID(mediaCtx, vaPicHEVC.picture_id));
codecHalPic->PicEntry = codecHalPic->FrameIdx;
}
else
{
codecHalPic->FrameIdx = CODECHAL_NUM_UNCOMPRESSED_SURFACE_HEVC;
codecHalPic->PicFlags = PICTURE_INVALID;
codecHalPic->PicEntry = 0xFF;
}
if (PICTURE_INVALID != codecHalPic->PicFlags)
{
codecHalPic->PicFlags = PICTURE_FRAME;
if (picReference)
{
if ((vaPicHEVC.flags & VA_PICTURE_HEVC_LONG_TERM_REFERENCE) == VA_PICTURE_HEVC_LONG_TERM_REFERENCE)
{
codecHalPic->PicFlags = (CODEC_PICTURE_FLAG)(codecHalPic->PicFlags | PICTURE_LONG_TERM_REFERENCE);
codecHalPic->PicEntry |= 0x80;
}
else
{
codecHalPic->PicFlags = (CODEC_PICTURE_FLAG)(codecHalPic->PicFlags | PICTURE_SHORT_TERM_REFERENCE);
}
}
}
}
uint32_t DdiEncodeHevc::getSliceParameterBufferSize()
{
return sizeof(VAEncSliceParameterBufferHEVC);
}
uint32_t DdiEncodeHevc::getSequenceParameterBufferSize()
{
return sizeof(VAEncSequenceParameterBufferHEVC);
}
uint32_t DdiEncodeHevc::getPictureParameterBufferSize()
{
return sizeof(VAEncPictureParameterBufferHEVC);
}
uint32_t DdiEncodeHevc::getQMatrixBufferSize()
{
return sizeof(VAQMatrixBufferHEVC);
}
bool DdiEncodeHevc::IsSccProfile()
{
return (m_encodeCtx->vaProfile==VAProfileHEVCSccMain
|| m_encodeCtx->vaProfile==VAProfileHEVCSccMain10
|| m_encodeCtx->vaProfile==VAProfileHEVCSccMain444
|| m_encodeCtx->vaProfile==VAProfileHEVCSccMain444_10);
}