基于TCP协议的网络摄像头的设计大部分和博文“基于UDP协议的网络摄像头的设计与实现”相同,本篇博文采用的TCP协议栈为NicheStack协议栈(同理,可使用LWIP协议栈实现),协议分析及上位机设计可参考博文“基于NicheStack协议栈的网络例程分析及客户端程序设计”。
二、实验平台
硬件平台:DIY_DE2
软件平台:Quartus II 9.0 + Nios II 9.0 + Visual Studio 2010
该部分可参考博文“基于UDP协议的网络摄像头的设计与实现”。
该篇博文介绍的重点是底层软件(NIOS II端)和上位机程序的设计,底层和上位机的通信流程图如下图所示。
图 1 底层和PC之间的通信流程图
以上是系统的整体流程图,下面对一些关键的调试过程做个阐述。
根据“基于UDP协议的网络摄像头的设计与实现”里面的调试经验,对系统进行调试。
首先,在C#端,重写buffer,验证C#显示控件的正常。调试图片如图2所示。
图2 C#控件显示调试图
底层的发送数据包长度为1500,TCP数据包的包头长度为54,所以一包数据可以显示(1500-54)/2=723个像素,在控件显示2行83个像素。在控件的顶端细节部分可以看到。
其次,在NIOS II写待发送的数据,发送到C#端,验证显示正常。这里采用TCP的拉模式。即C#端手动发送一次命令,底层发送上来一包数据,这样手动发送107次命令之后,C#控件可以显示出底层发送上来的一帧既定色彩的图像,如图3所示。
图3 底层发送的既定色彩图像
再次,在验证上述2个步骤的基础上,添加读取SRAM数据,即将获取的图像传输上来,并在C#中添加自动发送命令功能,则可以在C#端连续收到图像数据,如图4所示。
图4 图像效果图
按照1中的步骤可以将图像显示出来,只是速度很低,约30s显示出一帧图像,网络传输速度约为10KB/s。之前传输慢的原因是,网络传输采用的是拉模式,即C#发一次命令,底层传输一包数据,这样一帧图像要107次命令,可见效率极低。另外C#端的程序也有造成速度慢的原因。
改进1:C#端删除掉不必要的内容,接收及绘图部分单独开了一个线程。代码如下:
private void TelnetThread() { while (socket.Connected) { try { Receive(); //去掉不必要的输出,提高接收效率 //string str = Receive(); ////string str = ""; //str = str.Replace("\0", ""); //string delim = "\b"; //str = str.Trim(delim.ToCharArray()); //if (str.Length > 0) //{ // Console.WriteLine(str); // if (str == OUTPUTMARK + BACK) // { // //BackupSpace键处理 // this.rtbConsole.ReadOnly = false; // int curpos = rtbConsole.SelectionStart; // this.rtbConsole.Select(curpos - 1, 1); // this.rtbConsole.SelectedText = ""; // this.rtbConsole.ReadOnly = true; // } // else // { // Log(LogMsgType.Incoming, str); // } //} Thread.Sleep(100); } catch (Exception e) { Console.WriteLine(e.ToString()); } } this.sbpStatus.Text = "状态:已断开"; }
这个改进大大提高了C#端的数据接收速度,也解除了不能用for循环连续发送数据包的问题。另外,C#端每收到一帧图像数据后,自动发送一次命令,使底层继续传输下一帧图像。
改进2:底层部分,每发送一包数据,将发送指针指向发送数组的首地址,代码如下:
for(j = 0; j < 107; j++) { //每发送完一包数据,使指针指向数组的首地址 tx_wr_pos = tx_buf; for(k = 0; k < 1446; k++) { if((k%2) == 0) tx_buf[k] = a[k/2 + j*723]; else tx_buf[k] = b[k/2 + j*723]; tx_wr_pos++; } //写满发送数组之后,将其发送出去 send(conn->fd, tx_buf, tx_wr_pos - tx_buf, 0); printf("NIOS WORKING\n"); }
改进3:底层部分,PIO中断,每次进入PIO中断后,先将中断标志位清零,可是在没有中断源的情况下,系统还是频频进入中断服务函数,不知何解?无奈之举是,进入中断服务函数之后,直接关闭中断使能并将中断标志位清零,等uC/OS II端将图像数据完全传输出去之后,再开启中断使能。另外,uC/OS II系统启动之前,不能开启中断使能,所以在初始化的时候应将PIO中断使能禁止,当收到客户端的命令时,再开启中断使能。该部分的操作流程见图1。
通过上述3个方面的改进,传输速度大大提高了,约100KB/s,这样,显示一帧图像不到3s,显示效果也比较清晰。
根据上述几篇博文的阐述,分别完成了基于UDP和TCP传输协议的网络摄像头的设计与实现,博文重点分析了调试过程,即发现问题、解决问题的过程。博文论证了设计原理的正确性,同时,网络传输的速度也得到了测试,不过仍有许多改进和提高的地方,比如在传输的同时,写下一帧图像。
另外一个重点是,博文阐述的图像压缩使用的是有损压缩的方法,最终的分辨率为320*240,rgb555形式。因此,下一步将重点研究图像编解码算法,最大限度的降低码率。使视频更加流畅。