Posted by (10) Comment
平台移植:
uIP的设备驱动程序接口
uIP内核中有两个函数直接需要底层设备驱动程序的支持。
一是uip_input()。当设备驱动程序从网络层收到一个数据包时要调用这个函数,设备驱动程序必须事先将数据包存放到uip_buf[]中,包长放到uip_len,然后交由uip_input()处理。当函数返回时,如果uip_len不为0,则表明有带外数据(如SYN,ACK等)要发送。当需要ARP支持时,还需要考虑更新ARP表或发出ARP请求和回应。
另一个需要驱动程序支持的函数是uip_periodic(conn)。这个函数用于uIP内核对各连接的定时轮循,因此需要一个硬件支持的定时程序周期性地用它轮循各连接,一般用于检查主机是否有数据要发送,如有,则构造IP包。
uIP的应用程序接口
为了将用户的应用程序挂接到uIP中,必须将宏UIP_APPCALL()定义成实际的应用程序函数名, 这样每当某个uIP事件发生时,内核就会调用该应用程序进行处理。如果要加入应用程序状态的话,必须将宏UIP_APPSTATE_SIZE定义成应用程序状态结构体的长度。在应用程序函数中,依靠uIP事件检测函数来决定处理的方法,另外可以通过判断当前连接的端口号来区分处理不同的连接。
快速向导: 移植uIP到其它的平台
实际的TCP/IP代码无需任何修改, 但是目标网络设备的驱动程序(以太网控制器/串
口/其它)和实际的系统集成部分(比如, 主控制循环, 当数据到达或定期时钟超时需调用uI
P函数)需要重写.
移植步骤:
1. 阅读提供的文档.
2. 在uip-1.0/目录下为你的端口创建新的目录(选择一个简短的CPU架构名称, 比如
i386,用于C编译器).
3. 从unix/子目录拷贝uip_arch.c文件到新创建的目录. ls包含了一个普通的C校验
算法实现, 是一个32位的函数).
4. 从unix/子目录拷贝uipopt.h文件.
5. 根据你的项目编辑uipopt.h文件(文件是自描述型的).
6. 为你的硬件写设备驱动.(这大概是最难的部分.) 查阅unix/tapdev.c和uip/sli
pdev.c实例了解设备驱动如何实现.
7. 写好主控制循环, 然后调用uIP函数. 查阅unix/main.c实例了解主控制循环如何
实现.通过unix/main.c主循环实例了解如何使用ARP协议.
8. 写makefile文件, 然后编译代码. 确认你的项目(在你子目录中的.c文件)包含了../uip/uip.c文件. 如果你正使用web服务器程序, 请记住包含文件../apps/httpd/httpd.c ../apps/httpd/cgi.c ../apps/httpd/fs.c. 如果需支持
ARP, 请包含文件 ../uip/uip_arp.c.
9. 发现和纠正所有的程序错误. (这是平台移植中最需技巧的部分:)
Uip 源代码介绍
1.文件关系
弄清楚源代码之间的联系和各个主要函数的功能,移植就不困难了。
Apps à 这是作者写的一些应用代码。包括Http、Smtp、Telnet和Webclient等等。
Uip à 这是uip的核心代码。
Unix à 这是作者在unix系统下的一个工程。
Doc à 这是说明文档。
重点说说Uip和Unix这两个文件夹中比较重要的函数。
Uip:
Uip.c :
uip_process( ) 完成对ip,udp,tcp的数据的解析。
uip_udp_new() 建立一个udp。
uip_listen() 监听一个端口。
uip_connect() 准备建立一个tcp连接,发送同步信号。
Uip_arp.c
uip_arp_update()更新arp列表。
uip_arp_init() 初始化arp缓冲块
uip_arp_out() 发送一个arp请求
uip_arp_arpin() 处理收到一个arp包
uip_arp_ipin() 处理收到是arp包的ip包。
Slipdev.c 是关于SLIP 协议的文件
Unix:
Main.c uip服务的主循环。
Tapdev.c 和 tapdev.h 是低层数据的接收与发送。
Uip_arch.c 一些计算校验和的函数。
Uipopt.h 这是一个uip的配置文件。你可以修改IP,NETMASK,GATEWAY,MAC等等以便符合你的网络。
2,移植细节
在你的工程中,你需要包含如下文件:
Uip.c
Uip_arch.c
Uip_arp.c
Tapdev.c
Main.c
A, 网卡驱动移植
Tapdev.c 包含3个函数:
a> tapdev_init(void) 网卡初始化.
b> unsigned int tapdev_read(void) 接收网卡数据
c> void tapdev_send(void) 发送网卡数据
这3个函数与低层硬件有关.大家只需按照上述函数的接口,完成低层数据的收发便可.
B, UDP的移植
a> uipopt.h 中修改
#define UIP_UDP 1
#define UIP_UDP_CONNS 10(同时可建立udp的连接数)
#define UIP_UDP_APPCALL udp_appcall (UDP的用户接口函数)
添加 #include
b> 新建udp.c 和udp.h 两个文件
udp.c中定义两个函数
udpinit(void)
{
uip_ipaddr(ipaddr, RIPADDR0, RIPADDR1, RIPADDR2, RIPADDR3);
uip_udp_new(ipaddr, UDP_LPORT, UDP_RPORT); //建立一个udp,指定udp端口。
//注意:我对uip_udp_new()函数做了修改,原来本地端口是随机的,我改为了可以配置的。
}
//当UDP数据被tapdev_read ()收到,uip_process()函数对UDP进行解析,如果正确,则调用udp_appcall()来交给用户处理。此时,用户可以用uip_newdata()检测是否有新数据,新数据放在uip_appdata指针中,长度为uip_len。
//当定时轮询到达,后也会调用udp_appcall(),可以用uip_poll()检查。此时,用户可以主动发送数据。只须将数据放入指针uip_appdata后的空间中,并将数据长度传给uip_slen便可。
下面给出了函数的模型(仅供参考):
void udp_appcall(void)
{
if(uip_udp_conn->rport == HTONS(UDP_RPORT))
{
if(uip_poll())
{
/*
for(u16_t i=0; i<1000; i++)
{
*(uip_appdata++) = (u8_t)i;
}
*uip_appdata = ‘\0′;
uip_slen = 1000; //strlen((char*)uip_appdata);*/
}
if(uip_newdata())
{
uip_appdata[uip_len]=’\0′;
uip_slen = uip_len;
}
}
}
uIP0.9 keil移植要点
1. 打开Keil新建项目uIP0.9.uv2, 设置项目属性.
memory_model 设置为large 模式,这样默认的存储方式是xdata
因为uIP0.9编译后占用20K rom, 所以必须选一个32K(>20K)的rom的单片机,
比如Device可设置为SST89×58或者SST89×516xx,
解压缩官方下载的uIP0.9压缩包,添加文件至项目,
需添加至项目的文件有:uip\uip.c, uip.c\uip.h, uip.c\uip_arch.h,
uip.c\uip_arp.c,uip.c\uip_arp.h
unix\main.c, unix\uip_arch.c, unix\uipopt.h,
apps\httpd\所有文件
2. 因为data是系统关键字, 所以标识符data => dat
以下文件需要改动: fs.h, fsdata.h,httpd.c
3. 为RTL8019AS 编写驱动程序(具体如何操作寄存器老古的网站有详细的教程),
内容在压缩包中的RTL8019AS.c, RTL8019AS.h
需要更改main.h中的如下地方:
include “tapdev.h” => #include “rtl8019as.h”
tapdev_init() -> rtl8019as_init()
tapdev_send() -> rtl8019as_send()
tapdev_read() -> rtl8019as_read()
4. fsdata.c 首行添加 #include “fsdata.h”
关键字替换:
static const char -> const char code
const struct fsdata_file -> const struct fsdata_file code
fsdata.h 文件末尾添加:
#define FS_ROOT file_tcp_header_html
#define FS_NUMFILES 14
const char code data_cgi_files[];
const char code data_cgi_stats[];
const char code data_cgi_tcp[];
const char code data_img_bg_png[];
const char code data_about_html[];
const char code data_control_html[];
const char code data_404_html[];
const char code data_files_footer_plain[];
const char code data_files_header_html[];
const char code data_index_html[];
const char code data_stats_footer_plain[];
const char code data_stats_header_html[];
const char code data_tcp_footer_plain[];
const char code data_tcp_header_html[];
const struct fsdata_file code file_cgi_files[];
const struct fsdata_file code file_cgi_stats[];
const struct fsdata_file code file_cgi_tcp[];
const struct fsdata_file code file_img_bg_png[];
const struct fsdata_file code file_about_html[];
const struct fsdata_file code file_control_html[];
const struct fsdata_file code file_404_html[];
const struct fsdata_file code file_files_footer_plain[];
const struct fsdata_file code file_files_header_html[];
const struct fsdata_file code file_index_html[];
const struct fsdata_file code file_stats_footer_plain[];
const struct fsdata_file code file_stats_header_html[];
const struct fsdata_file code file_tcp_footer_plain[];
const struct fsdata_file code file_tcp_header_html[];
5. fs.c 第55行删除: #include “fsdata.c”
6. uipopt.h
181行: #define UIP_FIXEDETHADDR 0 -> 1
299行: #define UIP_ACTIVE_OPEN 1 ->0
497行: #define BYTE_ORDER LITTLE_ENDIAN -> BIG_ENDIAN
280行: #define UIP_UDP_APPCALL udp_appcall -> httpd_appcall
文件末尾添加:
#ifndef NULL
#define NULL (void *)0
#endif /* NULL */
7. httpd.c
删除以下内容:
extern const struct fsdata_file file_index_html;
extern const struct fsdata_file file_404_html;
220行更改:
fs_open(file_index_html.name, &fsfile); => file_index_html->name
224行同上更改
Posted by (3) Comment
源码公开的TCP/IP协议栈在远程监测中的应用
摘 要:介绍一个适用于8/16位单片机的嵌入式TCP/IP协议栈(uIP)在发电机远程监测系统中的应用。重点阐述uIP的功能特性、体系结构和相关接口,并详细介绍如何在该协议栈上实现一个嵌入式Web服务器。目前uIP已成功地移植到51单片机上。
关键词:TCP/IP协议栈 uIP 嵌入式Web服务器 远程监测
引 言:
目前,随着互联网的发展,越来越多的工业测控设备已经将网络接入功能作为其默认配置,以实现设备的远程监控和信息分布式处理。笔者曾参与某发电机射频监测仪的开发,该设备主要用于诊断和预警发电机早期故障,并通过RS232接口定时输出电平和状态数据,现场专门设一台PC作接收、显示及存储。每年都要有专家到各发电厂对以往数据作检查和诊断,不胜其烦。因此有必要设计一个RS232到Internet的数据传输模块,以便对发电机的运行状况作远程监测。设计该模块的关键在于如何实现一个嵌入式TCP/IP协议栈,根据以往的经验,自己设计一个协议栈的难度很可能超过应用本身控制工程网版权所有,而采用商业的协议栈似乎又无必要(功能过于复杂),最后笔者选用一种功能简易的免费TCP/IP协议栈uIP 0. 9作为设计核心。
1 嵌入式TCP/IP协议栈
目前,市面上几乎所有的嵌入式TCP/IP协议栈都是根据BSD版的TCP/IP协议栈改写的。在商业嵌入式TCP/IP协议栈大都相当昂贵的情况下,很多人转而使用一些源代码公开的免费协议栈,并加以改造应用。目前较为著名的免费协议栈有:
lwIP(Light weight TCP/IP Stack)——支持的协议比较完整,一般需要多任务环境支持,代码占用ROM>40KB,不适合8位机系统,没有完整的应用文档;
uC/IP (TCP/IP stack for uC/OS)——基于uC/OS的任务管理,接口较复杂,没有说明文档。
笔者采用的协议栈系瑞典计算机科学研究所Adam Dunkels开发的uIP0.9 。其功能特性总结如下:
◇完整的说明文档和公开的源代码(全部用C语言编写,并附有详细注释);
◇极少的代码占用量和RAM资源要求,尤其适用于8/16位单片机(见表1);
◇高度可配置性,以适应不同资源条件和应用场合;
◇支持ARP、IP、ICMP、TCP、UDP(可选)等必要的功能特性;
◇支持多个主动连接和被动连接并发,支持连接的动态分配和释放;
◇简易的应用层接口和设备驱动层接口;
◇完善的示例程序和应用协议实现范例。
正是由于uIP所具有的显著特点,自从0.6版本以来就被移植到多种处理器上,包括MSP430、AVR和Z80等。笔者使用的uIP0.9是2003年11月发布的版本。目前,笔者已将它成功移植到MCS-51 上了。
2 uIP0.9的体系结构
uIP0.9是一个适用于8/16位机上的小型嵌入式TCP/IP协议栈,简单易用,资源占用少是它的设计特点。它去掉了许多全功能协议栈中不常用的功能,而保留网络通信所必要的协议机制。 其设计重点放在IP、ICMP和TCP协议的实现上,将这三个模块合为一个有机的整体,而将UDP和ARP协议实现作为可选模块。uIP0.9的体系结构如图1所示。
uIP0.9处于网络通信的中间层,其上层协议在这里被称之为应用程序,而下层硬件或固件被称之为网络设备驱动。显然,uIP0.9并不是仅仅针对以太网设计的,它具有媒体无关性。
为了节省资源占用, 简化应用接口, uIP0.9在内部实现上作了特殊的处理。
① 注意各模块的融合,减少处理函数的个数和调用次数,提高代码复用率,以减少ROM占用。
② 基于单一全局数组的收发数据缓冲区,不支持内存动态分配, 由应用负责处理收发的数据。
③ 基于事件驱动的应用程序接口,各并发连接采用轮循处理,仅当网络事件发生时,由uIP内核唤起应用程序处理。这样,uIP用户只须关注特定应用就可以了。传统的TCP/IP实现一般要基于多任务处理环境,而大多数8位机系统不具备这个条件。
④ 应用程序主动参与部分协议栈功能的实现(如TCP的重发机制,数据包分段和流量控制),由uIP内核设置重发事件,应用程序重新生成数据提交发送,免去了大量内部缓存的占用。基于事件驱动的应用接口使得这些实现较为简单。
3 uIP的设备驱动程序接口
uIP内核中有两个函数直接需要底层设备驱动程序的支持。
一是uip_input()。当设备驱动程序从网络层收到一个数据包时要调用这个函数,设备驱动程序必须事先将数据包存放到uip_buf[]中,包长放到uip_len,然后交由uip_input()处理。当函数返回时,如果uip_len不为0,则表明有带外数据(如SYN,ACK等)要发送。当需要ARP支持时,还需要考虑更新ARP表或发出ARP请求和回应,示例如下。
#define BUF ((struct uip_eth_hdr *)&uip_buf[0])
uip_len = ethernet_devicedriver_poll(); //接收以太网数据包
//(设备驱动程序)
if(uip_len>0){ //收到数据
if(BUF->type = = HTONS(UIP_ETHTYPE_IP)) { //是IP包吗?
uip_arp_ipin(); //去除以太网头结
//构,更新ARP表
uip_input(); //IP包处理
if(uip_len>0){ //有带外回应数据
uip_arp_out(); //加以太网头结构,在主动连接时可能要
//构造ARP请求
ethernet_devicedriver_send(); //发送数据到以太网
//(设备驱动程序)
}
}else if (BUF->type = = HTONS(UIP_ETHTYPE_ARP)) {
//是ARP请求包
uip_arp_arpin(); //如是是ARP回应,更新ARP表;如果是
//请求,构造回应数据包
if(uip_len>0) { //是ARP请求,要发送回应
ethernet_devicedriver_send(); //发ARP回应到以太网上
}
}
另一个需要驱动程序支持的函数是uip_periodic(conn)。这个函数用于uIP内核对各连接的定时轮循,因此需要一个硬件支持的定时程序周期性地用它轮循各连接,一般用于检查主机是否有数据要发送,如有,则构造IP包。使用示例如下。
for(i=0 ; i
uip_periodic(i);
if(uip_len > 0){
uip_arp_out();
ethernet_devicedriver_send();
}
}
从本质上来说, uip_input()和uip_periodic()在内部是一个函数,即uip_process (u8t flag), UIP的设计者将uip_process(UIP_DATA)定义成uip_input(),而将uip_process(UIP_TIMER)定义成uip_periodic(),因此从代码实现上来说是完全复用的。
4 uIP的应用程序接口
为了将用户的应用程序挂接到uIP中,必须将宏UIP_APPCALL()定义成实际的应用程序函数名, 这样每当某个uIP事件发生时,内核就会调用该应用程序进行处理。如果要加入应用程序状态的话,必须将宏UIP_APPSTATE_SIZE定义成应用程序状态结构体的长度。在应用程序函数中,依靠uIP事件检测函数来决定处理的方法,另外可以通过判断当前连接的端口号来区分处理不同的连接。下面的示例程序是笔者实现的一个Web服务器应用的框架。
#define UIP_APPCALL uip51_appcall
#define UIP_APPSTATE_SIZE sizeof(struct uip51app_state)
struct uip51app_state{
unsigned char *dataptr;
unsigned int dataleft;};
void uip51_initapp{ //设置主机地址
u16_t ipaddr[2];
uip_ipaddr(ipaddr, 202 ,120,127,192 );
uip_sethostaddr(ipaddr);
uip_listen(HTTP_PORT); //HTTP WEB PORT(80);
}
void uip51_appcall(void){
struct uip51app_state *s;
s = (struct uip51app_state *)uip_conn->appstate;
//获取当前连接状态指针
if(uip_connected()) {
… //有一个客户机连上}
if(uip_newdata()||uip_rexmit()) { //收到新数据或需要重发
if(uip_datalen()>0){
if(uip_conn->lport = = 80) { //收到GET HTTP请求
update_table_data(); //根据电平状态数据表动态
//生成网页
s->dataptr=newpage;
s->dataleft=2653;
uip_send(s->dataptr,s->dataleft);
//发送长度为2653 B的网页
}
}
}
if(uip_acked()) {
//收到客户机的ACK
if(s->dataleft>uip_mss()&&uip_conn->lport = = 80){
//发送长度>最大段长时
s->dataptr+=uip_conn->len; //继续发送剩下的数据
s->dataleft-=uip_conn->len;
uip_send(s->dataptr,s->dataleft);
}
return;
}
if(uip_poll())
{ … //将串口缓存的数据复制到
//电平状态数据表
return;
}
if(uip_timedout()|| //重发确认超时
uip_closed()|| //客户机关闭了连接
uip_aborted()){ //客户机中断连接
return; }
}
5 uIP0.9在发电机远程监测系统中的应用
笔者设计了一个嵌入式Web模块UIPWEB51,用于将发电机射频监测仪串口输出的数据上网,以实现对发电机工作状态的远程监测,目前已取得初步成功。该模块的硬件框图如图2所示。
单片机采用的是Atmel的AT89C55WD,它内置20KB 程序Flash,512字节RAM,3个定时器/计数器,工作在22.1184MHz时具有约2MIPS的处理速度。 网卡芯片同样采用的是低成本的RTL8019AS, 是一款NE2000兼容的网卡芯片。系统外扩了32KB的SRAM,用于串口数据和网络数据的缓冲,另外还存放了uIP的许多全局变量。
UIPWEB51的主程序采用中断加轮循的方式,用中断触发的方式接收发电机射频监测仪发出的数据,并设置了一个接收队列暂存这些数据。在程序中轮循有无网络数据包输入,如有则调用uIP的相关处理函数(如上uip_input()使用示例);如无则检测定时轮循中断是否发生。这里将T2设为uIP的定时轮循计数器, 在T2中断中设置轮循标志,一旦主程序检测到这一标志就调用uip_periodic()轮循各连接(如上uip_periodic()使用示例)。
UIPWeb51的应用程序(如uIP的应用程序接口示例),这个Web服务器首先打开80端口的监听,一旦有客户机要求连上,uIP内部会给它分配一个连接项, 接着等收到客户机IE浏览器发出的“GET HTTP…”请求后, 将发电机电平与状态数据队列中的数据填入网页模板,生成一幅新的网页发给客户机。因为这幅网页的大小已经超过uIP的最大段长(MSS), 因此在uIP内核第一次实际只发出了MSS个字节, 在等到下一次轮循到该连接并且收到上次数据包的ACK时,发送剩下的网页数据。在连接处于空闲的时候(uip_poll()),应用程序可以从串口队列中读出原始数据,经格式处理后再存到发电机电平与状态数据队列中,而在这个队列中保存着当前1min的设备工作数据,以便下次更新网页时使用。在网页中添加了更新按钮控制工程网版权所有,一旦浏览器用户点击了按钮, 浏览器会自动发出CGI请求, UIPWEB51收到后,立即发送包含最新数据的网页。如果uIP接收ACK超时,它会自动设置重发标志,应用程序中可以用uip_rexmit()来检测这个标志,重新生成网页并发送。一旦用户关闭了浏览器,uIP也会自动检测到这一事件(应用程序中可以用uip_closed()来检测),并且释放掉这个连接项。
图3是UIPWEB51的总体程序结构图。
6 测试结果
将uIP0.9配置成允许4个并发连接,1个监听端口, 10个ARP表项,去掉UDP支持,UIP_BUFSIZE=1500和其它优化选项。用KEIL C编译,整个uIP0.9内核模块代码量小于8KB(含Web应用程序),内核对RAM的占用小于2KB(不含网页)。整个系统程序的代码量小于12KB,占用的RAM小于10KB。另外控制工程网版权所有,在公网上测试了该模块的传输速度,大于20Kbps,对于此项应用已达到要求。目前,该模块正准备应用于新一代的发电机射频监测系统中。
参考文献
1 RTL8019AS Realtek Full-Duplex Ethernet Controller with Plug and Play Function Specification, 2002
2 ATMEL AT89C55WD datasheet, 2001
3 Adam Dunkels . uIP 0.9 reference manual, 2003
4 Adam Dunkels. uIP – A free Small TCP/IP Stack, 2002
5 Douglas E.Comer. 用TCP/IP进行网际互联(卷1). 林瑶等译. 北京:电子工业出版社, 2001
6 王罡,林立志编著. 基于Windows的TCP/IP编程. 北京: 清华大学出版社, 2000
Posted by (2) Comment
1 数字压缩的必要性
数字信号有很多优点,但当模拟信号数字化后其频带大大加宽,一路6MHz的普通电视信号数字化后,其数码率将高达167Mbps,对储存器容量要求很大,占有的带宽将达80MHz左右,这 样将使数字信号失去实用价值。数字压缩技术很好地解决了上述困难,压缩后信号所占用的频带大大低于原模拟信号的频带。因此说,数字压缩编码技术是使数字信号走向实用化的关键技术之一,表4-1列出了各种应用的码率。
|
表4-1 各种应用的码率 |
|||||||
|
应用种类 |
比特数/象素 |
象素数/行 |
行数/帧 |
帧数/秒 |
亮色比 |
比特/秒(压缩前) |
比特/秒(压缩后) |
|
HDTV |
8 |
1920 |
1080 |
30 |
4:1:1 |
1.18Gbps |
20~25Mbps |
|
普通电视CCIR601 |
8 |
720 |
480 |
30 |
4:1:1 |
167Mbps |
4~8Mbps |
|
会议电视CIF |
8 |
352 |
288 |
30 |
4:1:1 |
36.5Mbps |
1.5~2Mbps |
|
桌上电视QCF |
8 |
176 |
144 |
30 |
4:1:1 |
9.1Mbps |
128kbps |
|
电视电话 |
8 |
128 |
112 |
30 |
4:1:1 |
5.2Mbps |
56kbps |
有线电视网中数字压缩技术主要包括用于会议电视系统的H.261压缩编码,用于计算机静止图像压缩的JPEG和用于活动图像压缩的MPEG数字压缩技术。
2 图像压缩编码的可能性
从信息论观点来看,图像作为一个信源,描述信源的数据 是信息量(信源熵)和信息冗余量之和。信息冗余量有许多种,如空间冗余,时间冗余,结构冗余,知识冗余,视觉冗余等,数据压缩实质上是减少这些冗余量。可见冗余量减少可以减少数据量而不减少信源的信息量。从数学上讲,图像可以看作一个多维函数,压缩描述这个函数的数据量实质是减少其相关性。另外在一些情况下,允许图像有一定的失真,而并不妨碍图像的实际应用,那么数据量压缩的可能性就更大了。
3 图像压缩编码方法的分类
编码压缩方法有许多种,从不同的角度出发有不同的分类方法,比如从信息论角度出发可分 为两大类:
(1)冗余度压缩方法,也称无损压缩,信息保持编码或熵编码。具体讲就是解码图像和压缩 编码前的图像严格相同,没有失真,从数学上讲是一种可逆运算。
(2)信息量压缩方法,也称有损压缩,失真度编码或熵压缩编码。也就是讲解码图像和原始图像是有差别的,允许有一定的失真。
应用在多媒体中的图像压缩编码方法,从压缩编码算法原理上可以分类为:
(1)无损压缩编码种类
·哈夫曼编码
·算术编码
·行程编码
·Lempel zev编码
(2)有损压缩编码种类
·预测编码:DPCM,运动补偿
·频率域方法:正文变换编码(如DCT),子带编码
·空间域方法:统计分块编码
·模型方法:分形编码,模型基编码
·基于重要性:滤波,子采样,比特分配,矢量量化
(3)混合编码
·JBIG,H261,JPEG,MPEG等技术标准
衡量一个压缩编码方法优劣的重要指标是:
(1)压缩比要高,有几倍、几十倍,也有几百乃至几千倍;
(2)压缩与解压缩要快,算法要简单,硬件实现容易;
(3)解压缩的图像质量要好。
最后要说明的是选用编码方法时一定要考虑图像信源本身的统计特征;多媒体系统(硬件和 软件产品)的适应能力;应用环境以及技术标准。
4 压缩编码方法简介
压缩编码的方法有几十种之多,并在编码过程中涉及较深的的数学里理论基础问题,在此仅介绍 几种常用的压缩编码方法,主要是从物理意义上作一定的解释,读者如对数据压缩专题感兴趣的话,请参看讲座结束后所附的参考资料。
4.1 莫尔斯码与信源编码
莫尔斯码即电报码,其精华之处在于用短码来表示常出现的英文字母,用长码来表示不常出 现的字母,以减小码率。这种方法非常有效,故延用至今。电视信号经过变换后,例如经差值脉冲编码后,发现前后像素幅度差值小的概率大,而差值大的概率小,因此可用短码表示概率大的信号,而用长码来代表概率小的信号,从而达到压缩码率的目的。
4.2 差值脉冲编码
电视图像基本上是由面积较大的像块(如蓝天、大地、服装等)组成。虽然每个像块的幅值各不相同,但像块内各样值的幅度是相近的或相同的,幅值跃变部分相应于像块的轮廓,只占整幅图像的很小一部分。帧间相同的概率就更大了,静止图像相邻帧间的相应位置的像素完全一样,这意味着前后像素之差或前后帧间相应位置像素之差为零或差值小的概率大,差值 大的概率小。这就是差值编码的基本想法,其原理框图见图4-1(a)。发端将当前样值和前一 样值相减所得差值经量化后进行传输,收端将收到的差值与前一个样值相加得到当前样值。在这个原理图中,输出的当前样值是输出的前一样值加上收到的差值,由于在当前差值中包 括当前的量化误差,而输出的前一样值又包括前一样值的量化误差,这就造成了量化误差的积累。因此实用电路为图4-1(b)。这时输入当前样值不是与输入的前一样值相减,而是与输 出的前一样值相减,因此在差值中已经包含了前一样值的量化误差的负值,在与输出的前一 个样值相加时,这部分量化误差被抵消,只剩下当前的量化误差,这就避免了量化误差的积累。
4.3 预测编码
预测编码利用像素的相关性,可进一步减小差值。
从前面的分析可以看出,如果差值编码中小幅度出现的机会增加,由于其对应的码长较短, 总数码率会进一步减小。如果能猜出下一个样值,那么差值就会是零,当然这种情况是没有意义的,因为若预先知道下一样值,就不需要进行通信了。但可以肯定,如果我们不仅利用 前后样值的相关性,同时也利用其它行、其它帧的像素的相关性,用更接近当前样值的预测值与当前样值相减,小幅度差值就会增加,总数码率就会减小,这就是预测编码的方法。预 测编码的电路与差值编码类似,或者说差值编码就是以前一样值为预测值的预测编码,又称为一维预测。如果用到以前行的像素或以前帧的像素,则称为二维或三维预测。在美国国际电话电报公司(ITT)生产的数字电视机芯片中有一个视频存储控制器芯片VMC2260就用了二维预测编码,预测器用了三个像素作为下一个像素的预测值,即预测值等于1/2前一像素加1/4 上一行相应像素再加上1/4上一行相应的前一像素。这样不仅利用了前一像素的相关性,也利用了上一行相应像素的相关性,这样做要比差值编码有更大的码率压缩。如果再用上前一 帧的像素会进一步降低数码率。但为了得到前一帧的像素必须要使用帧存储器,造价比较高。只用到帧内像素的处理称为帧编码(Intraframe Coding),用到前后帧像素的处理称为帧 间编码(Interframe Coding)。要得到较大的码率压缩就必须使用帧间编码。JPEG是典型的帧内编码方案,而MPEG是帧间编码方法。前者大多用于静止图像处理,而后者主要用于对运 动图像的处理。
4.4 哈达玛特变换
这是一种有效地去除噪波的方法,噪波的存在往往容易和小幅度变化的信号相混淆,利用多帧平均的方法,对于静止图像,各帧相同,平均的结果其值不变,对于噪波,多帧平均趋于零。
但如果图像中有运动,多帧平均就会造成运动模糊,故不能简单地进行平均,需要根据运动的大小来调节反馈量,即调节平均的程度,做到运动自适应降噪。
大多数情况下是利用帧差信号来判断图像中是否有运动,如果帧差小于一定值,就可视为是因噪波引起的,可取较大的反馈量;如果帧差大于一定值,就可视为图像中有运动。
但在许多情况下,仅从幅度的大小来判断是杂波还是图像是很困难的,如移动的云,近摄的 绿草地等图像信号所得到帧差信号也很小,所以BKU-904采用二维哈达玛特变换(Hadamard Transform)来区分是噪波还是图像信号。先将输入值按4×2分成小块,分别进行实时快速哈 达玛特变换(FHT)。
图像经变换后,转换成相应成分的系数,这些系数分别代表直流分量;水平方向细节和色度 分量等;垂直方向细节;斜方向细节及色度分量等,而噪波变换后均匀散在各系数中。这样就更有效地区分出信号和噪波,从而达到更有效地进行自适应降噪的目的。
4.5 离散余弦变换
离散余弦变换(Discrete cosine Transform)简称DCT。任何连续的实对称函数的傅里叶变换 中只含余弦项,因此余弦变换与傅里叶变换一样有明确 的物理量意义。DCT是先将整体图像分成N×N像素块,然后对N×N像素块逐一进行DCT变换。 由于 大多数图像的高频分量较小,相应于图像高频成分的系数经常为零,加上人眼对高频成分的失真不太敏感,所以可用更粗的量化,因此传送变换系数所用的数码率要大大小于传送图像 像素所用的数码率。到达接收端后再通过反离散余弦变换回到样值,虽然会有一定的失真,但人眼是可以接受的。
N代表像素数,一般N=8,8×8的二维数据块经DCT后变成8×8个变换系数,这些系数都 有 明确的物理意义:U代表水平像素号,V代表垂直像素号。如当U=0,V=0时,F(0,0)是原 64个 样值的平均,相当于直流分量,随着U、V值增加,相应系数分别代表逐步增加的水平空间频 率分量和垂直空间频率分量的大小。
4.6 量化(Q)
严格说DCT本身并不能进行码率压缩,因为64个样值仍然得到64个系数,如图4-2所示。这里 给出了一个8×8像块的具体例子,经DCT变换后,比特数增加了。在这个例子中样值是8比特 ,从0~225得到的即直流分量的最大值是原来256的64/8倍,即0~2047,交流分 量的范围是-1024~1023。只是在经过量化后,特别是按人眼的生理特征对低频分量和高频分 量设置不同的量化,会使大多数高频分量的系数变为零。一般说来,人眼对低频分量比较敏感,而对高频分量不太敏感。因此对低频分量采用较细的量化,而对高频分量采用较粗的量 化。
所谓量化,即根据不同的要求,设置不同的量化等级,从而降低数码率。
4.7 游程长度编码
读出数据和表示数据的方式也是减少码率的一个重要因素。读出的方式可以有多种选择 ,如 水平逐行读出、垂直逐列读出、之字型读出和交替读出等,其中之字型读出(Zig-Zag) 是最常用的一种。由于经DCT变换以后,系数大多数集中在左上角,即低频分量区,因此之 字型读出实际上是按二维频率的高低顺序读出系数的,这样一来就为游程长度编码(Runleng th Encoding)创造了条件。所谓游程长度编码是指一个码可同时表示码的值和前面几个零, 这样就可以把之字型读出的优点显示出来了。因为之字型读出在大多数情况下出现连零的机会比较多,尤其在最后,如果都是零,在读到最后一个数后只要给出“块结束”(EOB)码,就可以结束输出,因此节省了很多码率。
游程长度指的是由字构成的数据流中各个字符连续重复出现而形成字符串的长度。 基本的游程编码就是在数据流中直接用三个字符来给出上述三种信息,其数据结构如图4-3 所示。
SC表示有一个字符串在此位置,X代表构成串的字符,CC代表串的长度。
游程编码和哈夫曼编码等属于统计编码。
4.8 霍夫曼编码
霍夫曼编码是可变字长编码(VLC)的一种。 Huffman于1952年提出一种编码方法,该方法完全依据字符出现概率来构造异字头的平均长度最短的码字,有时称之为最佳编码,一般就叫作Huffman编码。下面引证一个定理,该定 理保证了按字符出现概率分配码长,可使平均码长最短。
定理:在变字长编码中,如果码字长度严格按照对应符号出现的概率大小逆序排列,则其平 均码字长度为最小。
现在通过一个实例来说明上述定理的实现过程。设将信源符号按出现的概率大小顺序排列为 :
|
U: |
( |
a1 |
a2 |
a3 |
a4 |
a5 |
a6 |
a7 |
) |
|
0.20 |
0.19 |
0.18 |
0.17 |
0.15 |
0.10 |
0.01 |
给概率最小的两个符号a6与a7分别指定为“1”与“0”,然后将它们的概率相加再与原来的 a1~a5组合并重新排序成新的原为:
|
U′: |
( |
a1 |
a2 |
a3 |
a4 |
a5 |
a6′ |
) |
|
0.20 |
0.19 |
0.18 |
0.17 |
0.15 |
0.11 |
对a5与a′6分别指定“1”与“0”后,再作概率相加并重新按概率排序得
U″:(0.26 0.20 0.19 0.18 0.17)…
直到最后得 U″″:(0.61 0.39)
分别给以“0”,“1”为止,如图4-4所示。}
霍夫曼编码的具体方法:先按出现的概率大小排队,把两个最小的概率相加,作为新的概率 和剩余的概率重新排队,再把最小的两个概率相加,再重新排队,直到最后变成1。每次相 加时都将“0”和“1”赋与相加的两个概率,读出时由该符号开始一直走到最后的“1”, 将路线上所遇到的“0”和“1”按最低位到最高位的顺序排好,就是该符号的霍夫曼编码。
例如a7从左至右,由U至U″″,其码字为0000;
a6按践线将所遇到的“0”和“1”按最低位到最高位的顺序排好,其码字为0001…
用霍夫曼编码所得的平均比特率为:Σ码长×出现概率
上例为: 0.2×2+0.19×2+0.18×3+0.17×3+0.15×3+0.1×4+0.01×4=2.72 bit
可以算出本例的信源熵为2.61bit,二者已经是很接近了。
4.9 运动估计的运动补偿编码
这是一种帧间编码的方法,其原理是利用帧间的空间相关性,减小空间冗余度。 帧间编码为什么可以减小冗余度,这是因为两帧之间有很大的相似性。如果将前后两帧相减 (移动物体作相应位移)得到的误差作编码所需比特要比帧内编码所需的比特少,帧间差集中在零附近,可以用短的码字传送。
实现帧间编码的方法是运动估计和运动补偿。用图4-5来说明这个过程。
当前帧在过去帧的窗口中寻找匹配部分,从中找到运动矢量;
根据运动矢量,将过去帧位移,求得对当前帧的估计;
将这个估计和当前帧相减,求得估计的误差值;
将运动矢量和估计的误差值送到接收端去。
接收端根据收到的运动矢量将过去帧作位移(也就是对当前帧的估计),再加上接收到的误差 值,就是当前帧了。
图4-7 运动估计的全局搜索块匹配实际上,在做运动估计和运动补偿时,是以16×16的块(称宏块)逐个进行的,如图4-6所示,这是将当前帧划分为N×N(16×16)的块。对每一块在过去帧中范围为 的范围内进行搜索,以求得最优匹配,从而得到运动矢量的估值(dx,dy)。衡量匹配好坏 的准则可以是均方误差最小准则。搜索方法可以是全局搜索法,即对搜索范围内的每一点都 计算均方误差,选最小值即对应最优匹配,如图4-7所示。
5 JPEG标准
JPEG是Joint Photographic Experts Group的缩写,主要用于计算机静止图像的压缩,在用于活动图像时,其算法仅限于帧内,便于编辑。
采用JPEG标准可以得到不同压缩比的图像,在使图像质量得到保证的情况下,可以从每个像 素24bit减到每个像素1bit甚至更小。
JPEG标准所根据的算法是基于DCT(离散余弦变换)和可变长编码。系统框图如图4-8所示, 从图中可见,JPEG的关键技术有变换编码、量化、差分编码、运动补偿、霍夫曼编码和游程编码等。
图4-8 JPEG系统框图 6 H.261标准 JPEG算法的原理是利用单帧内的空间相关性,减小空间冗余度,这种方式称为帧内编码。我 们知道电视图像(包括各种活动图像)各个连续帧之间也有很大的相关性,称为时间相关性。
为了进一步提高图像压缩比,要设法减小时间冗余度,这种编码方式称为帧间编码。H.261 是用于会议电视的国际标准,既采用了帧内编码,又采用了帧间编码,因此它的压缩比大致 是JPEG的三倍。 H.261标准用于音象业务的码率是p×64kbps(p=1,2…,30)。用于电视电话时p=1或2,用 于电视会议时p≥6。这种标准具有最小延迟实时对话的能力。
图4-9是H.261编码器的原理框图。从编码器中看到,它有一个和解码器一样的过程,解出的图像放在运动补偿 预测器(存储器)中形成过去帧,它的输出和当前帧一起加到“运动估计”,求得的运动矢 量一方面经VLC送到复用器中去,另一方面加到运动补偿预测器中,使之产生估计帧(对当前 帧),它和当前帧相减即求得差值,这个差值经DCT和Q、VLC也送到复用器中去。
图4-9 H.261编码器的原理框图 在进行帧间编码时,编码器和解码器必须使用相同的预测器,否则两者会脱轨。为了获得重 建图像,被量化以后的系数要用一个反量化器和反余弦变换(IDCT)来处理,为防止编码器和 解码器慢慢漂移分离,必须对误差的平均值加以严格规定,即使如此,仍然要周期地使用帧 内编码,使解码器处于一个已知状态。
运动补偿单元使帧间差最小,从而减少所需传输码率。搜索窗的大小在水平和垂直方向上都是±15个采样值。通常只对亮度信号作运动估计,但运动补偿不仅作用于亮度,也作用于色 度(亮度象素位移的一半)。
图4-10画出了解码器的框图。被压缩的数据送入缓冲器,然后作可变长度解码,解码器余下的 部分相似于编码器的后端,仅有的区别是不再需要运动估计。运动矢量和其它附带的信息是 直接从可变长解码器的输出得到的。
在编码器的输出端有缓冲器(Buffer),这是因为编码过程产生的比特率不是 恒定的,它取决于运动序列中各点的图像统计特征。在图像的“简单”部分允许节省一些比 特,而在“复杂”的部分要多花一些比特。对于每一个编码图像,比特的数目也允许变更。 但是在传输网络中的数据的比特率又必须是恒定的,所以在视频编码器的输出端必须有数据缓冲器来提供平滑的作用。相反的,在解码器要以非恒定的速率来利用接收到的信息,所以 也要包含一个解码器的缓冲器。 图4-10 H.261的解码器框图 在传输中,帧频的长期平均值是CIF的标准值,但是在短的时间间隔内帧频会有一定变化。
|
表4-2 CIF和QCIF格式 |
||||
|
格 式 |
CIF |
QCIF |
||
|
信号分量 |
行数/帧 |
象素数/行 |
行数/帧 |
象素数/行 |
|
亮度(Y) |
288 |
360(352) |
144 |
180(176) |
|
色度(Cb) |
144 |
180(176) |
72 |
90(88) |
|
色度(Cr) |
144 |
180(176) |
72 |
90(88) |
注:CIF和QCIF帧频是每秒30帧。
H.261的一幅图像是由块(Block)组成宏块(Macroblock),宏块组成图像组(GO B),图像组组 成图像,如图4-11所示。 两种格式的码率为:CIF:15~2Mbps QCIF:128kbps 7 MPEG- 1和MPEG-2标准 MPEG(Moving Picture Expert Group)意思是“运动图像专家组”。这个专家组的任务 是为了对数字存储媒质、电视广播、通信等方面的运动图像和伴音给出一种通用的编码 方法 。符合这种编码方法的运 MPEG用句法规定了一个层次性的结构,共分六层。这六层是图像序列(Video Sequence)-图像组(Group of Picture)-图像(Picture)-宏块条(Silce)- 宏块(Macroblock )-块(Block)。 一个图像包含亮度阵列和色度阵列。在MPEG- 1中亮度和色度的格式是4∶2∶0,而在MPEG-2 中,除这一格式外,还允许有4∶2∶2及4∶4∶4。
六个层次有其不同的功能,如表4-3所示。
|
表4-3 MPEG-1/-2规定的层次功能 |
|||
|
语法规定的层次 |
功 能 |
语法规定的层次 |
功 能 |
|
序列层(Sequence layer) |
随机存取段落 |
宏块条层(Slice layer) |
重新同步单元 |
|
图像组层(Group of picture layer) |
随机存取视频单元 |
宏块层(Macroblock layer) |
运动补偿单元 |
|
图像层(Picture layer) |
基本编码单元 |
块层(Block layer) |
DCT单元 |
所谓4∶2∶0是指在垂直方向每隔一行去除一行色度信号。
7.2 MPEG-1和MPEG-2中三种类型图像
MPEG在利用块匹配运动补偿来减小时间冗余度时,不仅用上一帧的图像预测当前图像, 而且也使用下一帧图像预测当前图像,即双向预测,这是和H.261标准有重要区别的地方。 因此 ,MPEG-1和2中有三种类型图像,即I、B、P三种,如图4-12所示。
I帧是帧内编码,P帧是正向预测,如图4-13所示,通过正向预测得到的图。B帧是双向预测图 ,如图4-14所示。由于B帧不能作其他图像的基准,所以对B帧编码校粗(步长较大),需要比特数比预测图P少。
7.3 MPEG- 1的视频压缩编码
MPEG-1中视频编码的关键压缩技术和H.261一样,仍是DCT、运动补偿和Huffman编码。编码 器和解码器的原理框图也和H.261没有区别。
MPEG-1的信源输入格式是SIF(Source Input Format)。CCIR601格式的信源要转换成SIF后进入MPEG- 1编码器,解码器输出也是SIF格式,显示时要经内插,扩充为CCIR601格式。PAL/NT SC都作如此处理。SIF格式如表4-4所示。
|
表4-4 SIF(525/625)格式 |
||
|
信号分量 |
行数/帧 |
象素数/行 |
|
亮度(Y) |
240/288 |
352 |
|
色度(Cb) |
120/144 |
176 |
|
色度(Cr) |
120/144 |
176 |
图4-15所示为MPEG-1视频编码器。图中和H.261不同的部分是有二组运动补偿和存储器,并有相应的转换开关。这是因为MPEG- 1有B图像要处理。开关有4种状态,‘0’是针对帧内 编码,“2”或“3”是用上一帧图像(经S2的虚线a/c)或用下一帧图像(经S2的实线 d/b) ,“4”是用了上一帧和下一帧两幅图像(经S2的实线b和实线c),这时候要相应产生2 个运 动矢量。
7.4 MPEG- 2视频压缩编码
研究制定MPEG标准是为了使应用于数字存储媒体、电视广播、通信等方面的运动图像和伴音 有一种通用的编码方法。使用这个标准意味着运动图像可以作为一种计算机数据来处理 ,并且能够存储在各种各样的存储器中,也可以在现有的或未来的网络中传送和接收,还可以在现在的或将来的广播信道中广播。
这个标准的应用很广泛,覆盖了从电视电话到高清晰度电视。
(1)划分为不同的“Profile”和“Level”(“类”和“级”)。由于想使这个标准适用于各种不同的应用,而各种应用在码率、分辨力、图像质量和服务方面要求又各不相同,所以希望这个标准要有通用性。在这个标准产生的过程中,考虑了各种应用的不同要求,开发了必要的算法,并且把它们集中成为一种单一的句法。正因为如此,这个标准使得各种不同应用的码 流之间可以灵活地相互改变。
既要使句法有通用性,又不能要求具体的解码器全面满足整个句法的需要,那样具体的解码器就太复杂了。为了解决通用性和特殊性的矛盾,设想将整个ISO/IEC的句法分成子集,这样分的子集就称为Profile,我们称之为“类”。这个“类”规定的子集还觉得太大,有必要再分得细一些。例如图像的尽寸有小的,有大的,大的可大到 ,实际上不会有一个解码器能够处理这么大的动态范围的图像,因此,在Profile中又规定了“level”,称为级。
ISO/IEC13818-2(即MPEG-2视频)规定了5个类和4个级如表4-5所示。
|
表4-5 MPEG- 2的Profile和Level |
|||||
|
类级 |
Simple Profile |
Main Profile |
SNR Scalable Profile |
Spstially Scalable Profile |
High Profile |
|
High Level |
|
√ |
|
|
√ |
|
High-1440 Level |
|
√ |
|
√ |
√ |
|
Main Level |
√ |
√ |
√ |
|
√ |
|
Low Level |
|
√ |
√ |
|
|
注:Main Profile(主类):图像质量合乎一定要求,允许有一定损伤,不具有可分级性;
Simple Profile (简化类):如Main Profile相同,只是不用B帧,这是为了节约RAM;
SNR Scalable Profile(信噪比可选类):比Main Profile改进之处是信噪比可分级;
Spatially Scalable Profile(空间尺寸可选类):空间分辨率方面也可分级;
HIgh Profile(高质量类):支持4∶2∶2并全面可分级(宏块的组成是:4个Y块+2个Cb块 +2个Cr块);
Low Level(低级):类似H.261中的CIF格式;
Wain Level(主级):相应于普通电视;
High 1440 Level(高1440级):大致相当于具有每行1440个采样的HDTV;
High Level(高级):大致相当于每行1920个采样的HDTV。
MPEG-2格式经常用级和类的缩写表示,如:MP@ML是指主类和主级,目前用于普通数字电视 、卫星、电缆、广播的DVB标准就是用这一格式。
(2)MPEG-2的编解码器和MPEG-1的异同。
①MPEG-1只处理逐行扫描的电视图像而MPEG-2既处理逐行扫描也处理隔行扫描,因此编码器中要有场/帧决策的功能;
②DCT有二种: 帧DCT或场DCT;
③运动估计有四种:场预测、帧预测、双场预测和16×8的运动补偿;
④压缩编码方式均采用运动检测补偿、DCT、量化、霍夫曼编码、游程编码和VLC等。
7.5 MPEG-2系统
MPEG-2系统的作用如图4-16所示。它有以下几个任务:
(1)对音频、视频、数据、控制等基本比特流起系统复用的作用。
(2)提供用于恢复时间基准的时间标志,缓冲器初始化和管理,音频和视频的解码时间,显示时间。
(3)给解码器提供一种信息(PSI),使之更容易和更迅速地找到所需节目。
(4)给误差恢复,有条件接入,随机接入,数字存储控制提供支持。
视频或音频编码器的输出被打成PES(Packetised Elementary Streanis),然后在PS复用器中被组合成PS(Program Stream)或在TS复用器中被组成成TS(Transport Strea m),前者用于相对无误差的环境,后者用于有噪声媒质。
FROM: http://blog.ednchina.com/XIE2099/138774/message.aspx
Posted by (1) Comment
QCIF全称Quarter common intermediate format。QCIF是常用的标准化图像格式。在H.323协议簇中,规定了视频采集设备的标准采集分辨率。QCIF = 176×144像素。
CIF是常用的标准化图像格式(Common Intermediate Format)。在H.323协议簇中,规定了视频采集设备的标准采集分辨率。CIF = 352×288像素
CIF格式具有如下特性:
(1) 电视图像的空间分辨率为家用录像系统(Video Home System,VHS)的分辨率,即352×288。
(2) 使用非隔行扫描(non-interlaced scan)。
(3) 使用NTSC帧速率,电视图像的最大帧速率为30 000/1001≈29.97幅/秒。
(4) 使用1/2的PAL水平分辨率,即288线。
(5) 对亮度和两个色差信号(Y、Cb和Cr)分量分别进行编码,它们的取值范围同ITU-R BT.601。即黑色=16,白色=235,色差的最大值等于240,最小值等于16。
下面为5种CIF 图像格式的参数说明。参数次序为“图象格式 亮度取样的象素个数(dx) 亮度取样的行数 (dy) 色度取样的象素个数(dx/2) 色度取样的行数(dy/2)”。
sub-QCIF 128×96 64 48
QCIF 176×144 88 72
CIF 352×288 176 144
4CIF 704×576 352 288(即我们经常说的D1)
16CIF 1408×1152 704 576
目前监控行业中主要使用QCIF(176×144)、CIF(352×288)、HALF D1(704×288)、D1
(704×576)等几种分辨率,CIF录像分辨率是主流分辨率,绝大部分产品都采用CIF分辨率。目前市场接受CIF分辨率,主要理由有四点:1、目前数码监控要求视频码流不能太高;2、视频传输带宽也有限制;3、使用HALF D1、D1分辨率可以提高清晰度,满足高质量的要求,但是以高码流为代价的。在现阶段,出现了众多D1的产品,但市场份额非常小;4、采用CIF分辨率,信噪比在32db以上,一般用户是可以接受的,但不是理想的视频图像质量。目前业内人士正在尝试用HALF D1来寻求CIF、D1之间的平衡。但随着单块硬盘的容量达到750GB甚至1000GB,而国内的大部分DVR已经可以做到连接8块1000GB的硬盘,故D1逐渐会变成时常的主流。
DCIF分辨率是什么?
经过研究发现一种更为有效的监控视频编码分辨率(DCIF),其像素为528×384。DCIF分辨率的是视频图像来历是将奇、偶两个HALF D1,经反隔行变换,组成一个D1(720*576),D1作边界处理,变成4CIF(704×576),4CIF经水平3/4缩小、垂直2/3缩小,转换成528×384.528×384的像素数正好是CIF像素数的两倍,为了与常说的2CIF(704*288)区分,我们称之为DOUBLE CIF,简称DCIF。显然,DCIF在水平和垂直两个方向上,比Half D1更加均衡。
为什么选用DCIF分辨率?
数字化监控行业对数字监控产品提出两项要求:首先要求数据量低,保证系统能够长时间录像和稳定实时的网络传输;其次要求回放图像清晰度高,满足对细节的要求。而DCIF分辨率在目前的软硬件平台上,能很好的满足以上两项要求。
Half D1分辨率已被部分产品采用,用来解决CIF清晰度不够高和D1存储量高、价格高昂的缺点。但由于他相对于CIF只是水平分辨率的提升,图像质量提高不是特别明显,但码流增加很大。
经过对大量视频信号进行测试,基于目前的视频压缩算法,DCIF分辨率比Half D1能更好解决CIF清晰度不够高和D1存储量高、价格高昂的缺点,用来解决CIF和4CIF,特别是在512Kbps码率之间,能获得稳定的高质量图像,满足用户对较高图像质量的要求,为视频编码提供更好的选择。
CIF清晰度不够高和D1存储量高、价格高昂的缺点分辨率,静态回放分辨率理论上最高可达360TVline的图像质量,超过模拟监控中标准VHS磁带录像机280TVline的图像水平,达到公安部安防行业视频标准二级和三级项目的清晰度要求,满足绝大部分视频监控的要求。
什么是D1?
做闭路电视监控系统这一行久了,大家都以为D1是硬盘录像机显示、录像、回放的分辨率,实际上不是的,D1是数字电视系统显示格式的标准,共分为以下5种规格:
D1:480i格式(525i):720×480(水平480线,隔行扫描),和NTSC模拟电视清晰度相同,行频为15.25kHz,相当于我们所说的4CIF(720×576)
D2:480P格式(525p):720×480(水平480线,逐行扫描),较D1隔行扫描要清晰不少,和逐行扫描DVD规格相同,行频为31.5kHz
D3:1080i格式(1125i):1920×1080(水平1080线,隔行扫描),高清放松采用最多的一种分辨率,分辨率为1920×1080i/60Hz,行频为33.75kHz
D4:720p格式(750p):1280×720(水平720线,逐行扫描),虽然分辨率较D3要低,但是因为逐行扫描,市面上更多人感觉相对于1080I(实际逐次540线)视觉效果更加清晰。不过个人感觉来说,在最大分辨率达到1920×1080的情况下,D3要比D4感觉更加清晰,尤其是文字表现力上,分辨率为1280×720p/60Hz,行频为45kHz
D5:1080p格式(1125p):1920×1080(水平1080线,逐行扫描),目前民用高清视频的最高标准,分辨率为1920×1080P/60Hz,行频为67.5KHZ。
其中D1 和D2标准是我们一般模拟电视的最高标准,并不能称的上高清晰,D3的1080i标准是高清晰电视的基本标准,它可以兼容720p格式,而D5的1080P只是专业上的标准,并不是民用级别的,上面所给出的60HZ只是理想状态下的场频,而它的行频为67.5KHZ,目前还没有如此高行频的电视问世,实际在专业领域里1080P的场频只有24HZ,25HZ和30HZ。
需要指出的一点是,D端子是日本独有的特殊接口,国内电视几乎没有带这种接口的,最多的是色差接口,而色差接口最多支持到D4,理论上肯定没有HDMI(纯数字信号,支持到1080P)的最高清晰度高,但在1920:1080以下分辨率的电视机上,一般也没有很大差别。
国内主流的硬盘录像机(DVR,Digital Video Recording)采用什么分辨率?怎样计算硬盘容量?
国内主流的硬盘录像机采用两种分辨率:CIF和4CIF(D1),分为两种型号。
硬盘录像机常见的路数有1路、2路、4路、8路、9路、12路和16路。最大可以连接8块2000GB的硬盘,总容量可高达1.6TV(可续目前市面上最大的硬盘只有1000GB),如果采用CIF分辨率,通常计算硬盘录像机的录像的硬盘容量为180MB~250MB/小时,通常情况下取值200MB/小时;如果是D1的分辨率每小时录像需要的硬盘容量为720MB~1000MB/小时,通常情况下为了减少硬盘的容量可以按照500MB/小时计算,帧率智能设置比25fps少一些,码流也要少一些!相信大家可以计算出一台装满8块500GB的16路硬盘录像机可以录像多长时间了吧?
FROM: http://www.jsa-cctv.com/suport/2008/0511/article_48_1.html
Posted by (7) Comment
Posted by (0) Comment
uIP 协议栈是一种免费的可实现的极小的TCP/IP协议栈,可以使用于由8位或16位微处理器构建的嵌入式系统。本文分析了uIP协议栈的结构和应用接口,并讨论了如何将其应用到51系列单片机上。
关键字:TCP/IP 单片机 嵌入式系统
一 引言
近几年来,人们对连接各种装置到一个现有的IP网络例如因特网上产生了浓厚的兴趣。为了可以通过因特网通讯,一个可实现的TCP/IP协议栈是必须的。对于由32位嵌入式处理器构建的中、高端网络接入嵌入式系统中,通常会运行一个集成有TCP/IP协议栈的操作系统。但是对于由8位和16位低端处理器构建的系统,由于其所具有的处理能力和资源十分有限,通常不运行操作系统,这就要求系统开发者根据应用的要求以及所选用的处理器的实际情况构建自己的TCP/IP协议栈。而TCP/IP协议的透明性掩盖了其实现的复杂性,从无到有构建一个协议栈是一件艰巨的任务,并且缺少有效的调试工具。uIPTCP/IP协议栈是使用于低端8位或16位微处理器构建的嵌入式系统的一个可实现的极小的TCP/IP协议栈。它可以自由分发和使用于商业和非商业目的。uIP使用C语言编写,使其方便于移植。并且uIP协议栈的代码大小和RAM的需求比其它一般的TCP/IP栈要小,这就使得它可以方便的应用到各种低端系统上。本文将简要描述uIP的实现方法,分析uIP协议栈的应用接口,并讨论如何将其应用到51系列单片机上。
二 uIP协议栈的实现方法简述
uIP实现了TCP/IP协议集的四个基本协议:ARP地址解析协议,IP网际互联协议,ICMP网络控制报文协议和TCP传输控制协议。为了在8位16位处理器上应用,uIP协议栈在各层协议实现时采用有针对性的方法,保持代码大小和存储器使用量最小。
1 实现ARP地址解析协议时为了节省存储器,ARP应答包直接覆盖ARP请求包。
2 实现IP网络协议时对原协议进行了极大的简化,它没有实现分片和重组。
3 实现ICMP网络控制报文协议时,只实现echo(回响)服务。uIP在生成回响报文时并不重新分配存储器空间,而是直接修改echo请求报文来生成回响报文。将ICMP类型字段从“echo”类型改变成“echoreply”类型,重新计算校验和修改校验和字段。
4 uIP里的TCP没有实现发送和接收数据的滑动窗口。每个TCP连接的状态由uip_conn结构保存,uip_conn结构包括当地和远端的TCP端口编号,远程主机的IP地址,重发时间值,上一段重发的编号,和连接的段的最大尺寸等信息。一个uip_conn结构数组用于保存所有的连接,数组的大小为支持的同时连接的最大数量。为了减少储存器的使用量,在处理重发时uIP并不缓存发送的数据包,而是由应用程序在需要重发时重新生成发送的数据。
三 uIP协议栈的接口
uIP协议栈为了具有最大的通用性,在实现时将底层硬件驱动和顶层应用层之外的所有协议集“打包“在一个“库“里。协议栈通过接口与底层硬件和顶层应用“通信“。通过这种方式,uIP具有极高的通用性和独立性,移植到不同系统和实现不同的应用都很方便,很好的体现了TCP/IP协议平台无关性的特点。uIP协议栈与系统底层和应用程序之间的接口关系如图(一)所示:

1uIP协议栈与系统底层的接口
uIP与系统底层的接口包括与设备驱动的接口和与系统定时器的接口两类。
1.1 uIP与设备驱动接口
uIP通过函数uip_input()和全局变量uip_buf、uip_len来实现与设备驱动的接口。uip_buf用于存放接收到的和要发送的数据包,为了减少存储器的使用,接收数据包和发送数据包使用相同的缓冲区。uip_len表明接收发送缓冲区里的数据长度,通过判断uip_len的值是否为0来判断是否接收到新的数据,是否有数据要发送。当设备驱动接收到一个IP包并放到输入包缓存里(uip_buf)后,应该调用uip_input()函数。uip_input()函数是uIP协议栈的底层入口,由它处理收到的IP包。当uip_input()返回,若有数据要发送,则发送数据包放在包缓冲区里。包的大小由全局变量uip_len指明。如果uip_len是0,没有包要发送;如果uip_len大于0则调用网络设备驱动发送数据包。
1.2 uIP与系统计时接口
TCP/IP协议要处理许多定时事件,例如包重发、ARP表项更新。系统计时用于为所有uIP内部时钟事件计时。当周期计时激发,每一个TCP连接应该调用uIP函数uip_periodic()。TCP连接编号作为参数传递给uip_periodic()函数。uip_periodic()函数检查参数指定的连接的状态,如果需要重发则将重发数据放到包缓冲区(uip_buf)中并修改uip_len的值。当uip_periodic()函数返回后,应该检查uip_len的值,若不为0则将uip_buf缓冲区中的数据包发送到到网络上。
ARP协议对于构建在以太网上的TCP/IP协议是必须的,但对于构建与其他网络接口(例如:串行链路)上的TCP/IP则不是必需的。为了结构化的目的,uIP将ARP协议作为一个可添加的模块单独实现。因此,ARP表项的定时更新要单独处理。系统定时器对ARP表的更新进行定时,定时时间到则调用uip_arp_timer()函数对过期表项进行清除。
2 uIP协议栈与应用程序的接口
应用程序作为单独的模块由用户实现,uIP协议栈提供一系列接口函数供用户程序调用。用户需将应用层入口程序作为接口提供给uIP协议栈,定义为宏UIP_APPCALL()。uIP在接收到底层传来的数据包后,若需要送上层应用程序处理,它就调用UIP_APPCALL()。uIP提供给应用程序的接口函数按功能描述如下:
2.1 接收数据接口:应用程序利用uip_newdata()函数检测是否有新数据到达。全局变量uip_appdata指针指向实际数据。数据的大小通过uip_datalen()函数获得。
2.2 发送数据接口:应用程序通过使用uIP函数uip_send()发送数据。uip_send()函数采用两个参数;一个指针指向发送数据起始地址,另一个指明数据的长度。
2.3 重发数据接口:应用程序通过测试函数uip_rexmit()来判断是否需要重发数据,如果需要重发则调用uip_send()函数重发数据包。
2.4 关闭连接接口:应用程序通过调用uip_close()函数关闭当前连接。
2.5 报告错误接口:uIP提供错误报告函数检测连接中出现的错误。应用程序可以使用两个测试函数uip_aborted()和uip_timedout()去测试那些错误情况。
2.6 轮询接口:当连接空闲时,uIP会周期性地轮询应用程序,判断是否有数据要发送。应用程序使用测试函数uip_poll()去检查它是否被轮询过。
2.7 监听端口接口:uIP维持一个监听知名TCP端口的列表。通过uip_listen()函数,一个新的监听端口打开并添加到监听列表中。当在一个监听端口上接收到一个新的连接请求时,uIP产生一个新的连接和调用该端口对应的应用程序。
2.8 打开连接接口:在uIP里面通过使用uip_connect()函数打开一个新连接。这个函数打开一个新连接到指定的IP地址和端口,返回一个新连接的指针到uip_conn结构。如果没有空余的连接槽,函数返回空值。
2.9 数据流控制接口:uIP提供函数uip_stop()和uip_restart()用于TCP连接的数据流控制。应用程序可以通过函数uip_stop()停止远程主机发送数据。当应用程序准备好接收更多数据,调用函数uip_restart()通知远程终端再次发送数据。函数uip_stopped()可以用于检查当前连接是否停止。
四 uIP在51系列单片机上的应用
51系列单片机具有悠久的历史和广泛的应用,许多公司推出了具有更高的处理速度的51内核的8位单片机,被应用在各个领域内。因此使用uIP这种免费的TCP/IP协议栈解决由51内核的单片机构建的低端嵌入式设备的网络接入问题具有一定的代表性。下面将讨论利用uIP协议栈在51单片机上实现简单的WEBSERVER,远端用户可以通过浏览器访问存储在单片机系统上的WEB页面。

硬件平台结构如图(二)所示:其中单片机选用PHILIPS公司的P89C51RD2,64K字节的串行EEPROM可以用于存储WEB页面。采用ISA接口的以太网接口芯片RTL8019AS连接到以太网上。通过MAX232实现与PC机的串行连接,可以显示调试信息。
uIP协议栈是以函数库的形式提供的,本身不提供底层网络驱动和上层应用程序。因此为了完成指定的功能,开发者必须添加以下几个模块:底层RTL8019AS网卡芯片的驱动、应用层基于HTTP协议的WEBSERVER的实现、系统定时器。
RTL8019AS的驱动主要包括三部分:init_8019as()函数完成网卡芯片的上电初始化,包括设定网卡物理地址,设定收发缓冲区位置和大小等;eth_send()函数完成数据的发送;eth_rcve()函数完成以太网数据的接收。底层网络设备驱动程序与uIP协议栈通过两个全局变量进行接口:变量uip_buf为收发缓冲区的首地址;uip_len为收发的数据长度。eth_send()函数将uip_buf里的uip_len长度的数据发送到以太网上。eth_rcve()函数将接收到的数据存储到uip_buf指定的缓冲区中,同时修改uip_len的值。
uIP提供的源代码中包括一个基于HTTP协议的WEBSERVER示例,该WEBSERVER通过简单的文件系统在数据存储器中存储静态页面,同时具有CGI功能。用户可以参照该示例以及uIP提供给应用程序的接口函数说明实现自己的应用层功能。用户的应用程序中必须将UIP_APPCALL宏定义为该层的服务程序。例如:在示例程序中WEBSERVER的处理程序为httpd()函数,则要进行如下的宏定义#defineUIP_APPCALLhttpd。
51系列单片机上都有2到3个定时计数器,可以选择其中的一个来为TCP/IP协议中与时间有关的事件定时。需要由用户处理的定时事件包括:为uip_periodic()函数的执行提供基准,还要为ARP表项的更新定时。uip_periodic()函数每0.5秒执行一次,ARP表项每10秒更新一次。
uIP的设置单独包含在一个叫uipopt.h的头文件里,都是以宏的形式定义方便于修改。用户应根据自己的应用在uipopt.h文件里设置本地的物理地址、IP地址、网关地址、收发缓冲区的大小、支持的最大连接数、ARP表大小等等选项。
添加了必须的模块,对uIP进行了正确地配置后,需要编写主程序函数。针对基于以太网的WEBSERVER应用,主程序在完成初始化后将不停的进行查询,如果有新数据包到达则送uip_input()函数处理;如果没有新数据包到达则处理定时事件。框架代码如下所示:
void main(void) //主程序开始
{ …… //省略部分代码
timer0_init(); //定时器初始化函数由开发者完成
serial_init(); //串口初始化函数由开发者完成
init_8019(); //网卡芯片初始化函数由开发者完成
uip_init(); //uIP协议栈初始化函数由uIP协议栈提供
httpd_init(); //HTTP应用程序初始化函数由WEB SERVER示例程序提供
uip_arp_init();//ARP协议初始化函数由ARP模块提供
while(1)
{ uip_len = eth_rcve(); //查询网卡是否有数据到来
if(uip_len == 0) //如果没有数据到来则处理定时事件
{ if(0.5秒定时时间到)
{ for(i = 0; i < UIP_CONNS; i++) // UIP_CONNS为TCP连接数
{ uip_periodic(i); //处理每一个TCP连接
if(uip_len > 0) //说明本连接有数据要发送或重发
{ uip_arp_out(); //由ARP处理部分添加以太网帧头
eth_send(); //由网卡驱动程序发送
}
}//对应于:for()
}// 对应于:if(0.5秒定时时间到)
if(ARP表项更新时间到)
uip_arp_timer(); //进行ARP表项更新
}else if(uip_len > 0) //说明接收到新的数据包
{ if(BUF->type == htons(UIP_ETHTYPE_IP))//如果收到IP数据包
{ uip_arp_ipin(); //送ARP模块进行表项更新
uip_len -= sizeof(struct uip_eth_hdr); //去除以太网帧头
uip_input(); //送uip_input()进行处理
if(uip_len > 0) //若uip_input()返回后uip_len不为零说明有数据要回送
{ uip_arp_out(); //由ARP部分添加以太网帧头
eth_send(); //送交网卡驱动发送
}//对应于:if()收到IP数据包
}else if(BUF->type == htons(UIP_ETHTYPE_ARP))//如果收到ARP包
{ uip_arp_arpin(); //由uip_arp_arpin()处理,如果为应答包则进行表项
//更新
//如果为请求包,则构造应答数据包
if(uip_len > 0) //说明收到的是ARP请求包,需要回送ARP应答包
eth_send(); //送网卡驱动发送
}//对应于:else if()收到ARP数据包
}//对应于:else if() 说明接收到新的数据包
}}
以上实例在keilC51编译器下设置大模式,优化等级6(速度优先)进行编译,对uIP代码部分可以不做任何修改,对HTTP示例代码仅需针对类型表达进行极少量的修改即可编译通过。在硬件平台上运行良好。
五 总结
uIP协议栈采用有效的方法和结构化的代码,使其存储器占用量很小并且可以很方便的应用到不同的工程项目中。同时它又是免费的可以自由使用于商业和非商业目的。uIP为低端嵌入式设备的网络接入提供了很好的解决方案,具有很高的应用价值。
参考文献
[1]DOUGLASE.COMER著,用TCP/IP进行网际互连(卷一、卷二)电子工业出版社,2000
[2]JEREMYBENTHAM著,嵌入式系统Web服务器——TCP/IPLean机械工业出版社,2003
[3]uIP协议栈网络站点http://dunkels.com/adam/uip/
[4]REALTEK公司.RTL8019ASDatasheet,2000
邓治国 张维新 供稿 来源:网络