树莓派 读写 framebuffer

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define PERFORMANCE_RUN_COUNT 5

#ifndef __ANDROID__
#define FBDEV "/dev/fb0"
#define BMP_PIC_DIR "./Test.bmp"
#define OUT_DIR "./"
#else
#define FBDEV "/dev/graphics/fb0"
#define OUT_DIR "./"
#endif

struct fb_var_screeninfo vinfo;
struct fb_fix_screeninfo finfo;
static char *frameBuffer = 0;
static int xres = 0;
static int yres = 0;
static int bits_per_pixel = 0;

unsigned long screensize = 0;

//14byte文件头
typedef struct {
    char cfType[2];		//文件类型,"BM"(0x4D42)
    long cfSize;		//文件大小(字节)
    long cfReserved;	//保留,值为0
    long cfoffBits;		//数据区相对于文件头的偏移量(字节)
}__attribute__((packed)) BITMAPFILEHEADER;
//__attribute__((packed))的作用是告诉编译器取消结构在编译过程中的优化对齐,按照实际占用字节数进行对齐
//40byte信息头

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

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

BITMAPFILEHEADER FileHead;
BITMAPINFOHEADER InfoHead;

//打印fb驱动中fix结构信息,注:在fb驱动加载后,fix结构不可被修改。
void printFixedInfo() {
    printf("Fixed screen info:\n"
           "\tid: %s\n"
           "\tsmem_start: 0x%lx\n"
           "\tsmem_len: %d\n"
           "\ttype: %d\n"
           "\ttype_aux: %d\n"
           "\tvisual: %d\n"
           "\txpanstep: %d\n"
           "\typanstep: %d\n"
           "\tywrapstep: %d\n"
           "\tline_length: %d\n"
           "\tmmio_start: 0x%lx\n"
           "\tmmio_len: %d\n"
           "\taccel: %d\n"
           "\n", finfo.id, finfo.smem_start, finfo.smem_len, finfo.type,
           finfo.type_aux, finfo.visual, finfo.xpanstep, finfo.ypanstep,
           finfo.ywrapstep, finfo.line_length, finfo.mmio_start,
           finfo.mmio_len, finfo.accel);
}

//打印fb驱动中var结构信息,注:fb驱动加载后,var结构可根据实际需要被重置
void printVariableInfo() {
    printf("Variable screen info:\n"
           "\txres: %d\n"
           "\tyres: %d\n"
           "\txres_virtual: %d\n"
           "\tyres_virtual: %d\n"
           "\tyoffset: %d\n"
           "\txoffset: %d\n"
           "\tbits_per_pixel: %d\n"
           "\tgrayscale: %d\n"
           "\tred: offset: -, length: -, msb_right: -\n"
           "\tgreen: offset: -, length: -, msb_right: -\n"
           "\tblue: offset: -, length: -, msb_right: -\n"
           "\ttransp: offset: -, length: -, msb_right: -\n"
           "\tnonstd: %d\n"
           "\tactivate: %d\n"
           "\theight: %d\n"
           "\twidth: %d\n"
           "\taccel_flags: 0x%x\n"
           "\tpixclock: %d\n"
           "\tleft_margin: %d\n"
           "\tright_margin: %d\n"
           "\tupper_margin: %d\n"
           "\tlower_margin: %d\n"
           "\thsync_len: %d\n"
           "\tvsync_len: %d\n"
           "\tsync: %d\n"
           "\tvmode: %d\n"
           "\n", vinfo.xres, vinfo.yres, vinfo.xres_virtual,
           vinfo.yres_virtual, vinfo.xoffset, vinfo.yoffset,
           vinfo.bits_per_pixel, vinfo.grayscale, vinfo.red.offset,
           vinfo.red.length, vinfo.red.msb_right, vinfo.green.offset,
           vinfo.green.length, vinfo.green.msb_right, vinfo.blue.offset,
           vinfo.blue.length, vinfo.blue.msb_right, vinfo.transp.offset,
           vinfo.transp.length, vinfo.transp.msb_right, vinfo.nonstd,
           vinfo.activate, vinfo.height, vinfo.width, vinfo.accel_flags,
           vinfo.pixclock, vinfo.left_margin, vinfo.right_margin,
           vinfo.upper_margin, vinfo.lower_margin, vinfo.hsync_len,
           vinfo.vsync_len, vinfo.sync, vinfo.vmode);
}

void performWriteSpeedTest(void *fb, int fbSize) {
	
    int i, j, run;
    struct timeval startTime, endTime;
    unsigned long long results[PERFORMANCE_RUN_COUNT];
    unsigned long long average;
    unsigned int *testImage;

    unsigned int randData[17] = { 0xffffffff, 0xffffffff, 0xffffffff, 
					    		  0xffffffff, 0xffffffff, 0xffffffff,
					              0xffffffff, 0xffffffff, 0xffffffff, 
					              0xff000000, 0xff000000, 0xff000000,
					              0xff000000, 0xff000000, 0xff000000, 
					              0xff000000,0xff000000 };

    printf("Frame Buffer Performance write test...\n");
    for (run = 0; run < PERFORMANCE_RUN_COUNT; ++run) {

        testImage = (unsigned int *) malloc(fbSize);
        j = run;
        for (i = 0; i < (int) (fbSize / sizeof(int)); ++i) {
            testImage[i] = randData[j];
            j++;
            if (j >= 17)
                j = 0;
        }

        gettimeofday(&startTime, NULL);
        memcpy(fb, testImage, fbSize);
        gettimeofday(&endTime, NULL);

        long secsDiff = endTime.tv_sec - startTime.tv_sec;
        results[run] = secsDiff * 1000000
                       + (endTime.tv_usec - startTime.tv_usec);

        free(testImage);
    }
    average = 0;
    for (i = 0; i < PERFORMANCE_RUN_COUNT; ++i)
        average += results[i];
    average = average / PERFORMANCE_RUN_COUNT;

    printf(" Average: %llu usecs\n", average);
    printf(" Bandwidth: %.03f MByte/Sec\n",
           (fbSize / 1048576.0) / ((double) average / 1000000.0));
    printf(" Max. FPS: %.03f fps\n\n", 1000000.0 / (double) average);
    memset(fb, 0, fbSize);
}

static unsigned char sg_BHeader[] =
{
    0x42, 0x4D, 0x36, 0xEC, 0x5E, 0x00, 0x00, 0x00,  0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x28, 0x00,
    0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x38, 0x04,  0x00, 0x00, 0x01, 0x00, 0x18, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x0B,  0x00, 0x00, 0x12, 0x0B, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

void SaveBMPFile(unsigned char *raw, char *filename) {
	
    unsigned long *p = (unsigned long *)raw;
    typedef unsigned int UINT;
    typedef unsigned char UCHAR;
    UINT m_Width = 1920, m_Height = 1080;
    UINT i, j;
    int bmp = open(filename, O_WRONLY | O_CREAT);
    if(bmp < 0)
        return;
    sg_BHeader[0x02] = (UCHAR)(m_Width * m_Height * 3 + 0x36) & 0xff;
    sg_BHeader[0x03] = (UCHAR)((m_Width * m_Height * 3 + 0x36) >> 8) & 0xff;
    sg_BHeader[0x04] = (UCHAR)((m_Width * m_Height * 3 + 0x36) >> 16) & 0xff;
    sg_BHeader[0x05] = (UCHAR)((m_Width * m_Height * 3 + 0x36) >> 24) & 0xff;
    sg_BHeader[0x12] = (UCHAR)m_Width & 0xff;
    sg_BHeader[0x13] = (UCHAR)(m_Width >> 8) & 0xff;
    sg_BHeader[0x14] = (UCHAR)(m_Width >> 16) & 0xff;
    sg_BHeader[0x15] = (UCHAR)(m_Width >> 24) & 0xff;
    sg_BHeader[0x16] = (UCHAR)m_Height & 0xff;
    sg_BHeader[0x17] = (UCHAR)(m_Height >> 8) & 0xff;
    sg_BHeader[0x18] = (UCHAR)(m_Height >> 16) & 0xff;
    sg_BHeader[0x19] = (UCHAR)(m_Height >> 24) & 0xff;
    write(bmp, sg_BHeader, sizeof(sg_BHeader));
    for(i = 0; i < m_Height; i++) {
        unsigned long *c = p + (m_Height - 1 - i) * m_Width;
        unsigned long cc;
        for(j = 0; j < m_Width; j++) {
            cc = *(c + j);
            //cc = *(c + j);
            write(bmp, &cc, 3);
        }
    }
    close(bmp);
}

void performReadSpeedTest(void *fb, int fbSize) {
	
    int i, j, run;
    struct timeval startTime, endTime;
    unsigned long long results[PERFORMANCE_RUN_COUNT];
    unsigned long long average;
    unsigned char *testImage;

    printf("Frame Buffer Performance read test...\n");
    for (run = 0; run < PERFORMANCE_RUN_COUNT; ++run) {

        testImage = (unsigned char *) malloc(fbSize);

        gettimeofday(&startTime, NULL);
        memcpy(testImage, fb, fbSize);
        gettimeofday(&endTime, NULL);

        long secsDiff = endTime.tv_sec - startTime.tv_sec;
        results[run] = secsDiff * 1000000
                       + (endTime.tv_usec - startTime.tv_usec);

    }
    
    average = 0;
    for (i = 0; i < PERFORMANCE_RUN_COUNT; ++i)
        average += results[i];
    average = average / PERFORMANCE_RUN_COUNT;

    printf(" Average: %llu usecs\n", average);
    printf(" Bandwidth: %.03f MByte/Sec\n",
           (fbSize / 1048576.0) / ((double) average / 1000000.0));
    printf(" Max. FPS: %.03f fps\n\n", 1000000.0 / (double) average);
    
    SaveBMPFile(testImage, "./fb_bmp.bmp");
    
    free(testImage);
    memset(fb, 0, fbSize);
}

int WriteBMPtoFB() {
	
    FILE *fp;
    PIXEL pix;
    int rc;
    const char *filename = BMP_PIC_DIR;
    unsigned int line_x = 0, line_y = 0;
    unsigned long tmp, location = 0, BytesPerLine = 0;
    unsigned char *imageBuffer;

    fp = fopen(filename, "rb" );
    if (fp == NULL) {
        printf("no picture!\n");
        exit(1);
    }
    rc = fread( &FileHead, sizeof(BITMAPFILEHEADER),1, fp );
    if ( rc != 1) {
        printf("read header error!\n");
        fclose( fp );
        exit(1);
    }
    if (memcmp(FileHead.cfType, "BM", 2) != 0) {
        printf("it's not a BMP file\n");
        fclose( fp );
        exit(1);
    }
    rc = fread( (char *)&InfoHead, sizeof(BITMAPINFOHEADER),1, fp );
    if ( rc != 1) {
        printf("read infoheader error!\n");
        fclose( fp );
        exit(1);
    }

	//跳转的数据区
    fseek(fp, FileHead.cfoffBits, SEEK_SET);
    printf("FileHead.cfoffBits = %ld\n",FileHead.cfoffBits);
        
	//向framebuffer中写BMP图片
	imageBuffer = (unsigned char *) malloc(screensize);

    while(!feof(fp)) {
	    rc = fread( (char *)&pix, 1, 3, fp);
        location = line_x * bits_per_pixel / 8 + (InfoHead.ciHeight - line_y - 1) * xres * bits_per_pixel / 8;
        //将每个像素填写到imageBuffer中
        imageBuffer[location + 3] = 0xff;
        imageBuffer[location + 2] = (pix.red & 0xff);
        imageBuffer[location + 1] = (pix.green & 0xff);
        imageBuffer[location + 0] = (pix.blue & 0xff);
        
        line_x++;
        if (line_x == InfoHead.ciWidth ) {
            line_x = 0;
            line_y++;

            if(line_y == InfoHead.ciHeight) {
                break;
            }
        }
    }
    memcpy(frameBuffer, imageBuffer, screensize);
   	//memset(frameBuffer, 0, screensize);
    fclose(fp);
    return(0);
}

int main() {
	
    const char *dev = FBDEV;
    int fd = 0;
    
    fd = open(dev, O_RDWR);
    if (fd == -1) {
        printf("Error: cannot open framebuffer device");
        exit(1);
    }

    //获取finfo信息并显示
    if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1) {
        printf("Error reading fixed information");
        exit(1);
    }
    printFixedInfo();
    
    //获取vinfo信息并显示
    if (ioctl(fd, FBIOGET_VSCREENINFO, &vinfo) == -1) {
        printf("Error reading variable information");
        exit(1);
    }
    printVariableInfo();
    
	//屏幕总的字节长度
    screensize = finfo.smem_len;
    
    xres = vinfo.xres;
    yres = vinfo.yres;
    
    bits_per_pixel = vinfo.bits_per_pixel;
    
	//内存映射
    frameBuffer = (char *) mmap(0, screensize, PROT_READ | PROT_WRITE,
                                MAP_SHARED, fd, 0);
    if (frameBuffer == MAP_FAILED) {
        printf("Error: Failed to map framebuffer device to memory");
        exit(1);
    }

    //测试virt fb的性能
    memset(frameBuffer, 0, screensize);
    performWriteSpeedTest(frameBuffer, screensize);
    performReadSpeedTest(frameBuffer, screensize);
    
    printf("Write a 32bpp BMP image to Fb!\n");
    WriteBMPtoFB();
	
    printf(" Done.\n");
    //memset(frameBuffer, 0, screensize);
    //munmap(frameBuffer, screensize);    //解除内存映射,与mmap对应
    close(fd);
    exit(0);
}

 

你可能感兴趣的:(raspberry)