来自原始像素数据的QImage损坏

时间:2013-07-02 14:19:42

标签: c++ multithreading qt bitmap qimage

基于我this answer的工作,我试图使用Qt的QGLWidget来渲染视频,但我遇到了一些问题。在我在视频解码线程中解码后立即保存帧时,它就出来了:

intact frame

但是在绘制时,它出现了可怕的损坏:

mangled frame

似乎正在复制图像并且副本没有完成,但是

  1. 我正在使用互斥锁来确保在绘图代码绘图时不会触摸图像。

  2. 我将指向QImage的指针传递给绘图代码,因此它应该是相同的内存块。

  3. 在解码线程中,我有以下内容:

    /* Read in the frame up here, skipped for brevity */
    
    // Set a new image
    auto frameImage = make_shared<QImage>(nextFrame->getPixels(),
                                          nextFrame->getWidth(),
                                          nextFrame->getHeight(),
                                          QImage::Format_RGB888);
    
    canvas->setImage(frameImage);
    // Post a new order to repaint.
    // Done this way because another thread cannot directly call repaint()
    QCoreApplication::postEvent(canvas, new QPaintEvent(canvas->rect()));
    

    然后,在画布(源自QGLWidget):

    void QGLCanvas::setImage(const std::shared_ptr<QImage>& image)
    {
        // Keep the QGL canvas from drawing while we change the image
        lock_guard<mutex> pixelLock(pixelsMutex);
        img = image; // img is just a shared_ptr
    }
    
    void QGLCanvas::paintEvent(QPaintEvent*)
    {
        QPainter painter(this);
        painter.setRenderHint(QPainter::SmoothPixmapTransform, 1);
    
        // Lock the image so that other threads can't access it at the same time
        lock_guard<mutex> pixelLock(pixelsMutex);
        painter.drawImage(this->rect(), *img);
    }
    

    这里发生了什么?

1 个答案:

答案 0 :(得分:1)

我忘了QImage,当给定像素数据时,是浅拷贝,而不是深拷贝。只要QImage存在,就可以通过保持分配的实际帧数据来解决问题,如下所示:

void QGLCanvas::setFrame(const std::shared_ptr<VideoFrame>& newFrame)
{
    // Keep the QGL canvas from drawing while we change the image
    lock_guard<mutex> pixelLock(pixelsMutex);

    // Keep a shared_ptr reference to our frame data
    frame = newFrame;

    // Create a new QImage, which is just a shallow copy of the frame.
    img.reset(new QImage(frame->getPixels(),
                         frame->getWidth(),
                         frame->getHeight(),
                         QImage::Format_RGB888));
}