• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * qv4l2 - Test Pattern Generator Tab
4  *
5  * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
6  */
7 
8 #include "qv4l2.h"
9 #include "general-tab.h"
10 
11 #include <QFrame>
12 #include <QVBoxLayout>
13 #include <QStatusBar>
14 #include <QLineEdit>
15 #include <QValidator>
16 #include <QLayout>
17 #include <QGridLayout>
18 #include <QLabel>
19 #include <QSlider>
20 #include <QSpinBox>
21 #include <QComboBox>
22 #include <QCheckBox>
23 #include <QPushButton>
24 #include <QToolButton>
25 #include <QToolTip>
26 
27 #include <math.h>
28 #include <fcntl.h>
29 #include <sys/ioctl.h>
30 #include <errno.h>
31 
addTpgTab(int m_winWidth)32 void ApplicationWindow::addTpgTab(int m_winWidth)
33 {
34 	QWidget *t = new QWidget(m_tabs);
35 	QVBoxLayout *vbox = new QVBoxLayout(t);
36 	QWidget *w = new QWidget(t);
37 	QCheckBox *check;
38 	QComboBox *combo;
39 	QSpinBox *spin;
40 
41 	m_col = m_row = 0;
42 	m_cols = 4;
43 	for (int j = 0; j < m_cols; j++) {
44 		m_maxw[j] = 0;
45 	}
46 
47 	vbox->addWidget(w);
48 
49 	QGridLayout *grid = new QGridLayout(w);
50 	QLabel *title_tab = new QLabel("Test Pattern Generator", parentWidget());
51 	QFont f = title_tab->font();
52 	f.setBold(true);
53 	title_tab->setFont(f);
54 	grid->addWidget(title_tab, m_row, m_col, 1, m_cols, Qt::AlignLeft);
55 	grid->setRowMinimumHeight(m_row, 25);
56 	m_row++;
57 
58 	QFrame *m_line = new QFrame(grid->parentWidget());
59 	m_line->setFrameShape(QFrame::HLine);
60 	m_line->setFrameShadow(QFrame::Sunken);
61 	grid->addWidget(m_line, m_row, m_col, 1, m_cols, Qt::AlignVCenter);
62 	m_row++;
63 
64 	m_tabs->addTab(t, "Test Pattern Generator");
65 	grid->addWidget(new QWidget(w), grid->rowCount(), 0, 1, m_cols);
66 
67 	addLabel(grid, "Test Pattern");
68 	combo = new QComboBox(w);
69 	for (int i = 0; tpg_pattern_strings[i]; i++)
70 		combo->addItem(tpg_pattern_strings[i]);
71 	addWidget(grid, combo);
72 	connect(combo, SIGNAL(activated(int)), SLOT(testPatternChanged(int)));
73 
74 	m_row++;
75 	m_col = 0;
76 
77 	addLabel(grid, "Horizontal Movement");
78 	combo = new QComboBox(w);
79 	combo->addItem("Move Left Fast");
80 	combo->addItem("Move Left");
81 	combo->addItem("Move Left Slow");
82 	combo->addItem("No Movement");
83 	combo->addItem("Move Right Slow");
84 	combo->addItem("Move Right");
85 	combo->addItem("Move Right Fast");
86 	combo->setCurrentIndex(3);
87 	addWidget(grid, combo);
88 	connect(combo, SIGNAL(activated(int)), SLOT(horMovementChanged(int)));
89 
90 	addLabel(grid, "Video Aspect Ratio");
91 	combo = new QComboBox(w);
92 	combo->addItem("Source Width x Height");
93 	combo->addItem("4x3");
94 	combo->addItem("14x9");
95 	combo->addItem("16x9");
96 	combo->addItem("16x9 Anamorphic");
97 	addWidget(grid, combo);
98 	connect(combo, SIGNAL(activated(int)), SLOT(videoAspectRatioChanged(int)));
99 
100 	addLabel(grid, "Vertical Movement");
101 	combo = new QComboBox(w);
102 	combo->addItem("Move Up Fast");
103 	combo->addItem("Move Up");
104 	combo->addItem("Move Up Slow");
105 	combo->addItem("No Movement");
106 	combo->addItem("Move Down Slow");
107 	combo->addItem("Move Down");
108 	combo->addItem("Move Down Fast");
109 	combo->setCurrentIndex(3);
110 	addWidget(grid, combo);
111 	connect(combo, SIGNAL(activated(int)), SLOT(vertMovementChanged(int)));
112 
113 	addLabel(grid, "Show Border");
114 	check = new QCheckBox(w);
115 	addWidget(grid, check);
116 	connect(check, SIGNAL(stateChanged(int)), SLOT(showBorderChanged(int)));
117 
118 	addLabel(grid, "Insert SAV Code in Image");
119 	check = new QCheckBox(w);
120 	addWidget(grid, check);
121 	connect(check, SIGNAL(stateChanged(int)), SLOT(insSAVChanged(int)));
122 
123 	addLabel(grid, "Show Square");
124 	check = new QCheckBox(w);
125 	addWidget(grid, check);
126 	connect(check, SIGNAL(stateChanged(int)), SLOT(showSquareChanged(int)));
127 
128 	addLabel(grid, "Insert EAV Code in Image");
129 	check = new QCheckBox(w);
130 	addWidget(grid, check);
131 	connect(check, SIGNAL(stateChanged(int)), SLOT(insEAVChanged(int)));
132 
133 	addLabel(grid, "Fill Percentage of Frame");
134 	spin = new QSpinBox(w);
135 	spin->setRange(0, 100);
136 	spin->setValue(100);
137 	addWidget(grid, spin);
138 	connect(spin, SIGNAL(valueChanged(int)), SLOT(fillPercentageChanged(int)));
139 
140 	addLabel(grid, "Colorspace");
141 	m_tpgColorspace = new QComboBox(w);
142 	m_tpgColorspace->addItem("Use Format", QVariant(0));
143 	m_tpgColorspace->addItem("SMPTE 170M", QVariant(V4L2_COLORSPACE_SMPTE170M));
144 	m_tpgColorspace->addItem("Rec. 709", QVariant(V4L2_COLORSPACE_REC709));
145 	m_tpgColorspace->addItem("sRGB", QVariant(V4L2_COLORSPACE_SRGB));
146 	m_tpgColorspace->addItem("opRGB", QVariant(V4L2_COLORSPACE_OPRGB));
147 	m_tpgColorspace->addItem("BT.2020", QVariant(V4L2_COLORSPACE_BT2020));
148 	m_tpgColorspace->addItem("DCI-P3", QVariant(V4L2_COLORSPACE_DCI_P3));
149 	m_tpgColorspace->addItem("SMPTE 240M", QVariant(V4L2_COLORSPACE_SMPTE240M));
150 	m_tpgColorspace->addItem("470 System M", QVariant(V4L2_COLORSPACE_470_SYSTEM_M));
151 	m_tpgColorspace->addItem("470 System BG", QVariant(V4L2_COLORSPACE_470_SYSTEM_BG));
152 	addWidget(grid, m_tpgColorspace);
153 	connect(m_tpgColorspace, SIGNAL(activated(int)), SLOT(tpgColorspaceChanged()));
154 
155 	addLabel(grid, "Transfer Function");
156 	m_tpgXferFunc = new QComboBox(w);
157 	m_tpgXferFunc->addItem("Use Format", QVariant(V4L2_XFER_FUNC_DEFAULT));
158 	m_tpgXferFunc->addItem("Rec. 709", QVariant(V4L2_XFER_FUNC_709));
159 	m_tpgXferFunc->addItem("sRGB", QVariant(V4L2_XFER_FUNC_SRGB));
160 	m_tpgXferFunc->addItem("opRGB", QVariant(V4L2_XFER_FUNC_OPRGB));
161 	m_tpgXferFunc->addItem("DCI-P3", QVariant(V4L2_XFER_FUNC_DCI_P3));
162 	m_tpgXferFunc->addItem("SMPTE 2084", QVariant(V4L2_XFER_FUNC_SMPTE2084));
163 	m_tpgXferFunc->addItem("SMPTE 240M", QVariant(V4L2_XFER_FUNC_SMPTE240M));
164 	m_tpgXferFunc->addItem("None", QVariant(V4L2_XFER_FUNC_NONE));
165 	addWidget(grid, m_tpgXferFunc);
166 	connect(m_tpgXferFunc, SIGNAL(activated(int)), SLOT(tpgXferFuncChanged()));
167 
168 	addLabel(grid, "Y'CbCr/HSV Encoding");
169 	m_tpgYCbCrEnc = new QComboBox(w);
170 	m_tpgYCbCrEnc->addItem("Use Format", QVariant(V4L2_YCBCR_ENC_DEFAULT));
171 	m_tpgYCbCrEnc->addItem("ITU-R 601", QVariant(V4L2_YCBCR_ENC_601));
172 	m_tpgYCbCrEnc->addItem("Rec. 709", QVariant(V4L2_YCBCR_ENC_709));
173 	m_tpgYCbCrEnc->addItem("xvYCC 601", QVariant(V4L2_YCBCR_ENC_XV601));
174 	m_tpgYCbCrEnc->addItem("xvYCC 709", QVariant(V4L2_YCBCR_ENC_XV709));
175 	m_tpgYCbCrEnc->addItem("BT.2020", QVariant(V4L2_YCBCR_ENC_BT2020));
176 	m_tpgYCbCrEnc->addItem("BT.2020 Constant Luminance", QVariant(V4L2_YCBCR_ENC_BT2020_CONST_LUM));
177 	m_tpgYCbCrEnc->addItem("SMPTE 240M", QVariant(V4L2_YCBCR_ENC_SMPTE240M));
178 	m_tpgYCbCrEnc->addItem("HSV with Hue 0-179", QVariant(V4L2_HSV_ENC_180));
179 	m_tpgYCbCrEnc->addItem("HSV with Hue 0-255", QVariant(V4L2_HSV_ENC_256));
180 	addWidget(grid, m_tpgYCbCrEnc);
181 	connect(m_tpgYCbCrEnc, SIGNAL(activated(int)), SLOT(tpgColorspaceChanged()));
182 
183 	addLabel(grid, "Quantization");
184 	m_tpgQuantRange = new QComboBox(w);
185 	m_tpgQuantRange->addItem("Use Format", QVariant(V4L2_QUANTIZATION_DEFAULT));
186 	m_tpgQuantRange->addItem("Full Range", QVariant(V4L2_QUANTIZATION_FULL_RANGE));
187 	m_tpgQuantRange->addItem("Limited Range", QVariant(V4L2_QUANTIZATION_LIM_RANGE));
188 	addWidget(grid, m_tpgQuantRange);
189 	connect(m_tpgQuantRange, SIGNAL(activated(int)), SLOT(tpgColorspaceChanged()));
190 
191 	addLabel(grid, "Limited RGB Range (16-235)");
192 	m_tpgLimRGBRange = new QCheckBox(w);
193 	addWidget(grid, m_tpgLimRGBRange);
194 	connect(m_tpgLimRGBRange, SIGNAL(stateChanged(int)), SLOT(limRGBRangeChanged(int)));
195 
196 	addLabel(grid, "Alpha Component");
197 	spin = new QSpinBox(w);
198 	spin->setRange(0, 255);
199 	spin->setValue(0);
200 	addWidget(grid, spin);
201 	connect(spin, SIGNAL(valueChanged(int)), SLOT(alphaComponentChanged(int)));
202 
203 	addLabel(grid, "Apply Alpha To Red Only");
204 	check = new QCheckBox(w);
205 	addWidget(grid, check);
206 	connect(check, SIGNAL(stateChanged(int)), SLOT(applyToRedChanged(int)));
207 
208 	m_row++;
209 	m_col = 0;
210 	addWidget(grid, new QWidget(w));
211 	grid->setRowStretch(grid->rowCount() - 1, 1);
212 	w = new QWidget(t);
213 	vbox->addWidget(w);
214 	fixWidth(grid);
215 
216 	int totalw = 0;
217 	int diff = 0;
218 	for (int i = 0; i < m_cols; i++) {
219 		totalw += m_maxw[i] + m_pxw;
220 	}
221 	if (totalw > m_winWidth)
222 		m_winWidth = totalw;
223 	else {
224 		diff = m_winWidth - totalw;
225 		grid->setHorizontalSpacing(diff/5);
226 	}
227 }
228 
testPatternChanged(int val)229 void ApplicationWindow::testPatternChanged(int val)
230 {
231 	tpg_s_pattern(&m_tpg, (tpg_pattern)val);
232 }
233 
horMovementChanged(int val)234 void ApplicationWindow::horMovementChanged(int val)
235 {
236 	tpg_s_mv_hor_mode(&m_tpg, (tpg_move_mode)val);
237 }
238 
vertMovementChanged(int val)239 void ApplicationWindow::vertMovementChanged(int val)
240 {
241 	tpg_s_mv_vert_mode(&m_tpg, (tpg_move_mode)val);
242 }
243 
showBorderChanged(int val)244 void ApplicationWindow::showBorderChanged(int val)
245 {
246 	tpg_s_show_border(&m_tpg, val);
247 }
248 
showSquareChanged(int val)249 void ApplicationWindow::showSquareChanged(int val)
250 {
251 	tpg_s_show_square(&m_tpg, val);
252 }
253 
insSAVChanged(int val)254 void ApplicationWindow::insSAVChanged(int val)
255 {
256 	tpg_s_insert_sav(&m_tpg, val);
257 }
258 
insEAVChanged(int val)259 void ApplicationWindow::insEAVChanged(int val)
260 {
261 	tpg_s_insert_eav(&m_tpg, val);
262 }
263 
videoAspectRatioChanged(int val)264 void ApplicationWindow::videoAspectRatioChanged(int val)
265 {
266 	tpg_s_video_aspect(&m_tpg, (tpg_video_aspect)val);
267 }
268 
updateLimRGBRange()269 void ApplicationWindow::updateLimRGBRange()
270 {
271 	if (m_tpgLimRGBRange == NULL)
272 		return;
273 
274 	v4l2_output out;
275 
276 	g_output(out.index);
277 	enum_output(out, true, out.index);
278 
279 	if (out.capabilities & V4L2_OUT_CAP_STD) {
280 		m_tpgLimRGBRange->setChecked(false);
281 	} else if (out.capabilities & V4L2_OUT_CAP_DV_TIMINGS) {
282 		v4l2_dv_timings timings;
283 
284 		g_dv_timings(timings);
285 		if (timings.bt.standards & V4L2_DV_BT_STD_CEA861)
286 			m_tpgLimRGBRange->setChecked(true);
287 		else
288 			m_tpgLimRGBRange->setChecked(false);
289 	} else {
290 		m_tpgLimRGBRange->setChecked(false);
291 	}
292 }
293 
tpgDefaultColorspace()294 __u32 ApplicationWindow::tpgDefaultColorspace()
295 {
296 	v4l2_dv_timings timings = { 0 };
297 	v4l2_output out;
298 	__u32 io_caps;
299 	bool dvi_d = false;
300 
301 	g_output(out.index);
302 	enum_output(out, true, out.index);
303 	io_caps = out.capabilities;
304 	v4l2_control ctrl = { V4L2_CID_DV_TX_MODE };
305 
306 	if (!g_ctrl(ctrl))
307 		dvi_d = ctrl.value == V4L2_DV_TX_MODE_DVI_D;
308 
309 	if (io_caps & V4L2_OUT_CAP_STD)
310 		return V4L2_COLORSPACE_SMPTE170M;
311 	if (!(io_caps & V4L2_OUT_CAP_DV_TIMINGS))
312 		return V4L2_COLORSPACE_SRGB;
313 
314 	g_dv_timings(timings);
315 
316 	if (!(timings.bt.standards & V4L2_DV_BT_STD_CEA861) || dvi_d)
317 		return V4L2_COLORSPACE_SRGB;
318 	if (timings.bt.width == 720 && timings.bt.height <= 576)
319 		return V4L2_COLORSPACE_SMPTE170M;
320 	return V4L2_COLORSPACE_REC709;
321 }
322 
combo2int(QComboBox * combo)323 static int combo2int(QComboBox *combo)
324 {
325 	return combo->itemData(combo->currentIndex()).toInt();
326 }
327 
tpgColorspaceChanged()328 void ApplicationWindow::tpgColorspaceChanged()
329 {
330 	cv4l_fmt fmt;
331 	int colorspace = combo2int(m_tpgColorspace);
332 	int xferFunc = combo2int(m_tpgXferFunc);
333 	int ycbcrEnc = combo2int(m_tpgYCbCrEnc);
334 	int quantization = combo2int(m_tpgQuantRange);
335 
336 	g_fmt(fmt);
337 	if (colorspace == V4L2_COLORSPACE_DEFAULT)
338 		colorspace = fmt.g_colorspace();
339 	if (colorspace == V4L2_COLORSPACE_DEFAULT)
340 		colorspace = tpgDefaultColorspace();
341 	if (xferFunc == V4L2_XFER_FUNC_DEFAULT)
342 		xferFunc = fmt.g_xfer_func();
343 	if (ycbcrEnc == V4L2_YCBCR_ENC_DEFAULT)
344 		ycbcrEnc = fmt.g_ycbcr_enc();
345 	if (quantization == V4L2_QUANTIZATION_DEFAULT)
346 		quantization = fmt.g_quantization();
347 	tpg_s_colorspace(&m_tpg, colorspace);
348 	tpg_s_xfer_func(&m_tpg, xferFunc);
349 	tpg_s_ycbcr_enc(&m_tpg, ycbcrEnc);
350 	tpg_s_quantization(&m_tpg, quantization);
351 }
352 
limRGBRangeChanged(int val)353 void ApplicationWindow::limRGBRangeChanged(int val)
354 {
355 	tpg_s_real_rgb_range(&m_tpg, val ? V4L2_DV_RGB_RANGE_LIMITED : V4L2_DV_RGB_RANGE_FULL);
356 }
357 
fillPercentageChanged(int val)358 void ApplicationWindow::fillPercentageChanged(int val)
359 {
360 	tpg_s_perc_fill(&m_tpg, val);
361 }
362 
alphaComponentChanged(int val)363 void ApplicationWindow::alphaComponentChanged(int val)
364 {
365 	tpg_s_alpha_component(&m_tpg, val);
366 }
367 
applyToRedChanged(int val)368 void ApplicationWindow::applyToRedChanged(int val)
369 {
370 	tpg_s_alpha_mode(&m_tpg, val);
371 }
372