You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Qt中如何在paintEvent中使用API视频数据构造的QImage?

问题分析与解决方案

核心问题:QImage浅拷贝导致内存失效

你当前用QImage(pData, width, height, bytesPerRow, QImage::Format_Indexed8)构造的QImage是浅拷贝模式——它不会复制传入的pData内存,只是保存指针引用。当API回调结束后,pData指向的内存很可能被释放或覆盖,等到paintEvent执行时,m_srcImage的内部数据已经失效,表现为isNull()为true。

另外还有两个次要问题:

  • RenderClass构造函数里初始化m_srcImage(nullptr)错误,QImage是值类型,不是指针,应该用默认初始化。
  • 信号连接用了Qt::DirectConnection,如果API回调在非UI线程触发,槽函数会在非UI线程执行,操作QOpenGLWidget相关对象会触发线程安全问题。

修复步骤

1. 改为QImage深拷贝

在槽函数receiveFrameData中,构造临时QImage后调用copy()生成深拷贝的图像,确保m_srcImage拥有独立的内存:

void RenderClass::receiveFrameData(uchar* pData, int width, int height, int bytesPerRow) 
{
    // 先构造临时浅拷贝QImage,再调用copy()生成深拷贝
    QImage tempImage(pData, width, height, bytesPerRow, QImage::Format_Indexed8);
    m_srcImage = tempImage.copy();
            
    qDebug() << "Slot is called." << m_srcImage;
    update(); // 触发paintEvent重绘
}

2. 修正RenderClass构造函数的初始化

把错误的指针初始化改成QImage默认构造:

RenderClass::RenderClass(QWidget* parent) :
    QOpenGLWidget(parent),
    m_srcImage() // 值类型默认初始化,替代nullptr
{
}

3. 调整信号连接类型为队列连接

确保槽函数在UI线程执行,避免跨线程操作UI对象:

const bool connected = QObject::connect(this, &GrabberClass::sendFrameData, 
                                        m_renderClass, &RenderClass::receiveFrameData, 
                                        Qt::QueuedConnection); // 替换DirectConnection
Q_ASSERT(connected);

4. 可选:确保图像格式匹配

如果是Indexed8格式,需要确认颜色表(color table)是否正确。如果API返回的是灰度图,你可以手动设置颜色表:

void RenderClass::receiveFrameData(uchar* pData, int width, int height, int bytesPerRow) 
{
    QImage tempImage(pData, width, height, bytesPerRow, QImage::Format_Indexed8);
    // 为灰度图生成颜色表
    QVector<QRgb> colorTable(256);
    for (int i = 0; i < 256; ++i) {
        colorTable[i] = qRgb(i, i, i);
    }
    tempImage.setColorTable(colorTable);
    m_srcImage = tempImage.copy();
            
    update();
}

原理说明

  • 深拷贝后的QImage会独立管理图像数据内存,不受原pData生命周期影响,确保paintEvent调用时数据有效。
  • Qt::QueuedConnection会把槽函数调用放入UI线程的事件队列,保证所有UI相关操作都在主线程执行,符合Qt的线程安全规则。
  • QOpenGLWidget的paintEvent会在主线程触发,此时访问m_srcImage是安全的,只要m_srcImage是有效的深拷贝图像,就能正常绘制。

内容的提问来源于stack exchange,提问作者taathy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 05:06:36