如何使用 QT 在 Raspberry Pi 上的 LCD 和 HDMI 上同时在 Linux 中绘制图像?

Posted

技术标签:

【中文标题】如何使用 QT 在 Raspberry Pi 上的 LCD 和 HDMI 上同时在 Linux 中绘制图像?【英文标题】:How to draw image in Linux at same time on LCD and HDMI on Raspberry Pi with QT? 【发布时间】:2016-06-21 12:54:06 【问题描述】:

有谁知道如何在 Linux、Raspberry Pi、Qt 中同时使用双帧缓冲区绘制图像。 我的意思是我想在 LCD 显示器上运行我的应用程序并同时将图像绘制到 HDMI时间。

【问题讨论】:

我认为这种事情的首选格式是提出问题,然后自己回答。您可能需要多解释一下,以便将来的读者清楚。 这不是问题!请将所有答案放入答案中,然后将问题编辑为问题。回答你自己的问题完全没问题! 为什么要添加额外的代码,而不是仅仅在其环境中使用QT_QPA_PLATFORM=linuxfbQT_QPA_GENERIC_PLUGINS=evdevtouch,evdevmouse,evdevkeyboardQT_QPA_EVDEV_KEYBOARD_PARAMETERS=grab=1 运行您的程序 - 这不是使用跨平台库的全部意义,例如Qt? 因为您不能在 QT 中同时使用双帧缓冲区。尝试使用 /dev/fb1 执行您的程序并将图像设置为 /dev/fb0 - 这就是该代码存在的原因。玩得开心 【参考方案1】:

我写了这段代码,但是在网上看到很多关于如何在Linux fraimbuffer上显示图像的问题。我会把它留在这里,也许有人需要帮助。该代码在 Raspberry Pi 2 型号 B、B+ 和 Linux Kernel 4.4.y 上进行了测试。使用 Qt 5.6

文件:fbdi.pro

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

文件: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;

【讨论】:

以上是关于如何使用 QT 在 Raspberry Pi 上的 LCD 和 HDMI 上同时在 Linux 中绘制图像?的主要内容,如果未能解决你的问题,请参考以下文章

我们如何在Qt工具包(Qt)应用程序中读取已挂载(Raspberry pi)usb中的所有mp3文件

Qt Raspberry Pi 3 Linux 键盘输入

我们如何在 Qt 工具包(Qt)应用程序中读取已安装(Raspberry pi)usb 中的所有 mp3 文件

如何从 Raspberry Pi 上的动作中获取 .mp4 视频?

使用 GPIO 后 Raspberry Pi 上的 SPI 重置

无法从 qt5.6 源代码为 raspberry pi 2 构建 qtwebengine