H.265硬件视频编码器xk265代码阅读 - 帧内预测

  源代码地址: https://github.com/openasic-org/xk265

  帧内预测具体逻辑包含在代码xk265\rtl\rec\rec_intra\intra_pred.v 文件中。

  module intra_pred() 看起来是每次计算某个4x4块的预测像素值。

  以下代码用来算每个pred_angle的具体数值,每个mode_i对应的pred_angle参考下图所示:

module intra_pred( ... )
...
//lookup table to get pred_angle
always @( * ) begin
	case (mode_i)
		2 ,34:pred_angle=7'd32;	11,25:pred_angle=-7'd2;
		3 ,33:pred_angle=7'd26;	12,24:pred_angle=-7'd5;
		4 ,32:pred_angle=7'd21;	13,23:pred_angle=-7'd9;
		5 ,31:pred_angle=7'd17;	14,22:pred_angle=-7'd13;
		6 ,30:pred_angle=7'd13;	15,21:pred_angle=-7'd17;
		7 ,29:pred_angle=7'd9;		16,20:pred_angle=-7'd21;
		8 ,28:pred_angle=7'd5;		17,19:pred_angle=-7'd26;
		9 ,27:pred_angle=7'd2;		18:   pred_angle=-7'd32;
		10,26:pred_angle=7'd0;
		default:pred_angle=7'd0;
	endcase
end

 

  以下代码用于获取当前4x4块的第一行四个像素在大块中的水平位置,其中size_i用于表示大块的大小。

//********************************************************************************
//get the location information of current 4x4 block
always @( * ) begin//x
	case(size_i)
		2'b00:begin//4x4
			x0='d0; x1='d1; x2='d2; x3='d3;
		end

		2'b01:begin//8x8
			if(!i4x4_x_i[0]) begin
				x0='d0; x1='d1; x2='d2; x3='d3;
			end
			else begin
				x0='d4; x1='d5; x2='d6; x3='d7;
			end
		end

		2'b10:begin//16x16
			case(i4x4_x_i[1:0])
				2'b00:begin
					x0='d0; x1='d1; x2='d2; x3='d3;
				end
				2'b01:begin
					x0='d4; x1='d5; x2='d6; x3='d7;
				end
				2'b10:begin
					x0='d8; x1='d9; x2='d10; x3='d11;
				end
				2'b11:begin
					x0='d12; x1='d13; x2='d14; x3='d15;
				end
			endcase
		end

		2'b11:begin//32x32
			case(i4x4_x_i[2:0])
				3'b000:begin
					x0='d0; x1='d1; x2='d2; x3='d3;
				end
				3'b001:begin
					x0='d4; x1='d5; x2='d6; x3='d7;
				end
				3'b010:begin
					x0='d8; x1='d9; x2='d10; x3='d11;
				end
				3'b011:begin
					x0='d12; x1='d13; x2='d14; x3='d15;
				end
				3'b100:begin
					x0='d16; x1='d17; x2='d18; x3='d19;
				end
				3'b101:begin
					x0='d20; x1='d21; x2='d22; x3='d23;
				end
				3'b110:begin
					x0='d24; x1='d25; x2='d26; x3='d27;
				end
				3'b111:begin
					x0='d28; x1='d29; x2='d30; x3='d31;
				end
			endcase
		end
	endcase
end

  以下代码用于获取当前4x4块的第一列四个像素在大块中的垂直位置,其中size_i用于表示大块的大小。

always @( * ) begin//y
	case(size_i)
		2'b00:begin//4x4
			y0='d0; y1='d1; y2='d2; y3='d3;
		end

		2'b01:begin//8x8
			if(!i4x4_y_i[0]) begin
				y0='d0; y1='d1; y2='d2; y3='d3;
			end
			else begin
				y0='d4; y1='d5; y2='d6; y3='d7;
			end
		end

		2'b10:begin//16x16
			case(i4x4_y_i[1:0])
				2'b00:begin
					y0='d0; y1='d1; y2='d2; y3='d3;
				end
				2'b01:begin
					y0='d4; y1='d5; y2='d6; y3='d7;
				end
				2'b10:begin
					y0='d8; y1='d9; y2='d10; y3='d11;
				end
				2'b11:begin
					y0='d12; y1='d13; y2='d14; y3='d15;
				end
			endcase
		end

		2'b11:begin//32x32
			case(i4x4_y_i[2:0])
				3'b000:begin
					y0='d0; y1='d1; y2='d2; y3='d3;
				end
				3'b001:begin
					y0='d4; y1='d5; y2='d6; y3='d7;
				end
				3'b010:begin
					y0='d8; y1='d9; y2='d10; y3='d11;
				end
				3'b011:begin
					y0='d12; y1='d13; y2='d14; y3='d15;
				end
				3'b100:begin
					y0='d16; y1='d17; y2='d18; y3='d19;
				end
				3'b101:begin
					y0='d20; y1='d21; y2='d22; y3='d23;
				end
				3'b110:begin
					y0='d24; y1='d25; y2='d26; y3='d27;
				end
				3'b111:begin
					y0='d28; y1='d29; y2='d30; y3='d31;
				end
			endcase
		end
	endcase
end

  以下代码用于选择参考像素的位置: model_i >=18,则参考水平像素行,否则参考垂直像素列,具体细节可以参考下图。

always @(posedge clk or negedge rst_n) begin//help to choose the reference pixel
	if(!rst_n) begin
		delta_idx_r <= 'd0;
	end
	else begin
		if(mode_i>=18)
			delta_idx_r <= {1'b0,x0};
		else
			delta_idx_r <= {1'b0,y0};
	end
end

  以下代码用于计算加权factor和偏移量idx,原理可以参考HM或者论文Intra Coding of the HEVC Standard。

预测像素值P_{x,y}通过以下公式计算:

//*********************************************************************************
//calculate idx and ifact for intra prediction
// 将 x0~x3 和 y0~y3 的值进行符号扩展(sign extension),确保它们在后续计算中不会因为位宽不足而丢失精度。
assign x0_sign_w={1'b0,x0};  // 在x0最高位前添加一个0,变为无符号数;
assign x1_sign_w={1'b0,x1};
assign x2_sign_w={1'b0,x2};
assign x3_sign_w={1'b0,x3};

assign y0_sign_w={1'b0,y0};
assign y1_sign_w={1'b0,y1};
assign y2_sign_w={1'b0,y2};
assign y3_sign_w={1'b0,y3};

always @(posedge clk or negedge rst_n) begin
	if(!rst_n) begin
		fact0<='d0;  idx0<='d0;
		fact1<='d0;  idx1<='d0;
		fact2<='d0;  idx2<='d0;
		fact3<='d0;  idx3<='d0;
	end
	else begin
		if (mode_i >= 18) begin
			fact0<=((y0+1)*pred_angle);
			fact1<=((y1+1)*pred_angle);
			fact2<=((y2+1)*pred_angle);
			fact3<=((y3+1)*pred_angle);

			idx0<=((y0_sign_w+1)*pred_angle)>>>5;
			idx1<=((y1_sign_w+1)*pred_angle)>>>5;
			idx2<=((y2_sign_w+1)*pred_angle)>>>5;
			idx3<=((y3_sign_w+1)*pred_angle)>>>5;
		end
		else begin
			fact0<=((x0+1)*pred_angle);
			fact1<=((x1+1)*pred_angle);
			fact2<=((x2+1)*pred_angle);
			fact3<=((x3+1)*pred_angle);

			idx0<=((x0_sign_w+1)*pred_angle)>>>5;
			idx1<=((x1_sign_w+1)*pred_angle)>>>5;
			idx2<=((x2_sign_w+1)*pred_angle)>>>5;
			idx3<=((x3_sign_w+1)*pred_angle)>>>5;
		end
	end
end

  以下代码用于将输入的预测像素排到ref_lxx_w和ref_txx_w寄存器中。ref_l0_w到ref_lN-1_w 从输入的ref_lN-1_i中拷贝, ref_lN_w到ref_l2N-1_w 从输入的ref_b0N_i中拷贝,因为参考像素的行和列的宽度是块大小的两倍(如下图所示)。

//**********************************************************************************
//get the real reference pixel
always @( * ) begin
	ref_l00_w = 'd0;  ref_l04_w = 'd0;  ref_l08_w = 'd0;  ref_l12_w = 'd0;	ref_l16_w = 'd0;  ref_l20_w = 'd0;  ref_l24_w = 'd0;  ref_l28_w = 'd0;
	ref_l01_w = 'd0;  ref_l05_w = 'd0;  ref_l09_w = 'd0;  ref_l13_w = 'd0;	ref_l17_w = 'd0;  ref_l21_w = 'd0;  ref_l25_w = 'd0;  ref_l29_w = 'd0;
	ref_l02_w = 'd0;  ref_l06_w = 'd0;  ref_l10_w = 'd0;  ref_l14_w = 'd0;	ref_l18_w = 'd0;  ref_l22_w = 'd0;  ref_l26_w = 'd0;  ref_l30_w = 'd0;
	ref_l03_w = 'd0;  ref_l07_w = 'd0;  ref_l11_w = 'd0;  ref_l15_w = 'd0;	ref_l19_w = 'd0;  ref_l23_w = 'd0;  ref_l27_w = 'd0;  ref_l31_w = 'd0;

	ref_l32_w = 'd0;  ref_l36_w = 'd0;  ref_l40_w = 'd0;  ref_l44_w = 'd0;	ref_l48_w = 'd0;  ref_l52_w = 'd0;  ref_l56_w = 'd0;  ref_l60_w = 'd0;
	ref_l33_w = 'd0;  ref_l37_w = 'd0;  ref_l41_w = 'd0;  ref_l45_w = 'd0;	ref_l49_w = 'd0;  ref_l53_w = 'd0;  ref_l57_w = 'd0;  ref_l61_w = 'd0;
	ref_l34_w = 'd0;  ref_l38_w = 'd0;  ref_l42_w = 'd0;  ref_l46_w = 'd0;	ref_l50_w = 'd0;  ref_l54_w = 'd0;  ref_l58_w = 'd0;  ref_l62_w = 'd0;
	ref_l35_w = 'd0;  ref_l39_w = 'd0;  ref_l43_w = 'd0;  ref_l47_w = 'd0;	ref_l51_w = 'd0;  ref_l55_w = 'd0;  ref_l59_w = 'd0;  ref_l63_w = 'd0;

	ref_t00_w = 'd0;  ref_t04_w = 'd0;  ref_t08_w = 'd0;  ref_t12_w = 'd0;	ref_t16_w = 'd0;  ref_t20_w = 'd0;  ref_t24_w = 'd0;  ref_t28_w = 'd0;
	ref_t01_w = 'd0;  ref_t05_w = 'd0;  ref_t09_w = 'd0;  ref_t13_w = 'd0;	ref_t17_w = 'd0;  ref_t21_w = 'd0;  ref_t25_w = 'd0;  ref_t29_w = 'd0;
	ref_t02_w = 'd0;  ref_t06_w = 'd0;  ref_t10_w = 'd0;  ref_t14_w = 'd0;	ref_t18_w = 'd0;  ref_t22_w = 'd0;  ref_t26_w = 'd0;  ref_t30_w = 'd0;
	ref_t03_w = 'd0;  ref_t07_w = 'd0;  ref_t11_w = 'd0;  ref_t15_w = 'd0;	ref_t19_w = 'd0;  ref_t23_w = 'd0;  ref_t27_w = 'd0;  ref_t31_w = 'd0;

	ref_t32_w = 'd0;  ref_t36_w = 'd0;  ref_t40_w = 'd0;  ref_t44_w = 'd0;	ref_t48_w = 'd0;  ref_t52_w = 'd0;  ref_t56_w = 'd0;  ref_t60_w = 'd0;
	ref_t33_w = 'd0;  ref_t37_w = 'd0;  ref_t41_w = 'd0;  ref_t45_w = 'd0;	ref_t49_w = 'd0;  ref_t53_w = 'd0;  ref_t57_w = 'd0;  ref_t61_w = 'd0;
	ref_t34_w = 'd0;  ref_t38_w = 'd0;  ref_t42_w = 'd0;  ref_t46_w = 'd0;	ref_t50_w = 'd0;  ref_t54_w = 'd0;  ref_t58_w = 'd0;  ref_t62_w = 'd0;
	ref_t35_w = 'd0;  ref_t39_w = 'd0;  ref_t43_w = 'd0;  ref_t47_w = 'd0;	ref_t51_w = 'd0;  ref_t55_w = 'd0;  ref_t59_w = 'd0;  ref_t63_w = 'd0;

	case(size_i)
		2'b00:begin
			ref_l00_w = ref_l00_i;  ref_l04_w = ref_d00_i;  ref_t00_w = ref_t00_i;  ref_t04_w = ref_r00_i;
			ref_l01_w = ref_l01_i;  ref_l05_w = ref_d01_i;  ref_t01_w = ref_t01_i;  ref_t05_w = ref_r01_i;
			ref_l02_w = ref_l02_i;  ref_l06_w = ref_d02_i;  ref_t02_w = ref_t02_i;  ref_t06_w = ref_r02_i;
			ref_l03_w = ref_l03_i;  ref_l07_w = ref_d03_i;  ref_t03_w = ref_t03_i;  ref_t07_w = ref_r03_i;
		end
		2'b0
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ITRonnie

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值