【H264解析Demo】12、去块滤波

框架结构

一帧的所有宏块的在重建完成解码像素之后,针对整个slice操作的,所以去块滤波的操作需要放在slice的解析中,对整个一帧数据

for (int idx = 0; idx < m_max_mb_number; idx++)
{
	m_macroblocks[idx]->Deblock_macroblock();
}

1、获取当前是否为上边沿和左边沿宏块
2、获取slice heder中的标志位,确定当前slice是否需要进行去块滤波
3、分别进行垂直和水平方向的滤波

//<去块滤波><1>针对每个宏块的去块滤波
int CMacroblock::Deblock_macroblock()
{
	int width_in_mb = m_slice->m_sps_active->Get_pic_width_in_mbs();
	int height_in_mb = m_slice->m_sps_active->Get_pic_height_in_mbs();
	int total_filter_strength = 0, filter_strength_arr[16] = { 0 };

	bool filterLeftMbEdgeFlag = (m_mb_idx % width_in_mb != 0);	//<去块滤波><1>是否是最左边的宏块
	bool filterTopMbEdgeFlag = (m_mb_idx >= width_in_mb);		//<去块滤波><1>不是上边沿应该要被滤波

	//<去块滤波><1>不需要进行去块滤波的操作
	if (m_slice->m_sliceHeader->m_disable_deblocking_filter_idc == 1)
	{
		return kPARSING_ERROR_NO_ERROR;
	}

	m_mb_alpha_c0_offset = m_slice->m_sliceHeader->m_slice_alpha_c0_offset;	//<去块滤波><1>判断每条边界是否需要滤波的一个判断条件所需要的数据
	m_mb_beta_offset = m_slice->m_sliceHeader->m_slice_beta_offset;

	// Vertical filtering luma		1、垂直方向的滤波

	// Horizontal filtering luma	2、水平方向的滤波


	return kPARSING_ERROR_NO_ERROR;
}

计算滤波强度

参考标准文档8.7.2.1,下面只是针对帧内预测编码的情况,最左边的边沿对应的滤波强度为4,非最左边的边沿为3

//<去块滤波><2>计算滤波强度:edge边界序号  strength这条边沿的滤波强度数组  标准文档8.7.2.1
int CMacroblock::get_filtering_strength(int edge, int strength[16])
{
	int total_strength = 0;
	for (int idx = 0; idx < 16; idx++)
	{
		strength[idx] = (edge == 0) ? 4 : 3;	//<去块滤波><2>只针对帧内预测edge == 0为宏块的边沿
		total_strength += strength[idx];
	}

	return total_strength;
}

获取参考像素

下图中虚线表示的边沿1,左边是0,后面是2和3,;参考像素为第一列子宏块的4个和第二列子宏块的4个
在这里插入图片描述

//<去块滤波><5>
/*获取边沿上参考像素的值:pixel_arr读取到的参考数据的值
 *target_mb_idx:左侧或者上边宏块序号
 *edge:第几个边沿
 *pix_idx:边沿的第几个像素
 */
int CMacroblock::get_edge_pixel_item(int dir, int target_mb_idx, int edge, int pix_idx, int luma, int pixel_arr[8])
{
	CMacroblock *target = NULL;	
	int neighbor_blk_idx = -1, blk_idx = pix_idx / 4, pix_pos = pix_idx % 4;//<去块滤波><5>blk_idx当前宏块所处的子块从上至下的序号  pix_pos像素在当前子块中的位置
	/*
	For luma:
		pix_idx ranges [0,15], so blk_idx means the block index the pixel belongs to, and pix_pos means the pixel index in the sub block.
	*/
	if (edge)// Internal Filtering
	{
		target = this;
		neighbor_blk_idx = edge - 1;	//<去块滤波><5>edge是从16*16宏块的最左边边沿开始的
	}
	else
	{
		target = m_slice->Get_macroblock_at_index(target_mb_idx);
		neighbor_blk_idx = 3;
	}

	if (luma)
	{
		if (!dir) // Vertical
		{
			for (int idx = 0; idx < 4; idx++)
			{
				pixel_arr[idx] = target->m_reconstructed_block[blk_idx][neighbor_blk_idx][pix_pos][idx];
			}
			for (int idx = 4; idx < 8; idx++)
			{
				pixel_arr[idx] = m_reconstructed_block[blk_idx][edge][pix_pos][idx-4];
			}
		}
		else //Horizontal
		{
			for (int idx = 0; idx < 4; idx++)
			{
				pixel_arr[idx] = target->m_reconstructed_block[neighbor_blk_idx][blk_idx][idx][pix_pos];
			}
			for (int idx = 4; idx < 8; idx++)
			{
				pixel_arr[idx] = m_reconstructed_block[edge][blk_idx][idx - 4][pix_pos];
			}
		}		
	}


	return kPARSING_ERROR_NO_ERROR;
}

滤波边界像素

1、准备条件:准备bs(滤波强度)、p0(参考像素)、α、β

avg_qp = (m_mb_qp + m_slice->Get_macroblock_at_index(mb_idx)->m_mb_qp + 1) >> 1;		//<去块滤波><6>边界两侧所属宏块qp的平均值

index_a = IClip(0, MAX_QP, avg_qp + m_mb_alpha_c0_offset);	//<去块滤波><6>两个索引值,m_mb_alpha_c0_offset从当前的slice中读取出来的
index_b = IClip(0, MAX_QP, avg_qp + m_mb_beta_offset);			//<去块滤波><6>IClip就是把输出的值限定到0到51内

alpha_val = ALPHA_TABLE[index_a];		//<去块滤波><6>α在标准文档表8-16中
beta_val = BETA_TABLE[index_b];				//<去块滤波><6>β
clip_table = CLIP_TAB[index_a];			//<去块滤波><6>在标准文档表8-17中

2、判断条件:(只有满足下面条件,当前边沿才是可以滤波的)

filterSamplesFlag = ( bS != 0 && Abs( p0 − q0 ) < α && Abs( p1 − p0 ) < β && Abs( q1 − q0 ) < β )

3、开始滤波边界像素
其实就是按照标准协议的公式,参考边沿两侧参考的像素点,进行边沿滤波

//<去块滤波><6>
/*pix_vals:滤波完输出的值
 *strength:强度
 *pixel_arr:参考像素
 *strength_idx:边沿的第几个像素
 *component:亮度还是色度
 *满足这个才滤波:filterSamplesFlag = ( bS != 0 && Abs( p0 − q0 ) < α && Abs( p1 − p0 ) < β && Abs( q1 − q0 ) < β )
 */
int CMacroblock::filter_pixel(int *pix_vals, int alpha_val, int beta_val, int *clip_table, int strength[16], int pixel_arr[8], int strength_idx, int component)
{
	int delta = -1, abs_delta = -1;
	int C0 = -1, c0 = -1, RL0 = -1, dif = -1;
	int filter_strength = strength[strength_idx];

	for (int i = 0; i < 8; i++)
	{
		pix_vals[i] = pixel_arr[i];
	}
	//<去块滤波><6>需满足bS != 0 
	if (!filter_strength)
	{
		return kPARSING_ERROR_NO_ERROR;
	}

	RL0 = pixel_arr[4] + pixel_arr[3];
	delta = pixel_arr[4] - pixel_arr[3];
	abs_delta = abs(delta);
	if (abs_delta >= alpha_val)		//<去块滤波><6>需满足Abs( p0 − q0 ) < α
	{
		return kPARSING_ERROR_NO_ERROR;
	}

	C0 = clip_table[filter_strength];
	int right_diff = abs(pixel_arr[4] - pixel_arr[5]) - beta_val, left_diff = abs(pixel_arr[3] - pixel_arr[2]) - beta_val;
	int right_diff2_negative = 0, left_diff2_negative = 0, small_gleft_diff2_negative = 0;
	if ((right_diff & left_diff) >= 0)		//<去块滤波><6>需满足 Abs( p1 − p0 ) < β   &&   Abs( q1 − q0 ) < β
	{
		return kPARSING_ERROR_NO_ERROR;
	}

	//<去块滤波><7>实现滤波操作
	if (!component) // Luma
	{
		right_diff2_negative = (abs(pixel_arr[4] - pixel_arr[6]) - beta_val) < 0;		//<去块滤波><7>ap = Abs(p2 − p0)
		left_diff2_negative = (abs(pixel_arr[3] - pixel_arr[1]) - beta_val) < 0;		//<去块滤波><7>aq = Abs( q2 − q0 )

		if (filter_strength == 3)		//<去块滤波><7>在8.7.2.3节中实现,左右各修改两个像素
		{
			c0 = C0 + right_diff2_negative + left_diff2_negative;	//<去块滤波><7>tC = tC0 + ((ap < β) ? 1 : 0) + ((aq < β) ? 1 : 0)
			dif = IClip(-c0, c0, ((delta << 2) + (pixel_arr[2] - pixel_arr[5]) + 4) >> 3);	//<去块滤波><7>∆ = Clip3(−tC, tC, ((((q0 − p0) << 2) + (p1 − q1) + 4) >> 3))
			pix_vals[3] = IClip(0, 255, pixel_arr[3] + dif);		//<去块滤波><7>p'0 = Clip1( p0 + ∆ )
			pix_vals[4] = IClip(0, 255, pixel_arr[4] - dif);		//<去块滤波><7>q'0 = Clip1( q0 − ∆ )

			if (left_diff2_negative)
			{
				pix_vals[2] += IClip(-C0, C0, (pixel_arr[1] + ((RL0 + 1) >> 1) - (pixel_arr[2] << 1)) >> 1);
			}
			if (right_diff2_negative)
			{
				pix_vals[5] += IClip(-C0, C0, (pixel_arr[6] + ((RL0 + 1) >> 1) - (pixel_arr[5] << 1)) >> 1);
			}
		}
		else if (filter_strength == 4)	//<去块滤波><7>在8.7.2.4节中实现,左右各修改3个
		{
			small_gleft_diff2_negative = ( abs_delta < ((alpha_val >> 2) + 2) );
			right_diff2_negative &= small_gleft_diff2_negative;		//<去块滤波><7>a < β && Abs( p0 − q0 ) < ( ( α >> 2 ) + 2 )
			left_diff2_negative &= small_gleft_diff2_negative;		//<去块滤波><7>ap < β && Abs(p0 − q0) < ((α >> 2) + 2)

			pix_vals[4] = right_diff2_negative ? (pix_vals[2] + ((pix_vals[5] + RL0) << 1) + pix_vals[6] + 4) >> 3 : ((pix_vals[5] << 1) + pix_vals[4] + pix_vals[2] + 2) >> 2;
			pix_vals[3] = left_diff2_negative  ? (pix_vals[5] + ((pix_vals[2] + RL0) << 1) + pix_vals[1] + 4) >> 3 : ((pix_vals[2] << 1) + pix_vals[3] + pix_vals[5] + 2) >> 2;

			pix_vals[5] = right_diff2_negative ? (pix_vals[6] + pix_vals[5] + pix_vals[4] + pix_vals[3] + 2) >> 2 : pix_vals[5];
			pix_vals[2] = left_diff2_negative  ? (pix_vals[1] + pix_vals[2] + pix_vals[3] + pix_vals[4] + 2) >> 2 : pix_vals[2];

			pix_vals[6] = right_diff2_negative ? (((pix_vals[7] + pix_vals[6]) << 1) + pix_vals[6] + pix_vals[5] + RL0 + 4) >> 3 : pix_vals[6];
			pix_vals[1] = left_diff2_negative  ? (((pix_vals[0] + pix_vals[1]) << 1) + pix_vals[1] + pix_vals[2] + RL0 + 4) >> 3 : pix_vals[1];
		}
	}

	return kPARSING_ERROR_NO_ERROR;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值