* [PATCH 0/9] qv4l2: scaling, pixel aspect ratio and render fixes
@ 2013-08-06 10:21 Bård Eirik Winther
2013-08-06 10:21 ` [PATCH 1/9] qv4l2: generalized opengl include guards Bård Eirik Winther
0 siblings, 1 reply; 10+ messages in thread
From: Bård Eirik Winther @ 2013-08-06 10:21 UTC (permalink / raw)
To: linux-media
The patch series depends on the qv4l2 ALSA and OpenGL patch series.
This adds scaling and aspect ratio support to the qv4l2 CaptureWin.
In that regard it fixes a lot of other issues that would otherwise make scaling
render incorrectly. It also fixes some issues with the original OpenGL patch series,
as well as adding tweaks and improvements left out in the original patches.
Some of the changes/improvements:
- CaptureWin have scaling support for video frames for all renderers
- CaptureWin support pixel aspect ratio scaling
- Aspect ratio and scaling can be changed during capture
- Reset and disable scaling options
- CaptureWin's setMinimumSize is now resize, which resizes the window to the frame size given
and minimum size is set automatically
- The YUY2 shader programs are rewritten and has the resizing issue fixed
- The Show Frames option in Capture menu can be toggled during capture
- Added a hotkey:
CTRL + F : (size to video 'F'rame)
When either the main window or capture window is selected
this will reset the scaling to fit the frame size.
This option is also available in the Capture menu.
Pixel Aspect Ratio Modes:
- Autodetect (if not supported this assumes square pixels)
- Square
- NTSC/PAL-M/PAL-60
- NTSC/PAL-M/PAL-60, Anamorphic
- PAL/SECAM
- PAL/SECAM, Anamorphic
Perfomance:
All tests are done using the 3.10 kernel with OpenGL enabled and desktop effects disabled.
Testing was done on an Intel i7-2600S (with Turbo Boost disabled)
using the integrated Intel HD 2000 graphics processor. The mothreboard is an ASUS P8H77-I
with 2x2GB CL 9-9-9-24 DDR3 RAM. The capture card is a Cisco test card with 4 HDMI
inputs connected using PCIe2.0x8. All video input streams used for testing are
progressive HD (1920x1080) with 60fps.
FPS for every input for a given number of streams
(BGR3, YU12 and YV12 are emulated using the CPU):
1 STREAM 2 STREAMS 3 STREAMS 4 STREAMS
RGB3 60 60 60 60
BGR3 60 60 60 58
YUYV 60 60 60 60
YU12 60 60 60 60
YV12 60 60 60 60
Sidenote:
- Performing scaling and colorspace conversion for 1080p60 using the CPU
can/will give a performance drop in framerate. Recommended to use OpenGL instead.
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 1/9] qv4l2: generalized opengl include guards
2013-08-06 10:21 [PATCH 0/9] qv4l2: scaling, pixel aspect ratio and render fixes Bård Eirik Winther
@ 2013-08-06 10:21 ` Bård Eirik Winther
2013-08-06 10:21 ` [PATCH 2/9] qv4l2: fix YUY2 shader Bård Eirik Winther
` (7 more replies)
0 siblings, 8 replies; 10+ messages in thread
From: Bård Eirik Winther @ 2013-08-06 10:21 UTC (permalink / raw)
To: linux-media
Created a general QtGL makefile condition and using config.h
to check in code if QtGL is present.
Signed-off-by: Bård Eirik Winther <bwinther@cisco.com>
---
configure.ac | 6 ++++--
utils/qv4l2/Makefile.am | 4 ++--
utils/qv4l2/capture-win-gl.cpp | 12 ++++++------
utils/qv4l2/capture-win-gl.h | 6 ++++--
4 files changed, 16 insertions(+), 12 deletions(-)
diff --git a/configure.ac b/configure.ac
index 5a0bb5f..e83baa4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -132,7 +132,9 @@ else
fi
PKG_CHECK_MODULES(QTGL, [QtOpenGL >= 4.4 gl], [qt_pkgconfig_gl=true], [qt_pkgconfig_gl=false])
-if test "x$qt_pkgconfig_gl" = "xfalse"; then
+if test "x$qt_pkgconfig_gl" = "xtrue"; then
+ AC_DEFINE([HAVE_QTGL], [1], [qt has opengl support])
+else
AC_MSG_WARN(Qt4 OpenGL or higher is not available)
fi
@@ -249,9 +251,9 @@ AM_CONDITIONAL([WITH_LIBDVBV5], [test x$enable_libdvbv5 = xyes])
AM_CONDITIONAL([WITH_LIBV4L], [test x$enable_libv4l != xno])
AM_CONDITIONAL([WITH_V4LUTILS], [test x$enable_v4lutils != xno])
AM_CONDITIONAL([WITH_QV4L2], [test ${qt_pkgconfig} = true -a x$enable_qv4l2 != xno])
-AM_CONDITIONAL([WITH_QV4L2_GL], [test WITH_QV4L2 -a ${qt_pkgconfig_gl} = true])
AM_CONDITIONAL([WITH_V4L_PLUGINS], [test x$enable_libv4l != xno -a x$enable_shared != xno])
AM_CONDITIONAL([WITH_V4L_WRAPPERS], [test x$enable_libv4l != xno -a x$enable_shared != xno])
+AM_CONDITIONAL([WITH_QTGL], [test ${qt_pkgconfig_gl} = true])
# append -static to libtool compile and link command to enforce static libs
AS_IF([test x$enable_libdvbv5 != xyes], [AC_SUBST([ENFORCE_LIBDVBV5_STATIC], ["-static"])])
diff --git a/utils/qv4l2/Makefile.am b/utils/qv4l2/Makefile.am
index 3aed18c..58ac097 100644
--- a/utils/qv4l2/Makefile.am
+++ b/utils/qv4l2/Makefile.am
@@ -7,8 +7,8 @@ nodist_qv4l2_SOURCES = moc_qv4l2.cpp moc_general-tab.cpp moc_capture-win.cpp moc
qv4l2_LDADD = ../../lib/libv4l2/libv4l2.la ../../lib/libv4lconvert/libv4lconvert.la ../libv4l2util/libv4l2util.la \
../libmedia_dev/libmedia_dev.la
-if WITH_QV4L2_GL
-qv4l2_CPPFLAGS = $(QTGL_CFLAGS) -DENABLE_GL
+if WITH_QTGL
+qv4l2_CPPFLAGS = $(QTGL_CFLAGS)
qv4l2_LDFLAGS = $(QTGL_LIBS)
else
qv4l2_CPPFLAGS = $(QT_CFLAGS)
diff --git a/utils/qv4l2/capture-win-gl.cpp b/utils/qv4l2/capture-win-gl.cpp
index 52412c7..c499f1f 100644
--- a/utils/qv4l2/capture-win-gl.cpp
+++ b/utils/qv4l2/capture-win-gl.cpp
@@ -26,7 +26,7 @@
CaptureWinGL::CaptureWinGL()
{
-#ifdef ENABLE_GL
+#ifdef HAVE_QTGL
CaptureWin::buildWindow(&m_videoSurface);
#endif
CaptureWin::setWindowTitle("V4L2 Capture (OpenGL)");
@@ -38,14 +38,14 @@ CaptureWinGL::~CaptureWinGL()
void CaptureWinGL::stop()
{
-#ifdef ENABLE_GL
+#ifdef HAVE_QTGL
m_videoSurface.stop();
#endif
}
void CaptureWinGL::setFrame(int width, int height, __u32 format, unsigned char *data, const QString &info)
{
-#ifdef ENABLE_GL
+#ifdef HAVE_QTGL
m_videoSurface.setFrame(width, height, format, data);
#endif
m_information.setText(info);
@@ -53,7 +53,7 @@ void CaptureWinGL::setFrame(int width, int height, __u32 format, unsigned char *
bool CaptureWinGL::hasNativeFormat(__u32 format)
{
-#ifdef ENABLE_GL
+#ifdef HAVE_QTGL
return m_videoSurface.hasNativeFormat(format);
#else
return false;
@@ -62,14 +62,14 @@ bool CaptureWinGL::hasNativeFormat(__u32 format)
bool CaptureWinGL::isSupported()
{
-#ifdef ENABLE_GL
+#ifdef HAVE_QTGL
return true;
#else
return false;
#endif
}
-#ifdef ENABLE_GL
+#ifdef HAVE_QTGL
CaptureWinGLEngine::CaptureWinGLEngine() :
m_frameHeight(0),
m_frameWidth(0),
diff --git a/utils/qv4l2/capture-win-gl.h b/utils/qv4l2/capture-win-gl.h
index 08e72b2..6e64269 100644
--- a/utils/qv4l2/capture-win-gl.h
+++ b/utils/qv4l2/capture-win-gl.h
@@ -18,10 +18,12 @@
#ifndef CAPTURE_WIN_GL_H
#define CAPTURE_WIN_GL_H
+#include <config.h>
+
#include "qv4l2.h"
#include "capture-win.h"
-#ifdef ENABLE_GL
+#ifdef HAVE_QTGL
#define GL_GLEXT_PROTOTYPES
#include <QGLWidget>
#include <QGLShader>
@@ -88,7 +90,7 @@ public:
bool hasNativeFormat(__u32 format);
static bool isSupported();
-#ifdef ENABLE_GL
+#ifdef HAVE_QTGL
CaptureWinGLEngine m_videoSurface;
#endif
};
--
1.8.3.2
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 2/9] qv4l2: fix YUY2 shader
2013-08-06 10:21 ` [PATCH 1/9] qv4l2: generalized opengl include guards Bård Eirik Winther
@ 2013-08-06 10:21 ` Bård Eirik Winther
2013-08-06 10:21 ` [PATCH 3/9] qv4l2: fix black screen with opengl after capture Bård Eirik Winther
` (6 subsequent siblings)
7 siblings, 0 replies; 10+ messages in thread
From: Bård Eirik Winther @ 2013-08-06 10:21 UTC (permalink / raw)
To: linux-media
Fixed the YUY2 shaders to support scaling.
The new solution has cleaner shader code and texture upload
uses a better format for OpenGL.
Signed-off-by: Bård Eirik Winther <bwinther@cisco.com>
---
utils/qv4l2/capture-win-gl.cpp | 68 ++++++++++++++++++++++--------------------
1 file changed, 35 insertions(+), 33 deletions(-)
diff --git a/utils/qv4l2/capture-win-gl.cpp b/utils/qv4l2/capture-win-gl.cpp
index c499f1f..6071410 100644
--- a/utils/qv4l2/capture-win-gl.cpp
+++ b/utils/qv4l2/capture-win-gl.cpp
@@ -1,5 +1,5 @@
/*
- * The YUY2 shader code was copied and simplified from face-responder. The code is under public domain:
+ * The YUY2 shader code is based on face-responder. The code is under public domain:
* https://bitbucket.org/nateharward/face-responder/src/0c3b4b957039d9f4bf1da09b9471371942de2601/yuv42201_laplace.frag?at=master
*
* All other OpenGL code:
@@ -446,47 +446,51 @@ QString CaptureWinGLEngine::shader_YUY2_invariant(__u32 format)
{
switch (format) {
case V4L2_PIX_FMT_YUYV:
- return QString("y = (luma_chroma.r - 0.0625) * 1.1643;"
- "if (mod(xcoord, 2.0) == 0.0) {"
- " u = luma_chroma.a;"
- " v = texture2D(tex, vec2(pixelx + texl_w, pixely)).a;"
+ return QString("if (mod(xcoord, 2.0) == 0.0) {"
+ " luma_chroma = texture2D(tex, vec2(pixelx, pixely));"
+ " y = (luma_chroma.r - 0.0625) * 1.1643;"
"} else {"
- " v = luma_chroma.a;"
- " u = texture2D(tex, vec2(pixelx - texl_w, pixely)).a;"
+ " luma_chroma = texture2D(tex, vec2(pixelx - texl_w, pixely));"
+ " y = (luma_chroma.b - 0.0625) * 1.1643;"
"}"
+ "u = luma_chroma.g - 0.5;"
+ "v = luma_chroma.a - 0.5;"
);
case V4L2_PIX_FMT_YVYU:
- return QString("y = (luma_chroma.r - 0.0625) * 1.1643;"
- "if (mod(xcoord, 2.0) == 0.0) {"
- " v = luma_chroma.a;"
- " u = texture2D(tex, vec2(pixelx + texl_w, pixely)).a;"
+ return QString("if (mod(xcoord, 2.0) == 0.0) {"
+ " luma_chroma = texture2D(tex, vec2(pixelx, pixely));"
+ " y = (luma_chroma.r - 0.0625) * 1.1643;"
"} else {"
- " u = luma_chroma.a;"
- " v = texture2D(tex, vec2(pixelx - texl_w, pixely)).a;"
+ " luma_chroma = texture2D(tex, vec2(pixelx - texl_w, pixely));"
+ " y = (luma_chroma.b - 0.0625) * 1.1643;"
"}"
+ "u = luma_chroma.a - 0.5;"
+ "v = luma_chroma.g - 0.5;"
);
case V4L2_PIX_FMT_UYVY:
- return QString("y = (luma_chroma.a - 0.0625) * 1.1643;"
- "if (mod(xcoord, 2.0) == 0.0) {"
- " u = luma_chroma.r;"
- " v = texture2D(tex, vec2(pixelx + texl_w, pixely)).r;"
+ return QString("if (mod(xcoord, 2.0) == 0.0) {"
+ " luma_chroma = texture2D(tex, vec2(pixelx, pixely));"
+ " y = (luma_chroma.g - 0.0625) * 1.1643;"
"} else {"
- " v = luma_chroma.r;"
- " u = texture2D(tex, vec2(pixelx - texl_w, pixely)).r;"
+ " luma_chroma = texture2D(tex, vec2(pixelx - texl_w, pixely));"
+ " y = (luma_chroma.a - 0.0625) * 1.1643;"
"}"
+ "u = luma_chroma.r - 0.5;"
+ "v = luma_chroma.b - 0.5;"
);
case V4L2_PIX_FMT_VYUY:
- return QString("y = (luma_chroma.a - 0.0625) * 1.1643;"
- "if (mod(xcoord, 2.0) == 0.0) {"
- " v = luma_chroma.r;"
- " u = texture2D(tex, vec2(pixelx + texl_w, pixely)).r;"
+ return QString("if (mod(xcoord, 2.0) == 0.0) {"
+ " luma_chroma = texture2D(tex, vec2(pixelx, pixely));"
+ " y = (luma_chroma.g - 0.0625) * 1.1643;"
"} else {"
- " u = luma_chroma.r;"
- " v = texture2D(tex, vec2(pixelx - texl_w, pixely)).r;"
+ " luma_chroma = texture2D(tex, vec2(pixelx - texl_w, pixely));"
+ " y = (luma_chroma.a - 0.0625) * 1.1643;"
"}"
+ "u = luma_chroma.b - 0.5;"
+ "v = luma_chroma.r - 0.5;"
);
default:
@@ -499,8 +503,8 @@ void CaptureWinGLEngine::shader_YUY2(__u32 format)
m_screenTextureCount = 1;
glGenTextures(m_screenTextureCount, m_screenTexture);
configureTexture(0);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, m_frameWidth, m_frameHeight, 0,
- GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, NULL);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_frameWidth / 2, m_frameHeight, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, NULL);
checkError("YUY2 shader");
QString codeHead = QString("uniform sampler2D tex;"
@@ -509,17 +513,15 @@ void CaptureWinGLEngine::shader_YUY2(__u32 format)
"void main()"
"{"
" float y, u, v;"
+ " vec4 luma_chroma;"
" float pixelx = gl_TexCoord[0].x;"
" float pixely = gl_TexCoord[0].y;"
" float xcoord = floor(pixelx * tex_w);"
- " vec4 luma_chroma = texture2D(tex, vec2(pixelx, pixely));"
);
QString codeBody = shader_YUY2_invariant(format);
- QString codeTail = QString(" u = u - 0.5;"
- " v = v - 0.5;"
- " float r = y + 1.5958 * v;"
+ QString codeTail = QString(" float r = y + 1.5958 * v;"
" float g = y - 0.39173 * u - 0.81290 * v;"
" float b = y + 2.017 * u;"
" gl_FragColor = vec4(r, g, b, 1.0);"
@@ -548,8 +550,8 @@ void CaptureWinGLEngine::render_YUY2()
glBindTexture(GL_TEXTURE_2D, m_screenTexture[0]);
GLint Y = m_glfunction.glGetUniformLocation(m_shaderProgram.programId(), "tex");
glUniform1i(Y, 0);
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
- GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, m_frameData);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth / 2, m_frameHeight,
+ GL_RGBA, GL_UNSIGNED_BYTE, m_frameData);
checkError("YUY2 paint");
}
#endif
--
1.8.3.2
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 3/9] qv4l2: fix black screen with opengl after capture
2013-08-06 10:21 ` [PATCH 1/9] qv4l2: generalized opengl include guards Bård Eirik Winther
2013-08-06 10:21 ` [PATCH 2/9] qv4l2: fix YUY2 shader Bård Eirik Winther
@ 2013-08-06 10:21 ` Bård Eirik Winther
2013-08-06 10:21 ` [PATCH 4/9] qv4l2: show frames option can be toggled during capture Bård Eirik Winther
` (5 subsequent siblings)
7 siblings, 0 replies; 10+ messages in thread
From: Bård Eirik Winther @ 2013-08-06 10:21 UTC (permalink / raw)
To: linux-media
Fixes the issue when the window was beeing resized/moved
and the frame image would become black.
Signed-off-by: Bård Eirik Winther <bwinther@cisco.com>
---
utils/qv4l2/capture-win-gl.cpp | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/utils/qv4l2/capture-win-gl.cpp b/utils/qv4l2/capture-win-gl.cpp
index 6071410..c8238c5 100644
--- a/utils/qv4l2/capture-win-gl.cpp
+++ b/utils/qv4l2/capture-win-gl.cpp
@@ -253,6 +253,12 @@ void CaptureWinGLEngine::paintGL()
changeShader();
if (m_frameData == NULL) {
+ glBegin(GL_QUADS);
+ glTexCoord2f(0.0f, 0.0f); glVertex2f(0.0, 0);
+ glTexCoord2f(1.0f, 0.0f); glVertex2f(m_frameWidth, 0);
+ glTexCoord2f(1.0f, 1.0f); glVertex2f(m_frameWidth, m_frameHeight);
+ glTexCoord2f(0.0f, 1.0f); glVertex2f(0, m_frameHeight);
+ glEnd();
return;
}
--
1.8.3.2
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 4/9] qv4l2: show frames option can be toggled during capture
2013-08-06 10:21 ` [PATCH 1/9] qv4l2: generalized opengl include guards Bård Eirik Winther
2013-08-06 10:21 ` [PATCH 2/9] qv4l2: fix YUY2 shader Bård Eirik Winther
2013-08-06 10:21 ` [PATCH 3/9] qv4l2: fix black screen with opengl after capture Bård Eirik Winther
@ 2013-08-06 10:21 ` Bård Eirik Winther
2013-08-06 10:21 ` [PATCH 5/9] qv4l2: create function getMargins Bård Eirik Winther
` (4 subsequent siblings)
7 siblings, 0 replies; 10+ messages in thread
From: Bård Eirik Winther @ 2013-08-06 10:21 UTC (permalink / raw)
To: linux-media
Signed-off-by: Bård Eirik Winther <bwinther@cisco.com>
---
utils/qv4l2/qv4l2.cpp | 79 +++++++++++++++++++++++++++------------------------
utils/qv4l2/qv4l2.h | 2 +-
2 files changed, 43 insertions(+), 38 deletions(-)
diff --git a/utils/qv4l2/qv4l2.cpp b/utils/qv4l2/qv4l2.cpp
index 5510041..ee0c22d 100644
--- a/utils/qv4l2/qv4l2.cpp
+++ b/utils/qv4l2/qv4l2.cpp
@@ -404,7 +404,7 @@ void ApplicationWindow::capVbiFrame()
m_capStartAct->setChecked(false);
return;
}
- if (m_showFrames) {
+ if (showFrames()) {
for (unsigned y = 0; y < m_vbiHeight; y++) {
__u8 *p = data + y * m_vbiWidth;
__u8 *q = m_capImage->bits() + y * m_capImage->bytesPerLine();
@@ -448,7 +448,7 @@ void ApplicationWindow::capVbiFrame()
m_tv = tv;
}
status = QString("Frame: %1 Fps: %2").arg(++m_frame).arg(m_fps);
- if (m_showFrames)
+ if (showFrames())
m_capture->setFrame(m_capImage->width(), m_capImage->height(),
m_capDestFormat.fmt.pix.pixelformat, m_capImage->bits(), status);
@@ -491,7 +491,7 @@ void ApplicationWindow::capFrame()
if (m_saveRaw.openMode())
m_saveRaw.write((const char *)m_frameData, s);
- if (!m_showFrames)
+ if (!showFrames())
break;
if (m_mustConvert)
err = v4lconvert_convert(m_convertData, &m_capSrcFormat, &m_capDestFormat,
@@ -515,7 +515,7 @@ void ApplicationWindow::capFrame()
if (again)
return;
- if (m_showFrames) {
+ if (showFrames()) {
if (m_mustConvert)
err = v4lconvert_convert(m_convertData, &m_capSrcFormat, &m_capDestFormat,
(unsigned char *)m_buffers[buf.index].start, buf.bytesused,
@@ -544,7 +544,7 @@ void ApplicationWindow::capFrame()
if (again)
return;
- if (m_showFrames) {
+ if (showFrames()) {
if (m_mustConvert)
err = v4lconvert_convert(m_convertData, &m_capSrcFormat, &m_capDestFormat,
(unsigned char *)buf.m.userptr, buf.bytesused,
@@ -590,10 +590,10 @@ void ApplicationWindow::capFrame()
.arg((m_totalAudioLatency.tv_sec * 1000 + m_totalAudioLatency.tv_usec / 1000) / m_frame));
}
#endif
- if (displaybuf == NULL && m_showFrames)
+ if (displaybuf == NULL && showFrames())
status.append(" Error: Unsupported format.");
- if (m_showFrames)
+ if (showFrames())
m_capture->setFrame(m_capImage->width(), m_capImage->height(),
m_capDestFormat.fmt.pix.pixelformat, displaybuf, status);
@@ -776,6 +776,15 @@ void ApplicationWindow::stopCapture()
refresh();
}
+bool ApplicationWindow::showFrames()
+{
+ if (m_showFramesAct->isChecked() && !m_capture->isVisible())
+ m_capture->show();
+ if (!m_showFramesAct->isChecked() && m_capture->isVisible())
+ m_capture->hide();
+ return m_showFramesAct->isChecked();
+}
+
void ApplicationWindow::startOutput(unsigned)
{
}
@@ -849,7 +858,6 @@ void ApplicationWindow::capStart(bool start)
m_capImage = NULL;
return;
}
- m_showFrames = m_showFramesAct->isChecked();
m_frame = m_lastFrame = m_fps = 0;
m_capMethod = m_genTab->capMethod();
@@ -857,7 +865,6 @@ void ApplicationWindow::capStart(bool start)
v4l2_format fmt;
v4l2_std_id std;
- m_showFrames = false;
g_fmt_sliced_vbi(fmt);
g_std(std);
fmt.fmt.sliced.service_set = (std & V4L2_STD_625_50) ?
@@ -896,14 +903,14 @@ 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];
- if (m_showFrames) {
- m_capture->setMinimumSize(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(),
- m_capDestFormat.fmt.pix.pixelformat, m_capImage->bits(), "No frame");
+ m_capture->setMinimumSize(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(),
+ m_capDestFormat.fmt.pix.pixelformat, m_capImage->bits(), "No frame");
+ if (showFrames())
m_capture->show();
- }
+
statusBar()->showMessage("No frame");
if (startCapture(m_vbiSize)) {
m_capNotifier = new QSocketNotifier(fd(), QSocketNotifier::Read, m_tabs);
@@ -917,30 +924,28 @@ void ApplicationWindow::capStart(bool start)
if (m_genTab->get_interval(interval))
set_interval(interval);
- m_mustConvert = m_showFrames;
m_frameData = new unsigned char[srcPix.sizeimage];
- if (m_showFrames) {
- m_capDestFormat = m_capSrcFormat;
- dstPix.pixelformat = V4L2_PIX_FMT_RGB24;
-
- if (m_capture->hasNativeFormat(srcPix.pixelformat)) {
- dstPix.pixelformat = srcPix.pixelformat;
- m_mustConvert = false;
- }
-
- if (m_mustConvert) {
- v4l2_format copy = m_capSrcFormat;
+ m_capDestFormat = m_capSrcFormat;
+ dstPix.pixelformat = V4L2_PIX_FMT_RGB24;
- 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
- // format since we do not want that happening.
- m_capSrcFormat = copy;
- }
+ if (m_capture->hasNativeFormat(srcPix.pixelformat)) {
+ dstPix.pixelformat = srcPix.pixelformat;
+ m_mustConvert = false;
+ } else {
+ m_mustConvert = true;
+ 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
+ // format since we do not want that happening.
+ m_capSrcFormat = copy;
+ }
- m_capture->setMinimumSize(dstPix.width, dstPix.height);
- m_capImage = new QImage(dstPix.width, dstPix.height, dstFmt);
- m_capImage->fill(0);
+ m_capture->setMinimumSize(dstPix.width, dstPix.height);
+ m_capImage = new QImage(dstPix.width, dstPix.height, dstFmt);
+ m_capImage->fill(0);
+ if (showFrames()) {
m_capture->setFrame(m_capImage->width(), m_capImage->height(),
m_capDestFormat.fmt.pix.pixelformat, m_capImage->bits(), "No frame");
m_capture->show();
diff --git a/utils/qv4l2/qv4l2.h b/utils/qv4l2/qv4l2.h
index 511a652..dd9db44 100644
--- a/utils/qv4l2/qv4l2.h
+++ b/utils/qv4l2/qv4l2.h
@@ -174,6 +174,7 @@ private:
void updateStandard();
void updateFreq();
void updateFreqChannel();
+ bool showFrames();
GeneralTab *m_genTab;
VbiTab *m_vbiTab;
@@ -195,7 +196,6 @@ private:
WidgetMap m_widgetMap;
ClassMap m_classMap;
bool m_haveExtendedUserCtrls;
- bool m_showFrames;
int m_vbiSize;
unsigned m_vbiWidth;
unsigned m_vbiHeight;
--
1.8.3.2
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 5/9] qv4l2: create function getMargins
2013-08-06 10:21 ` [PATCH 1/9] qv4l2: generalized opengl include guards Bård Eirik Winther
` (2 preceding siblings ...)
2013-08-06 10:21 ` [PATCH 4/9] qv4l2: show frames option can be toggled during capture Bård Eirik Winther
@ 2013-08-06 10:21 ` Bård Eirik Winther
2013-08-06 10:21 ` [PATCH 6/9] qv4l2: add video scaling for CaptureWin Bård Eirik Winther
` (3 subsequent siblings)
7 siblings, 0 replies; 10+ messages in thread
From: Bård Eirik Winther @ 2013-08-06 10:21 UTC (permalink / raw)
To: linux-media
Created a function to get the total margins (window frame) in pixels
outside the actual video frame beeing displayed.
Signed-off-by: Bård Eirik Winther <bwinther@cisco.com>
---
utils/qv4l2/capture-win.cpp | 14 ++++++++++----
utils/qv4l2/capture-win.h | 1 +
2 files changed, 11 insertions(+), 4 deletions(-)
diff --git a/utils/qv4l2/capture-win.cpp b/utils/qv4l2/capture-win.cpp
index 2d57909..8722066 100644
--- a/utils/qv4l2/capture-win.cpp
+++ b/utils/qv4l2/capture-win.cpp
@@ -54,16 +54,22 @@ void CaptureWin::buildWindow(QWidget *videoSurface)
vbox->setSpacing(b);
}
+QSize CaptureWin::getMargins()
+{
+ int l, t, r, b;
+ layout()->getContentsMargins(&l, &t, &r, &b);
+ return QSize(l + r, t + b + m_information.minimumSizeHint().height() + layout()->spacing());
+}
+
void CaptureWin::setMinimumSize(int minw, int minh)
{
QDesktopWidget *screen = QApplication::desktop();
QRect resolution = screen->screenGeometry();
QSize maxSize = maximumSize();
- int l, t, r, b;
- layout()->getContentsMargins(&l, &t, &r, &b);
- minw += l + r;
- minh += t + b + m_information.minimumSizeHint().height() + layout()->spacing();
+ QSize margins = getMargins();
+ minw += margins.width();
+ minh += margins.height();
if (minw > resolution.width())
minw = resolution.width();
diff --git a/utils/qv4l2/capture-win.h b/utils/qv4l2/capture-win.h
index ca60244..f662bd3 100644
--- a/utils/qv4l2/capture-win.h
+++ b/utils/qv4l2/capture-win.h
@@ -78,6 +78,7 @@ public:
protected:
void closeEvent(QCloseEvent *event);
void buildWindow(QWidget *videoSurface);
+ QSize getMargins();
/**
* @brief A label that can is used to display capture information.
--
1.8.3.2
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 6/9] qv4l2: add video scaling for CaptureWin
2013-08-06 10:21 ` [PATCH 1/9] qv4l2: generalized opengl include guards Bård Eirik Winther
` (3 preceding siblings ...)
2013-08-06 10:21 ` [PATCH 5/9] qv4l2: create function getMargins Bård Eirik Winther
@ 2013-08-06 10:21 ` Bård Eirik Winther
2013-08-06 10:21 ` [PATCH 7/9] qv4l2: added resize to frame size in Capture menu Bård Eirik Winther
` (2 subsequent siblings)
7 siblings, 0 replies; 10+ messages in thread
From: Bård Eirik Winther @ 2013-08-06 10:21 UTC (permalink / raw)
To: linux-media
Signed-off-by: Bård Eirik Winther <bwinther@cisco.com>
---
utils/qv4l2/capture-win-gl.cpp | 26 ++++++++++--
utils/qv4l2/capture-win-gl.h | 7 ++++
utils/qv4l2/capture-win-qt.cpp | 23 ++++++++++-
utils/qv4l2/capture-win-qt.h | 5 +++
utils/qv4l2/capture-win.cpp | 93 ++++++++++++++++++++++++++++++++----------
utils/qv4l2/capture-win.h | 14 ++++++-
utils/qv4l2/qv4l2.cpp | 22 ++++++++--
utils/qv4l2/qv4l2.h | 2 +
8 files changed, 159 insertions(+), 33 deletions(-)
diff --git a/utils/qv4l2/capture-win-gl.cpp b/utils/qv4l2/capture-win-gl.cpp
index c8238c5..27ff3d3 100644
--- a/utils/qv4l2/capture-win-gl.cpp
+++ b/utils/qv4l2/capture-win-gl.cpp
@@ -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;
diff --git a/utils/qv4l2/capture-win-gl.h b/utils/qv4l2/capture-win-gl.h
index 6e64269..0c3ff8b 100644
--- a/utils/qv4l2/capture-win-gl.h
+++ b/utils/qv4l2/capture-win-gl.h
@@ -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
diff --git a/utils/qv4l2/capture-win-qt.cpp b/utils/qv4l2/capture-win-qt.cpp
index 63c77d5..f746379 100644
--- a/utils/qv4l2/capture-win-qt.cpp
+++ b/utils/qv4l2/capture-win-qt.cpp
@@ -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)
diff --git a/utils/qv4l2/capture-win-qt.h b/utils/qv4l2/capture-win-qt.h
index d192045..6029109 100644
--- a/utils/qv4l2/capture-win-qt.h
+++ b/utils/qv4l2/capture-win-qt.h
@@ -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
diff --git a/utils/qv4l2/capture-win.cpp b/utils/qv4l2/capture-win.cpp
index 8722066..33f7084 100644
--- a/utils/qv4l2/capture-win.cpp
+++ b/utils/qv4l2/capture-win.cpp
@@ -26,11 +26,18 @@
#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)
diff --git a/utils/qv4l2/capture-win.h b/utils/qv4l2/capture-win.h
index f662bd3..dd19f2d 100644
--- a/utils/qv4l2/capture-win.h
+++ b/utils/qv4l2/capture-win.h
@@ -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
diff --git a/utils/qv4l2/qv4l2.cpp b/utils/qv4l2/qv4l2.cpp
index ee0c22d..50ba07a 100644
--- a/utils/qv4l2/qv4l2.cpp
+++ b/utils/qv4l2/qv4l2.cpp
@@ -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,7 +956,7 @@ void ApplicationWindow::capStart(bool start)
m_capSrcFormat = copy;
}
- m_capture->setMinimumSize(dstPix.width, dstPix.height);
+ m_capture->resize(dstPix.width, dstPix.height);
m_capImage = new QImage(dstPix.width, dstPix.height, dstFmt);
m_capImage->fill(0);
if (showFrames()) {
diff --git a/utils/qv4l2/qv4l2.h b/utils/qv4l2/qv4l2.h
index dd9db44..1402673 100644
--- a/utils/qv4l2/qv4l2.h
+++ b/utils/qv4l2/qv4l2.h
@@ -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;
--
1.8.3.2
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 7/9] qv4l2: added resize to frame size in Capture menu
2013-08-06 10:21 ` [PATCH 1/9] qv4l2: generalized opengl include guards Bård Eirik Winther
` (4 preceding siblings ...)
2013-08-06 10:21 ` [PATCH 6/9] qv4l2: add video scaling for CaptureWin Bård Eirik Winther
@ 2013-08-06 10:21 ` Bård Eirik Winther
2013-08-06 10:21 ` [PATCH 8/9] qv4l2: add hotkey for reset scaling to frame size Bård Eirik Winther
2013-08-06 10:21 ` [PATCH 9/9] qv4l2: add pixel aspect ratio support for CaptureWin Bård Eirik Winther
7 siblings, 0 replies; 10+ messages in thread
From: Bård Eirik Winther @ 2013-08-06 10:21 UTC (permalink / raw)
To: linux-media
This will resize the CaptureWin to the original frame size.
It also works with maximized windows.
Signed-off-by: Bård Eirik Winther <bwinther@cisco.com>
---
utils/qv4l2/capture-win.cpp | 12 ++++++++++++
utils/qv4l2/capture-win.h | 3 +++
utils/qv4l2/qv4l2.cpp | 6 ++++--
utils/qv4l2/qv4l2.h | 1 +
4 files changed, 20 insertions(+), 2 deletions(-)
diff --git a/utils/qv4l2/capture-win.cpp b/utils/qv4l2/capture-win.cpp
index 33f7084..3bd6549 100644
--- a/utils/qv4l2/capture-win.cpp
+++ b/utils/qv4l2/capture-win.cpp
@@ -61,6 +61,18 @@ void CaptureWin::buildWindow(QWidget *videoSurface)
vbox->setSpacing(b);
}
+void CaptureWin::resetSize()
+{
+ if (isMaximized())
+ showNormal();
+
+ int w = m_curWidth;
+ int h = m_curHeight;
+ m_curWidth = -1;
+ m_curHeight = -1;
+ resize(w, h);
+}
+
QSize CaptureWin::getMargins()
{
int l, t, r, b;
diff --git a/utils/qv4l2/capture-win.h b/utils/qv4l2/capture-win.h
index dd19f2d..eea0335 100644
--- a/utils/qv4l2/capture-win.h
+++ b/utils/qv4l2/capture-win.h
@@ -78,6 +78,9 @@ public:
void enableScaling(bool enable);
static QSize scaleFrameSize(QSize window, QSize frame);
+public slots:
+ void resetSize();
+
protected:
void closeEvent(QCloseEvent *event);
void buildWindow(QWidget *videoSurface);
diff --git a/utils/qv4l2/qv4l2.cpp b/utils/qv4l2/qv4l2.cpp
index 50ba07a..1a476f0 100644
--- a/utils/qv4l2/qv4l2.cpp
+++ b/utils/qv4l2/qv4l2.cpp
@@ -142,11 +142,14 @@ ApplicationWindow::ApplicationWindow() :
m_scalingAct->setCheckable(true);
m_scalingAct->setChecked(true);
connect(m_scalingAct, SIGNAL(toggled(bool)), this, SLOT(enableScaling(bool)));
+ m_resetScalingAct = new QAction("Resize to Frame Size", this);
+ m_resetScalingAct->setStatusTip("Resizes the capture window to match frame size");
QMenu *captureMenu = menuBar()->addMenu("&Capture");
captureMenu->addAction(m_capStartAct);
captureMenu->addAction(m_showFramesAct);
captureMenu->addAction(m_scalingAct);
+ captureMenu->addAction(m_resetScalingAct);
if (CaptureWinGL::isSupported()) {
m_renderMethod = QV4L2_RENDER_GL;
@@ -211,8 +214,6 @@ void ApplicationWindow::setDevice(const QString &device, bool rawOpen)
newCaptureWin();
- m_capture->setMinimumSize(150, 50);
-
QWidget *w = new QWidget(m_tabs);
m_genTab = new GeneralTab(device, *this, 4, w);
@@ -360,6 +361,7 @@ void ApplicationWindow::newCaptureWin()
m_capture->enableScaling(m_scalingAct->isChecked());
connect(m_capture, SIGNAL(close()), this, SLOT(closeCaptureWin()));
+ connect(m_resetScalingAct, SIGNAL(triggered()), m_capture, SLOT(resetSize()));
}
void ApplicationWindow::capVbiFrame()
diff --git a/utils/qv4l2/qv4l2.h b/utils/qv4l2/qv4l2.h
index 1402673..179cecb 100644
--- a/utils/qv4l2/qv4l2.h
+++ b/utils/qv4l2/qv4l2.h
@@ -187,6 +187,7 @@ private:
QAction *m_showAllAudioAct;
QAction *m_audioBufferAct;
QAction *m_scalingAct;
+ QAction *m_resetScalingAct;
QString m_filename;
QSignalMapper *m_sigMapper;
QTabWidget *m_tabs;
--
1.8.3.2
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 8/9] qv4l2: add hotkey for reset scaling to frame size
2013-08-06 10:21 ` [PATCH 1/9] qv4l2: generalized opengl include guards Bård Eirik Winther
` (5 preceding siblings ...)
2013-08-06 10:21 ` [PATCH 7/9] qv4l2: added resize to frame size in Capture menu Bård Eirik Winther
@ 2013-08-06 10:21 ` Bård Eirik Winther
2013-08-06 10:21 ` [PATCH 9/9] qv4l2: add pixel aspect ratio support for CaptureWin Bård Eirik Winther
7 siblings, 0 replies; 10+ messages in thread
From: Bård Eirik Winther @ 2013-08-06 10:21 UTC (permalink / raw)
To: linux-media
Adds hotkey CTRL + F for both CaptureWin and main Capture menu.
Resets the scaling of CaptureWin to fit frame size.
Signed-off-by: Bård Eirik Winther <bwinther@cisco.com>
---
utils/qv4l2/capture-win.cpp | 3 +++
utils/qv4l2/capture-win.h | 1 +
utils/qv4l2/qv4l2.cpp | 1 +
3 files changed, 5 insertions(+)
diff --git a/utils/qv4l2/capture-win.cpp b/utils/qv4l2/capture-win.cpp
index 3bd6549..3abb6cb 100644
--- a/utils/qv4l2/capture-win.cpp
+++ b/utils/qv4l2/capture-win.cpp
@@ -38,6 +38,8 @@ CaptureWin::CaptureWin() :
setWindowTitle("V4L2 Capture");
m_hotkeyClose = new QShortcut(Qt::CTRL+Qt::Key_W, this);
connect(m_hotkeyClose, SIGNAL(activated()), this, SLOT(close()));
+ m_hotkeyScaleReset = new QShortcut(Qt::CTRL+Qt::Key_F, this);
+ connect(m_hotkeyScaleReset, SIGNAL(activated()), this, SLOT(resetSize()));
}
CaptureWin::~CaptureWin()
@@ -48,6 +50,7 @@ CaptureWin::~CaptureWin()
layout()->removeWidget(this);
delete layout();
delete m_hotkeyClose;
+ delete m_hotkeyScaleReset;
}
void CaptureWin::buildWindow(QWidget *videoSurface)
diff --git a/utils/qv4l2/capture-win.h b/utils/qv4l2/capture-win.h
index eea0335..1bfb1e1 100644
--- a/utils/qv4l2/capture-win.h
+++ b/utils/qv4l2/capture-win.h
@@ -104,6 +104,7 @@ signals:
private:
QShortcut *m_hotkeyClose;
+ QShortcut *m_hotkeyScaleReset;
int m_curWidth;
int m_curHeight;
};
diff --git a/utils/qv4l2/qv4l2.cpp b/utils/qv4l2/qv4l2.cpp
index 1a476f0..c94b0a8 100644
--- a/utils/qv4l2/qv4l2.cpp
+++ b/utils/qv4l2/qv4l2.cpp
@@ -144,6 +144,7 @@ ApplicationWindow::ApplicationWindow() :
connect(m_scalingAct, SIGNAL(toggled(bool)), this, SLOT(enableScaling(bool)));
m_resetScalingAct = new QAction("Resize to Frame Size", this);
m_resetScalingAct->setStatusTip("Resizes the capture window to match frame size");
+ m_resetScalingAct->setShortcut(Qt::CTRL+Qt::Key_F);
QMenu *captureMenu = menuBar()->addMenu("&Capture");
captureMenu->addAction(m_capStartAct);
--
1.8.3.2
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 9/9] qv4l2: add pixel aspect ratio support for CaptureWin
2013-08-06 10:21 ` [PATCH 1/9] qv4l2: generalized opengl include guards Bård Eirik Winther
` (6 preceding siblings ...)
2013-08-06 10:21 ` [PATCH 8/9] qv4l2: add hotkey for reset scaling to frame size Bård Eirik Winther
@ 2013-08-06 10:21 ` Bård Eirik Winther
7 siblings, 0 replies; 10+ messages in thread
From: Bård Eirik Winther @ 2013-08-06 10:21 UTC (permalink / raw)
To: linux-media
Signed-off-by: Bård Eirik Winther <bwinther@cisco.com>
---
utils/qv4l2/capture-win.cpp | 36 ++++++++++++++++++------
utils/qv4l2/capture-win.h | 6 ++++
utils/qv4l2/general-tab.cpp | 68 +++++++++++++++++++++++++++++++++++++++++++++
utils/qv4l2/general-tab.h | 4 +++
utils/qv4l2/qv4l2.cpp | 21 ++++++++++----
utils/qv4l2/qv4l2.h | 1 +
6 files changed, 122 insertions(+), 14 deletions(-)
diff --git a/utils/qv4l2/capture-win.cpp b/utils/qv4l2/capture-win.cpp
index 3abb6cb..7538756 100644
--- a/utils/qv4l2/capture-win.cpp
+++ b/utils/qv4l2/capture-win.cpp
@@ -30,6 +30,7 @@
#define MIN_WIN_SIZE_HEIGHT 120
bool CaptureWin::m_enableScaling = true;
+double CaptureWin::m_pixelAspectRatio = 1.0;
CaptureWin::CaptureWin() :
m_curWidth(-1),
@@ -76,6 +77,14 @@ void CaptureWin::resetSize()
resize(w, h);
}
+int CaptureWin::actualFrameWidth(int width)
+{
+ if (m_enableScaling)
+ return (int)((double)width * m_pixelAspectRatio);
+
+ return width;
+}
+
QSize CaptureWin::getMargins()
{
int l, t, r, b;
@@ -108,7 +117,7 @@ void CaptureWin::resize(int width, int height)
m_curHeight = height;
QSize margins = getMargins();
- width += margins.width();
+ width = actualFrameWidth(width) + margins.width();
height += margins.height();
QDesktopWidget *screen = QApplication::desktop();
@@ -130,25 +139,36 @@ void CaptureWin::resize(int width, int height)
QSize CaptureWin::scaleFrameSize(QSize window, QSize frame)
{
- int actualFrameWidth = frame.width();;
- int actualFrameHeight = frame.height();
+ int actualWidth;
+ int actualHeight = frame.height();
if (!m_enableScaling) {
window.setWidth(frame.width());
window.setHeight(frame.height());
+ actualWidth = frame.width();
+ } else {
+ actualWidth = CaptureWin::actualFrameWidth(frame.width());
}
double newW, newH;
if (window.width() >= window.height()) {
- newW = (double)window.width() / actualFrameWidth;
- newH = (double)window.height() / actualFrameHeight;
+ newW = (double)window.width() / actualWidth;
+ newH = (double)window.height() / actualHeight;
} else {
- newH = (double)window.width() / actualFrameWidth;
- newW = (double)window.height() / actualFrameHeight;
+ newH = (double)window.width() / actualWidth;
+ newW = (double)window.height() / actualHeight;
}
double resized = std::min(newW, newH);
- return QSize((int)(actualFrameWidth * resized), (int)(actualFrameHeight * resized));
+ return QSize((int)(actualWidth * resized), (int)(actualHeight * resized));
+}
+
+void CaptureWin::setPixelAspectRatio(double ratio)
+{
+ m_pixelAspectRatio = ratio;
+ QResizeEvent *event = new QResizeEvent(QSize(width(), height()), QSize(width(), height()));
+ QCoreApplication::sendEvent(this, event);
+ delete event;
}
void CaptureWin::closeEvent(QCloseEvent *event)
diff --git a/utils/qv4l2/capture-win.h b/utils/qv4l2/capture-win.h
index 1bfb1e1..e8f0ada 100644
--- a/utils/qv4l2/capture-win.h
+++ b/utils/qv4l2/capture-win.h
@@ -76,6 +76,7 @@ public:
static bool isSupported() { return false; }
void enableScaling(bool enable);
+ void setPixelAspectRatio(double ratio);
static QSize scaleFrameSize(QSize window, QSize frame);
public slots:
@@ -99,6 +100,11 @@ protected:
*/
static bool m_enableScaling;
+ /**
+ * @note Aspect ratio it taken care of by scaling, frame size is for square pixels only!
+ */
+ static double m_pixelAspectRatio;
+
signals:
void close();
diff --git a/utils/qv4l2/general-tab.cpp b/utils/qv4l2/general-tab.cpp
index 5cfaf07..c404a3b 100644
--- a/utils/qv4l2/general-tab.cpp
+++ b/utils/qv4l2/general-tab.cpp
@@ -53,6 +53,7 @@ GeneralTab::GeneralTab(const QString &device, v4l2 &fd, int n, QWidget *parent)
m_tvStandard(NULL),
m_qryStandard(NULL),
m_videoTimings(NULL),
+ m_pixelAspectRatio(NULL),
m_qryTimings(NULL),
m_freq(NULL),
m_vidCapFormats(NULL),
@@ -210,6 +211,23 @@ GeneralTab::GeneralTab(const QString &device, v4l2 &fd, int n, QWidget *parent)
connect(m_qryTimings, SIGNAL(clicked()), SLOT(qryTimingsClicked()));
}
+ if (!isRadio() && !isVbi()) {
+ m_pixelAspectRatio = new QComboBox(parent);
+ m_pixelAspectRatio->addItem("Autodetect");
+ m_pixelAspectRatio->addItem("Square");
+ m_pixelAspectRatio->addItem("NTSC/PAL-M/PAL-60");
+ m_pixelAspectRatio->addItem("NTSC/PAL-M/PAL-60, Anamorphic");
+ m_pixelAspectRatio->addItem("PAL/SECAM");
+ m_pixelAspectRatio->addItem("PAL/SECAM, Anamorphic");
+
+ // Update hints by calling a get
+ getPixelAspectRatio();
+
+ addLabel("Pixel Aspect Ratio");
+ addWidget(m_pixelAspectRatio);
+ connect(m_pixelAspectRatio, SIGNAL(activated(int)), SLOT(changePixelAspectRatio()));
+ }
+
if (m_tuner.capability) {
QDoubleValidator *val;
double factor = (m_tuner.capability & V4L2_TUNER_CAP_LOW) ? 16 : 16000;
@@ -1105,6 +1123,56 @@ void GeneralTab::updateFrameSize()
updateFrameInterval();
}
+void GeneralTab::changePixelAspectRatio()
+{
+ // Update hints by calling a get
+ getPixelAspectRatio();
+ info("");
+ emit pixelAspectRatioChanged();
+}
+
+double GeneralTab::getPixelAspectRatio()
+{
+ switch (m_pixelAspectRatio->currentIndex()) {
+ case 0:
+ v4l2_cropcap ratio;
+ ratio.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ if (ioctl(VIDIOC_CROPCAP, &ratio) < 0) {
+ m_pixelAspectRatio->setStatusTip("Pixel Aspect Ratio 1:1");
+ m_pixelAspectRatio->setWhatsThis("Pixel Aspect Ratio 1:1");
+ return 1.0;
+ }
+
+ m_pixelAspectRatio->setStatusTip(QString("Pixel Aspect Ratio %1:%2")
+ .arg(ratio.pixelaspect.denominator)
+ .arg(ratio.pixelaspect.numerator));
+ m_pixelAspectRatio->setWhatsThis(QString("Pixel Aspect Ratio %1:%2")
+ .arg(ratio.pixelaspect.denominator)
+ .arg(ratio.pixelaspect.numerator));
+ return (double)ratio.pixelaspect.denominator / ratio.pixelaspect.numerator;
+ case 2:
+ m_pixelAspectRatio->setStatusTip("Pixel Aspect Ratio 10:11");
+ m_pixelAspectRatio->setWhatsThis("Pixel Aspect Ratio 10:11");
+ return 10.0 / 11.0;
+ case 3:
+ m_pixelAspectRatio->setStatusTip("Pixel Aspect Ratio 40:33");
+ m_pixelAspectRatio->setWhatsThis("Pixel Aspect Ratio 40:33");
+ return 40.0 / 33.0;
+ case 4:
+ m_pixelAspectRatio->setStatusTip("Pixel Aspect Ratio 12:11");
+ m_pixelAspectRatio->setWhatsThis("Pixel Aspect Ratio 12:11");
+ return 12.0 / 11.0;
+ case 5:
+ m_pixelAspectRatio->setStatusTip("Pixel Aspect Ratio 16:11");
+ m_pixelAspectRatio->setWhatsThis("Pixel Aspect Ratio 16:11");
+ return 16.0 / 11.0;
+ default:
+ m_pixelAspectRatio->setStatusTip("Pixel Aspect Ratio 1:1");
+ m_pixelAspectRatio->setWhatsThis("Pixel Aspect Ratio 1:1");
+ return 1.0;
+ }
+}
+
void GeneralTab::updateFrameInterval()
{
v4l2_frmivalenum frmival;
diff --git a/utils/qv4l2/general-tab.h b/utils/qv4l2/general-tab.h
index 6c51016..4540e1f 100644
--- a/utils/qv4l2/general-tab.h
+++ b/utils/qv4l2/general-tab.h
@@ -57,6 +57,7 @@ public:
void setAudioDeviceBufferSize(int size);
int getAudioDeviceBufferSize();
bool hasAlsaAudio();
+ double getPixelAspectRatio();
bool get_interval(struct v4l2_fract &interval);
int width() const { return m_width; }
int height() const { return m_height; }
@@ -90,6 +91,7 @@ public slots:
signals:
void audioDeviceChanged();
+ void pixelAspectRatioChanged();
private slots:
void inputChanged(int);
@@ -115,6 +117,7 @@ private slots:
void vidOutFormatChanged(int);
void vbiMethodsChanged(int);
void changeAudioDevice();
+ void changePixelAspectRatio();
private:
void updateVideoInput();
@@ -182,6 +185,7 @@ private:
QComboBox *m_tvStandard;
QPushButton *m_qryStandard;
QComboBox *m_videoTimings;
+ QComboBox *m_pixelAspectRatio;
QPushButton *m_qryTimings;
QLineEdit *m_freq;
QComboBox *m_freqTable;
diff --git a/utils/qv4l2/qv4l2.cpp b/utils/qv4l2/qv4l2.cpp
index c94b0a8..892d9c3 100644
--- a/utils/qv4l2/qv4l2.cpp
+++ b/utils/qv4l2/qv4l2.cpp
@@ -103,7 +103,7 @@ ApplicationWindow::ApplicationWindow() :
m_saveRawAct->setChecked(false);
connect(m_saveRawAct, SIGNAL(toggled(bool)), this, SLOT(saveRaw(bool)));
- m_showFramesAct = new QAction(QIcon(":/video-television.png"), "Show &Frames", this);
+ m_showFramesAct = new QAction(QIcon(":/video-television.png"), "&Show Frames", this);
m_showFramesAct->setStatusTip("Only show captured frames if set.");
m_showFramesAct->setCheckable(true);
m_showFramesAct->setChecked(true);
@@ -137,12 +137,12 @@ ApplicationWindow::ApplicationWindow() :
toolBar->addSeparator();
toolBar->addAction(quitAct);
- m_scalingAct = new QAction("Enable Video Scaling", this);
+ 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)));
- m_resetScalingAct = new QAction("Resize to Frame Size", this);
+ m_resetScalingAct = new QAction("Resize to &Frame Size", this);
m_resetScalingAct->setStatusTip("Resizes the capture window to match frame size");
m_resetScalingAct->setShortcut(Qt::CTRL+Qt::Key_F);
@@ -168,13 +168,13 @@ ApplicationWindow::ApplicationWindow() :
#ifdef HAVE_ALSA
captureMenu->addSeparator();
- m_showAllAudioAct = new QAction("Show All Audio Devices", this);
+ m_showAllAudioAct = new QAction("Show All Audio &Devices", this);
m_showAllAudioAct->setStatusTip("Show all audio input and output devices if set");
m_showAllAudioAct->setCheckable(true);
m_showAllAudioAct->setChecked(false);
captureMenu->addAction(m_showAllAudioAct);
- m_audioBufferAct = new QAction("Set Audio Buffer Capacity...", this);
+ m_audioBufferAct = new QAction("Set Audio &Buffer Capacity...", this);
m_audioBufferAct->setStatusTip("Set audio buffer capacity in amout of ms than can be stored");
connect(m_audioBufferAct, SIGNAL(triggered()), this, SLOT(setAudioBufferSize()));
captureMenu->addAction(m_audioBufferAct);
@@ -229,7 +229,7 @@ void ApplicationWindow::setDevice(const QString &device, bool rawOpen)
m_audioBufferAct->setEnabled(false);
}
#endif
-
+ connect(m_genTab, SIGNAL(pixelAspectRatioChanged()), this, SLOT(updatePixelAspectRatio()));
m_tabs->addTab(w, "General");
addTabs();
if (caps() & (V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE)) {
@@ -360,6 +360,7 @@ void ApplicationWindow::newCaptureWin()
break;
}
+ m_capture->setPixelAspectRatio(1.0);
m_capture->enableScaling(m_scalingAct->isChecked());
connect(m_capture, SIGNAL(close()), this, SLOT(closeCaptureWin()));
connect(m_resetScalingAct, SIGNAL(triggered()), m_capture, SLOT(resetSize()));
@@ -810,6 +811,12 @@ void ApplicationWindow::enableScaling(bool enable)
m_capture->enableScaling(enable);
}
+void ApplicationWindow::updatePixelAspectRatio()
+{
+ if (m_capture != NULL && m_genTab != NULL)
+ m_capture->setPixelAspectRatio(m_genTab->getPixelAspectRatio());
+}
+
void ApplicationWindow::startAudio()
{
#ifdef HAVE_ALSA
@@ -891,6 +898,7 @@ void ApplicationWindow::capStart(bool start)
m_vbiTab->slicedFormat(fmt.fmt.sliced);
m_vbiSize = fmt.fmt.sliced.io_size;
m_frameData = new unsigned char[m_vbiSize];
+ updatePixelAspectRatio();
if (startCapture(m_vbiSize)) {
m_capNotifier = new QSocketNotifier(fd(), QSocketNotifier::Read, m_tabs);
connect(m_capNotifier, SIGNAL(activated(int)), this, SLOT(capVbiFrame()));
@@ -959,6 +967,7 @@ void ApplicationWindow::capStart(bool start)
m_capSrcFormat = copy;
}
+ updatePixelAspectRatio();
m_capture->resize(dstPix.width, dstPix.height);
m_capImage = new QImage(dstPix.width, dstPix.height, dstFmt);
m_capImage->fill(0);
diff --git a/utils/qv4l2/qv4l2.h b/utils/qv4l2/qv4l2.h
index 179cecb..970a0e1 100644
--- a/utils/qv4l2/qv4l2.h
+++ b/utils/qv4l2/qv4l2.h
@@ -133,6 +133,7 @@ private slots:
void rejectedRawFile();
void setAudioBufferSize();
void enableScaling(bool enable);
+ void updatePixelAspectRatio();
void about();
--
1.8.3.2
^ permalink raw reply related [flat|nested] 10+ messages in thread
end of thread, other threads:[~2013-08-06 10:22 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-08-06 10:21 [PATCH 0/9] qv4l2: scaling, pixel aspect ratio and render fixes Bård Eirik Winther
2013-08-06 10:21 ` [PATCH 1/9] qv4l2: generalized opengl include guards Bård Eirik Winther
2013-08-06 10:21 ` [PATCH 2/9] qv4l2: fix YUY2 shader Bård Eirik Winther
2013-08-06 10:21 ` [PATCH 3/9] qv4l2: fix black screen with opengl after capture Bård Eirik Winther
2013-08-06 10:21 ` [PATCH 4/9] qv4l2: show frames option can be toggled during capture Bård Eirik Winther
2013-08-06 10:21 ` [PATCH 5/9] qv4l2: create function getMargins Bård Eirik Winther
2013-08-06 10:21 ` [PATCH 6/9] qv4l2: add video scaling for CaptureWin Bård Eirik Winther
2013-08-06 10:21 ` [PATCH 7/9] qv4l2: added resize to frame size in Capture menu Bård Eirik Winther
2013-08-06 10:21 ` [PATCH 8/9] qv4l2: add hotkey for reset scaling to frame size Bård Eirik Winther
2013-08-06 10:21 ` [PATCH 9/9] qv4l2: add pixel aspect ratio support for CaptureWin Bård Eirik Winther
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).