1. 项目概述最近在折腾一个视频处理的项目需要把摄像头采集到的原始视频流实时压缩成MPEG2格式方便存储和传输。找了一圈开源的硬件编码器要么是H.264/H.265这种复杂度太高FPGA资源扛不住要么就是一些老旧的JPEG编码器压缩率不够理想。后来在GitHub上发现了WangXuan95大佬的FPGA-MPEG2-encoder项目眼前一亮。这是一个纯Verilog实现的MPEG2视频编码器IP核主打高性能和无需外部存储正好契合我的需求。经过一番研究和实测发现这个IP核设计得非常巧妙接口简洁性能强悍在Xilinx Kintex-7上能达到268 MPixels/s的吞吐率对于1920x115260fps的视频编码绰绰有余。更重要的是它整个编码流程都在FPGA内部完成不需要外接DDR之类的存储器这对于简化系统设计、降低成本和功耗来说是个巨大的优势。这篇文章我就结合自己的使用和调试经验把这个FPGA MPEG2编码器的核心原理、使用方法和一些关键的实操细节掰开揉碎了讲清楚希望能给同样有视频压缩需求的硬件工程师或FPGA开发者提供一个可靠的参考方案。2. 核心架构与设计思路解析2.1 为什么选择MPEG2编码器在开始深入代码之前我们得先搞清楚在H.264/AVC、HEVC大行其道的今天为什么还要用MPEG2对于FPGA实现而言MPEG2标准ISO/IEC 13818-2有几个不可替代的优势。首先它的算法复杂度相对较低。MPEG2的帧间预测运动估计与补偿和帧内预测DCT变换、量化、熵编码的算法流程比H.264的多种预测模式、复杂的上下文自适应二进制算术编码CABAC要简单得多。这意味着在相同的FPGA资源下我们可以实现更高的处理吞吐率或者用更少的资源实现实时编码。其次MPEG2的专利已经基本过期不存在昂贵的授权费用问题对于开源项目和学术研究非常友好。最后MPEG2的码流结构清晰兼容性极好生成的.m2v文件可以被绝大多数播放器和编辑软件直接识别和播放省去了后期转码的麻烦。这个IP核的设计目标很明确在FPGA上实现一个高性能、免外部存储、接口简单的实时MPEG2编码器它完美地平衡了压缩效率、实现复杂度和实用性。2.2 整体数据流与“无外部存储”的秘密这个编码器最吸引我的特性就是“No external memory required”。传统的视频编码器无论是软件还是硬件都需要大量的帧缓存Frame Buffer来存储参考帧前一个P帧或I帧以便进行运动估计和补偿。对于高清视频一帧1920x1080的YUV420图像就需要近3MB的存储空间这对FPGA内部的Block RAMBRAM来说是难以承受的。那么这个IP核是如何做到的呢它的核心思路是流式处理Stream Processing和智能的片上缓存管理。整个编码流程可以概括为输入YUV444像素流 - 色彩空间下采样444转420 - 宏块分割与处理 - DCT变换与量化 - 运动估计与补偿仅P帧 - 熵编码VLC - 输出MPEG2码流。为了实现无外部存储设计者采用了宏块级流水线和参考帧的局部缓存策略。编码器以16x16的宏块Macroblock为基本处理单元。对于P帧编码需要用到前一帧参考帧中对应区域的数据来进行运动搜索。IP核没有存储整帧参考帧而是只缓存了当前宏块进行运动估计所需的一个**搜索窗口Search Window**的数据。这个窗口的大小由VECTOR_LEVEL参数决定例如VECTOR_LEVEL3对应±3像素的搜索范围即7x7的窗口。当前宏块的像素和参考帧对应区域的搜索窗口数据被同步送入运动估计单元在流水线中完成搜索、矢量计算和补偿。处理完一个宏块后窗口滑动缓存更新继续处理下一个宏块。通过这种“滑动窗口”的方式只需要在片上存储数量有限的几行像素数据具体行数取决于搜索范围而不是整帧图像从而将存储需求从兆字节级别降低到了千字节级别完全由FPGA的BRAM满足。这是整个设计中最精妙的部分也是其能实现高吞吐率的关键。2.3 关键参数选型背后的权衡模块提供了几个关键的参数XL,YL,VECTOR_LEVEL,Q_LEVEL这些参数直接决定了编码器的能力、资源消耗和输出质量。理解它们背后的权衡至关重要。XL和YL最大视频尺寸与BRAM消耗这两个参数定义了编码器能处理的最大视频分辨率。它们以16像素为单位XL6代表最大宽度为2^6 * 16 1024像素。选择时必须确保(XL, YL)能覆盖你的目标分辨率。例如对于1920x1152需要XL7 (2048)且YL7 (2048)。这里有个重要技巧虽然你可以为了通用性直接设为最大值如7但这会消耗最多的BRAM。如果你的应用场景固定如只处理720p那么精确设置XL6 (1024),YL5 (512)for 1280x720? 注意1280/1680需要XL至少为7这里原作者例子有误1280需要XL7因为2^712880而2^66480可以节省大量宝贵的BRAM资源。你需要计算ceil(log2(宽度/16))和ceil(log2(高度/16))来确定最小可用的XL和YL。VECTOR_LEVEL运动估计搜索范围与压缩率这个参数控制运动估计的精度。VECTOR_LEVEL1/2/3分别对应搜索范围为±1/2/3像素。搜索范围越大找到最佳匹配块的概率越高预测残差越小压缩率就越高但代价是运动估计单元的逻辑复杂度呈平方级增长消耗的LUT资源也大幅增加。实测经验对于运动平缓的视频如监控画面VECTOR_LEVEL1或2足以获得很好的效果对于运动剧烈的视频如体育赛事VECTOR_LEVEL3能显著提升压缩率但需要评估FPGA资源是否足够。Q_LEVEL量化级别与质量权衡量化是编码中产生信息损失压缩的主要步骤。Q_LEVEL越高量化步长越大压缩率越高但图像细节损失也越严重表现为块效应Blocking Artifact更明显。Q_LEVEL是一个在压缩率和主观质量之间取得平衡的杠杆。一个实用的建议对于最终成品可以通过主观观看测试来确定一个可接受的Q_LEVEL。在资源允许的情况下从较低的级别如2开始测试。注意VECTOR_LEVEL和Q_LEVEL是综合前的静态参数一旦烧录进FPGA就无法更改。而视频分辨率i_xsize16,i_ysize16和I帧间隔i_pframes_count是运行时动态可配的这提供了很大的灵活性。3. 接口详解与驱动时序设计3.1 像素输入接口高效的无反压流编码器的像素输入接口设计得非常高效采用**无握手、无背压No Backpressure**的流式接口。每个时钟周期可以输入同一扫描行中连续的4个YUV444像素。input wire i_en; input wire [ 7:0] i_Y0, i_Y1, i_Y2, i_Y3; input wire [ 7:0] i_U0, i_U1, i_U2, i_U3; input wire [ 7:0] i_V0, i_V1, i_V2, i_V3;i_en输入有效信号。当它为高电平时当前时钟周期i_Y0~i_V3上的数据被采样。像素顺序必须严格按照光栅扫描顺序逐帧Frame、逐行Line、逐列Pixel。每个时钟周期送入4个相邻的像素。无背压含义编码器内部流水线足够深理论上可以持续不断地接收像素数据i_en可以一直为高。这意味着上游数据源如摄像头接口、DDR读出控制器只要保证数据连续就能以最高速率喂给编码器最大化吞吐率。当然如果上游数据断续i_en也可以随时拉低插入“气泡”编码器会正常处理。驱动示例假设视频分辨率为W x HW和H必须是16的倍数。驱动一个帧的伪代码如下for (frame 0; frame N; frame) { for (row 0; row H; row) { for (col 0; col W; col 4) { (posedge clk); i_en 1; i_Y0 Y[frame][row][col]; i_Y1 Y[frame][row][col1]; // ... 赋值U0~U3, V0~V3 // 从存储器或前级模块读取YUV像素值 } } }关键细节在输入一个视频序列的**第一组4个像素即第0帧第0行第0~3列**的那个时钟周期必须同时给出视频配置参数i_xsize16,i_ysize16和i_pframes_count。它们在整个序列输入期间保持不变即可。3.2 控制与状态接口序列的生命周期管理编码器以视频序列Sequence为单位工作。一个序列包含若干帧以I帧开始中间有若干个P帧最后输出一个完整的.m2v文件。i_sequence_stop序列结束请求。当输入完一个序列的最后一个像素后需要将此信号置高一个时钟周期通知编码器开始收尾工作如写入序列结束码。o_sequence_busy编码器忙状态指示。高电平表示编码器正在处理一个视频序列包括接收像素和输出码流。这是最重要的同步信号。复位后o_sequence_busy为0编码器空闲可以开始输入新序列。输入开始后一旦开始输入像素o_sequence_busy会很快变为1并保持。序列结束后在i_sequence_stop有效后需要持续监控o_sequence_busy。当它从1跳变到0时表示该序列已完全处理完毕所有码流数据已输出可以安全地开始输入下一个序列。完整的序列控制流程确保o_sequence_busy 0。在第一个有效像素周期同时给出i_xsize16,i_ysize16,i_pframes_count。持续或断续输入像素数据i_en控制。输入完最后一组像素后在某个周期拉高i_sequence_stop一个周期。等待直到检测到o_sequence_busy从1变为0。返回步骤1开始下一个序列。警告绝对不能在o_sequence_busy1时开始输入新序列的像素这会导致编码器状态混乱输出无效码流。这是最容易出错的地方。3.3 码流输出接口小端序与数据对齐编码后的MPEG2码流通过以下接口输出output wire o_en; output wire o_last; output wire[255:0] o_data;o_en输出有效。高电平时o_data上的32字节码流数据有效。o_last序列结束标志。当o_en1且o_last1时表示当前输出的32字节是当前视频序列的最后一段有效数据。下一个o_en1的周期将属于下一个视频序列如果存在。o_data[255:0]码流数据小端序Little Endian。o_data[7:0]是第一个字节o_data[15:8]是第二个字节依此类推o_data[255:248]是第三十二个字节。小端序的重要性这种安排是为了与常用的总线标准如AXI4-Stream、Wishbone等保持一致。在将这些数据存入存储器或通过DMA传输时通常也是按字节地址递增的顺序进行。直接连接o_data到这类总线的数据线可以避免繁琐的字节重排操作。数据接收策略由于o_en可能非连续下游接收模块如FIFO、DMA控制器需要根据o_en来采样数据。一个简单的接收代码如下always (posedge clk) begin if (o_en) begin fifo_wdata o_data; fifo_wen 1b1; if (o_last) begin // 可选标记一个序列的结束用于文件分割或包封装 packet_end 1b1; end end else begin fifo_wen 1b0; end end存储为文件将采集到的字节流按顺序写入一个文件并赋予.m2v扩展名即可用VLC等播放器直接播放。4. 仿真环境搭建与测试向量生成4.1 使用Icarus Verilog (iverilog) 进行功能仿真项目作者提供了基于iverilog的仿真环境这是快速验证功能的好方法。仿真目录SIM/下的tb_mpeg2encoder.v是测试平台。仿真步骤详解准备仿真工具安装Icarus Verilog (iverilog) 和 GTKWave用于查看波形。在Ubuntu上可以使用sudo apt-get install iverilog gtkwave安装。在Windows上可以从 官方发布页 下载预编译版本。准备YUV测试文件解压SIM/data.zip得到288x208.yuv,640x320.yuv,1440x704.yuv三个文件。这些是作者提供的原始YUV444帧数据。YUV文件格式对于WxH分辨率的视频文件按顺序存储第0帧的所有Y像素WxH字节接着是所有U像素WxH字节然后是所有V像素WxH字节。然后重复第1帧第2帧...。注意这是YUV444格式每个像素的Y、U、V各占一个字节。运行仿真脚本在Windows下直接双击tb_run_iverilog.bat。在Linux下需要手动执行类似命令cd SIM iverilog -o simv tb_mpeg2encoder.v ../RTL/mpeg2encoder.v vvp simv仿真会依次处理三个YUV文件每个文件编码成一个独立的.m2v文件。这个过程非常耗时对于1440x704.yuv在我的电脑上需要数小时因为是在模拟硬件电路逐周期运行。结果验证仿真完成后会在SIM/目录下生成out0.m2v,out1.m2v,out2.m2v。使用VLC Media Player直接打开这些.m2v文件如果能正常播放出对应视频则说明编码器功能基本正确。4.2 生成自定义YUV测试文件使用ffmpeg可以轻松地将任何视频转换为编码器所需的YUV444原始格式。# 基本命令 ffmpeg -i input_video.mp4 -pix_fmt yuv444p -vsync 0 output.yuv # 更精确的控制指定分辨率、帧率、帧数 ffmpeg -i input.mp4 -vf scale1920:1080 -pix_fmt yuv444p -r 30 -frames 100 output_1920x1080_30fps_100frames.yuv-pix_fmt yuv444p指定输出像素格式为YUV444 Planar平面格式即Y、U、V三个分量分别存储符合编码器输入要求。-vsync 0禁止帧率同步按源视频时间戳输出每一帧避免因丢帧导致内容不完整。-vf scaleW:H缩放视频到指定分辨率。确保W和H是16的倍数。-r framerate设置输出帧率。-frames N只输出前N帧用于缩短仿真时间。重要提示编码器要求输入分辨率是16的倍数。如果源视频不是必须用scale滤镜进行缩放或填充Padding。例如处理1280x720的视频是没问题的1280和720都能被16整除。但处理1920x1080时1080不能被16整除1080/1667.5需要填充到108816的倍数。可以使用pad滤镜ffmpeg -i input.mp4 -vf padwidth1920:height1088:x0:y0:colorblack -pix_fmt yuv444p padded_output.yuv4.3 在Vivado/Quartus中集成仿真对于大型项目你可能需要将编码器集成到自己的Vivado或Quartus工程中。步骤类似添加源文件将RTL/mpeg2encoder.v添加到你的RTL工程中。创建Testbench可以借鉴tb_mpeg2encoder.v但需要将其适配到你的仿真器如Vivado XSim、Modelsim。关键修改点文件路径将其中读取YUV文件和写入M2V文件的路径从相对路径改为绝对路径或者使用仿真器支持的路径宏。系统任务确保$fopen,$fread,$fwrite,$finish等系统任务被支持。参数配置根据你的测试视频分辨率修改XL,YL,VECTOR_LEVEL,Q_LEVEL等参数以及i_xsize16,i_ysize16。运行仿真与调试在仿真器中运行可以观察内部信号波形调试驱动时序或编码问题。重点关注o_sequence_busy的状态转换、o_en的脉冲以及输出码流的起始码Start Code是否正确。5. 综合、实现与资源优化策略5.1 在不同FPGA平台上的部署该编码器使用纯Verilog-2001编写具有良好的可移植性。作者给出的资源数据是基于Xilinx Kintex-7 XC7K325TFFV676-1的。在实际部署到其他器件时资源消耗和最高频率会有所不同。Xilinx 7系列/UltraScale直接使用Vivado进行综合和实现即可。注意在约束文件XDC中定义时钟端口clk的周期约束。例如对于67MHz的目标频率create_clock -period 14.925 [get_ports clk]Intel (Altera) Cyclone/Arria系列使用Quartus Prime。同样需要添加.sdc时序约束文件。国产FPGA如安路、紫光同创等理论上代码是兼容的但需要验证综合工具对Verilog-2001特性的支持是否完整。可能需要对一些工具相关的属性如(* keep_hierarchy *)进行调整。5.2 资源消耗分析与优化建议以VECTOR_LEVEL3, XLYL6最大支持1024x1024在Kintex-7上的配置为例LUT: ~135kFF: ~77kBRAM36K: 405个约14.5MbDSP48E: 125个这是一个相当庞大的设计几乎用掉了XC7K325T一半的逻辑资源。资源消耗的大头主要在运动估计引擎尤其是VECTOR_LEVEL3时搜索范围大计算量大消耗大量LUT和FF。片上行缓存用于存储参考帧的搜索窗口和当前帧的像素行消耗大量BRAM。XL和YL越大缓存的行数需求可能越多为了支持更大的图像宽度BRAM消耗越大。DCT/IDCT变换使用DSP48E硬核实现乘加运算消耗125个DSP。优化策略降低VECTOR_LEVEL如果视频运动不剧烈这是节省LUT最有效的方法。从3降到2或1LUT用量可能减少20%-35%。精确设置XL和YL如前所述根据实际应用分辨率设置能直接减少BRAM消耗。降低Q_LEVEL虽然对逻辑资源影响不大但会影响输出码率。在可接受的质量下选择较低的量化级别。时钟频率与吞吐率权衡设计目标是268 MPixels/s 67MHz。如果你的视频分辨率较低或帧率要求不高可以尝试降低时钟频率如50MHz这可能会让综合工具在布局布线时有更多优化空间有时反而能降低资源使用或提高时序裕量。手动流水线调整对于高性能需求如果时序不满足可以查看关键路径报告在运动估计或DCT计算等模块中手动插入寄存器提高流水线深度以换取更高的运行频率。5.3 时序约束与收敛技巧对于这样一个高性能设计时序收敛是关键。基础时钟约束必须正确定义主时钟clk的周期、占空比和输入延迟。输入延迟约束对像素输入总线i_Y0~i_V3和配置信号i_xsize16等设置合理的set_input_delay约束它们相对于时钟沿的到达时间。输出延迟约束对码流输出总线o_data和标志信号o_en,o_last设置set_output_delay。虚假路径异步复位信号rstn通常被设置为虚假路径set_false_path因为它是异步的。多周期路径仔细分析设计如果某些计算明确需要多个周期完成应设置set_multicycle_path约束避免工具过度优化导致建立时间违例。使用流水线寄存器在大型组合逻辑路径如运动矢量比较器、累加器的输出端插入寄存器是改善时序最直接有效的方法。物理布局约束如果某些模块间信号交换频繁可以使用PBLOCK或RLOCXilinx等约束将它们布局在相邻的SLICE中减少布线延迟。调试经验综合实现后首先查看时序报告Timing Summary。如果存在建立时间Setup Time违例重点检查高扇出网络如使能信号、复位信号和长组合逻辑路径。使用Vivado的report_high_fanout_nets和report_timing_summary命令定位问题。对于高扇出网络可以考虑使用复制寄存器Register Duplication或BUFG来驱动。6. 系统集成与实战应用指南6.1 与摄像头采集系统的对接一个典型的应用场景是将编码器用于摄像头视频的实时压缩。假设我们有一个通过MIPI CSI-2或DVP接口接收的摄像头输出RGB或YUV格式的像素流。色彩空间转换编码器输入要求YUV444。如果摄像头输出是RGB如RGB888需要先进行RGB到YUV的转换。这可以在FPGA内用少量逻辑实现几个乘加运算也可以使用专用的视频处理IP核。// 简化的RGB转YUV BT.601公式 (8-bit精度) // Y 0.299*R 0.587*G 0.114*B // U -0.169*R - 0.331*G 0.500*B 128 // V 0.500*R - 0.419*G - 0.081*B 128 // 可用定点数乘法移位实现格式与同步确保摄像头输出的像素时钟pclk、行有效href、帧有效vsync与编码器的clk和i_en同步。通常需要一个异步FIFO或双端口RAM来做时钟域转换和数据缓冲。分辨率适配检查摄像头分辨率是否为16的倍数。如果不是需要添加一个预处理模块在行末或帧末填充黑色像素或通过插值缩放以满足要求。驱动状态机设计一个控制状态机负责在摄像头一帧开始时将i_xsize16和i_ysize16配置好然后持续将像素送入编码器。在一帧结束时根据应用需求决定是否拉高i_sequence_stop如果每个视频文件只存一帧或继续输入下一帧一个序列包含多帧。6.2 输出码流的处理与存储编码器输出的o_data是原始的MPEG2 Elementary Stream (ES)。要生成标准文件或进行网络传输通常还需要进行封装。直接存储为.m2v文件最简单的方式是将o_data通过DMA写入SD卡、eMMC或SSD等存储设备。当o_last有效时代表一个视频序列结束可以关闭当前文件并开启一个新文件。需要注意文件系统的写入速度和缓冲避免数据丢失。封装为PS/TS流为了网络流媒体传输或制作DVD需要将ES流打包成节目流Program Stream, PS或传输流Transport Stream, TS。这需要在FPGA内添加一个PS/TS复用器MUX模块在ES流基础上加入PES包头、PS包头或TS包头并插入PCRProgram Clock Reference等时间信息。这是一个相对复杂的模块但有很多开源参考设计。通过以太网/UDP传输将ES流或TS流打包进UDP数据包通过以太网PHY发送。需要在FPGA内实现一个轻量级的UDP/IP协议栈。这对于远程监控等应用非常有用。6.3 动态参数调整策略虽然VECTOR_LEVEL和Q_LEVEL是静态的但i_pframes_countI帧间隔是运行时可调的。这为自适应码率控制提供了可能。固定质量模式设置固定的i_pframes_count如23即约1秒一个I帧假设帧率24fps。编码器会以相对恒定的图像质量进行编码但输出码率会随场景复杂度波动。简单码率控制可以通过监控输出FIFO的填充水平来粗略控制码率。如果FIFO快满了码率过高可以动态增大i_pframes_count减少I帧频率因为P帧比I帧体积小来降低码率。注意改变i_pframes_count只对下一个GOPGroup of Pictures生效。更复杂的码率控制需要调整量化参数Q_LEVEL但该IP核不支持动态调整这是其一个局限性。7. 常见问题排查与调试心得7.1 编码输出文件无法播放这是最常见的问题。可能的原因和排查步骤检查分辨率配置确保i_xsize16和i_ysize16设置正确且与输入YUV文件的实际分辨率匹配除以16。这是最容易出错的一步。检查序列控制时序重中之重是o_sequence_busy信号。用仿真器抓取波形确保在开始输入新序列前o_sequence_busy已为低电平在输入序列期间它为高电平在发出i_sequence_stop后它最终会变低。任何时序违规都会导致码流结构错误。验证像素输入顺序确认像素输入是严格的逐行、逐帧扫描且每周期4个像素。可以编写一个简单的测试模块将输入的像素再按同样顺序存成YUV文件与原始文件对比确保数据源无误。检查输出字节顺序确认接收端是按小端序解读o_data的。错误的字节顺序会导致播放器无法识别码流头。使用码流分析工具如ffprobeffmpeg套件或专业的码流分析器如Elecard StreamEye。用它们打开生成的.m2v文件可以查看是否有起始码Start Code、序列头Sequence Header、图像头Picture Header等语法元素以及它们的值是否正确。ffprobe -show_streams output.m2v7.2 资源使用超出预期或时序违例参数过大首先检查XL,YL,VECTOR_LEVEL的设置是否过于保守。对于目标分辨率尝试使用允许的最小值。综合策略在Vivado中尝试不同的综合策略如Flow_PerfOptimized_high。对于布局布线尝试不同的策略如Performance_Explore。关键路径分析查看时序报告找到违例最严重的路径。通常这些路径位于运动估计的SAD绝对差和计算或DCT的蝶形运算单元。考虑在这些路径中插入额外的流水线寄存器。使用DSP和BRAM的硬核确保综合工具正确推断出了DSP48E和BRAM。检查综合后的原理图看乘加运算是否被映射到了DSP48E而不是用LUT实现。大型存储器应用(* ram_style block *)等属性引导工具使用BRAM。7.3 图像质量不佳块效应、模糊Q_LEVEL过高这是最主要的原因。尝试降低Q_LEVEL如从4降到2或1牺牲一些压缩率来换取质量。VECTOR_LEVEL过低对于运动场景过小的搜索范围可能找不到好的匹配块导致P帧的预测残差很大经过量化后信息损失严重。尝试增大VECTOR_LEVEL。输入视频本身质量确认输入的YUV数据是否正确色彩转换是否有误。可以用ffmpeg将输出的.m2v文件解码回YUV与原始输入YUV进行PSNR峰值信噪比计算客观比较质量差异。ffmpeg -i output.m2v -pix_fmt yuv444p output_decoded.yuv # 然后使用工具计算 original.yuv 和 output_decoded.yuv 的PSNR7.4 性能不达标帧率低时钟频率未达到检查时序是否收敛在目标频率如67MHz。如果未收敛参考7.2节进行优化。输入带宽瓶颈确保上游模块如摄像头接口、DDR控制器能持续以每周期4像素的速率供给数据。如果上游出现停顿i_en不能持续为高整体吞吐率就会下降。分析上游模块的吞吐能力。输出带宽瓶颈确保下游模块如DMA、存储接口能及时取走o_data。虽然编码器输出o_en非连续但在高码率场景下平均数据率仍然很高。如果输出FIFO溢出也会导致问题。经过几个项目的实际使用这个FPGA MPEG2编码器IP核表现出了出色的稳定性和性能。它的接口设计简洁明了一旦理解了其工作模式集成起来并不困难。最大的挑战在于资源管理和时序收敛需要根据目标FPGA的规模和性能仔细调整参数。对于需要中高画质、实时性要求高、且系统复杂度受限无外部DDR的应用场景它是一个非常优秀和实用的解决方案。