How to draw image in Linux at same time on LCD and HDMI on Raspberry Pi with QT?

为君一笑 提交于 2020-01-06 14:28:22

问题


Does anyone knows how to draw an image in Linux, Raspberry Pi, Qt with double framebuffer in same time. I mean i want to run my application on LCD display and draw image to HDMI in same time.


回答1:


I wrote this code, but I saw a lot of questions on the Internet how to display the image on Linux fraimbuffer. I'll leave it here, maybe someone need help with it. That code was tested on Raspberry Pi 2 model B,B+ and Linux Kernel 4.4.y. with Qt 5.6

File: fbdi.pro

QT += core
QT += gui
QT += widgets
CONFIG += c++11
TARGET = fbdi
CONFIG += console
CONFIG -= app_bundle
TEMPLATE = app
SOURCES += fbdi.cpp

File: fbdi.cpp

#include <QDebug>
#include <QImage>
#include <QRgb>
#include <sys/mman.h>
#include <sys/fcntl.h>
#include <sys/ioctl.h>
#include <linux/fb.h>
#include <unistd.h>

#define FB_ERROR_OPEN_FBD 0x0001  // Could not open the framebuffer device
#define FB_ERROR_READ_FSI 0x0002  // Read fixed display information failed
#define FB_ERROR_READ_VSI 0x0004  // Read variable display information failed
#define FB_ERROR_MAPS_MEM 0x0008  // Mapping memory failed
#define FB_ERROR_LOAD_IMG 0x0016  // Load image file failed
#define FB_ERROR_TRAN_IMG 0x0032  // Transformation image file

struct fb_fix_screeninfo;
struct fb_var_screeninfo;

typedef fb_fix_screeninfo finfo;
typedef fb_var_screeninfo vinfo;

struct linuxfb_t {
    int     device;     // file handler
    uint8_t *data;      // data ptr
    finfo   fix_info;   // fixed display information
    vinfo   var_info;   // variable display information
    int     err_code;   // error code
    char    *err_mesg;  // error mesage
    long    screensize; // calculated screen size
};

///
/// \brief  fb_error     Set error code and message
/// \param  fb           Pointer to struct linuxfb_t
/// \param  code         Error number
/// \param  message      Error message
/// \return bool         Always false
///
bool fb_error(linuxfb_t *fb, int code, QString message)
{
    fb->err_code = code;
    fb->err_mesg = message.toLocal8Bit().data();
    return false;
}

///
/// \brief fb_fatal     Output message if an error accurred
/// \param fb           Pointer to struct linuxfb_t
/// \return int         Error code
///
int fb_fatal(linuxfb_t *fb)
{
    qDebug("Error %d: %s", fb->err_code, fb->err_mesg);
    return fb->err_code;
}


///
/// \brief fb_draw      Draw specified image on linux framebuffer
/// \param fb           Pointer to struct linuxfb_t
/// \param device       Path to linux framebuffer device (eg. /dev/fb0)
/// \param filename     Path to image file which support by Qt
/// \return bool        True if the function success, overwise false
///
bool fb_draw(linuxfb_t *fb, const char *device, const char *filename)
{
    fb->device = open(device, O_RDWR);

    if( fb->device < 0 ) {
        return fb_error(fb, FB_ERROR_OPEN_FBD, QString("Unable to open specified device"));
    }

    if( ioctl(fb->device, FBIOGET_VSCREENINFO, &fb->var_info) ) {
        return fb_error(fb, FB_ERROR_READ_VSI, QString("Unable to read variable screen information"));
    }

    if( ioctl(fb->device, FBIOGET_FSCREENINFO, &fb->fix_info) ) {
        return fb_error(fb, FB_ERROR_READ_FSI, QString("Unable to get fixed screen information"));
    }

    fb->screensize = fb->var_info.xres * fb->var_info.yres * (fb->var_info.bits_per_pixel/8);
    fb->data = (uint8_t *) mmap(0, fb->screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fb->device, (off_t) 0);

    if( (intptr_t) fb->data == -1 ) {
        return fb_error(fb, FB_ERROR_MAPS_MEM, QString("Failed to map framebuffer device to memory"));
    }

    QImage img_orig;
    if( !img_orig.load(filename) ) {
        munmap(fb->data, fb->screensize);
        close(fb->device);
        return fb_error(fb, FB_ERROR_LOAD_IMG, "Could not open the file you specified");
    }

    QImage img_trans;
    img_trans = img_orig.scaled(fb->var_info.xres, fb->var_info.yres);
    if( img_trans.isNull() ) {
        munmap(fb->data, fb->screensize);
        close(fb->device);
        return fb_error(fb, FB_ERROR_TRAN_IMG, "Could not transform image");
    }

    for( uint32_t x=0; x < fb->var_info.xres; x++ ) {
        for( uint32_t y=0; y < fb->var_info.yres; y++ ) {
            long location = (x+fb->var_info.xoffset) * (fb->var_info.bits_per_pixel/8) +
                            (y+fb->var_info.yoffset) * fb->fix_info.line_length;

            QRgb color = img_trans.pixel(x,y);
            uint32_t pixel = (qRed(color)<<fb->var_info.red.offset)     |
                             (qGreen(color)<<fb->var_info.green.offset) |
                             (qBlue(color)<<fb->var_info.blue.offset)   ;

            *((uint32_t*)(fb->data+location)) = pixel;
        }
    }

    munmap(fb->data, fb->screensize);
    close(fb->device);

    return true;
}

///
/// \brief  main Application entry point
/// \return result
///
int main()
{
    // Create linuxfb variable
    linuxfb_t fb;

    // Output some image
    if( !fb_draw(&fb, "/dev/fb0", "/tmp/test.png") ) {

        // Failed
        return fb_fatal(&fb);
    }

    // success
    return 0;
}


来源:https://stackoverflow.com/questions/37945051/how-to-draw-image-in-linux-at-same-time-on-lcd-and-hdmi-on-raspberry-pi-with-qt

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!