qv4l2: add video scaling for CaptureWin
authorBård Eirik Winther <bwinther@cisco.com>
Thu, 8 Aug 2013 11:31:24 +0000 (11:31 +0000)
committerHans Verkuil <hans.verkuil@cisco.com>
Thu, 8 Aug 2013 12:46:35 +0000 (14:46 +0200)
Signed-off-by: Bård Eirik Winther <bwinther@cisco.com>
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
utils/qv4l2/capture-win-gl.cpp
utils/qv4l2/capture-win-gl.h
utils/qv4l2/capture-win-qt.cpp
utils/qv4l2/capture-win-qt.h
utils/qv4l2/capture-win.cpp
utils/qv4l2/capture-win.h
utils/qv4l2/qv4l2.cpp
utils/qv4l2/qv4l2.h

index c8238c5..27ff3d3 100644 (file)
@@ -43,6 +43,15 @@ void CaptureWinGL::stop()
 #endif
 }
 
+void CaptureWinGL::resizeEvent(QResizeEvent *event)
+{
+#ifdef HAVE_QTGL
+       QSize margins = getMargins();
+       m_videoSurface.setSize(width() - margins.width(), height() - margins.height());
+#endif
+       event->accept();
+}
+
 void CaptureWinGL::setFrame(int width, int height, __u32 format, unsigned char *data, const QString &info)
 {
 #ifdef HAVE_QTGL
@@ -109,11 +118,22 @@ void CaptureWinGLEngine::initializeGL()
        checkError("InitializeGL");
 }
 
+void CaptureWinGLEngine::setSize(int width, int height)
+{
+       QSize sizedFrame = CaptureWin::scaleFrameSize(QSize(width, height), QSize(m_frameWidth, m_frameHeight));
+
+       width = sizedFrame.width();
+       height = sizedFrame.height();
+
+       if (width > 0 && height > 0) {
+               setMaximumSize(width, height);
+               resizeGL(width, height);
+       }
+}
 
 void CaptureWinGLEngine::resizeGL(int width, int height)
 {
-       // Resizing is disabled by setting viewport equal to frame size
-       glViewport(0, 0, m_frameWidth, m_frameHeight);
+       glViewport(0, 0, width, height);
 }
 
 void CaptureWinGLEngine::setFrame(int width, int height, __u32 format, unsigned char *data)
@@ -123,8 +143,6 @@ void CaptureWinGLEngine::setFrame(int width, int height, __u32 format, unsigned
                m_frameWidth = width;
                m_frameHeight = height;
                m_frameFormat = format;
-
-               QGLWidget::setMaximumSize(m_frameWidth, m_frameHeight);
        }
 
        m_frameData = data;
index 6e64269..0c3ff8b 100644 (file)
@@ -23,6 +23,8 @@
 #include "qv4l2.h"
 #include "capture-win.h"
 
+#include <QResizeEvent>
+
 #ifdef HAVE_QTGL
 #define GL_GLEXT_PROTOTYPES
 #include <QGLWidget>
@@ -42,6 +44,7 @@ public:
        void stop();
        void setFrame(int width, int height, __u32 format, unsigned char *data);
        bool hasNativeFormat(__u32 format);
+       void setSize(int width, int height);
 
 protected:
        void paintGL();
@@ -90,6 +93,10 @@ public:
        bool hasNativeFormat(__u32 format);
        static bool isSupported();
 
+protected:
+       void resizeEvent(QResizeEvent *event);
+
+private:
 #ifdef HAVE_QTGL
        CaptureWinGLEngine m_videoSurface;
 #endif
index 63c77d5..f746379 100644 (file)
@@ -24,6 +24,8 @@ CaptureWinQt::CaptureWinQt() :
 {
 
        CaptureWin::buildWindow(&m_videoSurface);
+       m_scaledFrame.setWidth(0);
+       m_scaledFrame.setHeight(0);
 }
 
 CaptureWinQt::~CaptureWinQt()
@@ -31,6 +33,19 @@ CaptureWinQt::~CaptureWinQt()
        delete m_frame;
 }
 
+void CaptureWinQt::resizeEvent(QResizeEvent *event)
+{
+       if (m_frame->bits() == NULL)
+               return;
+
+       QPixmap img = QPixmap::fromImage(*m_frame);
+       m_scaledFrame = scaleFrameSize(QSize(m_videoSurface.width(), m_videoSurface.height()),
+                                      QSize(m_frame->width(), m_frame->height()));
+       img = img.scaled(m_scaledFrame.width(), m_scaledFrame.height(), Qt::IgnoreAspectRatio);
+       m_videoSurface.setPixmap(img);
+       QWidget::resizeEvent(event);
+}
+
 void CaptureWinQt::setFrame(int width, int height, __u32 format, unsigned char *data, const QString &info)
 {
        QImage::Format dstFmt;
@@ -41,6 +56,8 @@ void CaptureWinQt::setFrame(int width, int height, __u32 format, unsigned char *
        if (m_frame->width() != width || m_frame->height() != height || m_frame->format() != dstFmt) {
                delete m_frame;
                m_frame = new QImage(width, height, dstFmt);
+               m_scaledFrame = scaleFrameSize(QSize(m_videoSurface.width(), m_videoSurface.height()),
+                                              QSize(m_frame->width(), m_frame->height()));
        }
 
        if (data == NULL || !supported)
@@ -49,7 +66,11 @@ void CaptureWinQt::setFrame(int width, int height, __u32 format, unsigned char *
                memcpy(m_frame->bits(), data, m_frame->numBytes());
 
        m_information.setText(info);
-       m_videoSurface.setPixmap(QPixmap::fromImage(*m_frame));
+
+       QPixmap img = QPixmap::fromImage(*m_frame);
+       img = img.scaled(m_scaledFrame.width(), m_scaledFrame.height(), Qt::IgnoreAspectRatio);
+
+       m_videoSurface.setPixmap(img);
 }
 
 bool CaptureWinQt::hasNativeFormat(__u32 format)
index d192045..6029109 100644 (file)
@@ -25,6 +25,7 @@
 
 #include <QLabel>
 #include <QImage>
+#include <QResizeEvent>
 
 class CaptureWinQt : public CaptureWin
 {
@@ -39,10 +40,14 @@ public:
        bool hasNativeFormat(__u32 format);
        static bool isSupported() { return true; }
 
+protected:
+       void resizeEvent(QResizeEvent *event);
+
 private:
        bool findNativeFormat(__u32 format, QImage::Format &dstFmt);
 
        QImage *m_frame;
        QLabel m_videoSurface;
+       QSize m_scaledFrame;
 };
 #endif
index 8722066..33f7084 100644 (file)
 #include <QApplication>
 #include <QDesktopWidget>
 
-CaptureWin::CaptureWin()
+#define MIN_WIN_SIZE_WIDTH 160
+#define MIN_WIN_SIZE_HEIGHT 120
+
+bool CaptureWin::m_enableScaling = true;
+
+CaptureWin::CaptureWin() :
+       m_curWidth(-1),
+       m_curHeight(-1)
 {
        setWindowTitle("V4L2 Capture");
        m_hotkeyClose = new QShortcut(Qt::CTRL+Qt::Key_W, this);
-       QObject::connect(m_hotkeyClose, SIGNAL(activated()), this, SLOT(close()));
+       connect(m_hotkeyClose, SIGNAL(activated()), this, SLOT(close()));
 }
 
 CaptureWin::~CaptureWin()
@@ -61,30 +68,72 @@ QSize CaptureWin::getMargins()
        return QSize(l + r, t + b + m_information.minimumSizeHint().height() + layout()->spacing());
 }
 
-void CaptureWin::setMinimumSize(int minw, int minh)
+void CaptureWin::enableScaling(bool enable)
+{
+       if (!enable) {
+               QSize margins = getMargins();
+               QWidget::setMinimumSize(m_curWidth + margins.width(), m_curHeight + margins.height());
+       } else {
+               QWidget::setMinimumSize(MIN_WIN_SIZE_WIDTH, MIN_WIN_SIZE_HEIGHT);
+       }
+       m_enableScaling = enable;
+       QResizeEvent *event = new QResizeEvent(QSize(width(), height()), QSize(width(), height()));
+       QCoreApplication::sendEvent(this, event);
+       delete event;
+}
+
+void CaptureWin::resize(int width, int height)
 {
+       // Dont resize window if the frame size is the same in
+       // the event the window has been paused when beeing resized.
+       if (width == m_curWidth && height == m_curHeight)
+               return;
+
+       m_curWidth = width;
+       m_curHeight = height;
+
+       QSize margins = getMargins();
+       width += margins.width();
+       height += margins.height();
+
        QDesktopWidget *screen = QApplication::desktop();
        QRect resolution = screen->screenGeometry();
-       QSize maxSize = maximumSize();
 
-       QSize margins = getMargins();
-       minw += margins.width();
-       minh += margins.height();
-
-       if (minw > resolution.width())
-               minw = resolution.width();
-       if (minw < 150)
-               minw = 150;
-
-       if (minh > resolution.height())
-               minh = resolution.height();
-       if (minh < 100)
-               minh = 100;
-
-       QWidget::setMinimumSize(minw, minh);
-       QWidget::setMaximumSize(minw, minh);
-       updateGeometry();
-       QWidget::setMaximumSize(maxSize.width(), maxSize.height());
+       if (width > resolution.width())
+               width = resolution.width();
+       if (width < MIN_WIN_SIZE_WIDTH)
+               width = MIN_WIN_SIZE_WIDTH;
+
+       if (height > resolution.height())
+               height = resolution.height();
+       if (height < MIN_WIN_SIZE_HEIGHT)
+               height = MIN_WIN_SIZE_HEIGHT;
+
+       QWidget::setMinimumSize(MIN_WIN_SIZE_WIDTH, MIN_WIN_SIZE_HEIGHT);
+       QWidget::resize(width, height);
+}
+
+QSize CaptureWin::scaleFrameSize(QSize window, QSize frame)
+{
+       int actualFrameWidth = frame.width();;
+       int actualFrameHeight = frame.height();
+
+       if (!m_enableScaling) {
+               window.setWidth(frame.width());
+               window.setHeight(frame.height());
+       }
+
+       double newW, newH;
+       if (window.width() >= window.height()) {
+               newW = (double)window.width() / actualFrameWidth;
+               newH = (double)window.height() / actualFrameHeight;
+       } else {
+               newH = (double)window.width() / actualFrameWidth;
+               newW = (double)window.height() / actualFrameHeight;
+       }
+       double resized = std::min(newW, newH);
+
+       return QSize((int)(actualFrameWidth * resized), (int)(actualFrameHeight * resized));
 }
 
 void CaptureWin::closeEvent(QCloseEvent *event)
index f662bd3..dd19f2d 100644 (file)
@@ -34,7 +34,7 @@ public:
        CaptureWin();
        ~CaptureWin();
 
-       void setMinimumSize(int minw, int minh);
+       void resize(int minw, int minh);
 
        /**
         * @brief Set a frame into the capture window.
@@ -75,9 +75,13 @@ public:
         */
        static bool isSupported() { return false; }
 
+       void enableScaling(bool enable);
+       static QSize scaleFrameSize(QSize window, QSize frame);
+
 protected:
        void closeEvent(QCloseEvent *event);
        void buildWindow(QWidget *videoSurface);
+       static int actualFrameWidth(int width);
        QSize getMargins();
 
        /**
@@ -87,11 +91,17 @@ protected:
         */
        QLabel m_information;
 
+       /**
+        * @brief Determines if scaling is to be applied to video frame.
+        */
+       static bool m_enableScaling;
+
 signals:
        void close();
 
 private:
        QShortcut *m_hotkeyClose;
-
+       int m_curWidth;
+       int m_curHeight;
 };
 #endif
index e33254d..6258a93 100644 (file)
@@ -137,9 +137,16 @@ ApplicationWindow::ApplicationWindow() :
        toolBar->addSeparator();
        toolBar->addAction(quitAct);
 
+       m_scalingAct = new QAction("Enable Video Scaling", this);
+       m_scalingAct->setStatusTip("Scale video frames to match window size if set");
+       m_scalingAct->setCheckable(true);
+       m_scalingAct->setChecked(true);
+       connect(m_scalingAct, SIGNAL(toggled(bool)), this, SLOT(enableScaling(bool)));
+
        QMenu *captureMenu = menuBar()->addMenu("&Capture");
        captureMenu->addAction(m_capStartAct);
        captureMenu->addAction(m_showFramesAct);
+       captureMenu->addAction(m_scalingAct);
 
        if (CaptureWinGL::isSupported()) {
                m_renderMethod = QV4L2_RENDER_GL;
@@ -351,7 +358,8 @@ void ApplicationWindow::newCaptureWin()
                break;
        }
 
-       connect(m_capture, SIGNAL(close()), this, SLOT(closeCaptureWin()));
+       m_capture->enableScaling(m_scalingAct->isChecked());
+        connect(m_capture, SIGNAL(close()), this, SLOT(closeCaptureWin()));
 }
 
 void ApplicationWindow::capVbiFrame()
@@ -793,6 +801,12 @@ void ApplicationWindow::stopOutput()
 {
 }
 
+void ApplicationWindow::enableScaling(bool enable)
+{
+       if (m_capture != NULL)
+               m_capture->enableScaling(enable);
+}
+
 void ApplicationWindow::startAudio()
 {
 #ifdef HAVE_ALSA
@@ -903,7 +917,7 @@ void ApplicationWindow::capStart(bool start)
                        m_vbiHeight = fmt.fmt.vbi.count[0] + fmt.fmt.vbi.count[1];
                m_vbiSize = m_vbiWidth * m_vbiHeight;
                m_frameData = new unsigned char[m_vbiSize];
-               m_capture->setMinimumSize(m_vbiWidth, m_vbiHeight);
+               m_capture->resize(m_vbiWidth, m_vbiHeight);
                m_capImage = new QImage(m_vbiWidth, m_vbiHeight, dstFmt);
                m_capImage->fill(0);
                m_capture->setFrame(m_capImage->width(), m_capImage->height(),
@@ -933,8 +947,8 @@ void ApplicationWindow::capStart(bool start)
                m_mustConvert = false;
        } else {
                m_mustConvert = true;
-               v4l2_format copy = m_capSrcFormat;
 
+               v4l2_format copy = m_capSrcFormat;
                v4lconvert_try_format(m_convertData, &m_capDestFormat, &m_capSrcFormat);
                // v4lconvert_try_format sometimes modifies the source format if it thinks
                // that there is a better format available. Restore our selected source
@@ -942,13 +956,13 @@ void ApplicationWindow::capStart(bool start)
                m_capSrcFormat = copy;
        }
 
-       m_capture->setMinimumSize(dstPix.width, dstPix.height);
        // Ensure that the initial image is large enough for native 32 bit per pixel formats
        if (dstPix.pixelformat == V4L2_PIX_FMT_RGB32 || dstPix.pixelformat == V4L2_PIX_FMT_BGR32)
                dstFmt = QImage::Format_ARGB32;
        m_capImage = new QImage(dstPix.width, dstPix.height, dstFmt);
        m_capImage->fill(0);
-
+       m_capture->resize(dstPix.width, dstPix.height);
+       
        if (showFrames()) {
                m_capture->setFrame(m_capImage->width(), m_capImage->height(),
                                    m_capDestFormat.fmt.pix.pixelformat, m_capImage->bits(), "No frame");
index dd9db44..1402673 100644 (file)
@@ -132,6 +132,7 @@ private slots:
        void openRawFile(const QString &s);
        void rejectedRawFile();
        void setAudioBufferSize();
+       void enableScaling(bool enable);
 
        void about();
 
@@ -185,6 +186,7 @@ private:
        QAction *m_useGLAct;
        QAction *m_showAllAudioAct;
        QAction *m_audioBufferAct;
+       QAction *m_scalingAct;
        QString m_filename;
        QSignalMapper *m_sigMapper;
        QTabWidget *m_tabs;