libhevc: Implement 10-bit 444 Chroma Intra-Prediction

This commit adds spatial intra-prediction support for 10-bit 444
chroma blocks during the decoder's prediction stage.

Changes include:
- Updated ihevc_hbd_chroma_intra_pred_filters.c to add 444 scaling
  (sub_sample = 2 vs sub_sample = 1).
- Added support for 32x32 chroma block predictions (nt == 32), which
  is the maximum chroma transform unit size in the 444 profile.
- Integrated the new filtering logic by updating the CTB intra-prediction
  loop in ihevcd_iquant_itrans_recon_ctb.c
This commit is contained in:
Narayan Kalaburgi 2026-08-11 16:05:27 +05:30 • committed by Harish Mahendrakar
parent a2ff0ddeff
commit f90307a9d6
3 changed files with 194 additions and 23 deletions

View file

@ -135,6 +135,12 @@ typedef void ihevc_intra_pred_chroma_ref_filtering_ft(UWORD8 *pu1_src,
WORD32 mode,
WORD32 intra_smoothing_flags);
typedef void ihevc_hbd_intra_pred_chroma_ref_filtering_ft(UWORD16* pu2_src,
WORD32 nt,
UWORD16* pu2_dst,
WORD32 mode,
WORD32 intra_smoothing_flags);
typedef void ihevc_hbd_intra_pred_chroma_planar_ft(
UWORD16 *pu2_ref,
WORD32 src_strd,
@ -233,6 +239,7 @@ typedef void ihevc_hbd_intra_pred_chroma_ref_substitution_ft(UWORD16 *pu2_top_le
WORD32 nbr_flags,
UWORD16 *pu2_dst,
WORD32 dst_strd,
WORD32 chroma_format_idc,
UWORD8 bit_depth);
/* C function declarations */
@ -260,6 +267,7 @@ ihevc_hbd_intra_pred_chroma_mode_11_to_17_ft ihevc_hbd_intra_pred_chroma_mode_11
ihevc_hbd_intra_pred_chroma_mode_19_to_25_ft ihevc_hbd_intra_pred_chroma_mode_19_to_25;
ihevc_hbd_intra_pred_chroma_mode_27_to_33_ft ihevc_hbd_intra_pred_chroma_mode_27_to_33;
ihevc_hbd_intra_pred_chroma_ref_substitution_ft ihevc_hbd_intra_pred_chroma_ref_substitution;
ihevc_hbd_intra_pred_chroma_ref_filtering_ft ihevc_hbd_intra_pred_chroma_ref_filtering;
/* C function declarations */
ihevc_intra_pred_chroma_planar_ft ihevc_intra_pred_chroma_planar;

View file

@ -67,6 +67,7 @@
#include "ihevc_function_selector.h"
#include "ihevc_platform_macros.h"
#include "ihevc_intra_pred.h"
#include "ihevc_defs.h"
#include "ihevc_chroma_intra_pred.h"
#include "ihevc_common_tables.h"
@ -87,6 +88,97 @@
/* Function Definition */
/*****************************************************************************/
/**
*******************************************************************************
*
* @brief
* Intra prediction interpolation filter for chroma ref_filtering (4:4:4)
*
*
* @par Description:
* Reference DC filtering for neighboring chroma samples dependent on TU size and
* mode Refer to section 8.4.4.2.3 in the standard
*
* @param[in] pu2_src
* UWORD16 pointer to the source
*
* @param[out] pu2_dst
* UWORD16 pointer to the destination
*
* @param[in] nt
* integer Transform Block size
*
* @param[in] mode
* integer intraprediction mode
*
* @param[in] intra_smoothing_flag
* integer containing intra_smoothing_disabled_flag and strong_smoothing_enable_flag
*
* @returns
*
* @remarks
* None
*
*******************************************************************************
*/
void ihevc_hbd_intra_pred_chroma_ref_filtering(UWORD16* pu2_src,
WORD32 nt,
UWORD16* pu2_dst,
WORD32 mode,
WORD32 intra_smoothing_flag)
{
WORD32 filter_flag;
WORD32 i; /* Generic indexing variable */
WORD32 four_nt = 4 * nt;
UWORD16 au2_flt[((4 * MAX_CU_SIZE) + 1) * 2];
WORD32 intra_smoothing_disabled_flag = (intra_smoothing_flag >> 3) & 0x1;
WORD32 strong_intra_smoothing_enable_flag = intra_smoothing_flag & 0x1;
UNUSED(strong_intra_smoothing_enable_flag);
if (intra_smoothing_disabled_flag)
{
if (pu2_src == pu2_dst) return;
for (i = 0; i < (2 * (four_nt + 1)); i += 2)
{
pu2_dst[i] = pu2_src[i];
pu2_dst[i + 1] = pu2_src[i + 1];
}
return;
}
filter_flag = gau1_intra_pred_ref_filter[mode] & (1 << (CTZ(nt) - 2));
if (0 == filter_flag)
{
if (pu2_src == pu2_dst) return;
for (i = 0; i < (2 * (four_nt + 1)); i += 2)
{
pu2_dst[i] = pu2_src[i];
pu2_dst[i + 1] = pu2_src[i + 1];
}
}
else
{
/* Extremities Untouched*/
au2_flt[0] = pu2_src[0];
au2_flt[1] = pu2_src[1];
au2_flt[four_nt * 2] = pu2_src[four_nt * 2];
au2_flt[(four_nt * 2) + 1] = pu2_src[(four_nt * 2) + 1];
for (i = 2; i < four_nt * 2; i += 2)
{
au2_flt[i] = (pu2_src[i - 2] + 2 * pu2_src[i] + pu2_src[i + 2] + 2) >> 2;
au2_flt[i + 1] = (pu2_src[i - 1] + 2 * pu2_src[i + 1] + pu2_src[i + 3] + 2) >> 2;
}
for (i = 0; i < (2 * (four_nt + 1)); i += 2)
{
pu2_dst[i] = au2_flt[i];
pu2_dst[i + 1] = au2_flt[i + 1];
}
}
}
/**
*******************************************************************************
*
@ -135,6 +227,7 @@ void ihevc_hbd_intra_pred_chroma_ref_substitution(UWORD16 * pu2_top_left,
WORD32 nbr_flags,
UWORD16 * pu2_dst,
WORD32 dst_strd,
WORD32 chroma_format_idc,
UWORD8 bit_depth)
{
UWORD16 pu2_ref_u, pu2_ref_v;
@ -213,7 +306,7 @@ void ihevc_hbd_intra_pred_chroma_ref_substitution(UWORD16 * pu2_top_left,
pu2_dst[(4 * nt ) + 2 + i] = pu2_top[i]; // U-V interleaved Top-top right samples
}
}
if(nt == 4)
if (nt == 4 || (nt == 8 && chroma_format_idc == CHROMA_FMT_IDC_YUV444))
{
/* 1 bit extraction for all the neighboring blocks */
tp_left = (nbr_flags & 0x10000) >> 16;
@ -292,9 +385,10 @@ void ihevc_hbd_intra_pred_chroma_ref_substitution(UWORD16 * pu2_top_left,
}
}
}
else if(nt == 8)
else if (nt == 8 || (nt == 16 && chroma_format_idc == CHROMA_FMT_IDC_YUV444))
{
WORD32 nbr_flags_temp = 0;
WORD32 sub_sample = chroma_format_idc == CHROMA_FMT_IDC_YUV444 ? 2 : 1;
nbr_flags_temp = ((nbr_flags & 0xC)>>2) + ((nbr_flags & 0xC0) >> 4)
+ ((nbr_flags & 0x300) >> 4)
+ ((nbr_flags & 0x3000) >> 6)
@ -303,18 +397,18 @@ void ihevc_hbd_intra_pred_chroma_ref_substitution(UWORD16 * pu2_top_left,
/* compute trailing zeors based on nbr_flag for substitution process of below left see section .*/
/* as each bit in nbr flags corresponds to 8 pels for bot_left, left, top and topright but 1 pel for topleft */
{
nbr_id_from_bl = look_up_trailing_zeros(nbr_flags_temp & 0XF) * 4; /* for bottom left and left */
if(nbr_id_from_bl == 32)
nbr_id_from_bl = look_up_trailing_zeros(nbr_flags_temp & 0XF) * (4 * sub_sample); /* for bottom left and left */
if (nbr_id_from_bl == (32 * sub_sample))
{
nbr_id_from_bl = 16;
nbr_id_from_bl = (16 * sub_sample);
}
if(nbr_id_from_bl == 16)
if (nbr_id_from_bl == (16 * sub_sample))
{
/* for top left : 1 pel per nbr bit */
if(!((nbr_flags_temp >> 8) & 0x1))
{
nbr_id_from_bl++;
nbr_id_from_bl += look_up_trailing_zeros((nbr_flags_temp >> 4) & 0xF) * 4; /* top and top right; 8 pels per nbr bit */
nbr_id_from_bl += look_up_trailing_zeros((nbr_flags_temp >> 4) & 0xF) * (4 * sub_sample); /* top and top right; 8 pels per nbr bit */
}
}
@ -333,14 +427,14 @@ void ihevc_hbd_intra_pred_chroma_ref_substitution(UWORD16 * pu2_top_left,
}
/* for the loop of 4*Nt+1 pixels (excluding pixels computed from reverse substitution) */
while(nbr_id_from_bl < ((T8C_4NT) + 1))
while (nbr_id_from_bl < ((T8C_4NT * sub_sample) + 1))
{
/* To Obtain the next unavailable idx flag after reverse neighbor substitution */
/* Divide by 8 to obtain the original index */
frwd_nbr_flag = (nbr_id_from_bl >> 2);/*+ (nbr_id_from_bl & 0x1);*/
frwd_nbr_flag = (nbr_id_from_bl >> (chroma_format_idc == CHROMA_FMT_IDC_YUV444 ? 3 : 2));/*+ (nbr_id_from_bl & 0x1);*/
/* The Top-left flag is at the last bit location of nbr_flags*/
if(nbr_id_from_bl == (T8C_4NT / 2))
if (nbr_id_from_bl == (T8C_4NT * sub_sample / 2))
{
get_bits = GET_BIT(nbr_flags_temp, 8);
@ -359,24 +453,25 @@ void ihevc_hbd_intra_pred_chroma_ref_substitution(UWORD16 * pu2_top_left,
/* 8 pel substitution (other than TL) */
pu2_ref_u = pu2_dst[(2 * nbr_id_from_bl) - 2];
pu2_ref_v = pu2_dst[(2 * nbr_id_from_bl) - 1];
for(i = 0; i < 8; i+=2)
for (i = 0; i < 8 * sub_sample; i += 2)
{
pu2_dst[(2 * nbr_id_from_bl) + i] = pu2_ref_u;
pu2_dst[(2 * nbr_id_from_bl) + 1 + i] = pu2_ref_v;
}
}
}
nbr_id_from_bl += (nbr_id_from_bl == (T8C_4NT / 2)) ? 1 : 4;
nbr_id_from_bl += (nbr_id_from_bl == (T8C_4NT * sub_sample / 2)) ? 1 : 4 * sub_sample;
}
}
else if(nt == 16)
else if (nt == 16 || (nt == 32 && chroma_format_idc == CHROMA_FMT_IDC_YUV444))
{
WORD32 sub_sample = chroma_format_idc == CHROMA_FMT_IDC_YUV444 ? 2 : 1;
/* compute trailing ones based on mbr_flag for substitution process of below left see section .*/
/* as each bit in nbr flags corresponds to 4 pels for bot_left, left, top and topright but 1 pel for topleft */
{
nbr_id_from_bl = look_up_trailing_zeros((nbr_flags & 0XFF)) * 4; /* for bottom left and left */
nbr_id_from_bl = look_up_trailing_zeros((nbr_flags & 0XFF)) * 4 * sub_sample; /* for bottom left and left */
if(nbr_id_from_bl == 32)
if (nbr_id_from_bl == 32 * sub_sample)
{
/* for top left : 1 pel per nbr bit */
if(!((nbr_flags >> 16) & 0x1))
@ -384,7 +479,7 @@ void ihevc_hbd_intra_pred_chroma_ref_substitution(UWORD16 * pu2_top_left,
/* top left not available */
nbr_id_from_bl++;
/* top and top right; 4 pels per nbr bit */
nbr_id_from_bl += look_up_trailing_zeros((nbr_flags >> 8) & 0xFF) * 4;
nbr_id_from_bl += look_up_trailing_zeros((nbr_flags >> 8) & 0xFF) * 4 * sub_sample;
}
}
/* Reverse Substitution Process*/
@ -402,14 +497,14 @@ void ihevc_hbd_intra_pred_chroma_ref_substitution(UWORD16 * pu2_top_left,
}
/* for the loop of 4*Nt+1 pixels (excluding pixels computed from reverse substitution) */
while(nbr_id_from_bl < ((T16C_4NT) + 1))
while (nbr_id_from_bl < ((T16C_4NT * sub_sample) + 1))
{
/* To Obtain the next unavailable idx flag after reverse neighbor substitution */
/* Devide by 4 to obtain the original index */
frwd_nbr_flag = (nbr_id_from_bl >> 2);/*+ (nbr_id_from_bl & 0x1);*/
/* Divide by 4 to obtain the original index */
frwd_nbr_flag = (nbr_id_from_bl >> (chroma_format_idc == CHROMA_FMT_IDC_YUV444 ? 3 : 2));/*+ (nbr_id_from_bl & 0x1);*/
/* The Top-left flag is at the last bit location of nbr_flags*/
if(nbr_id_from_bl == (T16C_4NT / 2))
if (nbr_id_from_bl == (T16C_4NT * sub_sample / 2))
{
get_bits = GET_BIT(nbr_flags, 16);
/* only pel substitution for TL */
@ -427,14 +522,82 @@ void ihevc_hbd_intra_pred_chroma_ref_substitution(UWORD16 * pu2_top_left,
/* 4 pel substitution (other than TL) */
pu2_ref_u = pu2_dst[(2 * nbr_id_from_bl) - 2];
pu2_ref_v = pu2_dst[(2 * nbr_id_from_bl) - 1];
for(i = 0; i < 8; i+=2)
for (i = 0; i < 4 * sub_sample; i++)
{
pu2_dst[(2 * nbr_id_from_bl) + 2 * i] = pu2_ref_u;
pu2_dst[(2 * nbr_id_from_bl) + 1 + 2 * i] = pu2_ref_v;
}
}
}
nbr_id_from_bl += (nbr_id_from_bl == (T16C_4NT * sub_sample / 2)) ? 1 : 4 * sub_sample;
}
}
else if (nt == 32)
{
/* compute trailing ones based on mbr_flag for substitution process of below left see section .*/
/* as each bit in nbr flags corresponds to 8 pels for bot_left, left, top and topright but 1 pel for topleft */
{
nbr_id_from_bl = look_up_trailing_zeros((nbr_flags & 0XFF)) * 8; /* for bottom left and left */
if (nbr_id_from_bl == 64)
{
/* for top left : 1 pel per nbr bit */
if (!((nbr_flags >> 16) & 0x1))
{
/* top left not available */
nbr_id_from_bl++;
/* top and top right; 8 pels per nbr bit */
nbr_id_from_bl += look_up_trailing_zeros((nbr_flags >> 8) & 0xFF) * 8;
}
}
/* Reverse Substitution Process*/
if (nbr_id_from_bl)
{
/* Replicate the bottom-left and subsequent unavailable pixels with the 1st available pixel above */
pu2_ref_u = pu2_dst[2 * nbr_id_from_bl];
pu2_ref_v = pu2_dst[2 * nbr_id_from_bl + 1];
for (i = (2 * (nbr_id_from_bl - 1)); i >= 0; i -= 2)
{
pu2_dst[i] = pu2_ref_u;
pu2_dst[i + 1] = pu2_ref_v;
}
}
}
/* for the loop of 4*Nt+1 pixels (excluding pixels computed from reverse substitution) */
while (nbr_id_from_bl < (128 + 1))
{
/* To Obtain the next unavailable idx flag after reverse neighbor substitution */
/* Devide by 8 to obtain the original index */
frwd_nbr_flag = (nbr_id_from_bl >> 3);
/* The Top-left flag is at the last bit location of nbr_flags*/
if (nbr_id_from_bl == 64)
{
get_bits = GET_BIT(nbr_flags, 16);
/* only pel substitution for TL */
if (!get_bits)
{
pu2_dst[2 * nbr_id_from_bl] = pu2_dst[(2 * nbr_id_from_bl) - 2];
pu2_dst[(2 * nbr_id_from_bl) + 1] = pu2_dst[(2 * nbr_id_from_bl) - 1];
}
}
else
{
get_bits = GET_BIT(nbr_flags, frwd_nbr_flag);
if (!get_bits)
{
/* 8 pel substitution (other than TL) */
pu2_ref_u = pu2_dst[(2 * nbr_id_from_bl) - 2];
pu2_ref_v = pu2_dst[(2 * nbr_id_from_bl) - 1];
for (i = 0; i < 16; i += 2)
{
pu2_dst[(2 * nbr_id_from_bl) + i] = pu2_ref_u;
pu2_dst[(2 * nbr_id_from_bl) + 1 + i] = pu2_ref_v;
}
}
}
nbr_id_from_bl += (nbr_id_from_bl == (T16C_4NT / 2)) ? 1 : 4;
nbr_id_from_bl += (nbr_id_from_bl == T16C_4NT) ? 1 : 8;
}
}
}

View file

@ -1746,7 +1746,7 @@ WORD32 ihevcd_iquant_itrans_recon_ctb(process_ctxt_t *ps_proc)
{
ps_codec->s_func_selector.ihevc_hbd_intra_pred_chroma_ref_substitution_fptr((UWORD16 *)pu1_top_left,
(UWORD16 *)pu1_top, (UWORD16 *)pu1_left, ps_cb_tu->pred_strd, trans_size,
chroma_nbr_flags, (UWORD16 *)pu1_ref_sub_out, 1,
chroma_nbr_flags, (UWORD16 *)pu1_ref_sub_out, 1, ps_sps->i1_chroma_format_idc,
(UWORD8) i4_bit_depth_chroma);
/* use the look up to get the function idx */