QT使用 Linux framebuffer时候 支持QT本身不支持的其他格式(例如支持argb4444)的一种取巧方法,

        工作中遇到一个问题,就是使用QT作为界面库,但是由于底层编解码在叠加OSD的时候,如果使用argb32(QImage::Format_ARGB32)的时候,4K的图像图片太大,编解码叠加导致性能不足等问题,所以需要图片压缩成argb4444的格式来规避性能问题。不想搞插件,只说说我的做方法,愿意用插件的自己搞。

      由于framebuffer映射上来的格式是argb4444,所以上层需要修改QT源代码 qt-everywhere-src-5.14.2/qtbase/src/plugins/platforms/linuxfb下qlinuxfbscreen.cpp文件和qlinuxfbscreen.h文件,

        1、使映射到QT上层的framebuffer的格式为QImage::Format_ARGB32,主要修改函数:      bool QLinuxFbScreen::initialize()

bool QLinuxFbScreen::initialize()
{
    QRegularExpression ttyRx(QLatin1String("tty=(.*)"));
    QRegularExpression fbRx(QLatin1String("fb=(.*)"));
    QRegularExpression mmSizeRx(QLatin1String("mmsize=(\\d+)x(\\d+)"));
    QRegularExpression sizeRx(QLatin1String("size=(\\d+)x(\\d+)"));
    QRegularExpression offsetRx(QLatin1String("offset=(\\d+)x(\\d+)"));

    QString fbDevice, ttyDevice;
    QSize userMmSize;
    QRect userGeometry;
    bool doSwitchToGraphicsMode = true;

    // Parse arguments
    for (const QString &arg : qAsConst(mArgs)) {
        QRegularExpressionMatch match;
        if (arg == QLatin1String("nographicsmodeswitch"))
            doSwitchToGraphicsMode = false;
        else if (arg.contains(mmSizeRx, &match))
            userMmSize = QSize(match.captured(1).toInt(), match.captured(2).toInt());
        else if (arg.contains(sizeRx, &match))
            userGeometry.setSize(QSize(match.captured(1).toInt(), match.captured(2).toInt()));
        else if (arg.contains(offsetRx, &match))
            userGeometry.setTopLeft(QPoint(match.captured(1).toInt(), match.captured(2).toInt()));
        else if (arg.contains(ttyRx, &match))
            ttyDevice = match.captured(1);
        else if (arg.contains(fbRx, &match))
            fbDevice = match.captured(1);
    }

    if (fbDevice.isEmpty()) {
        fbDevice = QLatin1String("/dev/fb0");
        if (!QFile::exists(fbDevice))
            fbDevice = QLatin1String("/dev/graphics/fb0");
        if (!QFile::exists(fbDevice)) {
            qWarning("Unable to figure out framebuffer device. Specify it manually.");
            return false;
        }
    }

    // Open the device
    mFbFd = openFramebufferDevice(fbDevice);
    if (mFbFd == -1) {
        qErrnoWarning(errno, "Failed to open framebuffer %s", qPrintable(fbDevice));
        return false;
    }

    // Read the fixed and variable screen information
    fb_fix_screeninfo finfo;
    fb_var_screeninfo vinfo;
    memset(&vinfo, 0, sizeof(vinfo));
    memset(&finfo, 0, sizeof(finfo));

	

	//bkspidex
	fb_fix_screeninfo finfo32;
    fb_var_screeninfo vinfo32;
    memset(&vinfo32, 0, sizeof(vinfo32));
    memset(&finfo32, 0, sizeof(finfo32));
	//bkspidex

    if (ioctl(mFbFd, FBIOGET_FSCREENINFO, &finfo) != 0) {
        qErrnoWarning(errno, "Error reading fixed information");
        return false;
    }

    if (ioctl(mFbFd, FBIOGET_VSCREENINFO, &vinfo)) {
        qErrnoWarning(errno, "Error reading variable information");
        return false;
    }



    mDepth = 32;//determineDepth(vinfo);
    mBytesPerLine = finfo.line_length * 2;
	
	
    QRect geometry = determineGeometry(vinfo, userGeometry);
    mGeometry = QRect(QPoint(0, 0), geometry.size());
    mFormat = QImage::Format_ARGB32;//determineFormat(vinfo, mDepth);
    mPhysicalSize = determinePhysicalSize(vinfo, userMmSize, geometry.size());

    // mmap the framebuffer
    mMmap.size = finfo.smem_len;
    uchar *data = (unsigned char *)mmap(0, mMmap.size, PROT_READ | PROT_WRITE, MAP_SHARED, mFbFd, 0);
    if ((long)data == -1) {
        qErrnoWarning(errno, "Failed to mmap framebuffer");
        return false;
    }	

	//bkspidex
    mMmap.offset = geometry.y() * mBytesPerLine / 2 + geometry.x() * mDepth / 8 / 2;
    mMmap.data = data + mMmap.offset;

	//bkspidex
	data32 = (unsigned char *)malloc(mMmap.size * 2);
    if ((long)data32 == 0) {
        qErrnoWarning(errno, "Failed to malloc data32");
        return false;
    }
	memset(data32, 0, mMmap.size * 2);

	datatemp = (unsigned char *)malloc(mMmap.size);
	if ((long)datatemp == 0) {
		qErrnoWarning(errno, "Failed to malloc datatemp");
		return false;
	}
	memset(datatemp, 0, mMmap.size);


	qDebug() << "    mDepth: " << determineDepth(vinfo);
	qDebug() << "    finfo.line_length: " << finfo.line_length;
	qDebug() << "    finfo.smem_len: " << finfo.smem_len;
	qDebug() << "    mMmap.size: " << mMmap.size;
	qDebug() << "    mMmap.offset: " << mMmap.offset;
	qDebug() << "    mMmap.data: " << mMmap.data;
	
	qDebug() << "	 geometry.x(): " << geometry.x();
	qDebug() << "	 geometry.y(): " << geometry.y();
	qDebug() << "	 geometry.size(): " << geometry.size();

	qDebug() << "	 mPhysicalSize: " << mPhysicalSize;
	

	
	//bkspidex
	

    QFbScreen::initializeCompositor();
    //mFbScreenImage = QImage(mMmap.data, geometry.width(), geometry.height(), mBytesPerLine, mFormat);
    mFbScreenImage = QImage(data32, geometry.width(), geometry.height(), mBytesPerLine, QImage::Format_ARGB32);

    mCursor = new QFbCursor(this);

    mTtyFd = openTtyDevice(ttyDevice);
    if (mTtyFd == -1)
        qErrnoWarning(errno, "Failed to open tty");

    switchToGraphicsMode(mTtyFd, doSwitchToGraphicsMode, &mOldTtyMode);
    blankScreen(mFbFd, false);

    return true;
}

    

        2、将QT写入到framebufferd 数据转化成argb4444,主要修改函数:

QRegion QLinuxFbScreen::doRedraw()        

QRegion QLinuxFbScreen::doRedraw()
{
	//qDebug() << "	 doRedraw: " << 1;


    QRegion touched = QFbScreen::doRedraw();

	//qDebug() << "	 doRedraw: " << 2;

    if (touched.isEmpty())
        return touched;

	//qDebug() << "	 doRedraw: " << 3;

    if (!mBlitter)
        mBlitter = new QPainter(&mFbScreenImage);

	//qDebug() << "	 doRedraw: " << 4;

    mBlitter->setCompositionMode(QPainter::CompositionMode_Source);

	//qDebug() << "	 doRedraw: " << 5;
    for (const QRect &rect : touched)
        mBlitter->drawImage(rect, mScreenImage, rect);

	//qDebug() << "	 doRedraw: " << 6;

	//bkspidex
	int i = 0;
	memset(datatemp, 0, mMmap.size);
	uchar* data4444 = datatemp;
	uchar* data8888 = data32;

	//qDebug() << "	 doRedraw: " << 7;
	
	for(i = 0; i < (mMmap.size * 2); i += 4)
	{
		//b g r a 
		uchar b = *data8888;
		data8888++;
		uchar g = *data8888;
		data8888++;
		uchar r = *data8888;
		data8888++;
		uchar a = *data8888;
		data8888++;
		
		*data4444 = ((b >> 4) | ((g >> 4) << 4));
		data4444++;
		*data4444 = ((r >> 4) | ((a >> 4) << 4));
		data4444++;		
	}

	//qDebug() << "	 doRedraw: " << 8;

	memcpy(mMmap.data, datatemp, mMmap.size);

	//qDebug() << "	 doRedraw: " << 9;
	
	
    return touched;
}

        3、完成后需要重启编译QT源代码就行。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Qt is a popular cross-platform framework for developing graphical user interfaces (GUI) and applications. It provides support for Linux framebuffer, which allows you to create GUI applications that can run directly on the Linux framebuffer without the need for an X server. To use Qt with Linux framebuffer, you can follow these general steps: 1. Install the required dependencies: Make sure you have the necessary libraries and development packages installed on your Linux system. This may include framebuffer-related libraries like `libdrm` and `libgbm`. 2. Configure Qt with framebuffer support: When building Qt from source, you can enable framebuffer support by passing the `-qt-libinput` flag to the `configure` script. For example: ``` ./configure -qt-libinput ``` 3. Build your Qt application: Once Qt is configured with framebuffer support, you can build your application using the `qmake` and `make` commands as usual. Make sure to set the appropriate target platform, such as `linuxfb`. 4. Run your Qt application on the Linux framebuffer: After building your application, you can run it directly on the Linux framebuffer by setting the appropriate environment variables. For example: ``` export QT_QPA_PLATFORM=linuxfb export QT_QPA_FB_TTY=/dev/fb0 ./your_application ``` By following these steps, you should be able to develop and run Qt applications using the Linux framebuffer as the target platform. Keep in mind that framebuffer support may vary depending on your specific Linux distribution and hardware setup.

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值