blob: dabd845b3fb3e0efd6328c823a15fe8252f051c8 [file]
/*
* Copyright (c) 2019-2022, 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 decode_hevc_basic_feature.cpp
//! \brief Defines the common interface for decode hevc parameter
//!
#include <set>
#include "decode_hevc_basic_feature.h"
#include "decode_utils.h"
#include "decode_allocator.h"
namespace decode
{
MOS_STATUS HevcBasicFeature::Init(void *setting)
{
DECODE_FUNC_CALL();
DECODE_CHK_NULL(setting);
DECODE_CHK_NULL(m_hwInterface);
m_shortFormatInUse = ((CodechalSetting*)setting)->shortFormatInUse;
DECODE_CHK_STATUS(DecodeBasicFeature::Init(setting));
DECODE_CHK_STATUS(m_refFrames.Init(this, *m_allocator));
DECODE_CHK_STATUS(m_mvBuffers.Init(m_hwInterface, *m_allocator, *this,
CODEC_NUM_HEVC_INITIAL_MV_BUFFERS));
DECODE_CHK_STATUS(m_tileCoding.Init(this, (CodechalSetting*)setting));
return MOS_STATUS_SUCCESS;
}
HevcBasicFeature::~HevcBasicFeature()
{
if (m_allocator != nullptr)
{
m_allocator->Destroy(m_referenceBeforeLoopFilter);
}
}
MOS_STATUS HevcBasicFeature::Update(void *params)
{
DECODE_FUNC_CALL();
PERF_UTILITY_AUTO(__FUNCTION__, PERF_DECODE, PERF_LEVEL_HAL);
DECODE_CHK_NULL(params);
DECODE_CHK_STATUS(DecodeBasicFeature::Update(params));
CodechalDecodeParams* decodeParams = (CodechalDecodeParams*)params;
DECODE_CHK_NULL(decodeParams->m_picParams);
DECODE_CHK_NULL(decodeParams->m_sliceParams);
DECODE_CHK_NULL(decodeParams->m_iqMatrixBuffer);
m_hevcPicParams = static_cast<PCODEC_HEVC_PIC_PARAMS>(decodeParams->m_picParams);
m_hevcSliceParams = static_cast<PCODEC_HEVC_SLICE_PARAMS>(decodeParams->m_sliceParams);
m_hevcIqMatrixParams = static_cast<PCODECHAL_HEVC_IQ_MATRIX_PARAMS>(decodeParams->m_iqMatrixBuffer);
m_hevcRextPicParams = static_cast<PCODEC_HEVC_EXT_PIC_PARAMS>(decodeParams->m_extPicParams);
m_hevcRextSliceParams= static_cast<PCODEC_HEVC_EXT_SLICE_PARAMS>(decodeParams->m_extSliceParams);
m_hevcSccPicParams = static_cast<PCODEC_HEVC_SCC_PIC_PARAMS>(decodeParams->m_advPicParams);
m_hevcSubsetParams = static_cast<PCODEC_HEVC_SUBSET_PARAMS>(decodeParams->m_subsetParams);
DECODE_CHK_STATUS(SetPictureStructs());
DECODE_CHK_STATUS(SetSliceStructs());
return MOS_STATUS_SUCCESS;
}
MOS_STATUS HevcBasicFeature::ErrorDetectAndConceal()
{
DECODE_FUNC_CALL();
DECODE_CHK_COND(m_curRenderPic.FrameIdx >= CODECHAL_NUM_UNCOMPRESSED_SURFACE_HEVC,
"currPic.FrameIdx is out of range!");
DECODE_CHK_COND(m_hevcPicParams->PicHeightInMinCbsY == 0 || m_hevcPicParams->PicWidthInMinCbsY == 0,
"picture Weight/Height equals to 0!");
// check LCU size
// LCU is restricted based on the picture size.
// LCU 16x16 can only be used with picture width and height both fewer than or equal to 4222 pixels
if (m_width > CODECHAL_HEVC_MAX_DIM_FOR_MIN_LCU ||
m_height > CODECHAL_HEVC_MAX_DIM_FOR_MIN_LCU)
{
DECODE_CHK_COND(m_ctbSize == CODECHAL_HEVC_MIN_LCU, "Invalid LCU size.");
}
// Todo: The maximum support picture size is 16384 pixels for both encoder and decoder.
// check if slice number is valid
DECODE_CHK_COND(m_numSlices > CODECHAL_HEVC_MAX_NUM_SLICES_LVL_6 || m_numSlices == 0,
"slice number is out of range!");
// check if min CtbSize is valid
if (!(m_minCtbSize == 8 || m_minCtbSize == 16 || m_minCtbSize == 32 || m_minCtbSize == 64))
{
DECODE_ASSERTMESSAGE("MinCtbSize is invalid\n");
return MOS_STATUS_INVALID_PARAMETER;
}
// check if CtbSize is valid
if (!(m_ctbSize == 16 || m_ctbSize == 32 || m_ctbSize == 64))
{
DECODE_ASSERTMESSAGE("CtbSize is invalid\n");
return MOS_STATUS_INVALID_PARAMETER;
}
if (m_hevcPicParams->tiles_enabled_flag)
{
// check if tile_columns and tile_rows is valid
DECODE_CHK_COND((m_hevcPicParams->num_tile_columns_minus1 + 1 > HEVC_NUM_MAX_TILE_COLUMN) ||
(m_hevcPicParams->num_tile_rows_minus1 + 1 > HEVC_NUM_MAX_TILE_ROW),
"num_tile_columns_minus1 or num_tile_rows_minus1 is out of range!");
// valid range is [0, m_widthInCtb - 1]
if (m_hevcPicParams->num_tile_columns_minus1 > m_widthInCtb - 1)
{
DECODE_ASSERTMESSAGE("num_tile_columns_minus1 out of range: %d\n",
m_hevcPicParams->num_tile_columns_minus1);
return MOS_STATUS_INVALID_PARAMETER;
}
// valid range is [0, m_heightInCtb - 1]
if (m_hevcPicParams->num_tile_rows_minus1 > m_heightInCtb - 1)
{
DECODE_ASSERTMESSAGE("num_tile_rows_minus1 out of range: %d\n",
m_hevcPicParams->num_tile_rows_minus1);
return MOS_STATUS_INVALID_PARAMETER;
}
}
if (m_hevcPicParams->tiles_enabled_flag && !m_hevcPicParams->uniform_spacing_flag)
{
uint8_t num_tile_columns_minus1 = m_hevcPicParams->num_tile_columns_minus1;
uint8_t num_tile_rows_minus1 = m_hevcPicParams->num_tile_rows_minus1;
uint16_t tileColWidth[HEVC_NUM_MAX_TILE_COLUMN] = {0}; //!< Table of tile column width
uint16_t tileRowHeight[HEVC_NUM_MAX_TILE_ROW] = {0}; //!< Table of tile row height
tileColWidth[num_tile_columns_minus1] = m_widthInCtb & 0xffff;
for (auto i = 0; i < num_tile_columns_minus1; i++)
{
tileColWidth[i] = m_hevcPicParams->column_width_minus1[i] + 1;
DECODE_CHK_COND(tileColWidth[i] == 0,
"column_width_minus1 is invalid");
DECODE_CHK_COND(tileColWidth[i] > tileColWidth[num_tile_columns_minus1],
"column_width_minus1 is out of range");
tileColWidth[num_tile_columns_minus1] -= tileColWidth[i];
}
tileRowHeight[num_tile_rows_minus1] = m_heightInCtb & 0xffff;
for (auto i = 0; i < num_tile_rows_minus1; i++)
{
tileRowHeight[i] = m_hevcPicParams->row_height_minus1[i] + 1;
DECODE_CHK_COND(tileRowHeight[i] == 0,
"row_height_minus1 is invalid");
DECODE_CHK_COND(tileRowHeight[i] > tileRowHeight[num_tile_rows_minus1],
"row_height_minus1 is out of range");
tileRowHeight[num_tile_rows_minus1] -= tileRowHeight[i];
}
}
// diff_cu_qp_delta_depth range is [0, log2_diff_max_min_luma_coding_block_size]
if (m_hevcPicParams->diff_cu_qp_delta_depth > m_hevcPicParams->log2_diff_max_min_luma_coding_block_size)
{
DECODE_ASSERTMESSAGE("diff_cu_qp_delta_depth %d is invalid\n", m_hevcPicParams->diff_cu_qp_delta_depth);
m_hevcPicParams->diff_cu_qp_delta_depth = 0;
}
// cb_qp_offset range is [-12, 12]
if (m_hevcPicParams->pps_cb_qp_offset > 12 || m_hevcPicParams->pps_cb_qp_offset < -12)
{
DECODE_ASSERTMESSAGE("cb_qp_offset is invalid\n", m_hevcPicParams->pps_cb_qp_offset);
return MOS_STATUS_INVALID_PARAMETER;
}
// cr_qp_offset range is [-12, 12]
if (m_hevcPicParams->pps_cr_qp_offset > 12 || m_hevcPicParams->pps_cr_qp_offset < -12)
{
DECODE_ASSERTMESSAGE("cr_qp_offset is invalid\n", m_hevcPicParams->pps_cr_qp_offset);
return MOS_STATUS_INVALID_PARAMETER;
}
// log2_parallel_merge_level_minus2 is in range [0, 4]
if (m_hevcPicParams->log2_parallel_merge_level_minus2 > 4)
{
DECODE_ASSERTMESSAGE("log2_parallel_merge_level_minus2 is out of range\n");
return MOS_STATUS_INVALID_PARAMETER;
}
// The value of log2_parallel_merge_level_minus2 shall be in the range of 0 to CtbLog2SizeY - 2
if (m_hevcPicParams->log2_parallel_merge_level_minus2 >
(m_hevcPicParams->log2_min_luma_coding_block_size_minus3 + 1 + m_hevcPicParams->log2_diff_max_min_luma_coding_block_size))
{
DECODE_ASSERTMESSAGE("log2_parallel_merge_level_minus2 is out of range\n");
return MOS_STATUS_INVALID_PARAMETER;
}
if (m_hevcPicParams->entropy_coding_sync_enabled_flag && m_hevcPicParams->tiles_enabled_flag)
{
// check for non-scc
if (m_hevcSccPicParams == nullptr)
{
DECODE_ASSERTMESSAGE("Only SCC 4:4:4 allows both tiles_enabled_flag and entropy_coding_sync_enabled_flag to be on at the same time\n");
}
}
// Todo: check error detect for Rext
if (m_hevcRextPicParams != nullptr)
{
if (m_hevcPicParams->transform_skip_enabled_flag == 0)
{
m_hevcRextPicParams->log2_max_transform_skip_block_size_minus2 = 0;
DECODE_ASSERTMESSAGE("log2_max_transform_skip_block_size_minus2 should equal to 0 when transform_skip_enabled_flag not present\n");
}
if (m_hevcRextPicParams->diff_cu_chroma_qp_offset_depth > m_hevcPicParams->log2_diff_max_min_luma_coding_block_size)
{
DECODE_ASSERTMESSAGE("diff_cu_chroma_qp_offset_depth is out of range\n");
}
// only for 4:4:4 it can be program to non-zero
if (m_hevcPicParams->chroma_format_idc != 3)
{
DECODE_ASSERTMESSAGE("chroma_qp_offset_list_enabled_flag is only supported in 4:4:4\n");
}
// chroma_qp_offset_list_len_minus1 range is [0, 5]
if (m_hevcRextPicParams->chroma_qp_offset_list_len_minus1 > 5)
{
DECODE_ASSERTMESSAGE("chroma_qp_offset_list_len_minus1 is out of range [0, 5]\n");
}
// check if TU size is valid
auto maxTUSize = m_hevcPicParams->log2_diff_max_min_transform_block_size + m_hevcPicParams->log2_min_transform_block_size_minus2;
if (m_hevcRextPicParams->log2_max_transform_skip_block_size_minus2 > maxTUSize)
{
DECODE_ASSERTMESSAGE("log2_max_transform_skip_block_size_minus2 is out of range\n");
}
}
// Todo: check error detect for SCC
if (m_hevcSccPicParams != nullptr)
{
if (m_hevcPicParams->chroma_format_idc != 3)
{
if (m_hevcPicParams->entropy_coding_sync_enabled_flag && m_hevcPicParams->tiles_enabled_flag)
{
DECODE_ASSERTMESSAGE("Only SCC 4:4:4 allows both tiles_enabled_flag and entropy_coding_sync_enabled_flag to be on at the same time\n");
}
}
}
if (!m_shortFormatInUse)
{
for (uint32_t slcCount = 0; slcCount < m_numSlices; slcCount++)
{
for (uint32_t i = 0; i < 2; i++)
{
for (uint32_t j = 0; j < CODEC_MAX_NUM_REF_FRAME_HEVC; j++)
{
if (m_hevcSliceParams->RefPicList[i][j].FrameIdx > 0x7f)
{
DECODE_ASSERTMESSAGE("Reference frame index is out of range\n");
return MOS_STATUS_INVALID_PARAMETER;
}
}
}
}
}
return MOS_STATUS_SUCCESS;
}
MOS_STATUS HevcBasicFeature::SliceDataSizeCheck(uint32_t sliceIdx)
{
DECODE_FUNC_CALL();
if (m_hevcSliceParams[sliceIdx].slice_data_offset + m_hevcSliceParams[sliceIdx].slice_data_size > m_dataSize)
{
DECODE_ASSERTMESSAGE("invalid slice %d, data size overflow\n", sliceIdx);
return MOS_STATUS_INVALID_PARAMETER;
}
/* Check slice missing data size should not be dropped to 0 */
if (m_hevcSliceParams[sliceIdx].slice_data_size <= m_hevcSliceParams[sliceIdx].ByteOffsetToSliceData)
{
DECODE_ASSERTMESSAGE("slice data size %u should be greater than slice header length %u\n", m_hevcSliceParams[sliceIdx].slice_data_size, m_hevcSliceParams[sliceIdx].ByteOffsetToSliceData);
return MOS_STATUS_INVALID_PARAMETER;
}
return MOS_STATUS_SUCCESS;
}
MOS_STATUS HevcBasicFeature::SliceSegmentAddressCheck(uint32_t sliceIdx, std::vector<int> &sliceSegmentAddressVector)
{
DECODE_FUNC_CALL();
/* When sliceIdx = 0, it should be an independent slice, and its slice_segment_address should be 0 */
if (sliceIdx == 0)
{
if (!IsIndependentSlice(sliceIdx) || m_hevcSliceParams[sliceIdx].slice_segment_address != 0)
{
DECODE_ASSERTMESSAGE("Invalid slice %d, independent slice = %s, slice_segment_address = %d\n",
sliceIdx, IsIndependentSlice(sliceIdx) ? "True" : "False", m_hevcSliceParams[sliceIdx].slice_segment_address);
return MOS_STATUS_INVALID_PARAMETER;
}
}
/* Check slice_segment_address should be in range [0, picSizeInCtbsY - 1] and
* shall not be equal to the value of slice_segment_address of any other coded slice segment NAL unit of the same coded picture */
uint32_t picSizeInCtbsY = m_widthInCtb * m_heightInCtb;
if (sliceIdx != 0) // Previous check has conformed when sliceIdx = 0, slice_segment_address = 0
{
if ((m_hevcSliceParams[sliceIdx].slice_segment_address >= picSizeInCtbsY))
{
DECODE_ASSERTMESSAGE("slice segment address %d is out of range [0, %d]\n",
m_hevcSliceParams[sliceIdx].slice_segment_address, picSizeInCtbsY - 1);
return MOS_STATUS_INVALID_PARAMETER;
}
}
sliceSegmentAddressVector.push_back(m_hevcSliceParams[sliceIdx].slice_segment_address);
if (std::set<int>(sliceSegmentAddressVector.begin(), sliceSegmentAddressVector.end()).size() != sliceSegmentAddressVector.size()) // Has duplicate slice_segment_address
{
DECODE_ASSERTMESSAGE("%dth slice_segment_address %d has duplicated.\n", sliceIdx, m_hevcSliceParams[sliceIdx].slice_segment_address);
return MOS_STATUS_INVALID_PARAMETER;
}
return MOS_STATUS_SUCCESS;
}
MOS_STATUS HevcBasicFeature::NumEntryPointOffsetsCheck(uint32_t sliceIdx)
{
DECODE_FUNC_CALL();
/* Check num_entry_point_offsets */
if (m_hevcPicParams->tiles_enabled_flag || m_hevcPicParams->entropy_coding_sync_enabled_flag)
{
if (m_hevcPicParams->tiles_enabled_flag == 0 && m_hevcPicParams->entropy_coding_sync_enabled_flag == 1)
{
if (m_hevcSliceParams[sliceIdx].num_entry_point_offsets > m_hevcPicParams->PicHeightInMinCbsY - 1)
{
DECODE_ASSERTMESSAGE("num_entry_point_offsets %d is out of range [0, %d]\n",
m_hevcSliceParams[sliceIdx].num_entry_point_offsets, m_hevcPicParams->PicHeightInMinCbsY - 1);
return MOS_STATUS_INVALID_PARAMETER;
}
}
else if (m_hevcPicParams->tiles_enabled_flag == 1 && m_hevcPicParams->entropy_coding_sync_enabled_flag == 0)
{
if (m_hevcSliceParams[sliceIdx].num_entry_point_offsets > ((m_hevcPicParams->num_tile_columns_minus1 + 1) * (m_hevcPicParams->num_tile_rows_minus1 + 1) - 1))
{
DECODE_ASSERTMESSAGE("num_entry_point_offsets %d is out of range [0, %d]\n",
m_hevcSliceParams[sliceIdx].num_entry_point_offsets, (m_hevcPicParams->num_tile_columns_minus1 + 1) * (m_hevcPicParams->num_tile_rows_minus1 + 1) - 1);
return MOS_STATUS_INVALID_PARAMETER;
}
}
else
{
if (m_hevcSliceParams[sliceIdx].num_entry_point_offsets > ((m_hevcPicParams->num_tile_columns_minus1 + 1) * m_hevcPicParams->PicHeightInMinCbsY - 1))
{
DECODE_ASSERTMESSAGE("num_entry_point_offsets %d is out of range [0, %d]\n",
m_hevcSliceParams[sliceIdx].num_entry_point_offsets, (m_hevcPicParams->num_tile_columns_minus1 + 1) * m_hevcPicParams->PicHeightInMinCbsY - 1);
return MOS_STATUS_INVALID_PARAMETER;
}
}
}
return MOS_STATUS_SUCCESS;
}
MOS_STATUS HevcBasicFeature::ReferenceParamCheck(uint32_t sliceIdx)
{
DECODE_FUNC_CALL();
/* If it's P or B slice, the num_ref_idx_lx_active_minus1 should be in range [0, 14] */
if (decodeHevcISlice != m_hevcSliceParams[sliceIdx].LongSliceFlags.fields.slice_type)
{
if (m_hevcSliceParams[sliceIdx].num_ref_idx_l0_active_minus1 >= CODEC_MAX_NUM_REF_FRAME_HEVC )
{
DECODE_ASSERTMESSAGE("num_ref_idx_l0_active_minus1 %d is out of range [0, 14]\n", m_hevcSliceParams[sliceIdx].num_ref_idx_l0_active_minus1);
return MOS_STATUS_INVALID_PARAMETER;
}
if (decodeHevcBSlice == m_hevcSliceParams[sliceIdx].LongSliceFlags.fields.slice_type)
{
if (m_hevcSliceParams[sliceIdx].num_ref_idx_l1_active_minus1 >= CODEC_MAX_NUM_REF_FRAME_HEVC)
{
DECODE_ASSERTMESSAGE("num_ref_idx_l1_active_minus1 %d is out of range [0, 14]\n", m_hevcSliceParams[sliceIdx].num_ref_idx_l1_active_minus1);
return MOS_STATUS_INVALID_PARAMETER;
}
}
}
/* Check RefPicList[listIdx][refIdx].FrameIdx */
uint32_t num_ref_idx_active_minus1[2] = {0};
num_ref_idx_active_minus1[0] = m_hevcSliceParams[sliceIdx].num_ref_idx_l0_active_minus1;
num_ref_idx_active_minus1[1] = m_hevcSliceParams[sliceIdx].num_ref_idx_l1_active_minus1;
bool hasRefPic[2] = {false};
uint8_t reflistNum = 0;
switch (m_hevcSliceParams[sliceIdx].LongSliceFlags.fields.slice_type)
{
case decodeHevcISlice:
reflistNum = 0;
break;
case decodeHevcPSlice:
reflistNum = 1;
break;
case decodeHevcBSlice:
reflistNum = 2;
break;
default:
break;
}
for (uint8_t listIdx = 0; listIdx < reflistNum; listIdx++)
{
/* If num_ref_idx_lx_active_minus1 is in [0, 14], it should have at least 1 reference picture. */
for (uint8_t refListIdx = 0; refListIdx <= num_ref_idx_active_minus1[listIdx]; refListIdx++)
{
if (m_hevcSliceParams[sliceIdx].RefPicList[listIdx][refListIdx].FrameIdx < CODEC_MAX_NUM_REF_FRAME_HEVC)
{
hasRefPic[listIdx] = true;
break;
}
}
if (false == hasRefPic[listIdx])
{
DECODE_ASSERTMESSAGE("num_ref_idx_active_minus1[%d] = %d, RefPicList[%d].FrameIdx is all 127\n",
listIdx, num_ref_idx_active_minus1[listIdx], listIdx);
return MOS_STATUS_INVALID_PARAMETER;
}
}
return MOS_STATUS_SUCCESS;
}
MOS_STATUS HevcBasicFeature::CollocatedRefIdxCheck(uint32_t sliceIdx)
{
DECODE_FUNC_CALL();
if (m_hevcSliceParams[sliceIdx].LongSliceFlags.fields.slice_temporal_mvp_enabled_flag)
{
/* Check collocated_ref_idx */
if (((m_hevcSliceParams[sliceIdx].LongSliceFlags.fields.slice_type == decodeHevcPSlice) || (m_hevcSliceParams[sliceIdx].LongSliceFlags.fields.slice_type == decodeHevcBSlice))
&& m_hevcSliceParams[sliceIdx].LongSliceFlags.fields.collocated_from_l0_flag)
{
if (m_hevcSliceParams[sliceIdx].collocated_ref_idx > m_hevcSliceParams[sliceIdx].num_ref_idx_l0_active_minus1)
{
DECODE_ASSERTMESSAGE("collocated_ref_idx %d is out of range [%d, %d]\n", m_hevcSliceParams[sliceIdx].collocated_ref_idx, 0, m_hevcSliceParams[sliceIdx].num_ref_idx_l0_active_minus1);
return MOS_STATUS_INVALID_PARAMETER;
}
}
if ((m_hevcSliceParams[sliceIdx].LongSliceFlags.fields.slice_type == decodeHevcBSlice) && (m_hevcSliceParams[sliceIdx].LongSliceFlags.fields.collocated_from_l0_flag == 0))
{
if (m_hevcSliceParams[sliceIdx].collocated_ref_idx > m_hevcSliceParams[sliceIdx].num_ref_idx_l1_active_minus1)
{
DECODE_ASSERTMESSAGE("collocated_ref_idx %d is out of range [%d, %d]\n", m_hevcSliceParams[sliceIdx].collocated_ref_idx, 0, m_hevcSliceParams[sliceIdx].num_ref_idx_l1_active_minus1);
return MOS_STATUS_INVALID_PARAMETER;
}
}
}
return MOS_STATUS_SUCCESS;
}
MOS_STATUS HevcBasicFeature::ErrorDetectAndConcealForLongFormat()
{
DECODE_FUNC_CALL();
std::vector<int> sliceSegmentAddressVector;
for (uint32_t sliceIdx = 0; sliceIdx < m_numSlices; sliceIdx++)
{
DECODE_CHK_STATUS(SliceDataSizeCheck(sliceIdx));
DECODE_CHK_STATUS(SliceSegmentAddressCheck(sliceIdx, sliceSegmentAddressVector));
DECODE_CHK_STATUS(NumEntryPointOffsetsCheck(sliceIdx));
DECODE_CHK_STATUS(ReferenceParamCheck(sliceIdx));
DECODE_CHK_STATUS(CollocatedRefIdxCheck(sliceIdx));
}
return MOS_STATUS_SUCCESS;
}
bool HevcBasicFeature::IsLastSlice(uint32_t sliceIdx)
{
return (sliceIdx == (m_numSlices-1)) ||
m_hevcSliceParams[sliceIdx].LongSliceFlags.fields.LastSliceOfPic;
}
bool HevcBasicFeature::IsIndependentSlice(uint32_t sliceIdx)
{
return (sliceIdx == 0) ||
(! m_hevcSliceParams[sliceIdx].LongSliceFlags.fields.dependent_slice_segment_flag);
}
MOS_STATUS HevcBasicFeature::SetRequiredBitstreamSize(uint32_t requiredSize)
{
DECODE_FUNC_CALL();
if (requiredSize > m_dataSize)
{
m_dataOffset = 0;
m_dataSize = MOS_ALIGN_CEIL(requiredSize, MHW_CACHELINE_SIZE);
}
DECODE_NORMALMESSAGE("Estimate bitstream size in this Frame: %u", requiredSize);
return MOS_STATUS_SUCCESS;
}
MOS_STATUS HevcBasicFeature::SetPictureStructs()
{
DECODE_FUNC_CALL();
m_minCtbSize = 1 << (m_hevcPicParams->log2_min_luma_coding_block_size_minus3 + 3);
m_width = m_hevcPicParams->PicWidthInMinCbsY * m_minCtbSize;
m_height = m_hevcPicParams->PicHeightInMinCbsY * m_minCtbSize;
m_ctbSize = 1 << (m_hevcPicParams->log2_diff_max_min_luma_coding_block_size +
m_hevcPicParams->log2_min_luma_coding_block_size_minus3 + 3);
m_widthInCtb = MOS_ROUNDUP_DIVIDE(m_width, m_ctbSize);
m_heightInCtb = MOS_ROUNDUP_DIVIDE(m_height, m_ctbSize);
m_curRenderPic = m_hevcPicParams->CurrPic;
// Do error detection and concealment
DECODE_CHK_STATUS(ErrorDetectAndConceal());
m_secondField = CodecHal_PictureIsBottomField(m_curRenderPic);
m_isWPPMode = m_hevcPicParams->entropy_coding_sync_enabled_flag;
if (m_hevcSccPicParams == nullptr)
{
m_isSCCIBCMode = false;
m_isSCCPLTMode = false;
m_isSCCACTMode = false;
}
else
{
m_isSCCIBCMode = m_hevcSccPicParams->PicSCCExtensionFlags.fields.pps_curr_pic_ref_enabled_flag;
m_isSCCPLTMode = m_hevcSccPicParams->PicSCCExtensionFlags.fields.palette_mode_enabled_flag;
m_isSCCACTMode = m_hevcSccPicParams->PicSCCExtensionFlags.fields.residual_adaptive_colour_transform_enabled_flag;
}
if (m_isSCCIBCMode)
{
DECODE_CHK_STATUS(CreateReferenceBeforeLoopFilter());
}
m_refFrameIndexList.clear();
for(uint32_t i = 0; i < CODEC_MAX_NUM_REF_FRAME_HEVC; i++)
{
if (m_hevcPicParams->RefFrameList[i].FrameIdx < m_maxFrameIndex)
{
m_refFrameIndexList.push_back(m_hevcPicParams->RefFrameList[i].FrameIdx);
}
}
m_reportFrameCrc = m_hevcPicParams->RequestCRC;
DECODE_CHK_STATUS(m_refFrames.UpdatePicture(*m_hevcPicParams, m_isSCCIBCMode));
if (m_osInterface->pfnIsMismatchOrderProgrammingSupported())
{
for (auto &refFrameIdx : m_refFrameIndexList)
{
DECODE_CHK_STATUS(m_mvBuffers.ActiveCurBuffer(refFrameIdx));
}
DECODE_CHK_STATUS(m_mvBuffers.ActiveCurBuffer(m_curRenderPic.FrameIdx));
}
else
{
DECODE_CHK_STATUS(m_mvBuffers.UpdatePicture(m_curRenderPic.FrameIdx, m_refFrameIndexList));
}
DECODE_CHK_STATUS(m_tileCoding.UpdatePicture(*m_hevcPicParams));
// Not possible to determine whether P or B is used for short format.
// For long format iterating through all of the slices to determine P vs
// B, so in order to avoid this, declare all other pictures MIXED_TYPE.
m_pictureCodingType = m_refFrames.m_curIsIntra ? I_TYPE : MIXED_TYPE;
// Clean dummy reference slot, will be upated by Hevc picture packet accrodingly
MOS_ZeroMemory(m_dummyReferenceSlot, sizeof(m_dummyReferenceSlot));
return MOS_STATUS_SUCCESS;
}
MOS_STATUS HevcBasicFeature::SetSliceStructs()
{
DECODE_FUNC_CALL();
DECODE_CHK_STATUS(m_tileCoding.UpdateSlice(*m_hevcPicParams, m_hevcSliceParams));
if (m_numSlices > 0)
{
PCODEC_HEVC_SLICE_PARAMS lastSlice = m_hevcSliceParams + (m_numSlices - 1);
DECODE_CHK_STATUS(SetRequiredBitstreamSize(lastSlice->slice_data_offset + lastSlice->slice_data_size));
}
if (!m_shortFormatInUse)
{
DECODE_CHK_STATUS(ErrorDetectAndConcealForLongFormat());
}
return MOS_STATUS_SUCCESS;
}
MOS_STATUS HevcBasicFeature::CreateReferenceBeforeLoopFilter()
{
if (m_destSurface.dwWidth == 0 ||
m_destSurface.dwHeight == 0)
{
return MOS_STATUS_SUCCESS;
}
if (m_referenceBeforeLoopFilter == nullptr)
{
m_referenceBeforeLoopFilter = m_allocator->AllocateSurface(
m_destSurface.dwWidth, m_destSurface.dwHeight, "Reference before loop filter",
m_destSurface.Format, m_destSurface.bCompressible, resourceOutputPicture, notLockableVideoMem);
DECODE_CHK_NULL(m_referenceBeforeLoopFilter);
}
else
{
DECODE_CHK_STATUS(m_allocator->Resize(m_referenceBeforeLoopFilter, m_destSurface.dwWidth, m_destSurface.dwHeight,
notLockableVideoMem, false, "Reference before loop filter"));
}
return MOS_STATUS_SUCCESS;
}
} // namespace encode