Спасибо за ответы, но я наконец-то снова обратился к этой проблеме и нашел довольно простое решение, которое дает хорошую производительность. Он включает в себя вывод из QGLWidget
и переопределение функции paintEvent()
. Внутри функции paintEvent()
вы можете вызвать QPainter::drawImage(...)
, и она выполнит масштабирование до указанного прямоугольника, используя аппаратное обеспечение, если оно доступно. Так это выглядит примерно так:
class QGLCanvas : public QGLWidget
{
public:
QGLCanvas(QWidget* parent = NULL);
void setImage(const QImage& image);
protected:
void paintEvent(QPaintEvent*);
private:
QImage img;
};
QGLCanvas::QGLCanvas(QWidget* parent)
: QGLWidget(parent)
{
}
void QGLCanvas::setImage(const QImage& image)
{
img = image;
}
void QGLCanvas::paintEvent(QPaintEvent*)
{
QPainter p(this);
//Set the painter to use a smooth scaling algorithm.
p.setRenderHint(QPainter::SmoothPixmapTransform, 1);
p.drawImage(this->rect(), img);
}
При этом мне все еще нужно конвертировать YUV 420P в RGB32, но ffmpeg имеет очень быструю реализацию этого преобразования в libswscale. Основные выгоды связаны с двумя вещами:
- Нет необходимости в программном масштабировании. Масштабирование выполняется на видеокарте (если имеется)
- Преобразование из
QImage
в QPixmap
, которое происходит в функции QPainter::drawImage()
, выполняется с исходным разрешением изображения в отличие от увеличенного полноэкранного разрешения.
Я привязывал свой процессор только к дисплею (декодирование выполнялось в другом потоке) с помощью моего предыдущего метода. Теперь мой поток отображения использует только 8-9% ядра для полноэкранного воспроизведения 1920x1200 с частотой 30 кадров в секунду. Я уверен, что могло бы стать еще лучше, если бы я мог отправлять данные YUV прямо на видеокарту, но на данный момент этого достаточно.