帧缓存(Frame Buffer)

一、定义与功能

帧缓存,也称为帧缓冲存储器,是屏幕所显示画面的一个直接映象,又称为位映射图(Bit Map)或光栅。帧缓存的每一存储单元对应屏幕上的一个像素,整个帧缓存对应一帧图像。Linux中的帧缓存为显示设备提供了一个接口,把显存抽象后的一种设备,允许上层应用程序在图形模式下直接对显示缓冲区进行读写操作。

二、特点

  1. 抽象性:帧缓存将显存抽象为一种设备,用户不必关心物理显存的位置、换页机制等具体细节,这些由Framebuffer设备驱动来完成。
  2. 直接性:修改帧缓存中的内容,即表示修改屏幕上的内容,直接操作帧缓存可以直接从显示器上观察到效果。
  3. 多缓存支持:帧缓存可能包含多个缓存,如颜色缓存、深度缓存、模板缓存等,这些缓存共同作用下形成最终在屏幕上显示的图像。
  4. 位置灵活性:帧缓存可以在系统存储器(内存)的任意位置,只要是在GPU能够访问的空间范围内,都可以作为帧缓存使用。

三、应用与实现

  1. 图形绘制与交互:Linux帧缓冲为图形绘制和交互提供了接口,使得我们日常使用电脑时能够看到各种图形界面以及操作系统的反馈。
  2. 窗口系统:在Linux的桌面系统中,如Xwindow服务器,就是利用帧缓存进行窗口的绘制。
  3. 硬件抽象:Linux FrameBuffer 本质上只是提供了对图形设备的硬件抽象,开发者可以将FrameBuffer视为一块显示缓存,往其中写入特定格式的数据就意味着向屏幕输出内容。

四、操作方式

在Linux中,帧缓存设备为标准的字符型设备,用户可以通过以下步骤操作帧缓存:

  1. 打开/dev/fb0设备文件。
  2. 使用ioctl()操作取得当前显示屏幕的参数,如屏幕分辨率、每个像素点的比特数。
  3. 使用mmap()函数,将屏幕缓冲区映射到用户空间。
  4. 映射后就可以直接读/写屏幕缓冲区,进行绘图和图片显示了。
  5. 使用完帧缓冲设备后需要将其释放。
  6. 关闭文件。

五、优缺点

优点

  • 提高性能:通过缓存数据,减少读写磁盘的次数,提高系统的性能。
  • 减少磁盘磨损:由于减少了读写磁盘的次数,可以延长磁盘的使用寿命。
  • 实时性:帧缓存中的内容是实时更新的,能够反映最新的屏幕显示状态。

缺点

  • 内存占用:帧缓存需要占用一定的内存空间,如果缓存数据过多,可能会导致系统内存不足,影响系统的稳定性。
  • 数据一致性:在某些情况下,帧缓存中的数据可能与实际显示的数据存在不一致性,需要开发者注意数据同步问题。
void *pmem;
struct fb_var_screeninfo vinf;

int init_fb(char *devname)
{
	//1. 打开显示设备
	int fd = open(devname, O_RDWR);	
	if (-1 == fd)
	{
		perror("fail open fb");
		return -1;
	}
	
	//2、获取显示设备相关参数 分辨率 位深度
	int ret = ioctl(fd, FBIOGET_VSCREENINFO, &vinf);
	if (-1 ==ret)
	{
		perror("fail ioctl");
		return -1;
	}
	
	printf("xres = %d, yres = %d\n", vinf.xres, vinf.yres);
	printf("xres_virtual = %d, yres_virtual = %d\n", vinf.xres_virtual, vinf.yres_virtual);
	printf("bits_per_pixel : %d\n", vinf.bits_per_pixel);

	size_t len = vinf.xres_virtual * vinf.yres_virtual * vinf.bits_per_pixel/8;
	//3, 建立显存和用户空间的映射关系
	pmem = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
	if ((void *)-1 == pmem)
	{
		perror("fail mmap");
		return -1;
	}
	

	return fd;
}

画点:

void draw_point(int x, int y, unsigned int col)
{
	if (x >= vinf.xres || y >= vinf.yres)
	{
		return ;
	}
	if (vinf.bits_per_pixel == RGB888_FMT)
	{
		unsigned int *p = pmem;
		*(p + y * vinf.xres_virtual + x) = col;
	}
	else if (vinf.bits_per_pixel == RGB565_FMT)
	{
		unsigned short *p  = pmem;	
		*(p + y * vinf.xres_virtual + x) = col;
	}
	return ;
}

下面是一个简单的缓存实现,用于循环存储音视频: ```c #include <stdlib.h> #include <string.h> #define FRAME_BUFFER_SIZE 100 // 定义一个缓存结构体 typedef struct { int head; // 缓存头部指针 int tail; // 缓存尾部指针 int count; // 缓存中已存储的数 void *buffer[FRAME_BUFFER_SIZE]; // 缓存区 } FrameBuffer; // 初始化缓存 FrameBuffer* frame_buffer_init() { FrameBuffer *buffer = (FrameBuffer*)malloc(sizeof(FrameBuffer)); memset(buffer, 0, sizeof(FrameBuffer)); return buffer; } // 销毁缓存 void frame_buffer_destroy(FrameBuffer *buffer) { free(buffer); } // 向缓存中添加一 void frame_buffer_push(FrameBuffer *buffer, void *frame) { // 如果缓存区已满,覆盖掉最老的一 if (buffer->count >= FRAME_BUFFER_SIZE) { free(buffer->buffer[buffer->head]); buffer->head = (buffer->head + 1) % FRAME_BUFFER_SIZE; } else { buffer->count++; } buffer->buffer[buffer->tail] = frame; buffer->tail = (buffer->tail + 1) % FRAME_BUFFER_SIZE; } // 从缓存中读取一 void* frame_buffer_pop(FrameBuffer *buffer) { if (buffer->count <= 0) { return NULL; } void *frame = buffer->buffer[buffer->head]; buffer->head = (buffer->head + 1) % FRAME_BUFFER_SIZE; buffer->count--; return frame; } ``` 使用方法如下: ```c FrameBuffer *buffer = frame_buffer_init(); // 存储一数据到缓存中 void *frame = ...; // 待存储的音视频数据 frame_buffer_push(buffer, frame); // 从缓存中读取一数据 void *frame = frame_buffer_pop(buffer); if (frame != NULL) { // 处理音视频数据 } frame_buffer_destroy(buffer); ``` 此缓存实现中采用循环队列的方式存储音视频数据,当缓存区已满时,会覆盖掉最老的一数据。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值