linux学习:linux视频输出+FRAME BUFFER+jpeg库+lcd上显示

目录

概念

使用

struct fb_fix_screeninfo{ }

struct fb_bitfield { }

struct fb_var_screeninfo{ }

例子1

例子2

例子3

jpeg库

步骤


概念

framebuffer 是一种很底层的机制,在 Linux 系统中,为了能够屏蔽 各种不同的显示设备的具体细节,Linux 内核提供的一个覆盖于显示芯片之上的虚拟层,将 显卡或者显存设备抽象掉,提供给一个统一干净又抽象的编程接口,使得内核可以很方便地 将显卡硬件抽象成一块可直接操作的内存,而且还提供了封装好的各种操作和设置,大大提 高内核开发的效率。因此 framebuffer 的存在是为了方便显卡驱动的编写,而有时我们会 将这个术语用在诸多涉及 Linux 视频输出的场合

在用户层层面,我们更加不用关心具体的显存位置、显卡型号、换页机制等等细节,而 是直接基于 frame-buffer 来映射显存,frame-buffer 就是所谓的帧缓冲机制

LCD 显示器一般对应的设备节点文件是/dev/fb0,当然如果系统有多个显示设备的话,还可能有/dev/fb1、/deb/fb2 等,这些文件是读写显示设备的入口

们可以 将 frame-buffer 所抽象的内核物理显存(如果机器没有显卡,那么就是系统分配的一段充 当显存的物理内存)映射到用户空间的虚拟内存上,这样一来,我们就可以在应用程序直接 写屏了

使用

要使用 frame-buffer,需要先理解以下的结构体,他们在/usr/inlucde/linux/fb.h 中被定义

struct fb_fix_screeninfo{ }

这个结构体保存显示设备不能被修改的信息,比如显存(或起到显存作用的内存)的起 始物理地址、扫描线尺寸、显卡加速器类别等

150 struct fb_fix_screeninfo {
151     char id[16];
152     unsigned long smem_start; // 显存起始地址(实际物理地址)
153
154     __u32 smem_len; /* 显存大小 */
155     __u32 type; /* 像素构成 */
156     __u32 type_aux; /* 交叉扫描方案 */
157     __u32 visual; /* 色彩构成 */
158     __u16 xpanstep; /* x 轴平移步长(若支持)*/
159     __u16 ypanstep; /* y 轴平移步长(若支持)*/
160     __u16 ywrapstep; /* y 轴循环步长(若支持)*/
161     __u32 line_length; /* 扫描线大小(字节)*/
162     unsigned long mmio_start; /* 缺省映射内存地址 */
163     /* (物理地址) */
164     __u32 mmio_len; /* 缺省映射内存大小 */
165     __u32 accel; /* 当前显示加速器芯片 */
166     __u16 reserved[3]; /* 保留 */
167 }

由驱动程序根据硬件配置决定的,应用程序无法修改,应用程序应该根据该 结构体提供的具体信息来构建和操作 frame-buffer 映射内存,比如扫描线的大小,即一行 的字节数。这个大小决定了映射内存的宽度

struct fb_bitfield { }

180 struct fb_bitfield {
181     __u32 offset; /* 色彩位域偏移量 */
182     __u32 length; /* 色彩位域长度 */
183     __u32 msb_right;
184 };

struct fb_var_screeninfo{ }

体保存显示设备可以被调整的信息,比如可见显示区 X/Y 轴分辨率、虚拟显 示区 X/Y 轴分辨率、色彩深度、色彩构成等等

232
233 struct fb_var_screeninfo {
234 __u32 xres; /* 可见区的宽度分辨率 */
235 __u32 yres; /* 可见区的高度分辨率 */
236 __u32 xres_virtual; /* 虚拟区的宽度分辨率 */
237 __u32 yres_virtual; /* 虚拟区的高度分辨率 */
238 __u32 xoffset; /* 虚拟区到可见区的宽度偏移量 */
239 __u32 yoffset; /* 虚拟区到可见区的高度偏移量 */
240
241 __u32 bits_per_pixel; /* 色彩深度 */
242 __u32 grayscale; /* 灰阶(若为非 0) */
243
244 struct fb_bitfield red; /* 红色色彩位域构成 */
245 struct fb_bitfield green; /* 绿色色彩位域构成 */
246 struct fb_bitfield blue; /* 蓝色色彩位域构成 */
247 struct fb_bitfield transp; /* 透明属性 */
248
249 __u32 nonstd; /* 非标准像素格式(若为非 0) */
250
251 __u32 activate; /* 设置参数合适生效 */
252
253 __u32 height; /* 图片高度(单位毫米) */
254 __u32 width; /* 图片宽度(单位毫米) */
255
256 __u32 accel_flags; /* 显示卡选项 */
257
.....

各种分辨率和 X 轴和 Y 轴偏移量,他们的关系决定了 LCD 显示器 上显示的效果

例子1

以群创 AT070TN92-7 英寸液晶显示屏为例,写一个测试代码,将 LCD 的具体细节显 示出来,并且将一张图片显示在可见区,然后调整 yoffset 改变显示效果

1 #include <stdio.h>
2 #include <signal.h>
3 #include <stdlib.h>
4 #include <unistd.h>
5 #include <string.h>
6 #include <Linux/fb.h>
7
8 #include <fcntl.h>
9 #include <sys/types.h>
10 #include <sys/mman.h>
11 #include <sys/ioctl.h>
12 //显示有关帧缓冲设备的信息
13 void show_fix_screeninfo(struct fb_fix_screeninfo *p) //固定属性
14 {
15     printf("=== FIX SCREEN INFO === \n");
16
17     printf("\tid: %s\n", p->id);
18     printf("\tsmem_start: %#x\n", p->smem_start);
19     printf("\tsmem_len: %u bytes\n", p->smem_len);
20
21     printf("\ttype:");
22     switch(p->type)
23     {
24     case FB_TYPE_PACKED_PIXELS:
25         printf("PACKED_PIXELS\n");break;
26     case FB_TYPE_PLANES:
27         printf("PLANES\n");break;
28     case FB_TYPE_INTERLEAVED_PLANES:
29         printf("INTERLEAVED_PLANES\n");break;
30     case FB_TYPE_TEXT:
31         printf("TEXT\n");break;
32     case FB_TYPE_VGA_PLANES:
33         printf("VGA_PLANES\n");break;
34     }
35
36     printf("\tvisual:");
37     switch(p->visual)
38     {
39     case FB_VISUAL_MONO01:
40         printf("MONO01\n");break;
41     case FB_VISUAL_MONO10:
42         printf("MONO10\n");break;
43     case FB_VISUAL_TRUECOLOR:
44         printf("TRUECOLOR\n");break;
45     case FB_VISUAL_PSEUDOCOLOR:
46         printf("PSEUDOCOLOR\n");break;
47     case FB_VISUAL_DIRECTCOLOR:
48         printf("DIRECTCOLOR\n");break;
49     case FB_VISUAL_STATIC_PSEUDOCOLOR:
50         printf("STATIC_PSEUDOCOLOR\n");break;
51     }
52
53     printf("\txpanstep: %u\n", p->xpanstep);
54     printf("\typanstep: %u\n", p->ypanstep);
55     printf("\tywrapstep: %u\n", p->ywrapstep);
56     printf("\tline_len: %u bytes\n", p->line_length);
57
58     printf("\tmmio_start: %#x\n", p->mmio_start);
59     printf("\tmmio_len: %u bytes\n", p->mmio_len);
60
61     printf("\taccel: ");
62     switch(p->accel)
63     {
64     case FB_ACCEL_NONE: printf("none\n"); break;
65     default: printf("unkown\n");
66     }
67
68     printf("\n");
69 }
70 //显示帧缓冲设备的可变属性信息 打印了诸如水平同步长度、垂直同步长度、视频模式、可见屏幕大小、虚拟屏幕大小、每像素位数、激活状态、偏移量以及颜色位字段等属性
71 void show_var_screeninfo(struct fb_var_screeninfo *p) // 可变属性
72 {
73     printf("=== VAR SCREEN INFO === \n");
74
75     printf("\thsync_len: %u\n", p->hsync_len);
76     printf("\tvsync_len: %u\n", p->vsync_len);
77     printf("\tvmode: %u\n", p->vmode);
78
79     printf("\tvisible screen size: %ux%u\n", 
80         p->xres, p->yres);
81     printf("\tvirtual screen size: %ux%u\n\n", 
82         p->xres_virtual, 83 p->yres_virtual);
84
85     printf("\tbits per pixel: %u\n", p->bits_per_pixel);
86     printf("\tactivate: %u\n\n", p->activate);
87
88     printf("\txoffset: %d\n", p->xoffset);
89     printf("\tyoffset: %d\n", p->yoffset);
90
91     printf("\tcolor bit-fields:\n");
92     printf("\tR: [%u:%u]\n", p->red.offset, 
93         p->red.offset+p->red.length-1);
94     printf("\tG: [%u:%u]\n", p->green.offset, 
95         p->green.offset+p->green.length-1);
96     printf("\tB: [%u:%u]\n\n", p->blue.offset, 
97         p->blue.offset+p->blue.length-1);
98
99     printf("\n");
100 }
101
102 int main(void)
103 {
104     int lcd = open("/dev/fb0", O_RDWR|O_EXCL);//打开帧缓冲设备 /dev/fb0
105     if(lcd == -1)
106     {
107         perror("open()");
108         exit(1);
109     }
110
111     struct fb_fix_screeninfo finfo; // 显卡设备的固定属性结构体
112     struct fb_var_screeninfo vinfo; // 显卡设备的可变属性结构体
113
114     ioctl(lcd, FBIOGET_FSCREENINFO, &finfo); // 获取帧缓冲设备的固定属性
115     ioctl(lcd, FBIOGET_VSCREENINFO, &vinfo); // 获取帧缓冲设备的可变属性
116
117     show_fix_screeninfo(&finfo); // 打印相应的属性
118     show_var_screeninfo(&vinfo); // 打印相应的属性
119
120     // 将显示设备的具体信息保存起来,方便使用
121     unsigned long WIDTH = vinfo.xres;//屏幕的宽度
122     unsigned long HEIGHT = vinfo.yres;//高度
123     unsigned long VWIDTH = vinfo.xres_virtual;//虚拟宽度
124     unsigned long VHEIGHT = vinfo.yres_virtual;//虚拟高度
125     unsigned long BPP = vinfo.bits_per_pixel;//每像素位数
126
127     char *p = mmap(NULL, VWIDTH * VHEIGHT * BPP/8, 
128         PROT_READ|PROT_WRITE, 
129         MAP_SHARED, lcd, 0); // 申请一块虚拟区映射内存,并将图片数据加载到映射区
130
131     int image = open("images/girl.bin", O_RDWR);//打开一个二进制图像文件
132     int image_size = lseek(image, 0L, SEEK_END);//将文件指针移动到文件末尾,获取文件的大小
133     lseek(image, 0L, SEEK_SET);//将文件指针重新移动到文件的开头
134     read(image, p, image_size); // 获取图片数据并将之刷到映射内存
135
136
137     vinfo.xoffset = 0;
138     vinfo.yoffset = 0;
139     if(ioctl(lcd, FB_ACTIVATE_NOW, &vinfo)) // 偏移量均置位为 0,激活显示设备
140     {
141         perror("ioctl()");
142     }
143     ioctl(lcd, FBIOPAN_DISPLAY, &vinfo); // 配置属性并扫描显示,配置属性并扫描显示,将图片显示在屏幕上
144
145     sleep(1);
146     // Y 轴偏移量调整为 100 像素,并重新配置属性并扫描显示
147     vinfo.xoffset = 0;
148     vinfo.yoffset = 100; // 1 秒钟之后将 Y 轴偏移量调整为 100 像素
149     if(ioctl(lcd, FB_ACTIVATE_NOW, &vinfo))
150     {
151         perror("ioctl()");
152     }
153     show_var_screeninfo(&vinfo);
154     ioctl(lcd, FBIOPAN_DISPLAY, &vinfo); // 重新配置属性并扫描显示
155
156     return 0;
157 }

例子2

展示了 LCD 每隔 1 秒显示一种单色,用来检测 LCD 屏幕有没有坏点:

1 #include <stdio.h>
2 #include <signal.h>
3 #include <stdlib.h>
4 #include <unistd.h>
5 #include <string.h>
6 #include <Linux/fb.h>
7
8 #include <fcntl.h>
9 #include <sys/types.h>
10 #include <sys/mman.h>
11 #include <sys/ioctl.h>
12
13 enum color{red, green, blue};
14
15 // 根据 fb_var_screeninfo 的色彩构成生成一个颜色像素数据
16 unsigned long *create_pixel(struct fb_var_screeninfo *pinfo, 
17         enum color c)
18 {
19     unsigned long *pixel = calloc(1, pinfo->bits_per_pixel/8);//存储像素数据分配了内存
20     unsigned long *mask = calloc(1, pinfo->bits_per_pixel/8);//掩码分配了内存
21     *mask |= 0x1;//将掩码的最低位设置为 1     掩码用于确定要设置的像素位
22
23     int i;
24     switch(c)
25     {
26         case red://确定红色分量在像素数据中的偏移量和长度,并相应地生成掩码
27             for(i=0; i<pinfo->red.length-1; i++)
28             {
29                 *mask <<= 1;
30                 *mask |= 0x1;
31             }
32             *pixel |= *mask << pinfo->red.offset;
33         break;
34         case green://确定绿色分量在像素数据中的偏移量和长度,并相应地生成掩码
35             for(i=0; i<pinfo->green.length-1; i++)
36             {
37                 *mask <<= 1;
38                 *mask |= 0x1;
39             }
40             *pixel |= *mask << pinfo->green.offset;
41         break;
42         case blue://确定蓝色分量在像素数据中的偏移量和长度,并相应地生成掩码
43             for(i=0; i<pinfo->blue.length-1; i++)
44             {
45                 *mask <<= 1;
46                 *mask |= 0x1;
47             }
48             *pixel |= *mask << pinfo->blue.offset;
49     }
50
51     return pixel;
52 }
53
54 int main(void)
55 {
56     int lcd = open("/dev/fb0", O_RDWR);//打开帧缓冲设备 /dev/fb0
57     if(lcd == -1)
58     {
59         perror("open(\"/dev/fb0\")");
60         exit(1);
61     }
62
63     // 获取显示设备相关信息
64     struct fb_fix_screeninfo finfo;//固定信息
65     struct fb_var_screeninfo vinfo;//可变信息
66     ioctl(lcd, FBIOGET_FSCREENINFO, &finfo);
67     ioctl(lcd, FBIOGET_VSCREENINFO, &vinfo);
68
69     // 初始化可见区偏移量
70     vinfo.xoffset = 0;
71     vinfo.yoffset = 0;
72     ioctl(lcd, FBIOPAN_DISPLAY, &vinfo);
73     //计算每个像素所占的位数
74     unsigned long bpp = vinfo.bits_per_pixel;
75
76     // 创建三原色像素点  创建红色、绿色和蓝色的像素点数据
77     unsigned long *pixel[3] = {0};
78     pixel[0] = create_pixel(&vinfo, red);
79     pixel[1] = create_pixel(&vinfo, green);
80     pixel[2] = create_pixel(&vinfo, blue);
81
82     // 申请一块对应 LCD 设备的映射内存 
83     char *FB = mmap(NULL, vinfo.xres * vinfo.yres * bpp/8, 
84             PROT_READ | PROT_WRITE, MAP_SHARED, 85 lcd, 0);
86     int k;
87     for(k=0; ;k++)
88     {
89         int i;//每个像素并将相应颜色的像素数据复制到映射内存中
90         for(i=0; i<vinfo.xres * vinfo.yres; i++)
91         {
92             memcpy(FB+i*bpp/8, pixel[k%3], bpp/8);
93         }
94         sleep(1); // 每隔一秒刷一次屏
95     }
96
97     return 0;
98 }

例子3

在 LCD 上画图

先获取到一个图片的像素数据,生成一个二进制图片像素数据的*.bin文件,扫描模式选择水平扫描,灰度旋转32位真色彩,一个像素32位数据来表示,宽度高度分别是800和500

将这个bin文件读到内存中,然后将它刷到LCD所对应的FRAME-BUFFER上, 就实现了LCD显示图像了

pic_show.c

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<stdbool.h>
 4 #include<unistd.h>
 5 #include<string.h>
 6 #include<strings.h>
 7 #include<errno.h>
 8
 9 #include<sys/stat.h>
 10#include<sys/types.h>
 11#include<sys/mman.h>
 12#include<fcntl.h>
 13
 14#defineSCREEN_SIZE800*480 //群创AT070TN92显示屏像素总数
15#defineWIDTH 800
 16#defineHEIGHT480
 17
 18 voidwrite_lcd(char*p, intpicfd)
 19 {
 20 memset(p,0,SCREEN_SIZE*4);
 21
 22 intn,offset=0;
 23 while(1)//这个循环是以防万一不能一次将图片全部读出
24 {
 25 n=read(picfd,p+offset,SCREEN_SIZE*4);
 26 if(n<=0)
 27 break;
 28 offset+=n;
 29 }
 30 }
31
 32 intmain(void)
 33 {
 34 int lcd=open("/dev/fb0",O_RDWR);//打开LCD设备节点文件
35 if(lcd==-1)
 36 {
 37 perror("open()");
 38 exit(1);
 39 }
 40
 41 //将一块适当大小的内存映射为LCD设备的frame-buffer
 42 char*p=mmap(NULL,SCREEN_SIZE*4,
 43 PROT_READ|PROT_WRITE,
 44 MAP_SHARED, lcd,0);
 45
 46 intpicfd=open("girl.bin",O_RDONLY); //打开图片文件
47 if(picfd==-1)
 48 {
 49 perror("open()");
 50 exit(1);
 51 }
 52 write_lcd(p,picfd);//将文件刷进LCD设备对应的frame-buffer中
53
 54 return0;
 55 }

jpeg库

如果想直接对jpeg图片进行读取就需要用到这个库,要在代码中加入对jpeg压缩格式的解码库API

步骤

  • 下载jpeg库
  • 安装jpeg库
    • 进入解压后的目录 cd jpeg-9a/
    • 配置交叉环境 ./configure --host=arm-none-Linux-gnueabi
    • 编译并安装  make && make install
  • 将/usr/local/include和/usr/local/lib下关于jpeg的头文件和库拷贝到开发板
  • 在程序中加入对jpeg压缩图片的解压代码
  • main函数
    • 读取图片属性
    • 根据其大小分配内存缓冲区jpg_buffer
    • 声明解压缩结构体,以及错误管理结构体
    • 使用缺省的出错处理来初始化解压缩结构体
    • 配置该cinfo,使其从jpg_buffer 中读取jpg_size个字节
    • 读取jpeg文件的头,并判断其格式是否合法
    • 开始解压
    • 根据图片的尺寸大小分配一块相应的内存bmp_buffer
    • 用来存放从jpg_buffer解压出来的图像数据
    • 循环地将图片的每一行读出并解压到bmp_buffer中
    • 解压完了,将jpeg相关的资源释放掉
    • 打开屏幕文件
    • 获取LCD设备的当前参数
    • 根据当前LCD设备参数申请适当大小的FRAMEBUFFR
    • 将bmp_buffer中的RGB图像数据,写入FRAMEBUFFER中

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码农小白

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值