Bootstrap

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源代码就行。

;