Qt:如何使QImage知道更新的内存缓冲区?

时间:2019-04-26 14:39:39

标签: c++ qt vnc-viewer

我需要绘制由库保存为uint8_t *且经常且部分更新的像素数据。每次完成更新后,我都会从库中收到一个回调,如下所示:

void gotFrameBufferUpdate(int x, int y, int w, int h);

我尝试使用像素数据指针创建QImage

QImage bufferImage(frameBuffer, width, height, QImage::Format_RGBX8888);

然后让回调触发我的窗口小部件update()

void gotFrameBufferUpdate(int x, int y, int w, int h)
{
    update(QRect(QPoint(x, y), QSize(w, h)));
}

只需通过paint()绘制QImage的更新区域:

void MyWidget::paint(QPainter *painter)
{
    QRect rect = painter->clipBoundingRect().toRect();
    painter->drawImage(rect, bufferImage, rect);
}

这种方法的问题在于QImage似乎没有反映出像素缓冲区的任何更新。它一直显示其初始内容。

我当前的解决方法是每次更新缓冲区时重新创建一个QImage实例:

void gotFrameBufferUpdate(int x, int y, int w, int h)
{
    if (bufferImage)
        delete bufferImage;
    bufferImage = new QImage(frameBuffer, width, height,
                             QImage::Format_RGBX8888);

    update(QRect(QPoint(x, y), QSize(w, h)));
}

这有效,但对我来说似乎效率很低。有没有更好的方法来处理Qt中外部更新的像素数据?我可以让QImage知道其内存缓冲区的更新吗?

(背景:我正在使用C ++后端编写自定义QML类型,该类型应显示VNC会话的内容。为此,我使用LibVNC/libvncclient。)

3 个答案:

答案 0 :(得分:1)

如果调用 QImage::bits(),则更新 QImage。

它不会分配新的缓冲区,您可以丢弃结果,但它会神奇地触发图像的刷新。 每次想要刷新时都需要它。

我不知道这是否是有保证的行为,也不知道它是否比重新创建它节省了任何东西。

答案 1 :(得分:0)

我猜想某种缓存机制会干扰您的期望。 QImage有一个cacheKey,如果更改了QImage,它会更改。当然,只有通过QImage函数更改图像时,才会发生这种情况。据我所知,您正在直接更改基础缓冲区,因此QImage的{​​{1}}将保持不变。然后,Qt的像素图缓存在其缓存中具有该键,并出于性能原因而使用了缓存的像素图。

不幸的是,似乎没有直接的方法可以更新此cacheKey或“无效” cacheKey。您有两种选择:

  1. 在需要时重新创建QImage。无需QImage,因此您可以保存堆分配。创建后缓冲new似乎是“便宜”的操作,因此我怀疑这是一个瓶颈。
  2. QImage进行微不足道的操作(即在单个像素上将setPixel变黑,然后恢复到旧值)。这有点“骇人听闻”,但可能是解决此API缺陷的最有效方法(据我所知,它将触发对QImage的更新)。

答案 2 :(得分:0)

AFAICT QImage类已经按照您认为的方式工作了-尤其是,简单地写入外部帧缓冲区确实会更新QImage的内容。我的猜测是,在您的程序中,其他一些代码将QImage数据复制到内部的某个地方的QPixmap中(因为QPixmap将始终以硬件的本机格式存储其内部缓冲区因此重复绘制到屏幕上会更有效),并且QPixmap不会在frameBuffer更新时被修改。

为证明QImage实际上始终包含来自frameBuffer的数据,以下是一个程序,该程序每次您单击窗口时都会在其帧缓冲区中写入一种新颜色,然后调用{{ 1}}强制小部件重新绘制自身。我看到该小部件在每次单击鼠标时都会更改颜色:

update()