嵌入式Linux中基于framebuffer设备的jpeg格式在本地LCD屏显示
Framebuffer 是用一个视频输出设备从包含完整的帧数据的一个内存缓冲区中来驱动一个视频显示设备,本文我们来看看嵌入式Linux基于framebuffer的jpeg格式在本地LCD屏显示.
在基于Linux的视频监控采集系统中,摄像头采集到的一帧视频图像数据一般都是经过硬件自动压缩成jpeg格式的,然后再保存到摄像头设备的缓冲区.如果要把采集到的jpeg格式显示在本地LCD屏上,由于我们的Linux系统没有移植任何GUI系统,就要考虑以下方面:
1. 将jpeg格式解压缩为位图格式,也就是jpeg解码.
2. 将解码出来的位图格式输出到本地的LCD屏上. 在Linux系统下是通过写入帧缓冲(framebuffer)来实现的.
3. framebuffer相当于为LCD设备提供一个统一的接口,对framebuffer的操控会反映到LCD显示设备上去. 如果配置Linux内核时没有找到支持本地lcd屏这种型号的驱动,那我们要自己写lcd屏驱动,然后选择静态加入内核或以模块的形式加入内核动态加载. 针对以上三点,我们逐一解决:
1.jpeg解码
先了解一下jpeg标准的编码过程:原始的一帧未压缩过的图像可以看成是RGB(红绿蓝)色彩空间上的一组向量集合,但在RGB空间是不利于数据压缩的,因此为了压缩先要把图像映射到利于压缩的YUV空间上(原因是因为人类的眼睛对于亮度差异的敏感度高于色彩变化,而YUV空间的一个基向量Y就是亮度), 这一步叫色彩空间转换.
下一步可以在YUV空间上减少U(色调)和V(饱和度)的成分,也就是在亮度信息不减少的情况下移除部分色彩信息,谁叫人的眼睛对亮度的敏感优于对色彩的敏感呢.这一步叫缩减取样.下一步是将图像从色彩空间映射到频率空间,可以采用的变换方法有:离散余弦变换,傅氏变换,正弦变换等. 其中应用最广的是离散余弦变换(DCT).这一步是无损的,目的是为了在下一步称之为量化的过程中可以经过四舍五入删除高频量得到压缩后的矩阵.量化之后就是对这个矩阵的编码问题了.针对这个矩阵的分布特点,采用"Z"字形的顺序扫描编排,然后进行RLE行程编码,把大量连续重复的数据压缩.最后再用范式Huffman编码.要了解详细的过程,可以查看JPEG标准. 而解码就是以上编码的逆过程了.除非想要自己实现jpeg的编码和解码函数,我们可以不必细究这些过程,而是直接使用别人已经实现的jpeg编码解码库.在Linux平台下,有libjpeg库,它是完全用C语言编写的, 依照它的许可协议,可自由使用,不是GPL协议,它可以用于商业目的. libjpeg的6b版本有个问题,就是解码接口,它只接受文件源.打开源的函数jpeg_stdio_src(j_decompress_ptr cinfo, FILE *infile)要求解码源infile是文件.而我们希望解码的是直接来自映射内存中的数据.要解码内存流的话就要修改libjpeg的源码了,可以参考这里:http://my.unix-center.net/~Simon_fu/?p=565 目前libjpeg的最新版8c已经解决了这个接口不好的问题了,它增加了对内存流解码的支持.通过调用函数
jpeg_mem_src(&cinfo, fdmem, st.st_size);
就可以将保存在内存的jpeg格式数据作为源输入了.因此我们就用libjpeg 8c这个版本来解码,用到的函数主要有:
初始化jpeg解压对象:
- /*initjpegdecompressobjecterrorhandler*/
- cinfo.err=jpeg_std_error(&jerr);
- jpeg_create_decompress(&cinfo);
绑定jpeg解压对象到输入流:
- /*bindjpegdecompressobjecttoinfile*/
- READ_FILE//从jpeg文件读入
- jpeg_stdio_src(&cinfo,infile);
- fREAD_MEM//从内存读入jpeg格式
- jpeg_mem_src(&cinfo,fdmem,st.st_size);
- if
读取jpeg头部信息:
- /*readjpegheader*/
- jpeg_read_header(&cinfo,TRUE);
热门评论