linux-media.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH 0/7] qv4l2: scaling and pixel aspect ratio
@ 2013-08-05  8:56 Bård Eirik Winther
  2013-08-05  8:56 ` [RFC PATCH 1/7] qv4l2: fix YUY2 shader Bård Eirik Winther
  0 siblings, 1 reply; 9+ messages in thread
From: Bård Eirik Winther @ 2013-08-05  8:56 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.
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
- 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
- Reset and disable scaling options
- 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


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [RFC PATCH 1/7] qv4l2: fix YUY2 shader
  2013-08-05  8:56 [RFC PATCH 0/7] qv4l2: scaling and pixel aspect ratio Bård Eirik Winther
@ 2013-08-05  8:56 ` Bård Eirik Winther
  2013-08-05  8:56   ` [RFC PATCH 2/7] qv4l2: fix black screen with opengl after capture Bård Eirik Winther
                     ` (5 more replies)
  0 siblings, 6 replies; 9+ messages in thread
From: Bård Eirik Winther @ 2013-08-05  8:56 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 52412c7..bae6569 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] 9+ messages in thread

* [RFC PATCH 2/7] qv4l2: fix black screen with opengl after capture
  2013-08-05  8:56 ` [RFC PATCH 1/7] qv4l2: fix YUY2 shader Bård Eirik Winther
@ 2013-08-05  8:56   ` Bård Eirik Winther
  2013-08-05  8:56   ` [RFC PATCH 3/7] qv4l2: show frames option can be toggled during capture Bård Eirik Winther
                     ` (4 subsequent siblings)
  5 siblings, 0 replies; 9+ messages in thread
From: Bård Eirik Winther @ 2013-08-05  8:56 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 bae6569..edae60f 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] 9+ messages in thread

* [RFC PATCH 3/7] qv4l2: show frames option can be toggled during capture
  2013-08-05  8:56 ` [RFC PATCH 1/7] qv4l2: fix YUY2 shader Bård Eirik Winther
  2013-08-05  8:56   ` [RFC PATCH 2/7] qv4l2: fix black screen with opengl after capture Bård Eirik Winther
@ 2013-08-05  8:56   ` Bård Eirik Winther
  2013-08-05  8:56   ` [RFC PATCH 4/7] qv4l2: add function getMargins Bård Eirik Winther
                     ` (3 subsequent siblings)
  5 siblings, 0 replies; 9+ messages in thread
From: Bård Eirik Winther @ 2013-08-05  8:56 UTC (permalink / raw)
  To: linux-media

Signed-off-by: Bård Eirik Winther <bwinther@cisco.com>
---
 utils/qv4l2/qv4l2.cpp | 77 ++++++++++++++++++++++++++-------------------------
 utils/qv4l2/qv4l2.h   |  2 +-
 2 files changed, 41 insertions(+), 38 deletions(-)

diff --git a/utils/qv4l2/qv4l2.cpp b/utils/qv4l2/qv4l2.cpp
index e078e91..fa1425d 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);
 
@@ -490,7 +490,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,
@@ -514,7 +514,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,
@@ -592,10 +592,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);
 
@@ -778,6 +778,13 @@ void ApplicationWindow::stopCapture()
 	refresh();
 }
 
+bool ApplicationWindow::showFrames()
+{
+	if (m_showFramesAct->isChecked() && !m_capture->isVisible())
+		m_capture->show();
+	return m_showFramesAct->isChecked();
+}
+
 void ApplicationWindow::startOutput(unsigned)
 {
 }
@@ -851,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();
 
@@ -859,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) ?
@@ -898,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);
@@ -919,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 223db75..92d6f25 100644
--- a/utils/qv4l2/qv4l2.h
+++ b/utils/qv4l2/qv4l2.h
@@ -172,6 +172,7 @@ private:
 	void updateStandard();
 	void updateFreq();
 	void updateFreqChannel();
+	bool showFrames();
 
 	GeneralTab *m_genTab;
 	VbiTab *m_vbiTab;
@@ -193,7 +194,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] 9+ messages in thread

* [RFC PATCH 4/7] qv4l2: add function getMargins
  2013-08-05  8:56 ` [RFC PATCH 1/7] qv4l2: fix YUY2 shader Bård Eirik Winther
  2013-08-05  8:56   ` [RFC PATCH 2/7] qv4l2: fix black screen with opengl after capture Bård Eirik Winther
  2013-08-05  8:56   ` [RFC PATCH 3/7] qv4l2: show frames option can be toggled during capture Bård Eirik Winther
@ 2013-08-05  8:56   ` Bård Eirik Winther
  2013-08-05  8:56   ` [RFC PATCH 5/7] qv4l2: add video scaling for CaptureWin Bård Eirik Winther
                     ` (2 subsequent siblings)
  5 siblings, 0 replies; 9+ messages in thread
From: Bård Eirik Winther @ 2013-08-05  8:56 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   |  2 ++
 2 files changed, 12 insertions(+), 4 deletions(-)

diff --git a/utils/qv4l2/capture-win.cpp b/utils/qv4l2/capture-win.cpp
index 2d57909..e583900 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..6b72e00 100644
--- a/utils/qv4l2/capture-win.h
+++ b/utils/qv4l2/capture-win.h
@@ -78,6 +78,8 @@ 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] 9+ messages in thread

* [RFC PATCH 5/7] qv4l2: add video scaling for CaptureWin
  2013-08-05  8:56 ` [RFC PATCH 1/7] qv4l2: fix YUY2 shader Bård Eirik Winther
                     ` (2 preceding siblings ...)
  2013-08-05  8:56   ` [RFC PATCH 4/7] qv4l2: add function getMargins Bård Eirik Winther
@ 2013-08-05  8:56   ` Bård Eirik Winther
  2013-08-05  8:56   ` [RFC PATCH 6/7] qv4l2: add hotkey for reset scaling to frame size Bård Eirik Winther
  2013-08-05  8:56   ` [RFC PATCH 7/7] qv4l2: add aspect ratio support Bård Eirik Winther
  5 siblings, 0 replies; 9+ messages in thread
From: Bård Eirik Winther @ 2013-08-05  8:56 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   |   8 ++++
 utils/qv4l2/capture-win-qt.cpp |  24 +++++++++-
 utils/qv4l2/capture-win-qt.h   |   5 ++
 utils/qv4l2/capture-win.cpp    | 106 +++++++++++++++++++++++++++++++----------
 utils/qv4l2/capture-win.h      |  18 +++++--
 utils/qv4l2/qv4l2.cpp          |  27 +++++++++--
 utils/qv4l2/qv4l2.h            |   4 ++
 8 files changed, 181 insertions(+), 37 deletions(-)

diff --git a/utils/qv4l2/capture-win-gl.cpp b/utils/qv4l2/capture-win-gl.cpp
index edae60f..628aaec 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)
+{
+	QSize margins = getMargins();
+#ifdef ENABLE_GL
+	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 ENABLE_GL
@@ -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 08e72b2..ef06d0b 100644
--- a/utils/qv4l2/capture-win-gl.h
+++ b/utils/qv4l2/capture-win-gl.h
@@ -21,6 +21,9 @@
 #include "qv4l2.h"
 #include "capture-win.h"
 
+#include <QBoxLayout>
+#include <QResizeEvent>
+
 #ifdef ENABLE_GL
 #define GL_GLEXT_PROTOTYPES
 #include <QGLWidget>
@@ -40,6 +43,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();
@@ -88,6 +92,10 @@ public:
 	bool hasNativeFormat(__u32 format);
 	static bool isSupported();
 
+ protected:
+	void resizeEvent(QResizeEvent *event);
+
+private:
 #ifdef ENABLE_GL
 	CaptureWinGLEngine m_videoSurface;
 #endif
diff --git a/utils/qv4l2/capture-win-qt.cpp b/utils/qv4l2/capture-win-qt.cpp
index 63c77d5..0f6964b 100644
--- a/utils/qv4l2/capture-win-qt.cpp
+++ b/utils/qv4l2/capture-win-qt.cpp
@@ -22,8 +22,9 @@
 CaptureWinQt::CaptureWinQt() :
 	m_frame(new QImage(0, 0, QImage::Format_Invalid))
 {
-
 	CaptureWin::buildWindow(&m_videoSurface);
+	m_scaledFrame.setWidth(0);
+	m_scaledFrame.setHeight(0);
 }
 
 CaptureWinQt::~CaptureWinQt()
@@ -31,6 +32,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 +55,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 +65,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 e583900..4c5dd57 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()
@@ -54,37 +61,88 @@ void CaptureWin::buildWindow(QWidget *videoSurface)
 	vbox->setSpacing(b);
 }
 
+void CaptureWin::resetSize()
+{
+	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;
- 	layout()->getContentsMargins(&l, &t, &r, &b);
+	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)
+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 6b72e00..eea0335 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,12 +75,18 @@ public:
 	 */
 	static bool isSupported() { return false; }
 
+	void enableScaling(bool enable);
+	static QSize scaleFrameSize(QSize window, QSize frame);
+
+public slots:
+	void resetSize();
+
 protected:
 	void closeEvent(QCloseEvent *event);
 	void buildWindow(QWidget *videoSurface);
+	static int actualFrameWidth(int width);
 	QSize getMargins();
 
-
 	/**
 	 * @brief A label that can is used to display capture information.
 	 *
@@ -88,11 +94,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 fa1425d..6b64892 100644
--- a/utils/qv4l2/qv4l2.cpp
+++ b/utils/qv4l2/qv4l2.cpp
@@ -137,9 +137,20 @@ 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)));
+	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;
@@ -351,7 +362,9 @@ 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()));
+	connect(m_resetScalingAct, SIGNAL(triggered()), m_capture, SLOT(resetSize()));
 }
 
 void ApplicationWindow::capVbiFrame()
@@ -793,6 +806,12 @@ void ApplicationWindow::stopOutput()
 {
 }
 
+void ApplicationWindow::enableScaling(bool enable)
+{
+	if (m_capture != NULL)
+		m_capture->enableScaling(enable);
+}
+
 void ApplicationWindow::startAudio()
 {
 #ifdef ENABLE_ALSA
@@ -903,7 +922,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 +952,8 @@ void ApplicationWindow::capStart(bool start)
 		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
@@ -942,7 +961,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 92d6f25..3704ab1 100644
--- a/utils/qv4l2/qv4l2.h
+++ b/utils/qv4l2/qv4l2.h
@@ -130,6 +130,8 @@ private slots:
 	void openRawFile(const QString &s);
 	void rejectedRawFile();
 	void setAudioBufferSize();
+	void enableScaling(bool enable);
+
 
 	void about();
 
@@ -183,6 +185,8 @@ private:
 	QAction *m_useGLAct;
 	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] 9+ messages in thread

* [RFC PATCH 6/7] qv4l2: add hotkey for reset scaling to frame size
  2013-08-05  8:56 ` [RFC PATCH 1/7] qv4l2: fix YUY2 shader Bård Eirik Winther
                     ` (3 preceding siblings ...)
  2013-08-05  8:56   ` [RFC PATCH 5/7] qv4l2: add video scaling for CaptureWin Bård Eirik Winther
@ 2013-08-05  8:56   ` Bård Eirik Winther
  2013-08-05  8:56   ` [RFC PATCH 7/7] qv4l2: add aspect ratio support Bård Eirik Winther
  5 siblings, 0 replies; 9+ messages in thread
From: Bård Eirik Winther @ 2013-08-05  8:56 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 4c5dd57..435c19b 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 6b64892..92a415f 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] 9+ messages in thread

* [RFC PATCH 7/7] qv4l2: add aspect ratio support
  2013-08-05  8:56 ` [RFC PATCH 1/7] qv4l2: fix YUY2 shader Bård Eirik Winther
                     ` (4 preceding siblings ...)
  2013-08-05  8:56   ` [RFC PATCH 6/7] qv4l2: add hotkey for reset scaling to frame size Bård Eirik Winther
@ 2013-08-05  8:56   ` Bård Eirik Winther
  2013-08-05  9:31     ` Hans Verkuil
  5 siblings, 1 reply; 9+ messages in thread
From: Bård Eirik Winther @ 2013-08-05  8:56 UTC (permalink / raw)
  To: linux-media

Signed-off-by: Bård Eirik Winther <bwinther@cisco.com>
---
 utils/qv4l2/capture-win.cpp | 24 ++++++++++++++++++++++--
 utils/qv4l2/capture-win.h   |  8 +++++++-
 utils/qv4l2/general-tab.cpp | 36 ++++++++++++++++++++++++++++++++++++
 utils/qv4l2/general-tab.h   |  3 +++
 utils/qv4l2/qv4l2.cpp       | 22 +++++++++++++++-------
 utils/qv4l2/qv4l2.h         |  2 +-
 6 files changed, 84 insertions(+), 11 deletions(-)

diff --git a/utils/qv4l2/capture-win.cpp b/utils/qv4l2/capture-win.cpp
index 435c19b..415829a 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),
@@ -73,6 +74,14 @@ void CaptureWin::resetSize()
 	resize(w, h);
 }
 
+int CaptureWin::actualFrameWidth(int width)
+{
+	if (m_enableScaling)
+		return (int)((double)width * m_pixelAspectRatio);
+	else
+		return width;
+}
+
 QSize CaptureWin::getMargins()
 {
 	int l, t, r, b;
@@ -94,6 +103,14 @@ void CaptureWin::enableScaling(bool enable)
 	delete event;
 }
 
+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::resize(int width, int height)
 {
 	// Dont resize window if the frame size is the same in
@@ -105,7 +122,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();
@@ -127,12 +144,15 @@ void CaptureWin::resize(int width, int height)
 
 QSize CaptureWin::scaleFrameSize(QSize window, QSize frame)
 {
-	int actualFrameWidth = frame.width();;
+	int actualFrameWidth;
 	int actualFrameHeight = frame.height();
 
 	if (!m_enableScaling) {
 		window.setWidth(frame.width());
 		window.setHeight(frame.height());
+		actualFrameWidth = frame.width();
+	} else {
+		actualFrameWidth = CaptureWin::actualFrameWidth(frame.width());
 	}
 
 	double newW, newH;
diff --git a/utils/qv4l2/capture-win.h b/utils/qv4l2/capture-win.h
index 1bfb1e1..eded9e0 100644
--- a/utils/qv4l2/capture-win.h
+++ b/utils/qv4l2/capture-win.h
@@ -76,9 +76,10 @@ public:
 	static bool isSupported() { return false; }
 
 	void enableScaling(bool enable);
+	void setPixelAspectRatio(double ratio);
 	static QSize scaleFrameSize(QSize window, QSize frame);
 
-public slots:
+	public slots:
 	void resetSize();
 
 protected:
@@ -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 5996c03..53b7e36 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,20 @@ 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");
+
+		addLabel("Pixel Aspect Ratio");
+		addWidget(m_pixelAspectRatio);
+		connect(m_pixelAspectRatio, SIGNAL(activated(int)), SIGNAL(pixelAspectRatioChanged()));
+	}
+
 	if (m_tuner.capability) {
 		QDoubleValidator *val;
 		double factor = (m_tuner.capability & V4L2_TUNER_CAP_LOW) ? 16 : 16000;
@@ -1105,6 +1120,27 @@ void GeneralTab::updateFrameSize()
 	updateFrameInterval();
 }
 
+double GeneralTab::getPixelAspectRatio()
+{
+	if (m_pixelAspectRatio->currentText().compare("Autodetect") == 0) {
+		v4l2_cropcap ratio;
+		ratio.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		if (ioctl(VIDIOC_CROPCAP, &ratio) < 0)
+			return 1.0;
+
+		return (double)ratio.pixelaspect.denominator / ratio.pixelaspect.numerator;
+	}
+	if (m_pixelAspectRatio->currentText().compare("NTSC/PAL-M/PAL-60") == 0)
+		return 10.0/11.0;
+	if (m_pixelAspectRatio->currentText().compare("NTSC/PAL-M/PAL-60, Anamorphic") == 0)
+		return 40.0/33.0;
+	if (m_pixelAspectRatio->currentText().compare("PAL/SECAM") == 0)
+		return 12.0/11.0;
+	if (m_pixelAspectRatio->currentText().compare("PAL/SECAM, Anamorphic") == 0)
+		return 16.0/11.0;
+	return 1.0;
+}
+
 void GeneralTab::updateFrameInterval()
 {
 	v4l2_frmivalenum frmival;
diff --git a/utils/qv4l2/general-tab.h b/utils/qv4l2/general-tab.h
index c83368a..73e7a88 100644
--- a/utils/qv4l2/general-tab.h
+++ b/utils/qv4l2/general-tab.h
@@ -55,6 +55,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; }
@@ -88,6 +89,7 @@ public slots:
 
 signals:
 	void audioDeviceChanged();
+	void pixelAspectRatioChanged();
 
 private slots:
 	void inputChanged(int);
@@ -180,6 +182,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 92a415f..0ce3cd7 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);
 
@@ -169,13 +169,13 @@ ApplicationWindow::ApplicationWindow() :
 #ifdef ENABLE_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 Size...", this);
+	m_audioBufferAct = new QAction("Set Audio &Buffer Size...", 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);
@@ -216,8 +216,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);
 
@@ -233,6 +231,7 @@ void ApplicationWindow::setDevice(const QString &device, bool rawOpen)
 	}
 #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)) {
@@ -363,6 +362,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()));
@@ -813,6 +813,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 ENABLE_ALSA
@@ -894,6 +900,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()));
@@ -962,6 +969,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 3704ab1..859113a 100644
--- a/utils/qv4l2/qv4l2.h
+++ b/utils/qv4l2/qv4l2.h
@@ -131,7 +131,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] 9+ messages in thread

* Re: [RFC PATCH 7/7] qv4l2: add aspect ratio support
  2013-08-05  8:56   ` [RFC PATCH 7/7] qv4l2: add aspect ratio support Bård Eirik Winther
@ 2013-08-05  9:31     ` Hans Verkuil
  0 siblings, 0 replies; 9+ messages in thread
From: Hans Verkuil @ 2013-08-05  9:31 UTC (permalink / raw)
  To: Bård Eirik Winther; +Cc: linux-media

Hi Bård,

Some comments below...

On 08/05/2013 10:56 AM, Bård Eirik Winther wrote:
> Signed-off-by: Bård Eirik Winther <bwinther@cisco.com>
> ---
>  utils/qv4l2/capture-win.cpp | 24 ++++++++++++++++++++++--
>  utils/qv4l2/capture-win.h   |  8 +++++++-
>  utils/qv4l2/general-tab.cpp | 36 ++++++++++++++++++++++++++++++++++++
>  utils/qv4l2/general-tab.h   |  3 +++
>  utils/qv4l2/qv4l2.cpp       | 22 +++++++++++++++-------
>  utils/qv4l2/qv4l2.h         |  2 +-
>  6 files changed, 84 insertions(+), 11 deletions(-)
> 
> diff --git a/utils/qv4l2/capture-win.cpp b/utils/qv4l2/capture-win.cpp
> index 435c19b..415829a 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),
> @@ -73,6 +74,14 @@ void CaptureWin::resetSize()
>  	resize(w, h);
>  }
>  
> +int CaptureWin::actualFrameWidth(int width)
> +{
> +	if (m_enableScaling)
> +		return (int)((double)width * m_pixelAspectRatio);
> +	else

No need for the 'else' statement.

> +		return width;
> +}
> +
>  QSize CaptureWin::getMargins()
>  {
>  	int l, t, r, b;
> @@ -94,6 +103,14 @@ void CaptureWin::enableScaling(bool enable)
>  	delete event;
>  }
>  
> +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::resize(int width, int height)
>  {
>  	// Dont resize window if the frame size is the same in
> @@ -105,7 +122,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();
> @@ -127,12 +144,15 @@ void CaptureWin::resize(int width, int height)
>  
>  QSize CaptureWin::scaleFrameSize(QSize window, QSize frame)
>  {
> -	int actualFrameWidth = frame.width();;
> +	int actualFrameWidth;
>  	int actualFrameHeight = frame.height();
>  
>  	if (!m_enableScaling) {
>  		window.setWidth(frame.width());
>  		window.setHeight(frame.height());
> +		actualFrameWidth = frame.width();
> +	} else {
> +		actualFrameWidth = CaptureWin::actualFrameWidth(frame.width());
>  	}
>  
>  	double newW, newH;
> diff --git a/utils/qv4l2/capture-win.h b/utils/qv4l2/capture-win.h
> index 1bfb1e1..eded9e0 100644
> --- a/utils/qv4l2/capture-win.h
> +++ b/utils/qv4l2/capture-win.h
> @@ -76,9 +76,10 @@ public:
>  	static bool isSupported() { return false; }
>  
>  	void enableScaling(bool enable);
> +	void setPixelAspectRatio(double ratio);
>  	static QSize scaleFrameSize(QSize window, QSize frame);
>  
> -public slots:
> +	public slots:
>  	void resetSize();
>  
>  protected:
> @@ -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 5996c03..53b7e36 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,20 @@ 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");
> +
> +		addLabel("Pixel Aspect Ratio");
> +		addWidget(m_pixelAspectRatio);
> +		connect(m_pixelAspectRatio, SIGNAL(activated(int)), SIGNAL(pixelAspectRatioChanged()));
> +	}
> +
>  	if (m_tuner.capability) {
>  		QDoubleValidator *val;
>  		double factor = (m_tuner.capability & V4L2_TUNER_CAP_LOW) ? 16 : 16000;
> @@ -1105,6 +1120,27 @@ void GeneralTab::updateFrameSize()
>  	updateFrameInterval();
>  }
>  
> +double GeneralTab::getPixelAspectRatio()
> +{
> +	if (m_pixelAspectRatio->currentText().compare("Autodetect") == 0) {
> +		v4l2_cropcap ratio;
> +		ratio.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
> +		if (ioctl(VIDIOC_CROPCAP, &ratio) < 0)
> +			return 1.0;
> +
> +		return (double)ratio.pixelaspect.denominator / ratio.pixelaspect.numerator;
> +	}
> +	if (m_pixelAspectRatio->currentText().compare("NTSC/PAL-M/PAL-60") == 0)
> +		return 10.0/11.0;
> +	if (m_pixelAspectRatio->currentText().compare("NTSC/PAL-M/PAL-60, Anamorphic") == 0)
> +		return 40.0/33.0;
> +	if (m_pixelAspectRatio->currentText().compare("PAL/SECAM") == 0)
> +		return 12.0/11.0;
> +	if (m_pixelAspectRatio->currentText().compare("PAL/SECAM, Anamorphic") == 0)
> +		return 16.0/11.0;

These string compares are flaky: if someone changes the string in the GUI, then it is
all too easy to forget about changing this.

Take a look at how the audio mode (m_audioMode) is handled. You should do something
similar.

> +	return 1.0;
> +}
> +

Regards,

	Hans


^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2013-08-05  9:31 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-08-05  8:56 [RFC PATCH 0/7] qv4l2: scaling and pixel aspect ratio Bård Eirik Winther
2013-08-05  8:56 ` [RFC PATCH 1/7] qv4l2: fix YUY2 shader Bård Eirik Winther
2013-08-05  8:56   ` [RFC PATCH 2/7] qv4l2: fix black screen with opengl after capture Bård Eirik Winther
2013-08-05  8:56   ` [RFC PATCH 3/7] qv4l2: show frames option can be toggled during capture Bård Eirik Winther
2013-08-05  8:56   ` [RFC PATCH 4/7] qv4l2: add function getMargins Bård Eirik Winther
2013-08-05  8:56   ` [RFC PATCH 5/7] qv4l2: add video scaling for CaptureWin Bård Eirik Winther
2013-08-05  8:56   ` [RFC PATCH 6/7] qv4l2: add hotkey for reset scaling to frame size Bård Eirik Winther
2013-08-05  8:56   ` [RFC PATCH 7/7] qv4l2: add aspect ratio support Bård Eirik Winther
2013-08-05  9:31     ` Hans Verkuil

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).