Основываясь на моей работе от этот ответ, Я пытаюсь использовать Qt’s QGLWidget
для рендеринга видео, но у меня есть некоторые проблемы. При сохранении кадра сразу после того, как я декодировал его в моем потоке декодирования видео, он получается просто отлично:
но, рисуя его, он выходит ужасно изуродованным:
Похоже, что изображение копируется, а копия не завершена, но
Я использую мьютекс, чтобы убедиться, что изображение не трогается во время рисования кода.
Я передаю указатель на QImage
к коду рисования, так что это должен быть тот же кусок памяти.
В ветке декодирования у меня есть следующее:
/* 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);
}
Что тут происходит?
Я забыл что 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));
}
Других решений пока нет …