• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * The YUY2 shader code is based on face-responder. The code is under public domain:
4  * https://bitbucket.org/nateharward/face-responder/src/0c3b4b957039d9f4bf1da09b9471371942de2601/yuv42201_laplace.frag?at=master
5  *
6  * All other OpenGL code:
7  *
8  * Copyright 2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
9  */
10 
11 #include "capture.h"
12 
13 #include <QtCore/QTextStream>
14 #include <QtCore/QCoreApplication>
15 #include <QtGui/QOpenGLContext>
16 #if QT_VERSION < 0x060000
17 #include <QtGui/QOpenGLPaintDevice>
18 #else
19 #include <QOpenGLPaintDevice>
20 #endif
21 #include <QtGui/QContextMenuEvent>
22 #include <QtGui/QKeyEvent>
23 #include <QtGui/QPainter>
24 #include <QtCore/QSocketNotifier>
25 #include <QtMath>
26 #include <QTimer>
27 #include <QApplication>
28 
29 #include <netinet/in.h>
30 #include "v4l2-info.h"
31 
32 const __u32 formats[] = {
33 	V4L2_PIX_FMT_YUYV,
34 	V4L2_PIX_FMT_YVYU,
35 	V4L2_PIX_FMT_UYVY,
36 	V4L2_PIX_FMT_VYUY,
37 	V4L2_PIX_FMT_YUV422P,
38 	V4L2_PIX_FMT_YVU420,
39 	V4L2_PIX_FMT_YUV420,
40 	V4L2_PIX_FMT_NV12,
41 	V4L2_PIX_FMT_NV21,
42 	V4L2_PIX_FMT_NV16,
43 	V4L2_PIX_FMT_NV61,
44 	V4L2_PIX_FMT_NV24,
45 	V4L2_PIX_FMT_NV42,
46 	V4L2_PIX_FMT_NV16M,
47 	V4L2_PIX_FMT_NV61M,
48 	V4L2_PIX_FMT_YVU420M,
49 	V4L2_PIX_FMT_YUV420M,
50 	V4L2_PIX_FMT_YVU422M,
51 	V4L2_PIX_FMT_YUV422M,
52 	V4L2_PIX_FMT_YVU444M,
53 	V4L2_PIX_FMT_YUV444M,
54 	V4L2_PIX_FMT_NV12M,
55 	V4L2_PIX_FMT_NV21M,
56 	V4L2_PIX_FMT_YUV444,
57 	V4L2_PIX_FMT_YUV555,
58 	V4L2_PIX_FMT_YUV565,
59 	V4L2_PIX_FMT_YUV32,
60 	V4L2_PIX_FMT_AYUV32,
61 	V4L2_PIX_FMT_XYUV32,
62 	V4L2_PIX_FMT_VUYA32,
63 	V4L2_PIX_FMT_VUYX32,
64 	V4L2_PIX_FMT_YUVA32,
65 	V4L2_PIX_FMT_YUVX32,
66 	V4L2_PIX_FMT_RGB32,
67 	V4L2_PIX_FMT_XRGB32,
68 	V4L2_PIX_FMT_ARGB32,
69 	V4L2_PIX_FMT_RGBX32,
70 	V4L2_PIX_FMT_RGBA32,
71 	V4L2_PIX_FMT_BGR32,
72 	V4L2_PIX_FMT_XBGR32,
73 	V4L2_PIX_FMT_ABGR32,
74 	V4L2_PIX_FMT_BGRX32,
75 	V4L2_PIX_FMT_BGRA32,
76 	V4L2_PIX_FMT_RGB24,
77 	V4L2_PIX_FMT_BGR24,
78 	V4L2_PIX_FMT_RGB565,
79 	V4L2_PIX_FMT_RGB565X,
80 	V4L2_PIX_FMT_RGB444,
81 	V4L2_PIX_FMT_XRGB444,
82 	V4L2_PIX_FMT_ARGB444,
83 	V4L2_PIX_FMT_XBGR444,
84 	V4L2_PIX_FMT_ABGR444,
85 	V4L2_PIX_FMT_RGBX444,
86 	V4L2_PIX_FMT_RGBA444,
87 	V4L2_PIX_FMT_BGRX444,
88 	V4L2_PIX_FMT_BGRA444,
89 	V4L2_PIX_FMT_RGB555,
90 	V4L2_PIX_FMT_XRGB555,
91 	V4L2_PIX_FMT_ARGB555,
92 	V4L2_PIX_FMT_RGB555X,
93 	V4L2_PIX_FMT_XRGB555X,
94 	V4L2_PIX_FMT_ARGB555X,
95 	V4L2_PIX_FMT_RGBX555,
96 	V4L2_PIX_FMT_RGBA555,
97 	V4L2_PIX_FMT_XBGR555,
98 	V4L2_PIX_FMT_ABGR555,
99 	V4L2_PIX_FMT_BGRX555,
100 	V4L2_PIX_FMT_BGRA555,
101 	V4L2_PIX_FMT_RGB332,
102 	V4L2_PIX_FMT_BGR666,
103 	V4L2_PIX_FMT_SBGGR8,
104 	V4L2_PIX_FMT_SGBRG8,
105 	V4L2_PIX_FMT_SGRBG8,
106 	V4L2_PIX_FMT_SRGGB8,
107 	V4L2_PIX_FMT_SBGGR10,
108 	V4L2_PIX_FMT_SGBRG10,
109 	V4L2_PIX_FMT_SGRBG10,
110 	V4L2_PIX_FMT_SRGGB10,
111 	V4L2_PIX_FMT_SBGGR12,
112 	V4L2_PIX_FMT_SGBRG12,
113 	V4L2_PIX_FMT_SGRBG12,
114 	V4L2_PIX_FMT_SRGGB12,
115 	V4L2_PIX_FMT_SBGGR16,
116 	V4L2_PIX_FMT_SGBRG16,
117 	V4L2_PIX_FMT_SGRBG16,
118 	V4L2_PIX_FMT_SRGGB16,
119 	V4L2_PIX_FMT_HSV24,
120 	V4L2_PIX_FMT_HSV32,
121 	V4L2_PIX_FMT_GREY,
122 	V4L2_PIX_FMT_Y10,
123 	V4L2_PIX_FMT_Y12,
124 	V4L2_PIX_FMT_Y16,
125 	V4L2_PIX_FMT_Y16_BE,
126 	V4L2_PIX_FMT_Z16,
127 	0
128 };
129 
130 const __u32 fields[] = {
131 	V4L2_FIELD_NONE,
132 	V4L2_FIELD_TOP,
133 	V4L2_FIELD_BOTTOM,
134 	V4L2_FIELD_INTERLACED,
135 	V4L2_FIELD_SEQ_TB,
136 	V4L2_FIELD_SEQ_BT,
137 	V4L2_FIELD_ALTERNATE,
138 	V4L2_FIELD_INTERLACED_TB,
139 	V4L2_FIELD_INTERLACED_BT,
140 	0
141 };
142 
143 const __u32 colorspaces[] = {
144 	V4L2_COLORSPACE_SMPTE170M,
145 	V4L2_COLORSPACE_SMPTE240M,
146 	V4L2_COLORSPACE_REC709,
147 	V4L2_COLORSPACE_470_SYSTEM_M,
148 	V4L2_COLORSPACE_470_SYSTEM_BG,
149 	V4L2_COLORSPACE_SRGB,
150 	V4L2_COLORSPACE_OPRGB,
151 	V4L2_COLORSPACE_DCI_P3,
152 	V4L2_COLORSPACE_BT2020,
153 	0
154 };
155 
156 const __u32 xfer_funcs[] = {
157 	V4L2_XFER_FUNC_709,
158 	V4L2_XFER_FUNC_SRGB,
159 	V4L2_XFER_FUNC_OPRGB,
160 	V4L2_XFER_FUNC_DCI_P3,
161 	V4L2_XFER_FUNC_SMPTE2084,
162 	V4L2_XFER_FUNC_SMPTE240M,
163 	V4L2_XFER_FUNC_NONE,
164 	0
165 };
166 
167 const __u32 ycbcr_encs[] = {
168 	V4L2_YCBCR_ENC_601,
169 	V4L2_YCBCR_ENC_709,
170 	V4L2_YCBCR_ENC_XV601,
171 	V4L2_YCBCR_ENC_XV709,
172 	V4L2_YCBCR_ENC_BT2020,
173 	V4L2_YCBCR_ENC_BT2020_CONST_LUM,
174 	V4L2_YCBCR_ENC_SMPTE240M,
175 	0
176 };
177 
178 const __u32 hsv_encs[] = {
179 	V4L2_HSV_ENC_180,
180 	V4L2_HSV_ENC_256,
181 	0
182 };
183 
184 const __u32 quantizations[] = {
185 	V4L2_QUANTIZATION_FULL_RANGE,
186 	V4L2_QUANTIZATION_LIM_RANGE,
187 	0
188 };
189 
190 enum {
191 	CAPTURE_GL_WIN_RESIZE,
192 	CAPTURE_GL_WIN_SCROLLBAR,
193 };
194 
checkSubMenuItem(QMenu * menu,__u32 value)195 static void checkSubMenuItem(QMenu *menu, __u32 value)
196 {
197 	for (auto &action : menu->actions()) {
198 		if (action->data() == value) {
199 			action->setChecked(true);
200 			break;
201 		}
202 	}
203 }
204 
addSubMenuItem(QActionGroup * grp,QMenu * menu,const QString & text,int val)205 static QAction *addSubMenuItem(QActionGroup *grp, QMenu *menu, const QString &text, int val)
206 {
207 	QAction *a = grp->addAction(menu->addAction(text));
208 
209 	a->setData(QVariant(val));
210 	a->setCheckable(true);
211 	return a;
212 }
213 
CaptureWin(QScrollArea * sa,QWidget * parent)214 CaptureWin::CaptureWin(QScrollArea *sa, QWidget *parent) :
215 	QOpenGLWidget(parent),
216 	m_fd(0),
217 	m_sock(0),
218 	m_v4l_queue(0),
219 	m_frame(0),
220 	m_ctx(0),
221 	m_origPixelFormat(0),
222 	m_fps(0),
223 	m_singleStep(false),
224 	m_singleStepStart(0),
225 	m_singleStepNext(false),
226 	m_screenTextureCount(0),
227 	m_program(0),
228 	m_curIndex(-1),
229 	m_nextIndex(-1),
230 	m_scrollArea(sa)
231 {
232 	m_curSize[0] = 0;
233 	m_curData[0] = 0;
234 	m_canOverrideResolution = false;
235 	m_pixelaspect.numerator = 1;
236 	m_pixelaspect.denominator = 1;
237 	QMenu *menu = new QMenu("Override Pixel Format (P)");
238 	m_fmtMenu = menu;
239 	QActionGroup *grp = new QActionGroup(menu);
240 	addSubMenuItem(grp, menu, "No Override", 0)->setChecked(true);
241 	for (unsigned i = 0; formats[i]; i++) {
242 		std::string fmt = "'" + fcc2s(formats[i]) + "' " + pixfmt2s(formats[i]);
243 
244 		addSubMenuItem(grp, menu, fmt.c_str(), formats[i]);
245 	}
246 	connect(grp, SIGNAL(triggered(QAction *)), this, SLOT(fmtChanged(QAction *)));
247 
248 	menu = new QMenu("Override Field (I)");
249 	m_fieldMenu = menu;
250 	grp = new QActionGroup(menu);
251 	addSubMenuItem(grp, menu, "No Override", -1)->setChecked(true);
252 	for (unsigned i = 0; fields[i]; i++)
253 		addSubMenuItem(grp, menu,
254 			       field2s(fields[i]).c_str(), fields[i]);
255 	connect(grp, SIGNAL(triggered(QAction *)), this, SLOT(fieldChanged(QAction *)));
256 
257 	menu = new QMenu("Override Colorspace (C)");
258 	m_colorspaceMenu = menu;
259 	grp = new QActionGroup(menu);
260 	addSubMenuItem(grp, menu, "No Override", -1)->setChecked(true);
261 	for (unsigned i = 0; colorspaces[i]; i++)
262 		addSubMenuItem(grp, menu,
263 			       colorspace2s(colorspaces[i]).c_str(), colorspaces[i]);
264 	connect(grp, SIGNAL(triggered(QAction *)), this, SLOT(colorspaceChanged(QAction *)));
265 
266 	menu = new QMenu("Override Transfer Function (X)");
267 	m_xferFuncMenu = menu;
268 	grp = new QActionGroup(menu);
269 	addSubMenuItem(grp, menu, "No Override", -1)->setChecked(true);
270 	for (unsigned i = 0; xfer_funcs[i]; i++)
271 		addSubMenuItem(grp, menu,
272 			       xfer_func2s(xfer_funcs[i]).c_str(), xfer_funcs[i]);
273 	connect(grp, SIGNAL(triggered(QAction *)), this, SLOT(xferFuncChanged(QAction *)));
274 
275 	menu = new QMenu("Override Y'CbCr Encoding (Y)");
276 	m_ycbcrEncMenu = menu;
277 	grp = new QActionGroup(menu);
278 	addSubMenuItem(grp, menu, "No Override", -1)->setChecked(true);
279 	for (unsigned i = 0; ycbcr_encs[i]; i++)
280 		addSubMenuItem(grp, menu,
281 			       ycbcr_enc2s(ycbcr_encs[i]).c_str(), ycbcr_encs[i]);
282 	connect(grp, SIGNAL(triggered(QAction *)), this, SLOT(ycbcrEncChanged(QAction *)));
283 
284 	menu = new QMenu("Override HSV Encoding (H)");
285 	m_hsvEncMenu = menu;
286 	grp = new QActionGroup(menu);
287 	addSubMenuItem(grp, menu, "No Override", -1)->setChecked(true);
288 	for (unsigned i = 0; hsv_encs[i]; i++)
289 		addSubMenuItem(grp, menu,
290 			       ycbcr_enc2s(hsv_encs[i]).c_str(), hsv_encs[i]);
291 	connect(grp, SIGNAL(triggered(QAction *)), this, SLOT(hsvEncChanged(QAction *)));
292 
293 	menu = new QMenu("Override Quantization (R)");
294 	m_quantMenu = menu;
295 	grp = new QActionGroup(menu);
296 	addSubMenuItem(grp, menu, "No Override", -1)->setChecked(true);
297 	for (unsigned i = 0; quantizations[i]; i++)
298 		addSubMenuItem(grp, menu,
299 			       quantization2s(quantizations[i]).c_str(), quantizations[i]);
300 	connect(grp, SIGNAL(triggered(QAction *)), this, SLOT(quantChanged(QAction *)));
301 
302 	menu = new QMenu("Display Options");
303 	m_displayMenu = menu;
304 	grp = new QActionGroup(menu);
305 	addSubMenuItem(grp, menu, "Frame Resize", CAPTURE_GL_WIN_RESIZE)->setChecked(true);
306 	addSubMenuItem(grp, menu, "Window Scrollbars", CAPTURE_GL_WIN_SCROLLBAR)->setChecked(false);
307 	connect(grp, SIGNAL(triggered(QAction *)), this, SLOT(windowScalingChanged(QAction *)));
308 
309 	m_resolutionOverride = new QAction("Override resolution", this);
310 	m_resolutionOverride->setCheckable(true);
311 	connect(m_resolutionOverride, SIGNAL(triggered(bool)),
312 		this, SLOT(resolutionOverrideChanged(bool)));
313 
314 	m_enterFullScreen = new QAction("Enter fullscreen (F)", this);
315 	connect(m_enterFullScreen, SIGNAL(triggered(bool)),
316 		this, SLOT(toggleFullScreen(bool)));
317 
318 	m_exitFullScreen = new QAction("Exit fullscreen (F or Esc)", this);
319 	connect(m_exitFullScreen, SIGNAL(triggered(bool)),
320 		this, SLOT(toggleFullScreen(bool)));
321 }
322 
~CaptureWin()323 CaptureWin::~CaptureWin()
324 {
325 	makeCurrent();
326 	delete m_program;
327 }
328 
resizeEvent(QResizeEvent * event)329 void CaptureWin::resizeEvent(QResizeEvent *event)
330 {
331 	QSize origSize = correctAspect(QSize(m_origWidth, m_origHeight));
332 	QSize window = size();
333 	qreal scale;
334 
335 	if ((qreal)window.width() / (qreal)origSize.width() >
336 	    (qreal)window.height() / (qreal)origSize.height()) {
337 		// Horizontal scale factor > vert. scale factor
338 		scale = (qreal)window.height() / (qreal)origSize.height();
339 	} else {
340 		scale = (qreal)window.width() / (qreal)origSize.width();
341 	}
342 	m_viewSize = QSize((qreal)m_origWidth * scale, (qreal)m_origHeight * scale);
343 	QOpenGLWidget::resizeEvent(event);
344 }
345 
updateShader()346 void CaptureWin::updateShader()
347 {
348 	setV4LFormat(m_v4l_fmt);
349 	if (m_mode == AppModeTest || m_mode == AppModeTPG || m_mode == AppModeFile) {
350 		delete m_timer;
351 		m_timer = NULL;
352 		startTimer();
353 	}
354 	m_updateShader = true;
355 }
356 
showCurrentOverrides()357 void CaptureWin::showCurrentOverrides()
358 {
359 	static bool firstTime = true;
360 	const char *prefix = firstTime ? "" : "New ";
361 
362 	if (m_mode == AppModeTest)
363 		return;
364 
365 	if (m_canOverrideResolution || firstTime) {
366 		printf("%sPixel Format: '%s' %s\n", prefix,
367 		       fcc2s(m_origPixelFormat).c_str(),
368 		       pixfmt2s(m_origPixelFormat).c_str());
369 		printf("%sField: %s\n", prefix, field2s(m_origField).c_str());
370 	}
371 	printf("%sColorspace: %s\n", prefix, colorspace2s(m_origColorspace).c_str());
372 	printf("%sTransfer Function: %s\n", prefix, xfer_func2s(m_origXferFunc).c_str());
373 	if (m_is_hsv)
374 		printf("%sHSV Encoding: %s\n", prefix, ycbcr_enc2s(m_origHSVEnc).c_str());
375 	else if (!m_is_rgb)
376 		printf("%sY'CbCr Encoding: %s\n", prefix, ycbcr_enc2s(m_origYCbCrEnc).c_str());
377 	printf("%sQuantization: %s\n", prefix, quantization2s(m_origQuantization).c_str());
378 	firstTime = false;
379 }
380 
restoreAll(bool checked)381 void CaptureWin::restoreAll(bool checked)
382 {
383 	m_overridePixelFormat = m_origPixelFormat;
384 	m_overrideField = m_origField;
385 	m_overrideColorspace = m_origColorspace;
386 	m_overrideXferFunc = m_origXferFunc;
387 	m_overrideYCbCrEnc = m_origYCbCrEnc;
388 	m_overrideHSVEnc = m_origHSVEnc;
389 	m_overrideQuantization = m_origQuantization;
390 	m_overrideWidth = m_overrideHeight = 0;
391 	showCurrentOverrides();
392 	restoreSize();
393 }
394 
fmtChanged(QAction * a)395 void CaptureWin::fmtChanged(QAction *a)
396 {
397 	m_overridePixelFormat = a->data().toInt();
398 	if (m_overridePixelFormat == 0)
399 		m_overridePixelFormat = m_origPixelFormat;
400 	printf("New Pixel Format: '%s' %s\n",
401 	       fcc2s(m_overridePixelFormat).c_str(),
402 	       pixfmt2s(m_overridePixelFormat).c_str());
403 	updateShader();
404 }
405 
fieldChanged(QAction * a)406 void CaptureWin::fieldChanged(QAction *a)
407 {
408 	m_overrideField = a->data().toInt();
409 	if (m_overrideField == 0xffffffff)
410 		m_overrideField = m_origField;
411 	printf("New Field: %s\n", field2s(m_overrideField).c_str());
412 	updateShader();
413 }
414 
colorspaceChanged(QAction * a)415 void CaptureWin::colorspaceChanged(QAction *a)
416 {
417 	m_overrideColorspace = a->data().toInt();
418 	if (m_overrideColorspace == 0xffffffff)
419 		m_overrideColorspace = m_origColorspace;
420 	printf("New Colorspace: %s\n", colorspace2s(m_overrideColorspace).c_str());
421 	updateShader();
422 }
423 
xferFuncChanged(QAction * a)424 void CaptureWin::xferFuncChanged(QAction *a)
425 {
426 	m_overrideXferFunc = a->data().toInt();
427 	if (m_overrideXferFunc == 0xffffffff)
428 		m_overrideXferFunc = m_origXferFunc;
429 	printf("New Transfer Function: %s\n", xfer_func2s(m_overrideXferFunc).c_str());
430 	updateShader();
431 }
432 
ycbcrEncChanged(QAction * a)433 void CaptureWin::ycbcrEncChanged(QAction *a)
434 {
435 	m_overrideYCbCrEnc = a->data().toInt();
436 	if (m_overrideYCbCrEnc == 0xffffffff)
437 		m_overrideYCbCrEnc = m_origYCbCrEnc;
438 	printf("New Y'CbCr Encoding: %s\n", ycbcr_enc2s(m_overrideYCbCrEnc).c_str());
439 	updateShader();
440 }
441 
hsvEncChanged(QAction * a)442 void CaptureWin::hsvEncChanged(QAction *a)
443 {
444 	m_overrideHSVEnc = a->data().toInt();
445 	if (m_overrideHSVEnc == 0xffffffff)
446 		m_overrideHSVEnc = m_origHSVEnc;
447 	printf("New HSV Encoding: %s\n", ycbcr_enc2s(m_overrideHSVEnc).c_str());
448 	updateShader();
449 }
450 
quantChanged(QAction * a)451 void CaptureWin::quantChanged(QAction *a)
452 {
453 	m_overrideQuantization = a->data().toInt();
454 	if (m_overrideQuantization == 0xffffffff)
455 		m_overrideQuantization = m_origQuantization;
456 	printf("New Quantization Range: %s\n", quantization2s(m_overrideQuantization).c_str());
457 	updateShader();
458 }
459 
restoreSize(bool)460 void CaptureWin::restoreSize(bool)
461 {
462 	QSize s = correctAspect(QSize(m_origWidth, m_origHeight));
463 
464 	m_scrollArea->resize(s);
465 	resize(s);
466 	updateShader();
467 }
468 
correctAspect(const QSize & s) const469 QSize CaptureWin::correctAspect(const QSize &s) const
470 {
471 	qreal aspect
472 		= (qreal)m_pixelaspect.denominator
473 		/ (qreal)m_pixelaspect.numerator;
474 
475 	qreal w = s.width();
476 	qreal h = s.height();
477 
478 	if (aspect < 1.0)
479 		h *= 1.0 / aspect;
480 	else
481 		w *= aspect;
482 	return QSize(qFloor(w), qFloor(h));
483 }
484 
windowScalingChanged(QAction * a)485 void CaptureWin::windowScalingChanged(QAction *a)
486 {
487 	m_scrollArea->setWidgetResizable(a->data().toInt() == CAPTURE_GL_WIN_RESIZE);
488 	resize(correctAspect(QSize(m_origWidth, m_origHeight)));
489 	updateShader();
490 }
491 
resolutionOverrideChanged(bool checked)492 void CaptureWin::resolutionOverrideChanged(bool checked)
493 {
494 	if (m_overrideWidth)
495 		m_origWidth = m_overrideWidth;
496 	if (m_overrideHeight)
497 		m_origHeight = m_overrideHeight;
498 
499 	restoreSize();
500 }
501 
toggleFullScreen(bool)502 void CaptureWin::toggleFullScreen(bool)
503 {
504 	if (m_scrollArea->isFullScreen())
505 		m_scrollArea->showNormal();
506 	else
507 		m_scrollArea->showFullScreen();
508 }
509 
contextMenuEvent(QContextMenuEvent * event)510 void CaptureWin::contextMenuEvent(QContextMenuEvent *event)
511 {
512 	QMenu menu(this);
513 
514 	QAction *act = menu.addAction("Restore All");
515 	connect(act, SIGNAL(triggered(bool)), this, SLOT(restoreAll(bool)));
516 
517 	act = menu.addAction("Reset window");
518 	connect(act, SIGNAL(triggered(bool)), this, SLOT(restoreSize(bool)));
519 
520 	if (m_scrollArea->isFullScreen())
521 		menu.addAction(m_exitFullScreen);
522 	else
523 		menu.addAction(m_enterFullScreen);
524 
525 	if (m_canOverrideResolution) {
526 		menu.addAction(m_resolutionOverride);
527 		menu.addMenu(m_fmtMenu);
528 	}
529 	menu.addMenu(m_fieldMenu);
530 	menu.addMenu(m_colorspaceMenu);
531 	menu.addMenu(m_xferFuncMenu);
532 	if (m_is_hsv)
533 		menu.addMenu(m_hsvEncMenu);
534 	else if (!m_is_rgb)
535 		menu.addMenu(m_ycbcrEncMenu);
536 	menu.addMenu(m_quantMenu);
537 	menu.addMenu(m_displayMenu);
538 
539 	menu.exec(event->globalPos());
540 }
541 
mouseDoubleClickEvent(QMouseEvent * e)542 void CaptureWin::mouseDoubleClickEvent(QMouseEvent * e)
543 {
544 	if (e->button() != Qt::LeftButton)
545 		return;
546 
547 	toggleFullScreen();
548 }
549 
cycleMenu(__u32 & overrideVal,__u32 origVal,const __u32 values[],bool hasShift,bool hasCtrl)550 void CaptureWin::cycleMenu(__u32 &overrideVal, __u32 origVal,
551 			     const __u32 values[], bool hasShift, bool hasCtrl)
552 {
553 	unsigned i;
554 
555 	if (overrideVal == 0xffffffff || hasCtrl)
556 		overrideVal = origVal;
557 	if (hasCtrl)
558 		return;
559 	for (i = 0; values[i] && values[i] != overrideVal; i++);
560 	if (!values[i])
561 		overrideVal = values[0];
562 	else if (hasShift) {
563 		if (i)
564 			overrideVal = values[i - 1];
565 		else for (i = 0; values[i]; i++)
566 			overrideVal = values[i];
567 	} else {
568 		if (!values[i + 1])
569 			overrideVal = values[0];
570 		else
571 			overrideVal = values[i + 1];
572 	}
573 }
574 
keyPressEvent(QKeyEvent * event)575 void CaptureWin::keyPressEvent(QKeyEvent *event)
576 {
577 	unsigned w = m_v4l_fmt.g_width();
578 	unsigned h = m_v4l_fmt.g_frame_height();
579 	unsigned p = m_overrideHorPadding;
580 	bool hasShift = event->modifiers() & Qt::ShiftModifier;
581 	bool hasCtrl = event->modifiers() & Qt::ControlModifier;
582 	bool scalingEnabled = m_canOverrideResolution &&
583 			      m_resolutionOverride->isChecked();
584 
585 	switch (event->key()) {
586 	case Qt::Key_Space:
587 		if (m_mode == AppModeTest)
588 			m_cnt = 1;
589 		else if (m_singleStep && m_frame > m_singleStepStart)
590 			m_singleStepNext = true;
591 		return;
592 	case Qt::Key_Escape:
593 		if (!m_scrollArea->isFullScreen())
594 			return;
595 	case Qt::Key_Left:
596 		if (hasShift) {
597 			if (scalingEnabled && p >= 2)
598 				p -= 2;
599 		} else {
600 			if (scalingEnabled && w > 16)
601 				w -= 2;
602 		}
603 		break;
604 	case Qt::Key_Right:
605 		if (hasShift) {
606 			if (scalingEnabled && p < 10240)
607 				p += 2;
608 		} else {
609 			if (scalingEnabled && w < 10240)
610 				w += 2;
611 		}
612 		break;
613 	case Qt::Key_Up:
614 		if (scalingEnabled && h > 16)
615 			h -= 2;
616 		break;
617 	case Qt::Key_Down:
618 		if (scalingEnabled && h < 10240)
619 			h += 2;
620 		break;
621 
622 	case Qt::Key_C:
623 		cycleMenu(m_overrideColorspace, m_origColorspace,
624 			  colorspaces, hasShift, hasCtrl);
625 		printf("New Colorspace: %s\n", colorspace2s(m_overrideColorspace).c_str());
626 		checkSubMenuItem(m_colorspaceMenu, m_overrideColorspace);
627 		updateShader();
628 		return;
629 	case Qt::Key_F:
630 		toggleFullScreen();
631 		return;
632 	case Qt::Key_H:
633 		if (!m_is_hsv)
634 			return;
635 		cycleMenu(m_overrideHSVEnc, m_origHSVEnc,
636 			  hsv_encs, hasShift, hasCtrl);
637 		printf("New HSV Encoding: %s\n", ycbcr_enc2s(m_overrideHSVEnc).c_str());
638 		checkSubMenuItem(m_hsvEncMenu, m_overrideHSVEnc);
639 		updateShader();
640 		return;
641 	case Qt::Key_I:
642 		cycleMenu(m_overrideField, m_origField,
643 			  fields, hasShift, hasCtrl);
644 		printf("New Field: %s\n", field2s(m_overrideField).c_str());
645 		checkSubMenuItem(m_fieldMenu, m_overrideField);
646 		updateShader();
647 		return;
648 	case Qt::Key_P:
649 		if (!m_canOverrideResolution)
650 			return;
651 		cycleMenu(m_overridePixelFormat, m_origPixelFormat,
652 			  formats, hasShift, hasCtrl);
653 		printf("New Pixel Format: '%s' %s\n", fcc2s(m_overridePixelFormat).c_str(),
654 		       pixfmt2s(m_overridePixelFormat).c_str());
655 		checkSubMenuItem(m_fmtMenu, m_overridePixelFormat);
656 		updateShader();
657 		return;
658 	case Qt::Key_Q:
659 		QApplication::quit();
660 		return;
661 	case Qt::Key_R:
662 		cycleMenu(m_overrideQuantization, m_origQuantization,
663 			  quantizations, hasShift, hasCtrl);
664 		printf("New Quantization Range: %s\n", quantization2s(m_overrideQuantization).c_str());
665 		checkSubMenuItem(m_quantMenu, m_overrideQuantization);
666 		updateShader();
667 		return;
668 	case Qt::Key_X:
669 		cycleMenu(m_overrideXferFunc, m_origXferFunc,
670 			  xfer_funcs, hasShift, hasCtrl);
671 		printf("New Transfer Function: %s\n", xfer_func2s(m_overrideXferFunc).c_str());
672 		checkSubMenuItem(m_xferFuncMenu, m_overrideXferFunc);
673 		updateShader();
674 		return;
675 	case Qt::Key_Y:
676 		if (m_is_rgb || m_is_hsv)
677 			return;
678 		cycleMenu(m_overrideYCbCrEnc, m_origYCbCrEnc,
679 			  ycbcr_encs, hasShift, hasCtrl);
680 		printf("New Y'CbCr Encoding: %s\n", ycbcr_enc2s(m_overrideYCbCrEnc).c_str());
681 		checkSubMenuItem(m_ycbcrEncMenu, m_overrideYCbCrEnc);
682 		updateShader();
683 		return;
684 	default:
685 		QOpenGLWidget::keyPressEvent(event);
686 		return;
687 	}
688 
689 	if (scalingEnabled) {
690 		if (m_scrollArea->widgetResizable())
691 			m_scrollArea->resize(w, h);
692 		else
693 			resize(w, h);
694 
695 		if ((w + p) != m_v4l_fmt.g_bytesperline()) {
696 			printf("New horizontal resolution: %u + %u (%u)\n", w, p, w + p);
697 			setOverrideHorPadding(p);
698 			updateShader();
699 		}
700 	}
701 }
702 
supportedFmt(__u32 fmt)703 bool CaptureWin::supportedFmt(__u32 fmt)
704 {
705 	switch (fmt) {
706 	case V4L2_PIX_FMT_RGB565X:
707 	case V4L2_PIX_FMT_Y16_BE:
708 		return m_haveSwapBytes;
709 
710 	/*
711 	 * Note for RGB555(X) formats:
712 	 * openGL ES doesn't support GL_UNSIGNED_SHORT_1_5_5_5_REV
713 	 */
714 	case V4L2_PIX_FMT_RGB555:
715 	case V4L2_PIX_FMT_XRGB555:
716 	case V4L2_PIX_FMT_ARGB555:
717 	case V4L2_PIX_FMT_RGB555X:
718 	case V4L2_PIX_FMT_XRGB555X:
719 	case V4L2_PIX_FMT_ARGB555X:
720 	case V4L2_PIX_FMT_RGBX555:
721 	case V4L2_PIX_FMT_RGBA555:
722 	case V4L2_PIX_FMT_XBGR555:
723 	case V4L2_PIX_FMT_ABGR555:
724 	case V4L2_PIX_FMT_BGRX555:
725 	case V4L2_PIX_FMT_BGRA555:
726 	case V4L2_PIX_FMT_YUV555:
727 	case V4L2_PIX_FMT_RGB332:
728 	case V4L2_PIX_FMT_BGR666:
729 		return !context()->isOpenGLES();
730 	}
731 
732 	return true;
733 }
734 
checkError(const char * msg)735 void CaptureWin::checkError(const char *msg)
736 {
737 	int err;
738 	unsigned errNo = 0;
739 
740 	while ((err = glGetError()) != GL_NO_ERROR)
741 		fprintf(stderr, "OpenGL Error (no: %u) code 0x%x: %s.\n", errNo++, err, msg);
742 
743 	if (errNo)
744 		std::exit(errNo);
745 }
746 
configureTexture(size_t idx)747 void CaptureWin::configureTexture(size_t idx)
748 {
749 	glBindTexture(GL_TEXTURE_2D, m_screenTexture[idx]);
750 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
751 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
752 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
753 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
754 }
755 
setOverrideWidth(__u32 w)756 void CaptureWin::setOverrideWidth(__u32 w)
757 {
758 	m_overrideWidth = w;
759 
760 	if (!m_overrideWidth && m_canOverrideResolution)
761 		m_resolutionOverride->setChecked(true);
762 }
763 
setOverrideHeight(__u32 h)764 void CaptureWin::setOverrideHeight(__u32 h)
765 {
766 	m_overrideHeight = h;
767 
768 	if (!m_overrideHeight && m_canOverrideResolution)
769 		m_resolutionOverride->setChecked(true);
770 }
771 
setOverrideHorPadding(__u32 p)772 void CaptureWin::setOverrideHorPadding(__u32 p)
773 {
774 	m_overrideHorPadding = p;
775 
776 	if (!m_overrideHorPadding && m_canOverrideResolution)
777 		m_resolutionOverride->setChecked(true);
778 }
779 
setModeV4L2(cv4l_fd * fd)780 void CaptureWin::setModeV4L2(cv4l_fd *fd)
781 {
782 	m_mode = AppModeV4L2;
783 	m_fd = fd;
784 	QSocketNotifier *readSock = new QSocketNotifier(fd->g_fd(),
785 		QSocketNotifier::Read, this);
786 	QSocketNotifier *excepSock = new QSocketNotifier(fd->g_fd(),
787 		QSocketNotifier::Exception, this);
788 
789 	v4l2_event_subscription sub = { };
790 
791 	sub.type = V4L2_EVENT_SOURCE_CHANGE;
792 	m_fd->subscribe_event(sub);
793 	connect(readSock, SIGNAL(activated(int)), this, SLOT(v4l2ReadEvent()));
794 	connect(excepSock, SIGNAL(activated(int)), this, SLOT(v4l2ExceptionEvent()));
795 
796 	if (m_verbose && m_fd->g_direct())
797 		printf("using libv4l2\n");
798 }
799 
setModeSocket(int socket,int port)800 void CaptureWin::setModeSocket(int socket, int port)
801 {
802 	m_mode = AppModeSocket;
803 	m_sock = socket;
804 	m_port = port;
805 	if (m_ctx)
806 		free(m_ctx);
807 	m_ctx = fwht_alloc(m_v4l_fmt.g_pixelformat(), m_v4l_fmt.g_width(), m_v4l_fmt.g_height(),
808 			   m_v4l_fmt.g_width(), m_v4l_fmt.g_height(),
809 			   m_v4l_fmt.g_field(), m_v4l_fmt.g_colorspace(), m_v4l_fmt.g_xfer_func(),
810 			   m_v4l_fmt.g_ycbcr_enc(), m_v4l_fmt.g_quantization());
811 
812 	QSocketNotifier *readSock = new QSocketNotifier(m_sock,
813 		QSocketNotifier::Read, this);
814 
815 	connect(readSock, SIGNAL(activated(int)), this, SLOT(sockReadEvent()));
816 }
817 
setModeFile(const QString & filename)818 void CaptureWin::setModeFile(const QString &filename)
819 {
820 	m_mode = AppModeFile;
821 	m_file.setFileName(filename);
822 	if (!m_file.open(QIODevice::ReadOnly)) {
823 		fprintf(stderr, "could not open %s\n", filename.toUtf8().data());
824 		std::exit(EXIT_FAILURE);
825 	}
826 	m_canOverrideResolution = true;
827 }
828 
setModeTPG()829 void CaptureWin::setModeTPG()
830 {
831 	m_mode = AppModeTPG;
832 }
833 
setModeTest(unsigned cnt)834 void CaptureWin::setModeTest(unsigned cnt)
835 {
836 	m_mode = AppModeTest;
837 	m_test = cnt;
838 }
839 
setQueue(cv4l_queue * q)840 void CaptureWin::setQueue(cv4l_queue *q)
841 {
842 	m_v4l_queue = q;
843 	if (m_origPixelFormat == 0)
844 		updateOrigValues();
845 }
846 
updateV4LFormat(const cv4l_fmt & fmt)847 bool CaptureWin::updateV4LFormat(const cv4l_fmt &fmt)
848 {
849 	m_is_rgb = true;
850 	m_is_hsv = false;
851 	m_uses_gl_red = false;
852 	m_accepts_srgb = true;
853 	m_is_bayer = false;
854 
855 	switch (fmt.g_pixelformat()) {
856 	case V4L2_PIX_FMT_YUV422P:
857 	case V4L2_PIX_FMT_YUV420:
858 	case V4L2_PIX_FMT_YVU420:
859 	case V4L2_PIX_FMT_YUV420M:
860 	case V4L2_PIX_FMT_YVU420M:
861 	case V4L2_PIX_FMT_YUV422M:
862 	case V4L2_PIX_FMT_YVU422M:
863 	case V4L2_PIX_FMT_YUV444M:
864 	case V4L2_PIX_FMT_YVU444M:
865 	case V4L2_PIX_FMT_NV12:
866 	case V4L2_PIX_FMT_NV21:
867 	case V4L2_PIX_FMT_NV16:
868 	case V4L2_PIX_FMT_NV61:
869 	case V4L2_PIX_FMT_NV24:
870 	case V4L2_PIX_FMT_NV42:
871 	case V4L2_PIX_FMT_NV16M:
872 	case V4L2_PIX_FMT_NV61M:
873 	case V4L2_PIX_FMT_NV12M:
874 	case V4L2_PIX_FMT_NV21M:
875 		m_uses_gl_red = true;
876 		/* fall through */
877 	case V4L2_PIX_FMT_YUYV:
878 	case V4L2_PIX_FMT_YVYU:
879 	case V4L2_PIX_FMT_UYVY:
880 	case V4L2_PIX_FMT_VYUY:
881 	case V4L2_PIX_FMT_YUV444:
882 	case V4L2_PIX_FMT_YUV555:
883 	case V4L2_PIX_FMT_YUV565:
884 	case V4L2_PIX_FMT_YUV32:
885 	case V4L2_PIX_FMT_AYUV32:
886 	case V4L2_PIX_FMT_XYUV32:
887 	case V4L2_PIX_FMT_VUYA32:
888 	case V4L2_PIX_FMT_VUYX32:
889 	case V4L2_PIX_FMT_YUVA32:
890 	case V4L2_PIX_FMT_YUVX32:
891 		m_is_rgb = false;
892 		m_accepts_srgb = false;
893 		break;
894 	case V4L2_PIX_FMT_HSV24:
895 	case V4L2_PIX_FMT_HSV32:
896 		m_is_rgb = false;
897 		m_is_hsv = true;
898 		m_accepts_srgb = false;
899 		break;
900 	case V4L2_PIX_FMT_SBGGR8:
901 	case V4L2_PIX_FMT_SGBRG8:
902 	case V4L2_PIX_FMT_SGRBG8:
903 	case V4L2_PIX_FMT_SRGGB8:
904 	case V4L2_PIX_FMT_SBGGR10:
905 	case V4L2_PIX_FMT_SGBRG10:
906 	case V4L2_PIX_FMT_SGRBG10:
907 	case V4L2_PIX_FMT_SRGGB10:
908 	case V4L2_PIX_FMT_SBGGR12:
909 	case V4L2_PIX_FMT_SGBRG12:
910 	case V4L2_PIX_FMT_SGRBG12:
911 	case V4L2_PIX_FMT_SRGGB12:
912 	case V4L2_PIX_FMT_SBGGR16:
913 	case V4L2_PIX_FMT_SGBRG16:
914 	case V4L2_PIX_FMT_SGRBG16:
915 	case V4L2_PIX_FMT_SRGGB16:
916 		m_is_bayer = true;
917 		/* fall through */
918 	case V4L2_PIX_FMT_GREY:
919 	case V4L2_PIX_FMT_Y10:
920 	case V4L2_PIX_FMT_Y12:
921 	case V4L2_PIX_FMT_Y16:
922 	case V4L2_PIX_FMT_Y16_BE:
923 	case V4L2_PIX_FMT_Z16:
924 		m_uses_gl_red = true;
925 		/* fall through */
926 	case V4L2_PIX_FMT_BGR666:
927 	case V4L2_PIX_FMT_RGB565:
928 	case V4L2_PIX_FMT_RGB565X:
929 	case V4L2_PIX_FMT_RGB444:
930 	case V4L2_PIX_FMT_XRGB444:
931 	case V4L2_PIX_FMT_ARGB444:
932 	case V4L2_PIX_FMT_XBGR444:
933 	case V4L2_PIX_FMT_ABGR444:
934 	case V4L2_PIX_FMT_RGBX444:
935 	case V4L2_PIX_FMT_RGBA444:
936 	case V4L2_PIX_FMT_BGRX444:
937 	case V4L2_PIX_FMT_BGRA444:
938 	case V4L2_PIX_FMT_RGB32:
939 	case V4L2_PIX_FMT_XRGB32:
940 	case V4L2_PIX_FMT_ARGB32:
941 	case V4L2_PIX_FMT_RGBX32:
942 	case V4L2_PIX_FMT_RGBA32:
943 	case V4L2_PIX_FMT_BGR32:
944 	case V4L2_PIX_FMT_XBGR32:
945 	case V4L2_PIX_FMT_ABGR32:
946 	case V4L2_PIX_FMT_BGRX32:
947 	case V4L2_PIX_FMT_BGRA32:
948 		m_accepts_srgb = false;
949 		/* fall through */
950 	case V4L2_PIX_FMT_RGB24:
951 	case V4L2_PIX_FMT_BGR24:
952 	case V4L2_PIX_FMT_RGB555:
953 	case V4L2_PIX_FMT_XRGB555:
954 	case V4L2_PIX_FMT_ARGB555:
955 	case V4L2_PIX_FMT_RGB555X:
956 	case V4L2_PIX_FMT_XRGB555X:
957 	case V4L2_PIX_FMT_ARGB555X:
958 	case V4L2_PIX_FMT_RGBX555:
959 	case V4L2_PIX_FMT_RGBA555:
960 	case V4L2_PIX_FMT_XBGR555:
961 	case V4L2_PIX_FMT_ABGR555:
962 	case V4L2_PIX_FMT_BGRX555:
963 	case V4L2_PIX_FMT_BGRA555:
964 	case V4L2_PIX_FMT_RGB332:
965 		break;
966 	default:
967 		return false;
968 	}
969 	return true;
970 }
971 
setV4LFormat(cv4l_fmt & fmt)972 bool CaptureWin::setV4LFormat(cv4l_fmt &fmt)
973 {
974 	m_is_sdtv = false;
975 
976 	if (m_mode == AppModeFile && m_overridePixelFormat)
977 		fmt.s_pixelformat(m_overridePixelFormat);
978 
979 	if (!updateV4LFormat(fmt))
980 		return false;
981 
982 	if (m_is_bayer) {
983 		m_v4l_fmt.s_field(V4L2_FIELD_NONE);
984 		m_overrideField = 0;
985 	}
986 	if (m_mode == AppModeFile && m_overrideWidth)
987 		fmt.s_width(m_overrideWidth);
988 	if (m_mode == AppModeFile && m_overrideHorPadding)
989 		fmt.s_bytesperline(fmt.g_bytesperline() + m_overrideHorPadding);
990 	if (m_mode == AppModeFile && m_overrideField != 0xffffffff)
991 		fmt.s_field(m_overrideField);
992 	if (m_mode == AppModeFile && m_overrideHeight)
993 		fmt.s_frame_height(m_overrideHeight);
994 	if (m_overrideColorspace != 0xffffffff)
995 		fmt.s_colorspace(m_overrideColorspace);
996 	if (m_is_hsv && m_overrideHSVEnc != 0xffffffff)
997 		fmt.s_ycbcr_enc(m_overrideHSVEnc);
998 	else if (!m_is_rgb && m_overrideYCbCrEnc != 0xffffffff)
999 		fmt.s_ycbcr_enc(m_overrideYCbCrEnc);
1000 	if (m_overrideXferFunc != 0xffffffff)
1001 		fmt.s_xfer_func(m_overrideXferFunc);
1002 	if (m_overrideQuantization != 0xffffffff)
1003 		fmt.s_quantization(m_overrideQuantization);
1004 
1005 	m_v4l_fmt = fmt;
1006 
1007 	v4l2_input in;
1008 
1009 	m_std = 0;
1010 	if (m_fd && !m_fd->g_input(in.index) && !m_fd->enum_input(in, true, in.index)) {
1011 		if (in.capabilities & V4L2_IN_CAP_STD) {
1012 			m_is_sdtv = true;
1013 			if (m_fd->g_std(m_std))
1014 				m_std = fmt.g_frame_height() <= 480 ?
1015 					V4L2_STD_525_60 : V4L2_STD_625_50;
1016 		} else if (in.capabilities & V4L2_IN_CAP_DV_TIMINGS) {
1017 			v4l2_dv_timings timings;
1018 			if (m_fd->g_dv_timings(timings) == 0) {
1019 				m_is_sdtv = timings.bt.width <= 720 && timings.bt.height <= 576;
1020 				if (m_is_sdtv)
1021 					m_std = timings.bt.height <= 480 ?
1022 						V4L2_STD_525_60 : V4L2_STD_625_50;
1023 			}
1024 		}
1025 	}
1026 
1027 	switch (fmt.g_colorspace()) {
1028 	case V4L2_COLORSPACE_SMPTE170M:
1029 	case V4L2_COLORSPACE_SMPTE240M:
1030 	case V4L2_COLORSPACE_REC709:
1031 	case V4L2_COLORSPACE_470_SYSTEM_M:
1032 	case V4L2_COLORSPACE_470_SYSTEM_BG:
1033 	case V4L2_COLORSPACE_SRGB:
1034 	case V4L2_COLORSPACE_OPRGB:
1035 	case V4L2_COLORSPACE_BT2020:
1036 	case V4L2_COLORSPACE_DCI_P3:
1037 		break;
1038 	default:
1039 		// If the colorspace was not specified, then guess
1040 		// based on the pixel format.
1041 		if (m_is_rgb)
1042 			m_v4l_fmt.s_colorspace(V4L2_COLORSPACE_SRGB);
1043 		else if (m_is_sdtv)
1044 			m_v4l_fmt.s_colorspace(V4L2_COLORSPACE_SMPTE170M);
1045 		else
1046 			m_v4l_fmt.s_colorspace(V4L2_COLORSPACE_REC709);
1047 		break;
1048 	}
1049 	if (fmt.g_xfer_func() == V4L2_XFER_FUNC_DEFAULT)
1050 		m_v4l_fmt.s_xfer_func(V4L2_MAP_XFER_FUNC_DEFAULT(m_v4l_fmt.g_colorspace()));
1051 	if (m_is_hsv)
1052 		m_v4l_fmt.s_ycbcr_enc(fmt.g_hsv_enc());
1053 	else if (fmt.g_ycbcr_enc() == V4L2_YCBCR_ENC_DEFAULT)
1054 		m_v4l_fmt.s_ycbcr_enc(V4L2_MAP_YCBCR_ENC_DEFAULT(m_v4l_fmt.g_colorspace()));
1055 	if (fmt.g_quantization() == V4L2_QUANTIZATION_DEFAULT)
1056 		m_v4l_fmt.s_quantization(V4L2_MAP_QUANTIZATION_DEFAULT(m_is_rgb,
1057 				m_v4l_fmt.g_colorspace(), m_v4l_fmt.g_ycbcr_enc()));
1058 
1059 	if (m_accepts_srgb &&
1060 	    (m_v4l_fmt.g_quantization() == V4L2_QUANTIZATION_LIM_RANGE ||
1061 	    m_v4l_fmt.g_xfer_func() != V4L2_XFER_FUNC_SRGB)) {
1062 		/* Can't let openGL convert from non-linear to linear */
1063 		m_accepts_srgb = false;
1064 	}
1065 
1066 	if (m_verbose) {
1067 		v4l2_fmtdesc fmt;
1068 
1069 		strcpy((char *)fmt.description, fcc2s(m_v4l_fmt.g_pixelformat()).c_str());
1070 		if (m_fd) {
1071 			m_fd->enum_fmt(fmt, true);
1072 			while (fmt.pixelformat != m_v4l_fmt.g_pixelformat()) {
1073 				if (m_fd->enum_fmt(fmt))
1074 					break;
1075 			}
1076 		}
1077 
1078 		printf("\n");
1079 		switch (m_mode) {
1080 		case AppModeSocket:
1081 			printf("Mode:              Capture from socket\n");
1082 			break;
1083 		case AppModeFile:
1084 			printf("Mode:              Read from file\n");
1085 			break;
1086 		case AppModeTest:
1087 			printf("Mode:              Test Formats\n");
1088 			break;
1089 		case AppModeTPG:
1090 			printf("Mode:              Test Pattern Generator\n");
1091 			break;
1092 		case AppModeV4L2:
1093 		default:
1094 			printf("Mode:              Capture\n");
1095 			break;
1096 		}
1097 		printf("Width x Height:    %ux%u\n", m_v4l_fmt.g_width(), m_v4l_fmt.g_height());
1098 		printf("Field:             %s\n", field2s(m_v4l_fmt.g_field()).c_str());
1099 		printf("Pixel Format:      %s ('%s')\n", fmt.description, fcc2s(m_v4l_fmt.g_pixelformat()).c_str());
1100 		printf("Colorspace:        %s\n", colorspace2s(m_v4l_fmt.g_colorspace()).c_str());
1101 		if (m_is_hsv)
1102 			printf("HSV Encoding:      %s\n", ycbcr_enc2s(m_v4l_fmt.g_hsv_enc()).c_str());
1103 		else if (!m_is_rgb)
1104 			printf("Y'CbCr Encoding:   %s\n", ycbcr_enc2s(m_v4l_fmt.g_ycbcr_enc()).c_str());
1105 		printf("Transfer Function: %s\n", xfer_func2s(m_v4l_fmt.g_xfer_func()).c_str());
1106 		printf("Quantization:      %s\n", quantization2s(m_v4l_fmt.g_quantization()).c_str());
1107 		for (unsigned i = 0; i < m_v4l_fmt.g_num_planes(); i++) {
1108 			printf("Plane %d Image Size:     %u\n", i, m_v4l_fmt.g_sizeimage(i));
1109 			printf("Plane %d Bytes per Line: %u\n", i, m_v4l_fmt.g_bytesperline(i));
1110 		}
1111 	}
1112 	return true;
1113 }
1114 
setPixelAspect(const v4l2_fract & pixelaspect)1115 void CaptureWin::setPixelAspect(const v4l2_fract &pixelaspect)
1116 {
1117 	m_pixelaspect = pixelaspect;
1118 }
1119 
v4l2ReadEvent()1120 void CaptureWin::v4l2ReadEvent()
1121 {
1122 	cv4l_buffer buf(m_fd->g_type());
1123 
1124 	if (m_singleStep && m_frame > m_singleStepStart && !m_singleStepNext)
1125 		return;
1126 
1127 	m_singleStepNext = false;
1128 	if (m_fd->dqbuf(buf))
1129 		return;
1130 
1131 	for (unsigned i = 0; i < m_v4l_queue->g_num_planes(); i++) {
1132 		m_nextData[i] = (__u8 *)m_v4l_queue->g_dataptr(buf.g_index(), i);
1133 		m_nextSize[i] = buf.g_bytesused(i);
1134 	}
1135 	int next = m_nextIndex;
1136 	m_nextIndex = buf.g_index();
1137 	if (next != -1) {
1138 		buf.s_index(next);
1139 		m_fd->qbuf(buf);
1140 	}
1141 	m_frame++;
1142 	update();
1143 	if (m_cnt == 0)
1144 		return;
1145 	if (--m_cnt == 0)
1146 		std::exit(EXIT_SUCCESS);
1147 }
1148 
v4l2ExceptionEvent()1149 void CaptureWin::v4l2ExceptionEvent()
1150 {
1151 	v4l2_event ev;
1152 	cv4l_fmt fmt;
1153 
1154 	while (m_fd->dqevent(ev) == 0) {
1155 		switch (ev.type) {
1156 		case V4L2_EVENT_SOURCE_CHANGE:
1157 			m_fd->g_fmt(fmt);
1158 			if (!setV4LFormat(fmt)) {
1159 				fprintf(stderr, "Unsupported format: '%s' %s\n",
1160 					fcc2s(fmt.g_pixelformat()).c_str(),
1161 					pixfmt2s(fmt.g_pixelformat()).c_str());
1162 				std::exit(EXIT_FAILURE);
1163 			}
1164 			updateOrigValues();
1165 			m_updateShader = true;
1166 			break;
1167 		}
1168 	}
1169 }
1170 
listenForNewConnection()1171 void CaptureWin::listenForNewConnection()
1172 {
1173 	cv4l_fmt fmt;
1174 	v4l2_fract pixelaspect = { 1, 1 };
1175 
1176 	::close(m_sock);
1177 
1178 	for (unsigned p = 0; p < m_v4l_fmt.g_num_planes(); p++) {
1179 		m_curSize[p] = 0;
1180 		delete [] m_curData[p];
1181 		m_curData[p] = NULL;
1182 	}
1183 
1184 	int sock_fd;
1185 
1186 	for (;;) {
1187 		sock_fd = initSocket(m_port, fmt, pixelaspect);
1188 		if (setV4LFormat(fmt))
1189 			break;
1190 		fprintf(stderr, "Unsupported format: '%s' %s\n",
1191 			fcc2s(fmt.g_pixelformat()).c_str(),
1192 			pixfmt2s(fmt.g_pixelformat()).c_str());
1193 		::close(sock_fd);
1194 	}
1195 	if (m_ctx)
1196 		free(m_ctx);
1197 	m_ctx = fwht_alloc(fmt.g_pixelformat(), fmt.g_width(), fmt.g_height(),
1198 			   fmt.g_width(), fmt.g_height(),
1199 			   fmt.g_field(), fmt.g_colorspace(), fmt.g_xfer_func(),
1200 			   fmt.g_ycbcr_enc(), fmt.g_quantization());
1201 	setPixelAspect(pixelaspect);
1202 	updateOrigValues();
1203 	setModeSocket(sock_fd, m_port);
1204 	restoreSize();
1205 }
1206 
read_u32(__u32 & v)1207 int CaptureWin::read_u32(__u32 &v)
1208 {
1209 	int n;
1210 
1211 	v = 0;
1212 	n = read(m_sock, &v, sizeof(v));
1213 	if (n != sizeof(v)) {
1214 		fprintf(stderr, "could not read __u32\n");
1215 		return -1;
1216 	}
1217 	v = ntohl(v);
1218 	return 0;
1219 }
1220 
sockReadEvent()1221 void CaptureWin::sockReadEvent()
1222 {
1223 	int n;
1224 
1225 	if (m_singleStep && m_frame > m_singleStepStart && !m_singleStepNext)
1226 		return;
1227 	m_singleStepNext = false;
1228 
1229 	if (m_origPixelFormat == 0)
1230 		updateOrigValues();
1231 
1232 	if (m_curSize[0] == 0) {
1233 		for (unsigned p = 0; p < m_v4l_fmt.g_num_planes(); p++) {
1234 			m_curSize[p] = m_v4l_fmt.g_sizeimage(p);
1235 			m_curData[p] = new __u8[m_curSize[p]];
1236 		}
1237 	}
1238 
1239 	unsigned packet, sz;
1240 	bool is_fwht;
1241 
1242 	if (read_u32(packet))
1243 		goto new_conn;
1244 
1245 	if (packet == V4L_STREAM_PACKET_END) {
1246 		fprintf(stderr, "END packet read\n");
1247 		goto new_conn;
1248 	}
1249 
1250 	if (read_u32(sz))
1251 		goto new_conn;
1252 
1253 	if (packet != V4L_STREAM_PACKET_FRAME_VIDEO_RLE &&
1254 	    packet != V4L_STREAM_PACKET_FRAME_VIDEO_FWHT) {
1255 		char buf[1024];
1256 
1257 		fprintf(stderr, "expected FRAME_VIDEO, got 0x%08x\n", packet);
1258 		while (sz) {
1259 			unsigned rdsize = sz > sizeof(buf) ? sizeof(buf) : sz;
1260 
1261 			n = read(m_sock, buf, rdsize);
1262 			if (n < 0) {
1263 				fprintf(stderr, "error reading %d bytes\n", sz);
1264 				goto new_conn;
1265 			}
1266 			sz -= n;
1267 		}
1268 		return;
1269 	}
1270 
1271 	is_fwht = m_ctx && packet == V4L_STREAM_PACKET_FRAME_VIDEO_FWHT;
1272 
1273 	if (read_u32(sz))
1274 		goto new_conn;
1275 
1276 	if (sz != V4L_STREAM_PACKET_FRAME_VIDEO_SIZE_HDR) {
1277 		fprintf(stderr, "unsupported FRAME_VIDEO size\n");
1278 		goto new_conn;
1279 	}
1280 	if (read_u32(sz) ||  // ignore field
1281 	    read_u32(sz))    // ignore flags
1282 		goto new_conn;
1283 
1284 	for (unsigned p = 0; p < m_v4l_fmt.g_num_planes(); p++) {
1285 		__u32 max_size = is_fwht ? m_ctx->comp_max_size : m_curSize[p];
1286 		__u8 *dst = is_fwht ? m_ctx->state.compressed_frame : m_curData[p];
1287 		__u32 data_size;
1288 		__u32 offset;
1289 		__u32 size;
1290 
1291 		if (read_u32(sz))
1292 			goto new_conn;
1293 		if (sz != V4L_STREAM_PACKET_FRAME_VIDEO_SIZE_PLANE_HDR) {
1294 			fprintf(stderr, "unsupported FRAME_VIDEO plane size\n");
1295 			goto new_conn;
1296 		}
1297 		if (read_u32(size) || read_u32(data_size))
1298 			goto new_conn;
1299 		offset = is_fwht ? 0 : size - data_size;
1300 		sz = data_size;
1301 
1302 		if (data_size > max_size) {
1303 			fprintf(stderr, "data size is too large (%u > %u)\n",
1304 				data_size, max_size);
1305 			goto new_conn;
1306 		}
1307 		while (sz) {
1308 			n = read(m_sock, dst + offset, sz);
1309 			if (n < 0) {
1310 				fprintf(stderr, "error reading %d bytes\n", sz);
1311 				goto new_conn;
1312 			}
1313 			if ((__u32)n == sz)
1314 				break;
1315 			offset += n;
1316 			sz -= n;
1317 		}
1318 		if (is_fwht)
1319 			fwht_decompress(m_ctx, dst, data_size, m_curData[p], m_curSize[p]);
1320 		else
1321 			rle_decompress(dst, size, data_size,
1322 				       rle_calc_bpl(m_v4l_fmt.g_bytesperline(p), m_v4l_fmt.g_pixelformat()));
1323 	}
1324 	m_frame++;
1325 	update();
1326 	if (m_cnt == 0)
1327 		return;
1328 	if (--m_cnt == 0)
1329 		std::exit(EXIT_SUCCESS);
1330 	return;
1331 
1332 new_conn:
1333 	listenForNewConnection();
1334 }
1335 
resizeGL(int w,int h)1336 void CaptureWin::resizeGL(int w, int h)
1337 {
1338 	if (!m_canOverrideResolution || !m_resolutionOverride->isChecked())
1339 		return;
1340 	w &= ~1;
1341 	h &= ~1;
1342 	m_overrideWidth = w;
1343 	m_overrideHeight = h;
1344 	m_viewSize = QSize(m_overrideWidth, m_overrideHeight);
1345 	updateShader();
1346 	printf("New resolution: %ux%u\n", w, h);
1347 }
1348 
updateOrigValues()1349 void CaptureWin::updateOrigValues()
1350 {
1351 	m_origWidth = m_v4l_fmt.g_width();
1352 	m_origHeight = m_v4l_fmt.g_frame_height();
1353 	m_overrideWidth = m_overrideHeight = 0;
1354 	m_origPixelFormat = m_v4l_fmt.g_pixelformat();
1355 	m_origField = m_v4l_fmt.g_field();
1356 	m_origColorspace = m_v4l_fmt.g_colorspace();
1357 	m_origXferFunc = m_v4l_fmt.g_xfer_func();
1358 	if (m_is_rgb)
1359 		m_origXferFunc = V4L2_YCBCR_ENC_601;
1360 	else if (m_is_hsv)
1361 		m_origHSVEnc = m_v4l_fmt.g_hsv_enc();
1362 	else
1363 		m_origYCbCrEnc = m_v4l_fmt.g_ycbcr_enc();
1364 	m_origQuantization = m_v4l_fmt.g_quantization();
1365 	showCurrentOverrides();
1366 	m_viewSize = QSize(m_origWidth, m_origHeight);
1367 }
1368 
initImageFormat()1369 void CaptureWin::initImageFormat()
1370 {
1371 	updateV4LFormat(m_v4l_fmt);
1372 	tpg_s_fourcc(&m_tpg, m_v4l_fmt.g_pixelformat());
1373 	bool is_alt = m_v4l_fmt.g_field() == V4L2_FIELD_ALTERNATE;
1374 
1375 	tpg_reset_source(&m_tpg, m_v4l_fmt.g_width(),
1376 			 m_v4l_fmt.g_frame_height(), m_v4l_fmt.g_field());
1377 	tpg_s_field(&m_tpg, m_v4l_fmt.g_first_field(m_std), is_alt);
1378 	tpg_s_colorspace(&m_tpg, m_v4l_fmt.g_colorspace());
1379 	tpg_s_xfer_func(&m_tpg, m_v4l_fmt.g_xfer_func());
1380 	if (m_is_hsv)
1381 		tpg_s_hsv_enc(&m_tpg, m_v4l_fmt.g_hsv_enc());
1382 	else if (!m_is_rgb)
1383 		tpg_s_ycbcr_enc(&m_tpg, m_v4l_fmt.g_ycbcr_enc());
1384 	tpg_s_quantization(&m_tpg, m_v4l_fmt.g_quantization());
1385 	m_v4l_fmt.s_num_planes(tpg_g_buffers(&m_tpg));
1386 	for (unsigned p = 0; p < m_v4l_fmt.g_num_planes(); p++) {
1387 		if (m_mode == AppModeFile && m_overrideHorPadding)
1388 			tpg_s_bytesperline(&m_tpg, p, tpg_g_bytesperline(&m_tpg, p) + m_overrideHorPadding);
1389 
1390 		m_v4l_fmt.s_bytesperline(tpg_g_bytesperline(&m_tpg, p), p);
1391 		m_v4l_fmt.s_sizeimage(tpg_calc_plane_size(&m_tpg, p), p);
1392 	}
1393 	if (tpg_g_buffers(&m_tpg) == 1) {
1394 		unsigned size = 0;
1395 
1396 		for (unsigned p = 0; p < tpg_g_planes(&m_tpg); p++)
1397 			size += tpg_calc_plane_size(&m_tpg, p);
1398 		m_v4l_fmt.s_sizeimage(size, 0);
1399 	}
1400 	if (m_verbose)
1401 		tpg_log_status(&m_tpg);
1402 }
1403 
startTimer()1404 void CaptureWin::startTimer()
1405 {
1406 	if (m_origPixelFormat == 0)
1407 		updateOrigValues();
1408 	initImageFormat();
1409 
1410 	m_timer = new QTimer(this);
1411 	connect(m_timer, SIGNAL(timeout()), this, SLOT(tpgUpdateFrame()));
1412 
1413 	m_imageSize = 0;
1414 	for (unsigned p = 0; p < m_v4l_fmt.g_num_planes(); p++)
1415 		m_imageSize += m_v4l_fmt.g_sizeimage(p);
1416 
1417 	if (m_file.isOpen())
1418 		m_file.seek(0);
1419 
1420 	if (m_file.isOpen() && m_imageSize > m_file.size()) {
1421 		fprintf(stderr, "the file size is too small (expect at least %u, got %llu)\n",
1422 			m_imageSize, m_file.size());
1423 	}
1424 
1425 	for (unsigned p = 0; p < m_v4l_fmt.g_num_planes(); p++) {
1426 		m_curSize[p] = m_v4l_fmt.g_sizeimage(p);
1427 		delete [] m_curData[p];
1428 		if (m_canOverrideResolution)
1429 			m_curData[p] = new __u8[4096 * 2160 * (p ? 2 : 4)];
1430 		else
1431 			m_curData[p] = new __u8[m_curSize[p]];
1432 		if (m_file.isOpen())
1433 			m_file.read((char *)m_curData[p], m_curSize[p]);
1434 		else
1435 			tpg_fillbuffer(&m_tpg, 0, p, m_curData[p]);
1436 	}
1437 	bool is_alt = m_v4l_fmt.g_field() == V4L2_FIELD_ALTERNATE;
1438 	tpg_update_mv_count(&m_tpg, is_alt);
1439 	m_timer->setTimerType(Qt::PreciseTimer);
1440 	m_timer->setSingleShot(false);
1441 	m_timer->setInterval(1000.0 / (m_fps * (is_alt ? 2 : 1)));
1442 	m_timer->start(1000.0 / (m_fps * (is_alt ? 2 : 1)));
1443 	if (is_alt && m_cnt)
1444 		m_cnt *= 2;
1445 	if (m_mode == AppModeTest) {
1446 		fprintf(stderr, "test %s ('%s'), %s, %s, %s, ",
1447 			pixfmt2s(formats[m_testState.fmt_idx]).c_str(),
1448 			fcc2s(formats[m_testState.fmt_idx]).c_str(),
1449 			field2s(fields[m_testState.field_idx]).c_str(),
1450 			colorspace2s(colorspaces[m_testState.colorspace_idx]).c_str(),
1451 			xfer_func2s(xfer_funcs[m_testState.xfer_func_idx]).c_str());
1452 		if (m_is_rgb)
1453 			fprintf(stderr, "%s\n",
1454 				quantization2s(quantizations[m_testState.quant_idx]).c_str());
1455 		else if (m_is_hsv)
1456 			fprintf(stderr, "%s, %s\n",
1457 				ycbcr_enc2s(ycbcr_encs[m_testState.hsv_enc_idx]).c_str(),
1458 				quantization2s(quantizations[m_testState.quant_idx]).c_str());
1459 		else
1460 			fprintf(stderr, "%s, %s\n",
1461 				ycbcr_enc2s(ycbcr_encs[m_testState.ycbcr_enc_idx]).c_str(),
1462 				quantization2s(quantizations[m_testState.quant_idx]).c_str());
1463 	}
1464 }
1465 
tpgUpdateFrame()1466 void CaptureWin::tpgUpdateFrame()
1467 {
1468 	bool is_alt = m_v4l_fmt.g_field() == V4L2_FIELD_ALTERNATE;
1469 
1470 	if (m_mode != AppModeTest && m_singleStep && m_frame > m_singleStepStart &&
1471 	    !m_singleStepNext)
1472 		return;
1473 	m_singleStepNext = false;
1474 
1475 	if (m_mode == AppModeFile && m_file.pos() + m_imageSize > m_file.size())
1476 		m_file.seek(0);
1477 
1478 	if (m_mode != AppModeFile && is_alt) {
1479 		if (m_tpg.field == V4L2_FIELD_TOP)
1480 			tpg_s_field(&m_tpg, V4L2_FIELD_BOTTOM, true);
1481 		else
1482 			tpg_s_field(&m_tpg, V4L2_FIELD_TOP, true);
1483 	}
1484 
1485 	for (unsigned p = 0; p < m_v4l_fmt.g_num_planes(); p++) {
1486 		if (m_mode == AppModeFile)
1487 			m_file.read((char *)m_curData[p], m_curSize[p]);
1488 		else
1489 			tpg_fillbuffer(&m_tpg, 0, p, m_curData[p]);
1490 	}
1491 	m_frame++;
1492 	update();
1493 	if (m_cnt != 1)
1494 		tpg_update_mv_count(&m_tpg, is_alt);
1495 
1496 	if (m_cnt == 0)
1497 		return;
1498 	if (--m_cnt)
1499 		return;
1500 
1501 	delete m_timer;
1502 	m_timer = NULL;
1503 	if (!m_test)
1504 		std::exit(EXIT_SUCCESS);
1505 
1506 	m_cnt = m_test;
1507 
1508 	bool mask_quant = m_testState.mask & QUANT_MASK;
1509 	bool mask_ycbcr_enc = m_is_rgb || m_is_hsv || (m_testState.mask & YCBCR_HSV_ENC_MASK);
1510 	bool mask_hsv_enc = !m_is_hsv || (m_testState.mask & YCBCR_HSV_ENC_MASK);
1511 	bool mask_xfer_func = m_testState.mask & XFER_FUNC_MASK;
1512 	bool mask_colorspace = m_testState.mask & COLORSPACE_MASK;
1513 	bool mask_field = m_is_bayer || (m_testState.mask & FIELD_MASK);
1514 	bool mask_fmt = m_testState.mask & FMT_MASK;
1515 
1516 	if (mask_quant ||
1517 	    quantizations[++m_testState.quant_idx] == 0) {
1518 		if (!mask_quant)
1519 			m_testState.quant_idx = 0;
1520 		if (mask_ycbcr_enc ||
1521 		    ycbcr_encs[++m_testState.ycbcr_enc_idx] == 0) {
1522 			if (!mask_ycbcr_enc)
1523 				m_testState.ycbcr_enc_idx = 0;
1524 			if (mask_hsv_enc ||
1525 			    hsv_encs[++m_testState.hsv_enc_idx] == 0) {
1526 				if (!mask_hsv_enc)
1527 					m_testState.hsv_enc_idx = 0;
1528 				if (mask_xfer_func ||
1529 				    xfer_funcs[++m_testState.xfer_func_idx] == 0) {
1530 					if (!mask_xfer_func)
1531 						m_testState.xfer_func_idx = 0;
1532 					if (mask_colorspace ||
1533 					    colorspaces[++m_testState.colorspace_idx] == 0) {
1534 						if (!mask_colorspace)
1535 							m_testState.colorspace_idx = 0;
1536 						if (mask_field ||
1537 						    fields[++m_testState.field_idx] == 0) {
1538 							if (!mask_field)
1539 								m_testState.field_idx = 0;
1540 							if (mask_fmt ||
1541 							    formats[++m_testState.fmt_idx] == 0)
1542 								std::exit(EXIT_SUCCESS);
1543 						}
1544 					}
1545 				}
1546 			}
1547 		}
1548 	}
1549 
1550 	while (!supportedFmt(formats[m_testState.fmt_idx]))
1551 		if (formats[++m_testState.fmt_idx] == 0)
1552 			std::exit(EXIT_SUCCESS);
1553 
1554 	m_v4l_fmt.s_pixelformat(formats[m_testState.fmt_idx]);
1555 	updateV4LFormat(m_v4l_fmt);
1556 	m_v4l_fmt.s_field(fields[m_testState.field_idx]);
1557 	m_v4l_fmt.s_colorspace(colorspaces[m_testState.colorspace_idx]);
1558 	m_v4l_fmt.s_xfer_func(xfer_funcs[m_testState.xfer_func_idx]);
1559 	if (m_is_hsv)
1560 		m_v4l_fmt.s_ycbcr_enc(hsv_encs[m_testState.hsv_enc_idx]);
1561 	else
1562 		m_v4l_fmt.s_ycbcr_enc(ycbcr_encs[m_testState.ycbcr_enc_idx]);
1563 	m_v4l_fmt.s_quantization(quantizations[m_testState.quant_idx]);
1564 
1565 	if (m_accepts_srgb &&
1566 	    (m_v4l_fmt.g_quantization() == V4L2_QUANTIZATION_LIM_RANGE ||
1567 	    m_v4l_fmt.g_xfer_func() != V4L2_XFER_FUNC_SRGB)) {
1568 		/* Can't let openGL convert from non-linear to linear */
1569 		m_accepts_srgb = false;
1570 	}
1571 	startTimer();
1572 	m_updateShader = true;
1573 }
1574