您尚未登录。

楼主 #1 2020-03-17 23:06:27

Jmhh247
会员
注册时间: 2018-12-21
已发帖子: 262
积分: 262

[正点原子i.MX6UL] v4l2+framebuffer预览USB摄像头(二):显示照片

关键字: 正点原子,i.MX6UL,linux, framebuffer


- 主机环境:ubuntu16.04-64bit
- 硬件版本:正点原子i.MX6UL emmc

固件帖在本站:[[正点原子i.MX6UL开发板] 编译uboot、linux、buildroot-rootfs](https://whycan.cn/t_3550.html)

---

#### 一、本篇目标

接上篇- [[正点原子i.MX6UL]v4l2+framebuffer预览USB摄像头(一):采集拍照](https://whycan.cn/t_3658.html)

本篇主要实现把拍照保存的bmp图片,显示到framebuffer上。

#### 二、相关概念

一些是我自己的基本理解,比较粗糙~

帧缓冲(framebuffer)是Linux为显示设备提供的一个接口,把显存抽象后的一种设备,允许上层应用程序在图形模式下直接对显示缓冲区进行读写操作。framebuffer是LCD对应的一中HAL(硬件抽象层),提供抽象的,统一的接口操作,用户不必关心硬件层是怎么实施的。这些都是由 Framebuffer设备驱动来完成的。

- 帧缓冲设备对应的设备文件为/dev/fb*
- 使用时需要先获取到相关信息如屏幕尺寸,显存大小,RGB格式等
- 通常把帧缓冲显存映射至用户程序空间来使用,非常方便


##### s0:获取帧缓冲信息

主要是通过struct fb_var_screeninfo(表示可变信息)、struct fb_fix_screeninfo(表示固定信息)这2个结构体,在/usr/include/linux/fb.h中定义:

struct fb_fix_screeninfo {
	char id[16];			/* identification string eg "TT Builtin" */
	unsigned long smem_start;	/* Start of frame buffer mem */
					/* (physical address) */
	__u32 smem_len;			/* Length of frame buffer mem */
	__u32 type;			/* see FB_TYPE_*		*/
	__u32 type_aux;			/* Interleave for interleaved Planes */
	__u32 visual;			/* see FB_VISUAL_*		*/ 
	__u16 xpanstep;			/* zero if no hardware panning  */
	__u16 ypanstep;			/* zero if no hardware panning  */
	__u16 ywrapstep;		/* zero if no hardware ywrap    */
	__u32 line_length;		/* length of a line in bytes    */
	unsigned long mmio_start;	/* Start of Memory Mapped I/O   */
					/* (physical address) */
	__u32 mmio_len;			/* Length of Memory Mapped I/O  */
	__u32 accel;			/* Indicate to driver which	*/
					/*  specific chip/card we have	*/
	__u16 capabilities;		/* see FB_CAP_*			*/
	__u16 reserved[2];		/* Reserved for future compatibility */
};


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 = color, 1 = grayscale,	*/
					/* >1 = FOURCC			*/
	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;		/* (OBSOLETE) see fb_info.flags */

	/* 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 rotate;			/* angle we rotate counter clockwise */
	__u32 colorspace;		/* colorspace for FOURCC-based modes */
	__u32 reserved[4];		/* Reserved for future compatibility */
};

struct fb_bitfield {
	__u32 offset;			/* beginning of bitfield	*/
	__u32 length;			/* length of bitfield		*/
	__u32 msb_right;		/* != 0 : Most significant bit is right */ 
};

- 获取可变信息:

    if (ioctl(screen_fbd, FBIOGET_VSCREENINFO, &fb_var) == -1) {
        printf("err read screen info FBIOGET_VSCREENINFO.\n");
        close(screen_fbd);
        return 0;
    }

- 获取固定信息:

    if (ioctl(screen_fbd, FBIOGET_FSCREENINFO, &fb_fix) == -1) {
        printf("err read screen info FBIOGET_FSCREENINFO.\n");
        close(screen_fbd);
        return 0;
    }

##### s1:把帧缓冲映射至用户空间
映射显存:

    if ((fb_addr = (char*)mmap(0, fb_size, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0)) < 0) {
        printf("fb mmap error\n");
        exit(1);
    }

取消映射:

    munmap(fb_addr, fb_size);

#### 三、代码实现

- 代码1

本代码主要实现了获取帧缓冲的信息,相当于帧缓冲版的"hello world"。

/*
 * @FilePath: /0317/fb-getinfo.c
 * @Version: 1.0.0
 * @Author: zys
 * @LastAuthor   : zys
 * @CreationDate: 2020-03-17 21:54:30
 * @LastEditTime : 2020-03-17 22:06:54
 * @Description :  获取framebuffer的信息,相当于framebuffer版的"hello world"。
 */


#include <fcntl.h>
#include <linux/fb.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

/*

yz imx6ul test ok.

-build:
    $ARMGCC fb-getinfo.c -o fb-getinfo

-tftp get:    
    cp fb-getinfo /tftpboot/
    tftp -g -r fb-getinfo 192.168.2.119
*/

int main(int argc, char* argv[])
{
    int                      screen_fbd = 0;
    struct fb_fix_screeninfo fb_fix;
    struct fb_var_screeninfo fb_var;
    char*                    env = NULL;

    if (!(env = getenv("FRAMEBUFFER"))) {
        env = "/dev/fb0";
    }

    screen_fbd = open(env, O_RDWR);

    if (screen_fbd < 0) {
        printf("err open fb dev: %s \r\n", env);
        return 0;
    }
    else {
        printf("success open fb dev : %s \r\n", env);
    }

    if (ioctl(screen_fbd, FBIOGET_FSCREENINFO, &fb_fix) == -1) {
        printf("err read screen info FBIOGET_FSCREENINFO.\n");

        close(screen_fbd);
        return 0;
    }



    printf("fb_fix.id=\"%s\"\r\n", fb_fix.id);
    printf("fb_fix.smem_start=%#x\r\n", fb_fix.smem_start);
    printf("fb_fix.mem_len=%d\r\n", fb_fix.smem_len);
    printf("fb_fix.type=%d\r\n", fb_fix.type);
    printf("fb_fix.type_aux=%d\r\n", fb_fix.type_aux);
    printf("fb_fix.visual=%d\r\n", fb_fix.visual);
    printf("fb_fix.xpanstep=%s\r\n", fb_fix.xpanstep);
    printf("fb_fix.ypanstep=%d\r\n", fb_fix.ypanstep);
    printf("fb_fix.ywrapstep=%d\r\n", fb_fix.ywrapstep);
    printf("fb_fix.line_length=%d\r\n", fb_fix.line_length);
    printf("fb_fix.mmio_start=%#x\r\n", fb_fix.mmio_start);
    printf("fb_fix.mmio_len=%#x\r\n", fb_fix.mmio_len);
    printf("fb_fix.accel=%d\r\n", fb_fix.accel);
    printf("fb_fix.reserved[0]=%d\r\n", fb_fix.reserved[0]);
    printf("fb_fix.reserved[1]=%d\r\n", fb_fix.reserved[1]);
    printf("fb_fix.reserved[2]=%d\r\n", fb_fix.reserved[2]);

    if (ioctl(screen_fbd, FBIOGET_VSCREENINFO, &fb_var) == -1) {
        printf("err read screen info FBIOGET_VSCREENINFO.\n");
        close(screen_fbd);
        return 0;
    }

    printf("fb_var.xres=%d\r\n", fb_var.xres);
    printf("fb_var.yres=%d\r\n", fb_var.yres);
    printf("fb_var.xres_virtual=%d\r\n", fb_var.xres_virtual);
    printf("fb_var.yres_virtual=%d\r\n", fb_var.yres_virtual);
    printf("fb_var.xoffset=%d\r\n", fb_var.xoffset);
    printf("fb_var.yoffset=%d\r\n", fb_var.yoffset);
    printf("fb_var.bits_per_pixel=%d\r\n", fb_var.bits_per_pixel);
    printf("fb_var.grayscale=%d\r\n", fb_var.grayscale);


    printf("fb_bitfield red, offset = %u, length = %u, right = %u, \n\r", fb_var.red.offset, fb_var.red.length, fb_var.red.msb_right);
    printf("fb_bitfield green, offset = %u, length = %u, right = %u, \n\r", fb_var.green.offset, fb_var.green.length, fb_var.green.msb_right);
    printf("fb_bitfield blue, offset = %u, length = %u, right = %u, \n\r", fb_var.blue.offset, fb_var.blue.length, fb_var.blue.msb_right);
    printf("fb_bitfield transp, offset = %u, length = %u, right = %u, \n\r\n\r", fb_var.transp.offset, fb_var.transp.length, fb_var.transp.msb_right);

    printf("fb_var.red=%#x\r\n", fb_var.red);
    printf("fb_var.green=%#x\r\n", fb_var.green);
    printf("fb_var.blue=%#x\r\n", fb_var.blue);
    printf("fb_var.transp=%#x\r\n", fb_var.transp);
    printf("fb_var.nonstd=%d\r\n", fb_var.nonstd);
    printf("fb_var.activate=%d\r\n", fb_var.activate);
    printf("fb_var.height=%d\r\n", fb_var.height);
    printf("fb_var.width=%d\r\n", fb_var.width);
    printf("fb_var.accel_flags=%d\r\n", fb_var.accel_flags);
    printf("fb_var.pixclock=%d\r\n", fb_var.pixclock);
    printf("fb_var.left_margin=%d\r\n", fb_var.left_margin);
    printf("fb_var.right_margin=%d\r\n", fb_var.right_margin);
    printf("fb_var.upper_margin=%d\r\n", fb_var.upper_margin);
    printf("fb_var.lower_margin=%d\r\n", fb_var.lower_margin);
    printf("fb_var.hsync_len=%d\r\n", fb_var.hsync_len);
    printf("fb_var.vsync_len=%d\r\n", fb_var.vsync_len);
    printf("fb_var.sync=%d\r\n", fb_var.sync);
    printf("fb_var.vmode=%d\r\n", fb_var.vmode);
    printf("fb_var.rotate=%d\r\n", fb_var.rotate);
    printf("fb_var.reserved[0]=%d\r\n", fb_var.reserved[0]);
    printf("fb_var.reserved[1]=%d\r\n", fb_var.reserved[1]);
    printf("fb_var.reserved[2]=%d\r\n", fb_var.reserved[2]);
    printf("fb_var.reserved[3]=%d\r\n", fb_var.reserved[3]);


    close(screen_fbd);

    return 0;
}

显示bmp还未实现,后续会更新上~


#### 四、测试程序

- 编译程序

$ARMGCC fb-getinfo.c -o fb-getinfo

- 运行程序

先把程序复制到开发板,推荐用NF或TFTP。

运行程序:

# ./fb-getinfo
success open fb dev : /dev/fb0
fb_fix.id="mxs-lcdif"
fb_fix.smem_start=0x98100000
fb_fix.mem_len=33554432
fb_fix.type=0
fb_fix.type_aux=0
fb_fix.visual=2
fb_fix.xpanstep=(null)
fb_fix.ypanstep=1
fb_fix.ywrapstep=1
fb_fix.line_length=2048
fb_fix.mmio_start=0
fb_fix.mmio_len=0
fb_fix.accel=0
fb_fix.reserved[0]=0
fb_fix.reserved[1]=0
fb_fix.reserved[2]=0
fb_var.xres=1024
fb_var.yres=600
fb_var.xres_virtual=1024
fb_var.yres_virtual=600
fb_var.xoffset=0
fb_var.yoffset=0
fb_var.bits_per_pixel=16
fb_var.grayscale=0
fb_bitfield red, offset = 11, length = 5, right = 0,
fb_bitfield green, offset = 5, length = 6, right = 0,
fb_bitfield blue, offset = 0, length = 5, right = 0,
fb_bitfield transp, offset = 0, length = 0, right = 0,

fb_var.red=0xb
fb_var.green=0x5
fb_var.blue=0
fb_var.transp=0
fb_var.nonstd=0
fb_var.activate=128
fb_var.height=0
fb_var.width=0
fb_var.accel_flags=0
fb_var.pixclock=19607
fb_var.left_margin=140
fb_var.right_margin=160
fb_var.upper_margin=20
fb_var.lower_margin=12
fb_var.hsync_len=20
fb_var.vsync_len=3
fb_var.sync=1073741824
fb_var.vmode=0
fb_var.rotate=0
fb_var.reserved[0]=0
fb_var.reserved[1]=0
fb_var.reserved[2]=0
fb_var.reserved[3]=0
#

可以看到,屏用的是RGB565格式,而显存居然达32M,NXP的驱动工程师很任性~

最近编辑记录 Jmhh247 (2020-03-17 23:08:25)

离线

楼主 #3 2020-03-20 22:38:29

Jmhh247
会员
注册时间: 2018-12-21
已发帖子: 262
积分: 262

Re: [正点原子i.MX6UL] v4l2+framebuffer预览USB摄像头(二):显示照片

#### 显示照片代码测试OK
0320
---
#### 代码2 实现显示bmp照片

本程序的功能单纯就是bmp文件解码,从bmp图片文件读取RGB数据显示到framebuffer上面。

- 实现源码。

/*
 * @FilePath: /0318/load-bmp-on-fb.c
 * @Version: 1.0.0
 * @Author: zys
 * @LastAuthor   : zys
 * @CreationDate: 2020-03-18 22:58:04
 * @LastEditTime : 2020-03-18 23:07:45
 * @Description :  读取bmp图片显示到framebuffer。
 */



/*----------------------------------------------------------------------------*/
/* change log ----------------------------------------------------------------*/


/*

0318
yz imx6ul test ok.


-build:
    $ARMGCC load-bmp-on-fb.c -o load-bmp-on-fb

-tftp get:    
    cp load-bmp-on-fb /tftpboot/
    tftp -g -r load-bmp-on-fb 192.168.2.119
*/


/*----------------------------------------------------------------------------*/
/* Includes ------------------------------------------------------------------*/
#include <arpa/inet.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>


/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/*_attribute__((packed))的作用是告诉编译器取消结构在编译过程中的优化对齐  */

//14byte文件头
typedef struct
{
    unsigned char cfType[2];  //文件类型,"BM"(0x4D42)
    unsigned int  cfSize;     //文件大小(字节)
    unsigned int  cfReserved; //保留,值为0
    unsigned int  cfoffBits;  //数据区相对于文件头的偏移量(字节)
} __attribute__((packed)) BITMAPFILEHEADER;


//40byte信息头
typedef struct
{
    unsigned int       ciSize;            //BITMAPFILEHEADER所占的字节数
    unsigned int       ciWidth;           //宽度
    unsigned int       ciHeight;          //高度
    unsigned short int ciPlanes;          //目标设备的位平面数,值为1
    unsigned short int ciBitCount;        //每个像素的位数
    char               ciCompress[4];     //压缩说明
    unsigned int       ciSizeImage;       //用字节表示的图像大小,该数据必须是4的倍数
    unsigned int       ciXPelsPerMeter;   //目标设备的水平像素数/米
    unsigned int       ciYPelsPerMeter;   //目标设备的垂直像素数/米
    unsigned int       ciClrUsed;         //位图使用调色板的颜色数
    unsigned           intciClrImportant; //指定重要的颜色数,当该域的值等于颜色数时(或者等于0时),表示所有颜色都一样重要
} __attribute__((packed)) BITMAPINFOHEADER;

typedef struct
{
    unsigned char blue;
    unsigned char green;
    unsigned char red;
} __attribute__((packed)) PIXEL; //颜色模式RGB


/* Private function prototypes -----------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
BITMAPFILEHEADER FileHead;
BITMAPINFOHEADER InfoHead;
static int       xres           = 0;
static int       yres           = 0;
static int       bits_per_pixel = 0;
static char*     fb_addr        = NULL;

/* Global  variables ---------------------------------------------------------*/
/* Private functions ---------------------------------------------------------*/

int show_bmp(char* picname)
{
    FILE*                 fp;
    int                   rc;
    int                   line_x, line_y;
    long int              location = 0;
    char                  tmp[1024 * 10];
    static unsigned short b, g, r;
    static unsigned short rgb; /*2个字节*/
    PIXEL                 pix;
    int                   total_length = 0;
    int                   width, height;
    int                   flen = 0;


    printf("into show_bmp function\n");

    fp = fopen(picname, "rb");
    if (fp == NULL) {
        printf("open errror\n");
        return (-1);
    }

    /* BITMAPFILEHEADER*/
    rc = fread(&FileHead, sizeof(BITMAPFILEHEADER), 1, fp);
    if (rc != 1) {
        printf("read header error!\n");
        fclose(fp);
        return (-2);
    }
    printf("Read BITMAPFILEHEADER  OK\n");

    //检测是否是bmp图像
    if (memcmp(FileHead.cfType, "BM", 2) != 0) {
        printf("it's not a BMP file\n");
        fclose(fp);
        return (-3);
    }
    /*BITMAPINFOHEADER*/
    rc = fread((char*)&InfoHead, sizeof(BITMAPINFOHEADER), 1, fp);
    if (rc != 1) {
        printf("read infoheader error!\n");
        fclose(fp);
        return (-4);
    }
    printf("Read BITMAPINFOHEADER  OK\n");


    /* 求解文件长度 */
    fseek(fp, 0, SEEK_SET);
    fseek(fp, 0, SEEK_END);

    flen = ftell(fp);

    /* 再移位到文件头部 */
    fseek(fp, 0, SEEK_SET);


    width  = InfoHead.ciWidth;
    height = InfoHead.ciHeight;

    printf("FileHead.cfSize =%d byte\n", FileHead.cfSize);
    printf("flen = %d\n", flen);
    printf("width = %d, height = %d\n", width, height);

    total_length = width * height * 3;

    printf("total_length = %d\n", total_length);

    //跳转的数据区
    fseek(fp, FileHead.cfoffBits, SEEK_SET);

    printf("FileHead.cfoffBits = %d\n", FileHead.cfoffBits);
    printf("InfoHead.ciBitCount = %d\n", InfoHead.ciBitCount);


    for (line_y = 0; line_y < height; line_y++) {
        // printf("read pix rgb...\n");

        for (line_x = 0; line_x < width; line_x++) {

            // printf("read pix rgb...\n");
            // rc = fread(&(pix.blue), 1, 1, fp);
            // rc = fread(&(pix.green), 1, 1, fp);
            // rc = fread(&(pix.red), 1, 1, fp);

            rc = fread(&pix, sizeof(PIXEL), 1, fp);

            // rgb565每像素占2个字节
            location = line_x * 2 + (height - 1 - line_y) * xres * 2;

            r   = ((pix.red >> 3) << 11) & 0xfb80;
            g   = ((pix.green >> 2) << 5) & 0x07e0;
            b   = (pix.blue >> 3) & 0x001f;
            rgb = r | g | b;

            // 写入显存
            *((unsigned short*)(fb_addr + location)) = rgb;
        }
    }

    fclose(fp);

    return 0;
}


int fb_init(void)
{
    int                      fbfd, fb_size;
    struct fb_var_screeninfo vinfo;
    struct fb_fix_screeninfo finfo;

    fbfd = open("/dev/fb0", O_RDWR | O_CREAT, S_IRWXU);
    if (fbfd < 0) {
        printf("open error\n");
        exit(1);
    }

    if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo)) {
        printf("Error reading variable information.\n");
        exit(1);
    }


    if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo)) {
        printf("Error reading variable information.\n");
        exit(1);
    }
    
    printf("R:%d,G:%d,B:%d \n", vinfo.red, vinfo.green, vinfo.blue);
    printf("%dx%d, %dbpp\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel);

    xres           = vinfo.xres;
    yres           = vinfo.yres;
    bits_per_pixel = vinfo.bits_per_pixel;
    fb_size        = xres * yres * ((bits_per_pixel + 7) / 8);

    printf("fbsize: %d \n", fb_size);

    if ((fb_addr = (char*)mmap(0, fb_size, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0)) < 0) {
        printf("fb mmap error\n");
        exit(1);
    }

    close(fbfd);

    printf("fb init ok!\n");

    return fb_size;
}

int main(int argc, char* argv[])
{
    int fb_size;

    fb_size = fb_init();

    printf("show_bmp\n");
    show_bmp(argv[1]);

    munmap(fb_addr, fb_size);

    return 0;
}


/*************************** (C) COPYRIGHT 2020 ZYS ************END OF FILE****/

- 测试程序

首于本程序只负责显示,所以拍照需要用到上篇的代码,分两步完成测试。

先拍照保存:

# ./av4l2grap-uvc-savebmp-x /dev/video1

再显示出来:

# ./load-bmp-on-fb uvc_grap.bmp

完整的运行程序log:

# ls
av4l2grap-uvc-savebmp-x  load-bmp-on-fb
# ./av4l2grap-uvc-savebmp-x /dev/video1

----- v4l2 savebmp app start -----
using:          /dev/video1
driver:         uvcvideo
card:           Aoni HD Camera
bus_info:       usb-ci_hdrc.1-1.4
version:        262415
capabilities:   84200001
/dev/video1:    supports capture.
/dev/video1:    supports streaming.

Support format:
        1.MJPEG
        2.YUV 4:2:2 (YUYV)

fmt.type:               1
pix.pixelformat:        YUYV
pix.height:             480
pix.width:              640
pix.field:              1
set fps OK!
get fps OK:
timeperframe.numerator  : 1
timeperframe.denominator: 25
set fps : 25
Supported format: MJPEG
        Supported size: 640x480
        Supported size: 1280x720
        Supported size: 1184x656
        Supported size: 1024x576
        Supported size: 960x720
        Supported size: 960x540
        Supported size: 864x486
        Supported size: 800x600
        Supported size: 752x423
        Supported size: 640x360
        Supported size: 320x240
Supported format: YUV 4:2:2 (YUYV)
        Supported size with the current format: 640x480
        Supported size with the current format: 1280x720
        Supported size with the current format: 1184x656
        Supported size with the current format: 1024x576
        Supported size with the current format: 960x720
        Supported size with the current format: 960x540
        Supported size with the current format: 864x486
        Supported size with the current format: 800x600
        Supported size with the current format: 752x423
        Supported size with the current format: 640x360
        Supported size with the current format: 320x240
init /dev/video1        [OK]
start capture
buf index: 0
yuyv to rgb888 done
save bmp  function
save ./uvc_grap.bmp done
app exit.

# ls
av4l2grap-uvc-savebmp-x  load-bmp-on-fb           uvc_grap.bmp


# ./load-bmp-on-fb uvc_grap.bmp
R:11,G:5,B:0
1024x600, 16bpp
fbsize: 1228800
fb init ok!
show_bmp
into show_bmp function
Read BITMAPFILEHEADER  OK
Read BITMAPINFOHEADER  OK
FileHead.cfSize =921654 byte
flen = 921654
width = 640, height = 480
total_length = 921600
FileHead.cfoffBits = 54
InfoHead.ciBitCount = 24
#

- 显示效果

bmp-on-fb.jpg


本篇由两个程序合作,完成了静态照片的显示,下篇会完成动态实时预览~

离线

页脚

工信部备案:粤ICP备20025096号 Powered by FluxBB

感谢为中文互联网持续输出优质内容的各位老铁们。 QQ: 516333132, 微信(wechat): whycan_cn (哇酷网/挖坑网/填坑网) service@whycan.cn