/*
* fb_demo.c — 极简版: JPEG 解码 → 直接写到 /dev/fb0 (左上角)
*
* 只做 3 件事:
* 1. jpeg 解码出 RGB 像素
* 2. mmap 映射显存
* 3. RGB24 → XRGB8888 逐像素写入 (图片放屏幕左上角)
*
* 简化假设 (本机 /dev/fb0 实测 = 1280x800 32bpp XRGB8888):
* - 屏幕 32bpp: 每像素 4 字节, 内存序 [B][G][R][X]
* - 每行 1280*4 = 5120 字节
* 换板子时改 SCREEN_W 和 bpp 相关代码即可。
*
* 编译: make fb_demo 用法: ./fb_demo <输入.jpg>
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <jpeglib.h>
#define SCREEN_W 1280
#define SCREEN_H 800
/* ---------- ① JPEG 解码 (和 jpeg_de.c 一样) ---------- */
static unsigned char *decode_jpeg(const char *path, int *out_w, int *out_h)
{
FILE *fp = fopen(path, "rb");
if (!fp) { perror("fopen"); return NULL; }
struct jpeg_decompress_struct cinfo;
struct jpeg_error_mgr jerr;
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_decompress(&cinfo);
jpeg_stdio_src(&cinfo, fp);
if (jpeg_read_header(&cinfo, TRUE) != JPEG_HEADER_OK) return NULL;
cinfo.out_color_space = JCS_RGB;
jpeg_start_decompress(&cinfo);
unsigned int rowbytes = cinfo.output_width * cinfo.output_components;
unsigned char *buf = malloc(rowbytes * cinfo.output_height);
unsigned char *row = buf;
while (cinfo.output_scanline < cinfo.output_height) {
jpeg_read_scanlines(&cinfo, &row, 1);
row += rowbytes;
}
jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
fclose(fp);
*out_w = cinfo.output_width;
*out_h = cinfo.output_height;
return buf;
}
int main(int argc, char *argv[])
{
if (argc < 2) {
fprintf(stderr, "用法: %s <输入.jpg>\n", argv[0]);
return 1;
}
/* ① 解码 -> RGB 缓冲 */
int w, h;
unsigned char *rgb = decode_jpeg(argv[1], &w, &h);
if (!rgb) { fprintf(stderr, "解码失败\n"); return 1; }
printf("解码: %dx%d RGB\n", w, h);
/* ② 打开屏幕设备 + 映射显存 */
int fbfd = open("/dev/fb0", O_RDWR);
if (fbfd < 0) { perror("open /dev/fb0"); return 1; }
size_t fb_size = (size_t)SCREEN_W * SCREEN_H * 4;
unsigned char *fb = mmap(NULL, fb_size, PROT_READ | PROT_WRITE,
MAP_SHARED, fbfd, 0);
if (fb == MAP_FAILED) { perror("mmap"); return 1; }
memset(fb, 0, fb_size); /* 整屏刷黑 */
/* ③ 写入: 图片从 (0,0) 开始, 每行 src 是 3 字节 RGB,
* 每行 dst 是 4 字节 BGRX (XRGB8888 小端内存序) */
for (int y = 0; y < h && y < SCREEN_H; y++) {
unsigned char *src = rgb + (size_t)y * w * 3;
unsigned char *dst = fb + (size_t)y * SCREEN_W * 4;
for (int x = 0; x < w && x < SCREEN_W; x++) {
dst[x*4 + 0] = src[x*3 + 2]; /* B */
dst[x*4 + 1] = src[x*3 + 1]; /* G */
dst[x*4 + 2] = src[x*3 + 0]; /* R */
dst[x*4 + 3] = 0xFF; /* X = 不透明 */
}
}
printf("已写入 /dev/fb0 左上角 (%dx%d), 屏幕 %dx%d 32bpp\n", w, h, SCREEN_W, SCREEN_H);
munmap(fb, fb_size);
close(fbfd);
free(rgb);
return 0;
}