From bf3b9239b572b16abd7f0016ebbec13cff935679 Mon Sep 17 00:00:00 2001 From: tux3 Date: Sat, 16 May 2015 13:16:41 +0200 Subject: [PATCH] Never resize frames with Qt, use sws_scale If we're going to convert between pixel formats with sws_scale, we might as well do the rescaling in the same step. Giving a potentially hueg fram to Qt and having it rescale in a separate step is wasted cycles. --- src/video/videoframe.cpp | 45 ++++++++++++++++++++++++++++--------- src/video/videoframe.h | 7 ++++-- src/widget/videosurface.cpp | 9 +++++--- 3 files changed, 45 insertions(+), 16 deletions(-) diff --git a/src/video/videoframe.cpp b/src/video/videoframe.cpp index 6e42fe70a..0c0be6b84 100644 --- a/src/video/videoframe.cpp +++ b/src/video/videoframe.cpp @@ -52,14 +52,14 @@ VideoFrame::~VideoFrame() releaseFrameLockless(); } -QImage VideoFrame::toQImage() +QImage VideoFrame::toQImage(QSize size) { - if (!convertToRGB24()) + if (!convertToRGB24(size)) return QImage(); QMutexLocker locker(&biglock); - return QImage(*frameRGB24->data, width, height, *frameRGB24->linesize, QImage::Format_RGB888); + return QImage(*frameRGB24->data, frameRGB24->width, frameRGB24->height, *frameRGB24->linesize, QImage::Format_RGB888); } vpx_image *VideoFrame::toVpxImage() @@ -86,13 +86,10 @@ vpx_image *VideoFrame::toVpxImage() return img; } -bool VideoFrame::convertToRGB24() +bool VideoFrame::convertToRGB24(QSize size) { QMutexLocker locker(&biglock); - if (frameRGB24) - return true; - AVFrame* sourceFrame; if (frameOther) { @@ -108,6 +105,22 @@ bool VideoFrame::convertToRGB24() return false; } + if (size.isEmpty()) + { + size.setWidth(sourceFrame->width); + size.setHeight(sourceFrame->height); + } + + if (frameRGB24) + { + if (frameRGB24->width == size.width() && frameRGB24->height == size.height()) + return true; + + av_free(frameRGB24->opaque); + av_frame_unref(frameRGB24); + av_frame_free(&frameRGB24); + } + frameRGB24=av_frame_alloc(); if (!frameRGB24) { @@ -115,7 +128,7 @@ bool VideoFrame::convertToRGB24() return false; } - uint8_t* buf = (uint8_t*)av_malloc(avpicture_get_size(AV_PIX_FMT_RGB24, width, height)); + uint8_t* buf = (uint8_t*)av_malloc(avpicture_get_size(AV_PIX_FMT_RGB24, size.width(), size.height())); if (!buf) { qCritical() << "av_malloc failed"; @@ -124,11 +137,16 @@ bool VideoFrame::convertToRGB24() } frameRGB24->opaque = buf; - avpicture_fill((AVPicture*)frameRGB24, buf, AV_PIX_FMT_RGB24, width, height); + avpicture_fill((AVPicture*)frameRGB24, buf, AV_PIX_FMT_RGB24, size.width(), size.height()); + frameRGB24->width = size.width(); + frameRGB24->height = size.height(); + + // Bilinear is better for shrinking, bicubic better for upscaling + int resizeAlgo = size.width()<=width ? SWS_BILINEAR : SWS_BICUBIC; SwsContext *swsCtx = sws_getContext(width, height, (AVPixelFormat)pixFmt, - width, height, AV_PIX_FMT_RGB24, - SWS_BILINEAR, nullptr, nullptr, nullptr); + size.width(), size.height(), AV_PIX_FMT_RGB24, + resizeAlgo, nullptr, nullptr, nullptr); sws_scale(swsCtx, (uint8_t const * const *)sourceFrame->data, sourceFrame->linesize, 0, height, frameRGB24->data, frameRGB24->linesize); @@ -216,3 +234,8 @@ void VideoFrame::releaseFrameLockless() av_frame_free(&frameRGB24); } } + +QSize VideoFrame::getSize() +{ + return {width, height}; +} diff --git a/src/video/videoframe.h b/src/video/videoframe.h index 67433ca81..9191c0a4d 100644 --- a/src/video/videoframe.h +++ b/src/video/videoframe.h @@ -37,18 +37,21 @@ public: VideoFrame(AVFrame* frame, int w, int h, int fmt, std::function freelistCallback); ~VideoFrame(); + /// Return the size of the original frame + QSize getSize(); + /// Frees all internal buffers and frame data, removes the freelistCallback /// This makes all converted objects that shares our internal buffers invalid void releaseFrame(); /// Converts the VideoFrame to a QImage that shares our internal video buffer - QImage toQImage(); + QImage toQImage(QSize size = QSize()); /// Converts the VideoFrame to a vpx_image_t that shares our internal video buffer /// Free it with operator delete, NOT vpx_img_free vpx_image* toVpxImage(); protected: - bool convertToRGB24(); + bool convertToRGB24(QSize size = QSize()); bool convertToYUV420(); void releaseFrameLockless(); diff --git a/src/widget/videosurface.cpp b/src/widget/videosurface.cpp index 710a4c0c9..5eff9b61c 100644 --- a/src/widget/videosurface.cpp +++ b/src/widget/videosurface.cpp @@ -15,6 +15,7 @@ #include "videosurface.h" #include "src/video/videoframe.h" #include +#include VideoSurface::VideoSurface(QWidget* parent) : QWidget{parent} @@ -102,12 +103,14 @@ void VideoSurface::paintEvent(QPaintEvent*) painter.fillRect(painter.viewport(), Qt::black); if (lastFrame) { + QSize frameSize = lastFrame->getSize(); QRect rect = painter.viewport(); - QImage frame = lastFrame->toQImage(); - int width = frame.width()*rect.height()/frame.height(); + int width = frameSize.width()*rect.height()/frameSize.height(); rect.setLeft((rect.width()-width)/2); rect.setWidth(width); - painter.drawImage(rect, frame); + + QImage frame = lastFrame->toQImage(rect.size()); + painter.drawImage(rect, frame, frame.rect(), Qt::NoFormatConversion); } frameLock = false; }