Framebuffer是把記憶體中視頻資料輸出的裝置驅動程式,Linux的framebuffer是獨立的硬體抽象層,它可以把顯示裝置抽象為框架緩衝區,並把自己當作顯示記憶體的一個映像,開發人員可以通過這個映像映射到進程地址空間,直接進行讀寫操作。簡單的說它把硬體抽象化後,可使上層不再關心硬體是如何操作,只是完成映像的顯示功能,該驅動的裝置檔案一般是/dev/fb0、/dev/fb1,framebuffer最多支援32個裝置。說明了Framebuffer在Linux系統的位置,它高於一般的驅動程式,在中間屏蔽下層驅動功能。
但是對程式員和Linux系統來是,framebuffer裝置與其它的檔案沒有區別,可以通過配置對framebuffer裝置檔案完成對硬體的參數設定,framebuffer映射可以通過read()和write()進行資料的讀取,或者通過mmap()函數將內部資料對應到應用程式空間,通過ioctl()進行其它操作或者設定其參數,用mmap()函數把記憶體中的映像資料直接映射到framebuffer並顯示出來耗時短、效率高。記憶體中映像資料出來完後就可通過mmap()進行映射。
Framebuffer在Linux系統中的位置
映像顯示過程
螢幕顯示調用的是framebuffer,首先建立一個fb_dev結構體,裡邊有裝置指標、記憶體空間指標、橫豎像素數、顏色位元等資訊:
struct fb_dev { int fb; void *fb_mem; int fb_width, fb_height, fb_line_len, fb_size; int fb_bpp; } fbdev; |
初始化framebuffer裝置,並進行記憶體位址映射,可以直接把處理後的資料對應到framebuffer的緩衝中進行顯示:
int fb; if ((fb = open("/dev/fb0", O_RDWR)) < 0) { perror(__func__); return (-1); } fb_stat(fb); fbdev.fb_mem = mmap (NULL, fbdev.fb_size, PROT_READ|PROT_WRITE,MAP_SHARED,fb,0); fbdev.fb = fb; |
其中fb_stat(fb)函數如下定義,得到framebuffer的長、寬和位寬,成功則返回0,失敗返回-1:
int fb_stat(int fd) { struct fb_fix_screeninfo fb_finfo; struct fb_var_screeninfo fb_vinfo; if (ioctl(fd, FBIOGET_FSCREENINFO, &fb_finfo)) { perror(__func__); return (-1); } if (ioctl(fd, FBIOGET_VSCREENINFO, &fb_vinfo)) { perror(__func__); return (-1); } fbdev.fb_width = fb_vinfo.xres; fbdev.fb_height = fb_vinfo.yres; fbdev.fb_bpp = fb_vinfo.bits_per_pixel; bdev.fb_line_len = fb_finfo.line_length; fbdev.fb_size = fb_finfo.smem_len; return (0); } |
在螢幕上顯示資料,需要直接對像素點上直接顯示像素顏色,因為原始解碼的資料是24位RGB資料,而螢幕的顏色位元是16位,則需要將RGB888轉換為RGB565資料:主要是對不用顏色位元進行移位。
代碼如下
color=(unsigned short) (((buffer[x3s]<<8) & 0xF800)|((buffer[x3s+1]<<3) & 0x07E0)|((buffer[x3s+2] >> 3) & 0x001F)); |
因為開發板內建的NEC 3.5寸液晶屏解析度是240×320,而網路攝影機輸出的資料為320×240,故顯示時需進行矩陣轉置,由fbmem基址 + x * width + y確定:
if ((x > width) || (y > height) return (-1); unsigned short *dst = ((unsigned short *) fbmem + x * width + y); *dst = color; |
在程式最後,需要解除記憶體映射和關閉裝置:
munmap(fbdev.fb_mem,fbdev.fb_size); close(fb); |