fb_var_screeninfo解析

本文详细解析了fb_var_screeninfo结构的组成部分,包括分辨率、颜色深度、定时设置等,并介绍了如何利用该结构进行双缓冲、平滑滚动屏幕以及颜色深度改变的操作,特别强调了其在显示管理中的实际应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转自:http://blog.163.com/zhaoxin851055@126/blog/static/81129298201203183430680/

struct fb_var_screeninfo {
__u32 xres/* visible resolution */

__u32 yres;
__u32 xres_virtual; /* virtual resolution */

__u32 yres_virtual;
__u32 xoffset; /* offset from virtual to visible */

__u32 yoffset; /* resolution */

__u32 bits_per_pixel; /* guess what */

__u32 grayscale; /* != 0 Graylevels instead of colors
*/

struct fb_bitfield red; /*
bitfield in fb mem if true color, */


struct fb_bitfield green; /*
else only length is significant */


struct fb_bitfield blue;
struct fb_bitfield transp; /*
transparency */

__u32 nonstd; /* != 0 Non standard pixel format */

__u32 activate; /* see FB_ACTIVATE_* */

__u32 height; /* height of picture in mm???
*/


__u32 width; /* width of picture in mm????
*/

__u32 accel_flags; /* acceleration flags (hints) */

/* Timing: All values in pixclocks, except pixclock (of
course) */


__u32 pixclock; /* pixel clock in ps (pico seconds) */

__u32 left_margin; /* time from sync to picture */

__u32 right_margin; /* time from picture to sync */

__u32 upper_margin; /* time from sync to picture */

__u32 lower_margin;
__u32 hsync_len; /* length of horizontal sync */

__u32 vsync_len; /* length of vertical sync */

__u32 sync; /* see FB_SYNC_* */

__u32 vmode; /* see FB_VMODE_* */

__u32 reserved[6]; /* Reserved for future compatibility
*/


};

前几个成员决定了分辨率。xres和yres是在屏幕上可见的实际分辨率,在通常的vga模式将为640和400(也许是480,by highbar)。*res-virtual决定了构建屏幕时视频卡读取屏幕内存的方式。当实际的垂直分辨率为400,虚拟分辨率可以是800。这意味着800行的数据被保存在了屏幕内存区中。因为只有400行可以被显示,决定从那一行开始显示就是你的事了。这个可以通过设置*offset来实现。给yoffset赋0将显示前400行,赋35将显示第36行到第435行,如此重复。这个功能在许多情形下非常方便实用。它可以用来做双缓冲。双缓冲就是你的程序分配了可以填充两个屏幕的内存。将offset设为0,将显示前400行(假设是标准的vga),同时可以秘密的在400行到799行构建另一个屏幕,当构建结束时,将yoffset设为400,新的屏幕将立刻显示出来。现在将开始在第一块内存区中构建下一个屏幕的数据,如此继续。这在动画中十分有用。

另外一个应用就是用来平滑的滚动整个屏幕。就像在前面屏幕中一样,在内存分配800行的空间。每隔10毫秒设定一个定时器(timer,见man settimer和man
signal / man sigaction),将offset设为1或是比上次更多,瞧,你看到了一个平滑滚动的屏幕。确保你的信号(signal)不要因为最佳输出的原因被信号处理程序阻塞。


bits_per_pixel 设为1,2,4,8,16,24或32来改变颜色深度(color depth)。不是所有的视频卡和驱动都支持全部颜色深度。当颜色深度改变,驱动将自动改变fb-bitfields。这些指出,在一个特定的颜色基准上,多少和哪些比特被哪种颜色使用。如果bits-per-pixel小于8,则fb-bitfields将无定义而且颜色映射将启用。

在fb-var-screeninfo结构结尾的定时的设置是当你选择一个新的分辨率的时候用来设定视频定时的。(
EXAMINE AND EXPLAIN TIMINGS! )


/* * @Author: ilikara 3435193369@qq.com * @Date: 2025-01-07 06:55:37 * @LastEditors: ilikara 3435193369@qq.com * @LastEditTime: 2025-04-05 09:28:46 * @FilePath: /smartcar/opencv_demo1/opencv_demo1.cpp * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE */ #include <chrono> #include <fcntl.h> #include <iomanip> #include <linux/fb.h> #include <opencv2/opencv.hpp> #include <sstream> #include <sys/ioctl.h> #include <sys/mman.h> #include <unistd.h> using namespace cv; using namespace std; // 将 RGB888 转换为 RGB565 ushort rgb888_to_rgb565(const Vec3b& color) { return ((color[2] >> 3) << 11) | ((color[1] >> 2) << 5) | (color[0] >> 3); } // 获取当前时间字符串 string getCurrentTime() { auto now = chrono::system_clock::now(); auto now_time_t = chrono::system_clock::to_time_t(now); auto now_tm = *localtime(&now_time_t); stringstream ss; ss << put_time(&now_tm, "%Y-%m-%d %H:%M:%S"); return ss.str(); } int main() { // 打开 USB 摄像头 VideoCapture cap(0); // 0 表示默认摄像头 if (!cap.isOpened()) { cerr << "Error: Cannot open camera" << endl; return -1; } // 设置摄像头分辨率(可选) cap.set(CAP_PROP_FRAME_WIDTH, 320); cap.set(CAP_PROP_FRAME_HEIGHT, 240); // Framebuffer 设备 const char* fb_device = "/dev/fb0"; int fb_fd = open(fb_device, O_RDWR); if (fb_fd == -1) { cerr << "Error: Cannot open framebuffer device" << endl; return -1; } // 获取 Framebuffer 信息 struct fb_var_screeninfo vinfo; if (ioctl(fb_fd, FBIOGET_VSCREENINFO, &vinfo)) { cerr << "Error: Cannot get framebuffer information" << endl; close(fb_fd); return -1; } // 检查 Framebuffer 是否支持 RGB565 if (vinfo.bits_per_pixel != 16) { cerr << "Error: Framebuffer is not RGB565 format" << endl; close(fb_fd); return -1; } // 映射 Framebuffer 到内存 size_t fb_size = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8; ushort* fb_data = (ushort*)mmap(0, fb_size, PROT_READ | PROT_WRITE, MAP_SHARED, fb_fd, 0); if (fb_data == MAP_FAILED) { cerr << "Error: Failed to map framebuffer to memory" << endl; close(fb_fd); return -1; } // 主循环 Mat frame, resizedFrame; int frameCount = 0; while (true) { // 从摄像头捕获一帧图像 cap >> frame; if (frame.empty()) { cerr << "Error: Captured frame is empty" << endl; break; } // 调整图像大小为 160x128 resize(frame, resizedFrame, Size(160, 128)); // 获取当前时间和帧数 string timeStr = getCurrentTime(); string frameStr = "Frame: " + to_string(frameCount); // 在图像左上角绘制黑色边框的白色文字 int fontFace = FONT_HERSHEY_SIMPLEX; double fontScale = 0.4; int thickness = 1; // 计算文字位置 Point timePos(5, 15); // 时间文字位置 Point framePos(5, 30); // 帧数文字位置 // 绘制黑色边框 putText(resizedFrame, timeStr, timePos + Point(-1, -1), fontFace, fontScale, Scalar(0, 0, 0), thickness + 1); putText(resizedFrame, timeStr, timePos + Point(1, -1), fontFace, fontScale, Scalar(0, 0, 0), thickness + 1); putText(resizedFrame, timeStr, timePos + Point(-1, 1), fontFace, fontScale, Scalar(0, 0, 0), thickness + 1); putText(resizedFrame, timeStr, timePos + Point(1, 1), fontFace, fontScale, Scalar(0, 0, 0), thickness + 1); putText(resizedFrame, frameStr, framePos + Point(-1, -1), fontFace, fontScale, Scalar(0, 0, 0), thickness + 1); putText(resizedFrame, frameStr, framePos + Point(1, -1), fontFace, fontScale, Scalar(0, 0, 0), thickness + 1); putText(resizedFrame, frameStr, framePos + Point(-1, 1), fontFace, fontScale, Scalar(0, 0, 0), thickness + 1); putText(resizedFrame, frameStr, framePos + Point(1, 1), fontFace, fontScale, Scalar(0, 0, 0), thickness + 1); // 绘制白色文字 putText(resizedFrame, timeStr, timePos, fontFace, fontScale, Scalar(255, 255, 255), thickness); putText(resizedFrame, frameStr, framePos, fontFace, fontScale, Scalar(255, 255, 255), thickness); // 将图像数据写入 Framebuffer for (int y = 0; y < resizedFrame.rows; y++) { for (int x = 0; x < resizedFrame.cols; x++) { Vec3b color = resizedFrame.at<Vec3b>(y, x); fb_data[y * vinfo.xres + x] = rgb888_to_rgb565(color); } } // 更新帧数 frameCount++; // 等待一段时间(例如 30ms) usleep(30000); } // 释放资源 munmap(fb_data, fb_size); close(fb_fd); cap.release(); return 0;是什么意思
06-04
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值