H265视频压缩与解码在FPGA图传领域应用广泛,Xilinx高端器件已经内嵌了H265加速器,在Linux系统下调用API即可使用,但对于需要定制私有算法或者协议的H264视频压缩与解码应用或者学习研究者而言,纯verilog代码实现H264视频压缩依然具有实用价值,本设计采用纯verilog代码实现H265视频压缩,没有使用任何IP,具有参考价值;
本文详细描述了FPGA纯verilog代码实现H265视频压缩的设计方案,工程代码可综合编译上板调试,但目前只做到了仿真层面,可直接项目移植,适用于在校学生、研究生项目开发,也适用于在职工程师做项目开发,可应用于医疗、军工等行业的数字成像和图像压缩领域;
提供完整的、跑通的工程源码和技术支持;
工程源码和技术支持的获取方式放在了文章末尾,请耐心看到最后;
我这里有图像的JPEG解压缩、JPEG-LS压缩、H264编解码、H265编解码以及其他方案,后续还会出更多方案,我把他们整合在一个专栏里面,会持续更新,专栏地址:
直接点击前往
请参考这篇文章,感觉写得挺好:https://blog.csdn.net/qq_39969848/article/details/129003896
性能表现如下:
输入视频格式:YUV4:2:0;
输出视频码流:h265视频流;8位;伴随数据有效信号;
支持分辨率:最大4K@30Hz;
GOP:I/P;即帧内帧间预测算法;
多达35种预测模式;
CTU:64x64;
CU:8x8~64x64;
PU:4x4~64x64;
TU:4x4/8x8/16x16/32x32;
1/4 Sub-pixel;
Search range:64;
CABAC熵编码;
SAO(Sample Adaptive Offset);
SKIP/MERGE;
视频压缩编码的基本过程可以概括如下 :
1、 利用某种方式对当前处理图像块像素进行预测 ;
2、 将原始的像素值与预测出来的像素值相减得到残差值 ;
3、 将残差进行变换及量化处理,得到输出的残差系数再进过熵编码形成最后的压缩码流 ;
4、残差系数经过反量化及反变换处理,再与之前得到的预测像素相加得到重建像素,存储作为预测的参考像素。
H264视频压缩代码顶层接口如下:
module helai_h265_encode_2023(
input clk , //系统时钟,最大支持 400MHz
input rstn , //系统复位--低电平有效
//初始化配置
//db -->Deblocking filter 块滤波器
//sao-->sample adaptive offseta 自适应采样偏移
input i_h265_start , //输入--开启h265压缩--高电平有效
output o_h265_ec_OK , //输出--h265压缩完成标志--高电平有效
input [`PIC_WIDTH -1 :0] i_yuv_width , //输入--压缩视频总宽度
input [`PIC_HEIGHT-1 :0] i_yuv_height , //输入--压缩视频总高度
input [5 :0] i_init_QP , //输入--初始化QP值--例程给的27
input i_DataRate_type , //输入--码流类型: 0-->Intra ; 1-->Inter
input i_IinP_en , //输入--enable I block in P frame
input i_db_en , //输入--块滤波器使能
input i_sao_en , //输入--SAO使能--SAO(Sample Adaptive Offset)
input [5-1:0] i_blok4x4bit , //输入--4X4模块则填入4
input [32-1:0] i_skip_cost_thre_08 , //输入--skip开销阈值;例程设置为0
input [32-1:0] i_skip_cost_thre_16 ,
input [32-1:0] i_skip_cost_thre_32 ,
input [32-1:0] i_skip_cost_thre_64 ,
// RC(Rate control) 配置
// roi(region of interest_--图像感兴趣区域
output [32 -1 :0] o_rc_mod64_sum , //输出--mod64校验
input [32 -1 :0] i_rc_bitnum , //输入--cabac编码bit数,一般为10000
input [16 -1 :0] i_rc_k , //输入--rc k 值,一般给0
input [6 -1 :0] i_rc_roi_height , //输入--roi 高度
input [7 -1 :0] i_rc_roi_width , //输入--roi 宽度
input [7 -1 :0] i_rc_roi_x , //输入--roi 起始 X 轴坐标
input [7 -1 :0] i_rc_roi_y , //输入--roi 起始 Y 轴坐标
input i_rc_roi_en , //输入--roi 使能
input [10 -1 :0] i_rc_L1_frame_byte , //输入--一级流水线处理帧数
input [10 -1 :0] i_rc_L2_frame_byte , //输入--二级流水线处理帧数
input i_rc_lcu_en , //输入--LCU 使能
input [6 -1 :0] i_rc_QP_max , //输入--QP最大值
input [6 -1 :0] i_rc_QP_min , //输入--QP最小值
input [6 -1 :0] i_rc_QP_delta , //输入--roi QP值
//IME 配置
input [CMD_NUM_WIDTH -1 :0] i_IME_cmd_num , //输入--IME指令
input [CMD_DAT_WIDTH -1 :0] i_IME_cmd_data , //输入--IME数据
//外部缓存包括(原始输入视频缓存--重构缓存)
//ori-->original : ori_yuv_mem-->原始输入视频缓存器
//rb -->rebuild : rb_pix_mem -->像素重构缓存器
output [1-1 : 0] o_rb_pix_mem_video_vs , //输出--告诉像素重构缓存开始接收,相当于VGA时序的vs
input [1-1 : 0] i_rb_pix_mem_video_OK , //输入--像素重构缓存告诉h265压缩模块,接收一帧视频结束
output [5-1 : 0] o_ext_mem_do_mode , //输出--告诉外部缓存操作指示,详情请看文章
output [6+`PIC_X_WIDTH -1: 0] o_ext_mem_x_position , //输出--告诉外部缓存当前视频的 X 坐标
output [6+`PIC_Y_WIDTH -1: 0] o_ext_mem_y_position , //输出--告诉外部缓存当前视频的 Y 坐标
output [8-1 : 0] o_ext_mem_video_width , //输出--告诉外部缓存--视频总宽度
output [8-1 : 0] o_ext_mem_video_height, //输出--告诉外部缓存--视频总高度
input i_ori_yuv_mem_video_de, //输入--原始输入视频缓存--输入的 yuv4:2:0 视频数据有效
input [16*`PIXEL_WIDTH-1: 0] i_ori_yuv_mem_video , //输入--原始输入视频缓存--输入的 yuv4:2:0 视频数据
input i_rb_pix_mem_video_de , //输入--像素重构缓存告诉h265压缩模块--我需要像素数据
output [16*`PIXEL_WIDTH-1: 0] o_rb_pix_mem_video , //输出--给像素重构缓存灌的像素数据
// h265 output
output o_h265_video_de , //输出--压缩后的 h265 视频数据有效
output [7 : 0] o_h265_video //输出--压缩后的 h265 视频数据
);
输入输出操作时序图请参考资料包里的vivado工程里的仿真波形图,料包里有仿真教程;
输入部分时序如下:
输出部分时序如下:
建立Vivado工程,将源码复制进去,目的是进行功能仿真和综合;
开发板FPGA型号:xc7k410tffg676-2;
输入:测试激励YUV 4:2:0视频流文件;
应用:功能仿真和综合;
FPGA资源消耗如下:
资源消耗比较大,请参考自己的FPGA是否满足资源要求;
由于我这里只做到了仿真层面,还没上板调试,但你可以拿去移植上板,移植上板只需解决两个问题,1是输入时序,2是预估FPGA资源;
输入时序请参考vivado工程的仿真文件和仿真波形,查看仿真输入激励文件和波形就能了解驶入时序,然后对应着灌入数据即可;FPGA资源消耗请看上面的“7、Vivado工程详解中的FPGA资源消耗”;另外,移植上板可提供技术支持;
由于仿真过程比较复杂,我专门做了一个PPT教程,详细讲述了仿真流程,手把手教程,PPT教程一并在资料包里给出;位置如下:
正确仿真的结果如下:
福利:工程代码的获取
代码太大,无法邮箱发送,以某度网盘链接方式发送,
资料获取方式:文章末尾的V名片。
网盘资料如下: