altera公司FPGA的视频流帧抓取

我们在用FPGA对视频进行处理时,常常会遇到:有时候图像中的某些文字显示模糊----这有可能是缩放导致;有时可能是AD/DA模块采用了不同厂家的芯片----导致转换后的效果不同;有可能在图像YUV422与YUV420互相转换----算法间接导致图像效果变差。林林总总,当然还有其它不同的图像处理而有可能降低画质的场景。在针对图像质量跟踪定位时,最直观的,莫过于直接抓取各图像处理功能模块的输入输出,取出前后图像直接对比,就能立竿见影的诊断出该模块是否异常。所以:如何在FPGA中抓取视频流中的一帧图像呢?本文将记录图像质量定位的实践中,如何对altera公司的fpga在高清视频流中,抓取图像。
在使用alera公司的fpga时,SignalTab是一个很方便的诊断工具。而用SignalTab进行图像抓取的时候,它的抓取深度最大为128K。而在实际的工程应用中,往往难以预留出128K的RAM,大多时候8K已是极限。更不用说,对于CycloneII/III系列,只能腾挪出2K也是常事。因此,想要一次性的将高清视频流的帧图像抓取出来,这点RAM是无法做到的。通过不断的逐次次抓取1到4行,然后将其拼接成一帧完整的图像成为一个可行的方法。

应用于还发现SignalTab存储的日志频率与深度有极大的相关性:深度为8K的时候,1秒只它只能记录1个日志;而深度为2K的时候,1秒它能记录4个日志。所以深度为2K的抓取效率(1次1行,1秒4行)与8K的抓取效率(1次3行,1秒3行)相近,并且从通信性考虑深度以2K为宜。从而做到让SignalTab在1秒内抓取4条日志,1条日志对应视频流帧图像中的1行有效数据。

对于1080p的高清视频,一行的有效数据是1920,如果现一行的有效数据就立即进行抓取,会因为SignalTab在抓取触发前截取1/8预留数据的这一特性,而无法得到1920的足量有效数据(此时只能抓取到1792个图像据)。基于SignalTab的这一特性,需要加一逻辑:在找到有效数据后,再偏移160个拍子(1792+160=1952大于1920),就能抓取成功啦。如下:基于YUV422视频流的抓取模块:

module vi_sync_gen_xy(
    // input //
    input sys_rst_n,
    input vp_clk_in,
    input [15:0]	vp_data_in,
    //	output	//
    output reg [10:0] y,
    output this2out
    output [15:0]	video_data,
);        

输入:复位,时钟,YUV422数据;输出:列号y,有效数据位标志this2out,采集到的数据;

对于1080p/30的视频1秒30帧,SignalTab是1秒记录4个日志,所以可以近似的每8帧取1行视频数据,以便SignalTab平滑的记录每行的数据。以下是verilog实现模块代码:

1,解析EAV和SAV,感知有效行数据

//SAV和EAV为四个
	 reg    [15 : 0]   pdata_t1;
	 reg    [15 : 0]   pdata_t2;
	 reg    [15 : 0]   pdata_t3;
	 reg    [15 : 0]   pdata_t4;
	//SAV和EAV的XY字节
	 wire 	            xy_b7;
	 wire 	            xy_f;
	 wire 	            xy_v;
	 wire 	            xy_h;
	 wire 	            xy_p3;
	 wire 	            xy_p2;
	 wire 	            xy_p1;
	 wire 	            xy_p0;
	 wire 	            is_xy;
//------ Extract the synchronization from video stream in BT1120 format------//
   assign 	xy_b7 = pdata_t1[7];
   assign 	xy_f  = pdata_t1[6];
   assign 	xy_v  = pdata_t1[5];
   assign 	xy_h  = pdata_t1[4];
   assign 	xy_p3 = pdata_t1[3];
   assign 	xy_p2 = pdata_t1[2];
   assign 	xy_p1 = pdata_t1[1];
   assign 	xy_p0 = pdata_t1[0];
 	//确定SAV和EAV的XY
assign 	is_xy = (xy_b7==1‘b1) & (xy_p3==xy_v^xy_h) & (xy_p2==xy_f^xy_h) & (xy_p1==xy_f^xy_v) & (xy_p0==xy_f^xy_v^xy_h);

always @(posedge vp_clk_in or negedge sys_rst_n)
     begin
	    if(!sys_rst_n)
	      begin
	        pdata_t1	<=   8‘h00;
	        pdata_t2	<=   8‘h00;
	        pdata_t3	<=   8‘h00;
	        pdata_t4	<=   8‘h00;
	      end
	    else
	      begin
	        pdata_t1	<=   vp_data_in;
	        pdata_t2	<=   pdata_t1;
	        pdata_t3	<=   pdata_t2;
	        pdata_t4	<=   pdata_t3;
	      end
     end
//produce sorts of EAV and SAV according to the protocol of SMPTE294
   assign eav_sav_pulse = (&pdata_t4[7:0]) & (!(|pdata_t3[7:0])) & (!(pdata_t2[7:0])) & is_xy;
   assign valid_sav = eav_sav_pulse & (~xy_f) & (~xy_v) & (~xy_h);//8080
   assign valid_eav = eav_sav_pulse & (~xy_f) & (~xy_v) & (xy_h); //9D9D
   assign blank_sav = eav_sav_pulse & (~xy_f) & (xy_v) & (~xy_h); //ABAB
   assign blank_eav = eav_sav_pulse & (~xy_f) & (xy_v) & (xy_h);  //B6B6

  

2,场同步和行同步

// produce hsync_flag,行同步,有效行
   always @ ( posedge vp_clk_in  or negedge sys_rst_n)
     if ( !sys_rst_n )
       hsync_flag  <=  1‘b0;
     else  if ( valid_sav )
       hsync_flag  <=  1‘b1;
     else  if ( valid_eav | blank_eav )
       hsync_flag  <=  1‘b0;
     else
       hsync_flag  <= hsync_flag;
//有效行的开始,和有效行结束的信号
   always @ ( posedge vp_clk_in  or negedge sys_rst_n)
     if ( !sys_rst_n )
	      hsync_flag_buf  <=  1‘b0;
     else
	      hsync_flag_buf  <=  hsync_flag;

   assign  hsync_ad  =  hsync_flag_buf && (!hsync_flag);	//有效行结束
	assign  hsync_ad_pos = hsync_flag && (!hsync_flag_buf); //有效行开始

// produce vsync_flag	场同步,一帧图像有效数据标志
   always @ ( posedge vp_clk_in  or negedge sys_rst_n)
     if ( !sys_rst_n )
       vsync_flag  <=  1‘b0;
     else  if ( valid_sav | valid_eav )
       vsync_flag  <=  1‘b1;
     else  if ( blank_eav )
       vsync_flag  <=  1‘b0;
     else
       vsync_flag  <= vsync_flag;

   //有效数据开始信号
   always @ ( posedge vp_clk_in  or negedge sys_rst_n)
     if ( !sys_rst_n )
       begin
         vsync_flag_buf    <=  1‘b0;
       end
     else
       begin
         vsync_flag_buf    <= vsync_flag;
       end

   assign  vsync_ad     =  vsync_flag && (!vsync_flag_buf);   //positive edge of vsynn_flag 有效数据开始信号
	assign  vsync_ad_neg =  (!vsync_flag) && vsync_flag_buf;	//negedge edge of vsync_flah 有效数据结束信号

3,有效数据抓取逻辑

//y,图像中行号逻辑
reg [10:0] max_y;	//需要知道场扫描中,宽度
always @ ( posedge vp_clk_in  or negedge sys_rst_n)
     if ( !sys_rst_n )
       begin
         y    <=  1‘b0;
	     max_y <=  1‘b0;
       end
     else
       begin
			if (vsync_ad)
				y <= 1‘b0;
			else begin
				if (vsync_flag) //在读取有效数据时
						if ( hsync_ad)	//每读完一行 y自增,其它时间维持原值
							y <= y + 1‘b1;
						else
							y <= y;
				else if(vsync_ad_neg) begin
					max_y <= y;
					y <= 1‘b0;
				end
				else
					y <= 1‘b0;
			end
       end
//x,图像中每行中x逻辑
reg [10:0] x;
reg state_x;
	always @ ( posedge vp_clk_in  or negedge sys_rst_n)
     if ( !sys_rst_n )
       begin
         x    <=  1‘b0;
			state_x <= 1‘b0;
       end
     else
       begin
			if (vsync_ad)
				x <= 1‘b0;
			else begin
				if (vsync_flag) //在读取有效数据时
						if ( hsync_ad) begin	//每读完一行有效数据后, x归0,直到出现下行一的有效数据时,此间一直维持为0
							state_x <= 1‘b0;
							x <= 1‘b0;
						end
						else if (hsync_ad_pos) begin //找到SAV后,即为有效数据的读取,x开始自增,直到离开有效数据时归0
							state_x <= 1‘b1;
							x <= 1‘b0;
						end
						else begin
							if ( state_x)		//读取有效数据,则自增
								x <= x + 1‘b1;
							else			//非有效数据,持续为0
								x <= 1‘b0;
						end
				else
					x <= 1‘b0;
			end
       end
//开始抓取this2out的输出逻辑
        reg [10:0] last_y;
	reg [15:0] ticks;
	reg [10:0] max_ticks;
	parameter  V1080P30_TICK  = 11‘d8;

	//隔一定的时间,取图像中一行
	always @ ( posedge vp_clk_in  or negedge sys_rst_n)
	  if ( !sys_rst_n )
		 begin
			last_y    <=  1‘b0;
			ticks		 <= 1‘b0;
			max_ticks <= V1080P30_TICK;
		 end
	  else begin
			if (max_y>0)
				max_ticks <= (16‘d8640/max_y)+1‘d1;
			else
				max_ticks <= max_ticks;
			if ( ticks >= max_ticks)
				begin
					ticks <= 1‘b0;
					if ( last_y >= max_y )
						last_y <= 1‘b0;
					else
						last_y <= last_y + 3‘d1;
				end
			else
				if ( vsync_ad)
					ticks <= ticks + 1‘b1;
				else
					ticks <= ticks;
	  end

	//定义thisout的逻辑
	assign this2out = (last_y == y && vsync_flag && x > 11‘d160);
//定义video_data
assign  video_data = pdata_t1;

因为抓取数据,需要SignalTab,都需要连接仿真器,所以对于选择的控制,可以添加一个ISSP的IP核,手动选取输出哪一路视频

之后,只需要将抓取模块添加到工程中,导入要监控的视频即可:

//qseng
 wire sv2st_rst,sv2st_clk;
 wire [15:0]sv2st_videodata;
 wire [5:0] sv2st_sel;
 isspv isspv_inst( .probe(), .source(sv2st_sel));
 select_video_to_signaltab sv2st_inst(
				.sel(sv2st_sel),
				.rst1(reset_n),.clk1(VP1_FP1_TO_FP2_CLK),.vdata1(VP1_FP1_TO_FP2),			//vp1
				.rst2(reset_n),.clk2(VP2_FP1_TO_FP2_CLK),.vdata2(VP2_FP1_TO_FP2),			//vp2
				.rst(sv2st_rst), .clk(sv2st_clk), .videoData(sv2st_videodata));
 vi_sync_gen_xy signaltab_catch_video(
					//           input           //
					.sys_rst_n(sv2st_rst),         // reset
					.vp_clk_in(sv2st_clk), 			 // clock
					.vp_data_in(sv2st_videodata)
			);

然后,添加stp文件,并创建需要监控的y,this2out和video_data

注意:this2out需要置1,只有抓取逻辑成立时才取相应数据。右边的时钟,与Sample depth如下:

在实际的工程应用中,抓取效果如下:

需要记下第一次抓取时的y值,如上为156h,直到下一次再次重复为156h时,表示一帧抓取结束。点击右下方的保存日志,此时有1000多条日志。这时不要日志进行导出(1000多条,一个一个导出肯定手也会酸吧),我们改为存储stp文件的方式,一次性的导出所有已存储的数据:

在出现的对话框中,新建一个名字,另存为一个新的stp文件

接下来,需要进行windows编程,解析此stp文件,并显示图片,并可以将该图片,存储为BMP文件,以便后续的分析。

可以直接到git的widnwos_release目录下,运行YUVSee.exe来解析刚才保存的stp文件。

关于stp的文件解析,请参看:YUVSee解析SignalTab保存的日志文件。

所有FPGA和YUVSee的源码,在github下:

https://github.com/qseng/zieee/tree/master/SignalTab_Capture_VideoFrame

原文地址:https://www.cnblogs.com/qseng/p/10347524.html

时间: 2024-08-03 17:30:47

altera公司FPGA的视频流帧抓取的相关文章

用libvlc 抓取解码后的帧数据

vlc是一套优秀的开源媒体库,其特点是提供了完整的流媒体框架, 用它可以非常方便的实现抓取解码帧的功能. 与此功能有关的关键API为 libvlc_video_set_callbacks /*设置回调,用来抓取解码后的帧*/ libvlc_video_set_format /*设置解码帧的格式 yuv or rgba ?*/ 这个函数将三个函数指针作为参数 /*callback function, lock the shared memory, and tell vlc where to put

java实现抓取某公司官网新闻

这里先说一下,实习期的一个项目,当时并没有该合作公司的获取新闻的接口,但是项目又急着上线,所以总监就让我来做一个简单的抓取,现将主要的工具类NewsUtil.java贴出来供大家参考. NewsUtil.java 1 package org.news.util; 2 3 import java.io.BufferedReader; 4 import java.io.IOException; 5 import java.io.InputStream; 6 import java.io.InputS

Altera 的 FPGA 的 AS、PS 和 JTAG 配置模式

FPGA 器件有三种配置下载方式:主动配置方式(AS)和被动配置方式(PS)和最常用的(JTAG)配置方式. AS 模式(Active Serial Configuration Mode): FPGA 器件每次上电时作为控制器,由 FPGA 器件引导配置操作过程,它控制着外部存储器和初始化过程,从配置器件 EPCS 主动发出读取数据信号,从而把 EPCS 的数据读入 FPGA 中,实现对 FPGA 的编程配置数据通过 DATA0 引脚送入 FPGA,配置数据被同步在 DCLK 输入上,1 个时钟

利用wireshark抓取TCP的整个过程分析。

原文地址:https://www.cnblogs.com/NickQ/p/9226579.html 最近,已经很久都没有更新博客了.看看时间,想想自己做了哪些事情,突然发现自己真的是太贪心,到头来却一个都没搞好.手头的嵌入式都还没学出名堂,竟然还想着学FPGA,物联网,机器学习.然而,遇到新奇的事物,就会控制不住的去想,去找资料,实际上只是逃避遇到的问题,不想去解决而已..最后的结果就是手头的活堆起来了,然后花大把整块的时间解决.真的是讨厌现在的自己. 以后还是慢慢记录吧,不管做了什么,都慢慢尝

使用Wireshark mac下抓取分析iphone数据包 --IOS端

mac系统版本:mac 10.10 Yosemite xcode版本:6.3.1 在追踪bug或者分析借鉴其他公司的app通讯思路时,抓包这件事是非常有必要的.下面说说Wireshark怎么截获iphone的数据包. 安装wireshark wireshark是依赖x11的,所以首先确认安装了x11,mac自带,可以打开升级一下.前往-实用工具-x11,打开后点击菜单栏上的x11,检查更新 即可.中间提取包内容过程比较长,耐心等待. 下载Wireshark最新版,尽量去官网下载:https://

关于curl跳转抓取

今天在公司碰到了一个bug,就是以前一直用curl下载的MP3录音文件为空了,但是浏览器去get请求是有文件的,并且大小还不是0kb,但是我用curl下载下来就是0K,百思不得其解.终于功夫不负有心人,得到了方法,原来我一直要去第三方的接口拿到录音数据,但是今天的录音数据中地址跳转了,也就是第一次请求的地址返回的是302, 这是以前的代码 $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); // curl_setopt($ch, CUR

xilinx和altera的fpga的不同之处!----如果不知道,你将为之付出代价! --转载

本人从2004年接触fpga开始,至今已经8年了.开发过altera的flex系列和cyclone3系列:开发过xilinx的vii和v5系列.下面谈谈本人对二者的一些不同,以便引起开发者对一些细节上的注意,免得为之付出代价,再走弯路!(1)altera的任意一个管脚都可以连接到这样的sig信号上always @ (posedge(sig)) ……:但是xilinx的fpga不能,只有clk信号才能够分配这样的信号.本人最早使用a公司flex系列的fpga,当fpga和dsp的emif连接时,为

为何大量网站不能抓取?爬虫突破封禁的6种常见方法

在互联网上进行自动数据采集(抓取)这件事和互联网存在的时间差不多一样长.今天大众好像更倾向于用“网络数据采集”,有时会把网络数据采集程序称为网络机器人(bots).最常用的方法是写一个自动化程序向网络服务器请求数据(通常是用 HTML 表单或其他网页文件),然后对数据进行解析,提取需要的信息. 本文假定读者已经了解如何用代码来抓取一个远程的 URL,并具备表单如何提交及 JavaScript 在浏览器如何运行的机制.想更多了解网络数据采集基础知识,可以参考文后的资料. 在采集网站的时会遇到一些比

一站式学习Wireshark(八):应用Wireshark过滤条件抓取特定数据流

应用抓包过滤,选择Capture | Options,扩展窗口查看到Capture Filter栏.双击选定的接口,如下图所示,弹出Edit Interface Settints窗口. 下图显示了Edit Interface Settings窗口,这里可以设置抓包过滤条件.如果你确知抓包过滤条件的语法,直接在Capture Filter区域输入.在输入错误时,Wireshark通过红色背景区域表明无法处理过滤条件.最有可能的情况是,过滤条件中含有输入错误,或是使用了display filter的