1 /*
2 * The YUY2 shader code is based on face-responder. The code is under public domain:
3 * https://bitbucket.org/nateharward/face-responder/src/0c3b4b957039d9f4bf1da09b9471371942de2601/yuv42201_laplace.frag?at=master
4 *
5 * All other OpenGL code:
6 *
7 * Copyright 2013 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
8 *
9 * This program is free software; you may redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; version 2 of the License.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
14 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
15 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
16 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
17 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
18 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 * SOFTWARE.
21 */
22
23 #include "capture-win-gl.h"
24
25 #include <stdio.h>
26
CaptureWinGL(ApplicationWindow * aw)27 CaptureWinGL::CaptureWinGL(ApplicationWindow *aw) :
28 CaptureWin(aw)
29 {
30 #ifdef HAVE_QTGL
31 CaptureWin::buildWindow(&m_videoSurface);
32 #endif
33 CaptureWin::setWindowTitle("V4L2 Capture (OpenGL)");
34 }
35
~CaptureWinGL()36 CaptureWinGL::~CaptureWinGL()
37 {
38 }
39
stop()40 void CaptureWinGL::stop()
41 {
42 #ifdef HAVE_QTGL
43 m_videoSurface.stop();
44 #endif
45 }
46
closeEvent(QCloseEvent * event)47 void CaptureWinGL::closeEvent(QCloseEvent *event)
48 {
49 this->hide();
50 event->ignore();
51 emit close();
52 }
53
resizeEvent(QResizeEvent * event)54 void CaptureWinGL::resizeEvent(QResizeEvent *event)
55 {
56 #ifdef HAVE_QTGL
57 // Get size of frame viewport. Can't use size of m_videoSurface
58 // since it is a subwidget of this widget.
59 QSize margins = getMargins();
60 m_windowSize = size() - margins;
61 // Re-calculate sizes
62 m_frame.updated = true;
63 CaptureWin::updateSize();
64 // Lock viewport size to follow calculated size
65 m_videoSurface.lockSize(m_scaledSize);
66 #endif
67 event->accept();
68 }
69
setRenderFrame()70 void CaptureWinGL::setRenderFrame()
71 {
72 #ifdef HAVE_QTGL
73 m_videoSurface.setFrame(m_frame.size.width(), m_frame.size.height(),
74 m_crop.delta.width(), m_crop.delta.height(),
75 m_frame.format,
76 m_frame.planeData[0],
77 m_frame.planeData[1],
78 m_frame.planeData[2]);
79 #endif
80 m_frame.updated = false;
81 m_crop.updated = false;
82 }
83
hasNativeFormat(__u32 format)84 bool CaptureWinGL::hasNativeFormat(__u32 format)
85 {
86 #ifdef HAVE_QTGL
87 return m_videoSurface.hasNativeFormat(format);
88 #else
89 return false;
90 #endif
91 }
92
isSupported()93 bool CaptureWinGL::isSupported()
94 {
95 #ifdef HAVE_QTGL
96 return true;
97 #else
98 return false;
99 #endif
100 }
101
setColorspace(unsigned colorspace,unsigned xfer_func,unsigned ycbcr_enc,unsigned quantization,bool is_sdtv)102 void CaptureWinGL::setColorspace(unsigned colorspace, unsigned xfer_func,
103 unsigned ycbcr_enc, unsigned quantization, bool is_sdtv)
104 {
105 #ifdef HAVE_QTGL
106 m_videoSurface.setColorspace(colorspace, xfer_func,
107 ycbcr_enc, quantization, is_sdtv);
108 #endif
109 }
110
setField(unsigned field)111 void CaptureWinGL::setField(unsigned field)
112 {
113 #ifdef HAVE_QTGL
114 m_videoSurface.setField(field);
115 #endif
116 }
117
setBlending(bool enable)118 void CaptureWinGL::setBlending(bool enable)
119 {
120 #ifdef HAVE_QTGL
121 m_videoSurface.setBlending(enable);
122 #endif
123 }
124
setLinearFilter(bool enable)125 void CaptureWinGL::setLinearFilter(bool enable)
126 {
127 #ifdef HAVE_QTGL
128 m_videoSurface.setLinearFilter(enable);
129 #endif
130 }
131
132 #ifdef HAVE_QTGL
CaptureWinGLEngine()133 CaptureWinGLEngine::CaptureWinGLEngine() :
134 m_frameWidth(0),
135 m_frameHeight(0),
136 m_WCrop(0),
137 m_HCrop(0),
138 m_colorspace(V4L2_COLORSPACE_REC709),
139 m_xfer_func(V4L2_XFER_FUNC_DEFAULT),
140 m_ycbcr_enc(V4L2_YCBCR_ENC_DEFAULT),
141 m_quantization(V4L2_QUANTIZATION_DEFAULT),
142 m_is_sdtv(false),
143 m_is_rgb(false),
144 m_field(V4L2_FIELD_NONE),
145 m_screenTextureCount(0),
146 m_formatChange(false),
147 m_frameFormat(0),
148 m_frameData(NULL),
149 m_blending(false),
150 m_mag_filter(GL_NEAREST),
151 m_min_filter(GL_NEAREST)
152 {
153 makeCurrent();
154 #if QT_VERSION < 0x060000
155 m_glfunction.initializeGLFunctions(context());
156 #endif
157 }
158
~CaptureWinGLEngine()159 CaptureWinGLEngine::~CaptureWinGLEngine()
160 {
161 clearShader();
162 }
163
setColorspace(unsigned colorspace,unsigned xfer_func,unsigned ycbcr_enc,unsigned quantization,bool is_sdtv)164 void CaptureWinGLEngine::setColorspace(unsigned colorspace, unsigned xfer_func,
165 unsigned ycbcr_enc, unsigned quantization, bool is_sdtv)
166 {
167 bool is_rgb = true;
168
169 switch (m_frameFormat) {
170 case V4L2_PIX_FMT_YUYV:
171 case V4L2_PIX_FMT_YVYU:
172 case V4L2_PIX_FMT_UYVY:
173 case V4L2_PIX_FMT_VYUY:
174 case V4L2_PIX_FMT_YUV422M:
175 case V4L2_PIX_FMT_YVU422M:
176 case V4L2_PIX_FMT_YUV422P:
177 case V4L2_PIX_FMT_YVU420:
178 case V4L2_PIX_FMT_YUV420:
179 case V4L2_PIX_FMT_YVU420M:
180 case V4L2_PIX_FMT_YUV420M:
181 case V4L2_PIX_FMT_NV12:
182 case V4L2_PIX_FMT_NV21:
183 case V4L2_PIX_FMT_NV12M:
184 case V4L2_PIX_FMT_NV21M:
185 case V4L2_PIX_FMT_NV16:
186 case V4L2_PIX_FMT_NV61:
187 case V4L2_PIX_FMT_NV16M:
188 case V4L2_PIX_FMT_NV61M:
189 case V4L2_PIX_FMT_NV24:
190 case V4L2_PIX_FMT_NV42:
191 case V4L2_PIX_FMT_YUV444M:
192 case V4L2_PIX_FMT_YVU444M:
193 case V4L2_PIX_FMT_YUV444:
194 case V4L2_PIX_FMT_YUV555:
195 case V4L2_PIX_FMT_YUV565:
196 case V4L2_PIX_FMT_YUV32:
197 case V4L2_PIX_FMT_AYUV32:
198 case V4L2_PIX_FMT_XYUV32:
199 case V4L2_PIX_FMT_VUYA32:
200 case V4L2_PIX_FMT_VUYX32:
201 case V4L2_PIX_FMT_YUVA32:
202 case V4L2_PIX_FMT_YUVX32:
203 case V4L2_PIX_FMT_HSV24:
204 case V4L2_PIX_FMT_HSV32:
205 is_rgb = false;
206 break;
207 }
208
209 switch (colorspace) {
210 case V4L2_COLORSPACE_SMPTE170M:
211 case V4L2_COLORSPACE_SMPTE240M:
212 case V4L2_COLORSPACE_REC709:
213 case V4L2_COLORSPACE_470_SYSTEM_M:
214 case V4L2_COLORSPACE_470_SYSTEM_BG:
215 case V4L2_COLORSPACE_SRGB:
216 case V4L2_COLORSPACE_OPRGB:
217 case V4L2_COLORSPACE_BT2020:
218 case V4L2_COLORSPACE_DCI_P3:
219 break;
220 default:
221 // If the colorspace was not specified, then guess
222 // based on the pixel format.
223 if (is_rgb)
224 colorspace = V4L2_COLORSPACE_SRGB;
225 else if (is_sdtv)
226 colorspace = V4L2_COLORSPACE_SMPTE170M;
227 else
228 colorspace = V4L2_COLORSPACE_REC709;
229 break;
230 }
231 if (m_colorspace == colorspace && m_xfer_func == xfer_func &&
232 m_ycbcr_enc == ycbcr_enc && m_quantization == quantization &&
233 m_is_sdtv == is_sdtv && m_is_rgb == is_rgb)
234 return;
235 m_colorspace = colorspace;
236 if (xfer_func == V4L2_XFER_FUNC_DEFAULT)
237 xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(colorspace);
238 if (ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT)
239 ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(colorspace);
240 if (quantization == V4L2_QUANTIZATION_DEFAULT)
241 quantization = V4L2_MAP_QUANTIZATION_DEFAULT(is_rgb, colorspace, ycbcr_enc);
242 m_xfer_func = xfer_func;
243 m_ycbcr_enc = ycbcr_enc;
244 m_quantization = quantization;
245 m_is_sdtv = is_sdtv;
246 m_is_rgb = is_rgb;
247 m_formatChange = true;
248 }
249
setField(unsigned field)250 void CaptureWinGLEngine::setField(unsigned field)
251 {
252 if (m_field == field)
253 return;
254 m_field = field;
255 m_formatChange = true;
256 }
257
setLinearFilter(bool enable)258 void CaptureWinGLEngine::setLinearFilter(bool enable)
259 {
260 if (enable) {
261 m_mag_filter = GL_LINEAR;
262 m_min_filter = GL_LINEAR;
263 }
264 else {
265 m_mag_filter = GL_NEAREST;
266 m_min_filter = GL_NEAREST;
267 }
268 m_formatChange = true;
269 }
270
clearShader()271 void CaptureWinGLEngine::clearShader()
272 {
273 if (m_screenTextureCount)
274 glDeleteTextures(m_screenTextureCount, m_screenTexture);
275 if (m_shaderProgram.isLinked()) {
276 m_shaderProgram.release();
277 m_shaderProgram.removeAllShaders();
278 }
279 }
280
stop()281 void CaptureWinGLEngine::stop()
282 {
283 // Setting the m_frameData to NULL stops OpenGL
284 // from updating frames on repaint
285 m_frameData = NULL;
286 m_frameData2 = NULL;
287 }
288
initializeGL()289 void CaptureWinGLEngine::initializeGL()
290 {
291 #if QT_VERSION >= 0x060000
292 initializeOpenGLFunctions();
293 #endif
294 glShadeModel(GL_FLAT);
295 glEnable(GL_TEXTURE_2D);
296 glEnable(GL_BLEND);
297 glDisable(GL_DEPTH_TEST);
298
299 // Check if the the GL_FRAMEBUFFER_SRGB feature is available.
300 // If it is, then the GPU can perform the SRGB transfer function
301 // for us.
302 GLint res = 0;
303 glGetIntegerv(GL_FRAMEBUFFER_SRGB_CAPABLE_EXT, &res);
304 // With Qt6 enabling sRGB results in dark colors for some reason.
305 // It is fine with Qt5.
306 // Since qvidcap also ignores this (i.e. it never enables sRGB)
307 // I decided to do the same for qv4l2, so just set this to false.
308 m_haveFramebufferSRGB = false;
309 if (m_haveFramebufferSRGB)
310 glEnable(GL_FRAMEBUFFER_SRGB);
311 m_hasGLRed = glGetString(GL_VERSION)[0] >= '3';
312 m_glRed = m_hasGLRed ? GL_RED : GL_LUMINANCE;
313 m_glRed16 = m_hasGLRed ? GL_R16 : GL_LUMINANCE;
314 m_glRedGreen = m_hasGLRed ? GL_RG : GL_LUMINANCE_ALPHA;
315
316 glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
317 glBlendFunc(GL_ONE, GL_ZERO);
318 checkError("InitializeGL");
319 }
320
lockSize(QSize size)321 void CaptureWinGLEngine::lockSize(QSize size)
322 {
323 if ((size.width() > 0) && (size.height() > 0)) {
324 setFixedSize(size);
325 }
326 }
327
resizeGL(int width,int height)328 void CaptureWinGLEngine::resizeGL(int width, int height)
329 {
330 glViewport(0, 0, width, height);
331 }
332
setFrame(int width,int height,int WCrop,int HCrop,__u32 format,unsigned char * data,unsigned char * data2,unsigned char * data3)333 void CaptureWinGLEngine::setFrame(int width, int height, int WCrop, int HCrop,
334 __u32 format, unsigned char *data, unsigned char *data2,
335 unsigned char *data3)
336 {
337 if (format != m_frameFormat || width != m_frameWidth || height != m_frameHeight
338 || WCrop != m_WCrop || HCrop != m_HCrop) {
339 m_formatChange = true;
340 m_frameWidth = width;
341 m_frameHeight = height;
342 m_WCrop = WCrop;
343 m_HCrop = HCrop;
344 m_frameFormat = format;
345 }
346
347 m_frameData = data;
348 m_frameData2 = data2 ? data2 : data;
349 m_frameData3 = data3 ? data3 : data;
350 #if QT_VERSION < 0x060000
351 updateGL();
352 #else
353 update();
354 #endif
355 }
356
checkError(const char * msg)357 void CaptureWinGLEngine::checkError(const char *msg)
358 {
359 int err = glGetError();
360 if (err) fprintf(stderr, "OpenGL Error 0x%x: %s.\n", err, msg);
361 }
362
hasNativeFormat(__u32 format)363 bool CaptureWinGLEngine::hasNativeFormat(__u32 format)
364 {
365 static const __u32 supported_fmts[] = {
366 V4L2_PIX_FMT_RGB32,
367 V4L2_PIX_FMT_XRGB32,
368 V4L2_PIX_FMT_ARGB32,
369 V4L2_PIX_FMT_BGR32,
370 V4L2_PIX_FMT_XBGR32,
371 V4L2_PIX_FMT_ABGR32,
372 V4L2_PIX_FMT_RGB24,
373 V4L2_PIX_FMT_BGR24,
374 V4L2_PIX_FMT_RGB565,
375 V4L2_PIX_FMT_RGB565X,
376 V4L2_PIX_FMT_RGB444,
377 V4L2_PIX_FMT_XRGB444,
378 V4L2_PIX_FMT_ARGB444,
379 V4L2_PIX_FMT_RGB555,
380 V4L2_PIX_FMT_XRGB555,
381 V4L2_PIX_FMT_ARGB555,
382 V4L2_PIX_FMT_RGB555X,
383 V4L2_PIX_FMT_XRGB555X,
384 V4L2_PIX_FMT_ARGB555X,
385 V4L2_PIX_FMT_RGB332,
386 V4L2_PIX_FMT_BGR666,
387 V4L2_PIX_FMT_SBGGR8,
388 V4L2_PIX_FMT_SGBRG8,
389 V4L2_PIX_FMT_SGRBG8,
390 V4L2_PIX_FMT_SRGGB8,
391 V4L2_PIX_FMT_SBGGR10,
392 V4L2_PIX_FMT_SGBRG10,
393 V4L2_PIX_FMT_SGRBG10,
394 V4L2_PIX_FMT_SRGGB10,
395 V4L2_PIX_FMT_SBGGR12,
396 V4L2_PIX_FMT_SGBRG12,
397 V4L2_PIX_FMT_SGRBG12,
398 V4L2_PIX_FMT_SRGGB12,
399 V4L2_PIX_FMT_SBGGR16,
400 V4L2_PIX_FMT_SGBRG16,
401 V4L2_PIX_FMT_SGRBG16,
402 V4L2_PIX_FMT_SRGGB16,
403 V4L2_PIX_FMT_YUYV,
404 V4L2_PIX_FMT_YVYU,
405 V4L2_PIX_FMT_UYVY,
406 V4L2_PIX_FMT_VYUY,
407 V4L2_PIX_FMT_YUV422M,
408 V4L2_PIX_FMT_YVU422M,
409 V4L2_PIX_FMT_YUV422P,
410 V4L2_PIX_FMT_YVU420,
411 V4L2_PIX_FMT_YUV420,
412 V4L2_PIX_FMT_NV12,
413 V4L2_PIX_FMT_NV21,
414 V4L2_PIX_FMT_NV16,
415 V4L2_PIX_FMT_NV61,
416 V4L2_PIX_FMT_NV24,
417 V4L2_PIX_FMT_NV42,
418 V4L2_PIX_FMT_YUV444M,
419 V4L2_PIX_FMT_YVU444M,
420 V4L2_PIX_FMT_NV16M,
421 V4L2_PIX_FMT_NV61M,
422 V4L2_PIX_FMT_YVU420M,
423 V4L2_PIX_FMT_YUV420M,
424 V4L2_PIX_FMT_NV12M,
425 V4L2_PIX_FMT_NV21M,
426 V4L2_PIX_FMT_YUV444,
427 V4L2_PIX_FMT_YUV555,
428 V4L2_PIX_FMT_YUV565,
429 V4L2_PIX_FMT_YUV32,
430 V4L2_PIX_FMT_AYUV32,
431 V4L2_PIX_FMT_XYUV32,
432 V4L2_PIX_FMT_VUYA32,
433 V4L2_PIX_FMT_VUYX32,
434 V4L2_PIX_FMT_YUVA32,
435 V4L2_PIX_FMT_YUVX32,
436 V4L2_PIX_FMT_GREY,
437 V4L2_PIX_FMT_Z16,
438 V4L2_PIX_FMT_INZI,
439 V4L2_PIX_FMT_Y10,
440 V4L2_PIX_FMT_Y12,
441 V4L2_PIX_FMT_Y16,
442 V4L2_PIX_FMT_Y16_BE,
443 V4L2_PIX_FMT_HSV24,
444 V4L2_PIX_FMT_HSV32,
445 0
446 };
447
448 #if QT_VERSION < 0x060000
449 if (!m_glfunction.hasOpenGLFeature(QGLFunctions::Shaders))
450 return false;
451 #else
452 if (!hasOpenGLFeature(QOpenGLFunctions::Shaders))
453 return false;
454 #endif
455
456 for (int i = 0; supported_fmts[i]; i++)
457 if (supported_fmts[i] == format)
458 return true;
459
460 return false;
461 }
462
changeShader()463 void CaptureWinGLEngine::changeShader()
464 {
465 m_formatChange = false;
466 clearShader();
467
468 glMatrixMode(GL_PROJECTION);
469 glLoadIdentity();
470 glOrtho(0, m_frameWidth, m_frameHeight, 0, 0, 1);
471 #if QT_VERSION < 0x060000
472 resizeGL(QGLWidget::width(), QGLWidget::height());
473 #else
474 resizeGL(QOpenGLWidget::width(), QOpenGLWidget::height());
475 #endif
476 checkError("Render settings.\n");
477
478 switch (m_frameFormat) {
479 case V4L2_PIX_FMT_YUYV:
480 case V4L2_PIX_FMT_YVYU:
481 case V4L2_PIX_FMT_UYVY:
482 case V4L2_PIX_FMT_VYUY:
483 shader_YUY2(m_frameFormat);
484 break;
485
486 case V4L2_PIX_FMT_NV16:
487 case V4L2_PIX_FMT_NV61:
488 case V4L2_PIX_FMT_NV16M:
489 case V4L2_PIX_FMT_NV61M:
490 shader_NV16(m_frameFormat);
491 break;
492
493 case V4L2_PIX_FMT_NV12:
494 case V4L2_PIX_FMT_NV21:
495 case V4L2_PIX_FMT_NV12M:
496 case V4L2_PIX_FMT_NV21M:
497 shader_NV12(m_frameFormat);
498 break;
499
500 case V4L2_PIX_FMT_NV24:
501 case V4L2_PIX_FMT_NV42:
502 shader_NV24(m_frameFormat);
503 break;
504
505 case V4L2_PIX_FMT_YUV444:
506 case V4L2_PIX_FMT_YUV555:
507 case V4L2_PIX_FMT_YUV565:
508 case V4L2_PIX_FMT_YUV32:
509 case V4L2_PIX_FMT_AYUV32:
510 case V4L2_PIX_FMT_XYUV32:
511 case V4L2_PIX_FMT_VUYA32:
512 case V4L2_PIX_FMT_VUYX32:
513 case V4L2_PIX_FMT_YUVA32:
514 case V4L2_PIX_FMT_YUVX32:
515 shader_YUV_packed(m_frameFormat);
516 break;
517
518 case V4L2_PIX_FMT_YUV422P:
519 case V4L2_PIX_FMT_YUV420:
520 case V4L2_PIX_FMT_YVU420:
521 case V4L2_PIX_FMT_YUV420M:
522 case V4L2_PIX_FMT_YVU420M:
523 case V4L2_PIX_FMT_YUV422M:
524 case V4L2_PIX_FMT_YVU422M:
525 case V4L2_PIX_FMT_YUV444M:
526 case V4L2_PIX_FMT_YVU444M:
527 shader_YUV(m_frameFormat);
528 break;
529
530 case V4L2_PIX_FMT_SBGGR8:
531 case V4L2_PIX_FMT_SGBRG8:
532 case V4L2_PIX_FMT_SGRBG8:
533 case V4L2_PIX_FMT_SRGGB8:
534 case V4L2_PIX_FMT_SBGGR10:
535 case V4L2_PIX_FMT_SGBRG10:
536 case V4L2_PIX_FMT_SGRBG10:
537 case V4L2_PIX_FMT_SRGGB10:
538 case V4L2_PIX_FMT_SBGGR12:
539 case V4L2_PIX_FMT_SGBRG12:
540 case V4L2_PIX_FMT_SGRBG12:
541 case V4L2_PIX_FMT_SRGGB12:
542 case V4L2_PIX_FMT_SBGGR16:
543 case V4L2_PIX_FMT_SGBRG16:
544 case V4L2_PIX_FMT_SGRBG16:
545 case V4L2_PIX_FMT_SRGGB16:
546 shader_Bayer(m_frameFormat);
547 break;
548
549 case V4L2_PIX_FMT_RGB332:
550 case V4L2_PIX_FMT_BGR666:
551 case V4L2_PIX_FMT_RGB555:
552 case V4L2_PIX_FMT_XRGB555:
553 case V4L2_PIX_FMT_ARGB555:
554 case V4L2_PIX_FMT_RGB444:
555 case V4L2_PIX_FMT_XRGB444:
556 case V4L2_PIX_FMT_ARGB444:
557 case V4L2_PIX_FMT_RGB555X:
558 case V4L2_PIX_FMT_XRGB555X:
559 case V4L2_PIX_FMT_ARGB555X:
560 case V4L2_PIX_FMT_RGB565:
561 case V4L2_PIX_FMT_RGB565X:
562 case V4L2_PIX_FMT_RGB24:
563 case V4L2_PIX_FMT_BGR24:
564 case V4L2_PIX_FMT_RGB32:
565 case V4L2_PIX_FMT_BGR32:
566 case V4L2_PIX_FMT_XRGB32:
567 case V4L2_PIX_FMT_XBGR32:
568 case V4L2_PIX_FMT_ARGB32:
569 case V4L2_PIX_FMT_ABGR32:
570 case V4L2_PIX_FMT_GREY:
571 case V4L2_PIX_FMT_Z16:
572 case V4L2_PIX_FMT_INZI:
573 case V4L2_PIX_FMT_Y10:
574 case V4L2_PIX_FMT_Y12:
575 case V4L2_PIX_FMT_Y16:
576 case V4L2_PIX_FMT_Y16_BE:
577 case V4L2_PIX_FMT_HSV24:
578 case V4L2_PIX_FMT_HSV32:
579 default:
580 shader_RGB(m_frameFormat);
581 break;
582 }
583 }
584
paintFrame()585 void CaptureWinGLEngine::paintFrame()
586 {
587 float HCrop_f = (float)m_HCrop / m_frameHeight;
588 float WCrop_f = (float)m_WCrop / m_frameWidth;
589
590 glBegin(GL_QUADS);
591 glTexCoord2f(WCrop_f, HCrop_f); glVertex2f(0, 0);
592 glTexCoord2f(1.0f - WCrop_f, HCrop_f); glVertex2f(m_frameWidth, 0);
593 glTexCoord2f(1.0f - WCrop_f, 1.0f - HCrop_f); glVertex2f(m_frameWidth, m_frameHeight);
594 glTexCoord2f(WCrop_f, 1.0f - HCrop_f); glVertex2f(0, m_frameHeight);
595 glEnd();
596 }
597
paintSquare()598 void CaptureWinGLEngine::paintSquare()
599 {
600 // Draw a black square on the white background to
601 // test the alpha channel.
602 unsigned w4 = m_frameWidth / 4;
603 unsigned h4 = m_frameHeight / 4;
604
605 glClear(GL_COLOR_BUFFER_BIT);
606 glBindTexture(GL_TEXTURE_2D, 0);
607
608 glBegin(GL_QUADS);
609 glColor4f(0.0f, 0.0f, 0.0f, 1.0f);
610 glVertex2f(w4, h4);
611 glVertex2f(w4, 3 * h4);
612 glVertex2f(3 * w4, 3 * h4);
613 glVertex2f(3 * w4, h4);
614 glEnd();
615 }
616
paintGL()617 void CaptureWinGLEngine::paintGL()
618 {
619 if (m_frameWidth < 1 || m_frameHeight < 1) {
620 return;
621 }
622
623 if (m_formatChange)
624 changeShader();
625
626 if (m_frameData == NULL) {
627 paintFrame();
628 return;
629 }
630
631 if (m_blending) {
632 paintSquare();
633 glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);
634 }
635
636 switch (m_frameFormat) {
637 case V4L2_PIX_FMT_YUYV:
638 case V4L2_PIX_FMT_YVYU:
639 case V4L2_PIX_FMT_UYVY:
640 case V4L2_PIX_FMT_VYUY:
641 render_YUY2(m_frameFormat);
642 break;
643
644 case V4L2_PIX_FMT_NV16:
645 case V4L2_PIX_FMT_NV61:
646 case V4L2_PIX_FMT_NV16M:
647 case V4L2_PIX_FMT_NV61M:
648 render_NV16(m_frameFormat);
649 break;
650
651 case V4L2_PIX_FMT_NV12:
652 case V4L2_PIX_FMT_NV21:
653 case V4L2_PIX_FMT_NV12M:
654 case V4L2_PIX_FMT_NV21M:
655 render_NV12(m_frameFormat);
656 break;
657
658 case V4L2_PIX_FMT_NV24:
659 case V4L2_PIX_FMT_NV42:
660 render_NV24(m_frameFormat);
661 break;
662
663 case V4L2_PIX_FMT_YUV422P:
664 case V4L2_PIX_FMT_YUV420:
665 case V4L2_PIX_FMT_YVU420:
666 case V4L2_PIX_FMT_YUV420M:
667 case V4L2_PIX_FMT_YVU420M:
668 case V4L2_PIX_FMT_YUV422M:
669 case V4L2_PIX_FMT_YVU422M:
670 case V4L2_PIX_FMT_YUV444M:
671 case V4L2_PIX_FMT_YVU444M:
672 render_YUV(m_frameFormat);
673 break;
674
675 case V4L2_PIX_FMT_YUV444:
676 case V4L2_PIX_FMT_YUV555:
677 case V4L2_PIX_FMT_YUV565:
678 case V4L2_PIX_FMT_YUV32:
679 case V4L2_PIX_FMT_AYUV32:
680 case V4L2_PIX_FMT_XYUV32:
681 case V4L2_PIX_FMT_VUYA32:
682 case V4L2_PIX_FMT_VUYX32:
683 case V4L2_PIX_FMT_YUVA32:
684 case V4L2_PIX_FMT_YUVX32:
685 render_YUV_packed(m_frameFormat);
686 break;
687
688 case V4L2_PIX_FMT_SBGGR8:
689 case V4L2_PIX_FMT_SGBRG8:
690 case V4L2_PIX_FMT_SGRBG8:
691 case V4L2_PIX_FMT_SRGGB8:
692 case V4L2_PIX_FMT_SBGGR10:
693 case V4L2_PIX_FMT_SGBRG10:
694 case V4L2_PIX_FMT_SGRBG10:
695 case V4L2_PIX_FMT_SRGGB10:
696 case V4L2_PIX_FMT_SBGGR12:
697 case V4L2_PIX_FMT_SGBRG12:
698 case V4L2_PIX_FMT_SGRBG12:
699 case V4L2_PIX_FMT_SRGGB12:
700 case V4L2_PIX_FMT_SBGGR16:
701 case V4L2_PIX_FMT_SGBRG16:
702 case V4L2_PIX_FMT_SGRBG16:
703 case V4L2_PIX_FMT_SRGGB16:
704 render_Bayer(m_frameFormat);
705 break;
706
707 case V4L2_PIX_FMT_GREY:
708 case V4L2_PIX_FMT_Z16:
709 case V4L2_PIX_FMT_INZI:
710 case V4L2_PIX_FMT_Y10:
711 case V4L2_PIX_FMT_Y12:
712 case V4L2_PIX_FMT_Y16:
713 case V4L2_PIX_FMT_Y16_BE:
714 case V4L2_PIX_FMT_RGB332:
715 case V4L2_PIX_FMT_BGR666:
716 case V4L2_PIX_FMT_RGB555:
717 case V4L2_PIX_FMT_XRGB555:
718 case V4L2_PIX_FMT_ARGB555:
719 case V4L2_PIX_FMT_RGB555X:
720 case V4L2_PIX_FMT_XRGB555X:
721 case V4L2_PIX_FMT_ARGB555X:
722 case V4L2_PIX_FMT_RGB444:
723 case V4L2_PIX_FMT_XRGB444:
724 case V4L2_PIX_FMT_ARGB444:
725 case V4L2_PIX_FMT_RGB565:
726 case V4L2_PIX_FMT_RGB565X:
727 case V4L2_PIX_FMT_RGB24:
728 case V4L2_PIX_FMT_BGR24:
729 case V4L2_PIX_FMT_RGB32:
730 case V4L2_PIX_FMT_BGR32:
731 case V4L2_PIX_FMT_XRGB32:
732 case V4L2_PIX_FMT_XBGR32:
733 case V4L2_PIX_FMT_ARGB32:
734 case V4L2_PIX_FMT_ABGR32:
735 case V4L2_PIX_FMT_HSV24:
736 case V4L2_PIX_FMT_HSV32:
737 default:
738 render_RGB(m_frameFormat);
739 break;
740 }
741 paintFrame();
742
743 if (m_blending)
744 glBlendFunc(GL_ONE, GL_ZERO);
745 }
746
configureTexture(size_t idx)747 void CaptureWinGLEngine::configureTexture(size_t idx)
748 {
749 glBindTexture(GL_TEXTURE_2D, m_screenTexture[idx]);
750 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_min_filter);
751 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, m_mag_filter);
752 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
753 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
754 }
755
756 // Normalize y to [0...1] and uv to [-0.5...0.5], taking into account the
757 // colorspace.
codeYUVNormalize()758 QString CaptureWinGLEngine::codeYUVNormalize()
759 {
760 switch (m_quantization) {
761 case V4L2_QUANTIZATION_FULL_RANGE:
762 if (m_ycbcr_enc != V4L2_YCBCR_ENC_XV601 &&
763 m_ycbcr_enc != V4L2_YCBCR_ENC_XV709)
764 return "";
765 /*
766 * xv709 and xv601 always have limited range quantization. But the
767 * result are values outside the normal 0-1 range, which is the
768 * point of these extended gamut encodings.
769 */
770
771 /* fall-through */
772 default:
773 return QString(" y = (255.0 / 219.0) * (y - (16.0 / 255.0));"
774 " u = (255.0 / 224.0) * u;"
775 " v = (255.0 / 224.0) * v;"
776 );
777 }
778 }
779
780 // Normalize r, g and b to [0...1]
codeRGBNormalize()781 QString CaptureWinGLEngine::codeRGBNormalize()
782 {
783 switch (m_quantization) {
784 case V4L2_QUANTIZATION_FULL_RANGE:
785 return "";
786 default:
787 return QString(" r = (255.0 / 219.0) * (r - (16.0 / 255.0));"
788 " g = (255.0 / 219.0) * (g - (16.0 / 255.0));"
789 " b = (255.0 / 219.0) * (b - (16.0 / 255.0));"
790 );
791 }
792 }
793
794 // Convert Y'CbCr (aka YUV) to R'G'B', taking into account the
795 // colorspace.
codeYUV2RGB()796 QString CaptureWinGLEngine::codeYUV2RGB()
797 {
798 switch (m_ycbcr_enc) {
799 case V4L2_YCBCR_ENC_SMPTE240M:
800 // Old obsolete HDTV standard. Replaced by REC 709.
801 // SMPTE 240M has its own luma coefficients
802 return QString(" float r = y + 1.5756 * v;"
803 " float g = y - 0.2253 * u - 0.4768 * v;"
804 " float b = y + 1.8270 * u;"
805 );
806 case V4L2_YCBCR_ENC_BT2020:
807 // BT.2020 luma coefficients
808 return QString(" float r = y + 1.4719 * v;"
809 " float g = y - 0.1646 * u - 0.5703 * v;"
810 " float b = y + 1.8814 * u;"
811 );
812 case V4L2_YCBCR_ENC_BT2020_CONST_LUM:
813 // BT.2020_CONST_LUM luma coefficients
814 return QString(" float b = u <= 0.0 ? y + 1.9404 * u : y + 1.5816 * u;"
815 " float r = v <= 0.0 ? y + 1.7184 * v : y + 0.9936 * v;"
816 " float lin_r = (r < 0.081) ? r / 4.5 : pow((r + 0.099) / 1.099, 1.0 / 0.45);"
817 " float lin_b = (b < 0.081) ? b / 4.5 : pow((b + 0.099) / 1.099, 1.0 / 0.45);"
818 " float lin_y = (y < 0.081) ? y / 4.5 : pow((y + 0.099) / 1.099, 1.0 / 0.45);"
819 " float lin_g = lin_y / 0.6780 - lin_r * 0.2627 / 0.6780 - lin_b * 0.0593 / 0.6780;"
820 " float g = (lin_g < 0.018) ? lin_g * 4.5 : 1.099 * pow(lin_g, 0.45) - 0.099;"
821 );
822 case V4L2_YCBCR_ENC_601:
823 case V4L2_YCBCR_ENC_XV601:
824 // These colorspaces all use the BT.601 luma coefficients
825 return QString(" float r = y + 1.403 * v;"
826 " float g = y - 0.344 * u - 0.714 * v;"
827 " float b = y + 1.773 * u;"
828 );
829 default:
830 // The HDTV colorspaces all use REC 709 luma coefficients
831 return QString(" float r = y + 1.5701 * v;"
832 " float g = y - 0.1870 * u - 0.4664 * v;"
833 " float b = y + 1.8556 * u;"
834 );
835 }
836 }
837
838 // Convert non-linear R'G'B' to linear RGB, taking into account the
839 // colorspace.
codeTransformToLinear()840 QString CaptureWinGLEngine::codeTransformToLinear()
841 {
842 switch (m_xfer_func) {
843 case V4L2_XFER_FUNC_SMPTE240M:
844 // Old obsolete HDTV standard. Replaced by REC 709.
845 // This is the transfer function for SMPTE 240M
846 return QString(" r = (r < 0.0913) ? r / 4.0 : pow((r + 0.1115) / 1.1115, 1.0 / 0.45);"
847 " g = (g < 0.0913) ? g / 4.0 : pow((g + 0.1115) / 1.1115, 1.0 / 0.45);"
848 " b = (b < 0.0913) ? b / 4.0 : pow((b + 0.1115) / 1.1115, 1.0 / 0.45);"
849 );
850 case V4L2_XFER_FUNC_SRGB:
851 // This is used for sRGB as specified by the IEC FDIS 61966-2-1 standard
852 return QString(" r = (r < -0.04045) ? -pow((-r + 0.055) / 1.055, 2.4) : "
853 " ((r <= 0.04045) ? r / 12.92 : pow((r + 0.055) / 1.055, 2.4));"
854 " g = (g < -0.04045) ? -pow((-g + 0.055) / 1.055, 2.4) : "
855 " ((g <= 0.04045) ? g / 12.92 : pow((g + 0.055) / 1.055, 2.4));"
856 " b = (b < -0.04045) ? -pow((-b + 0.055) / 1.055, 2.4) : "
857 " ((b <= 0.04045) ? b / 12.92 : pow((b + 0.055) / 1.055, 2.4));"
858 );
859 case V4L2_XFER_FUNC_OPRGB:
860 return QString(" r = pow(max(r, 0.0), 2.19921875);"
861 " g = pow(max(g, 0.0), 2.19921875);"
862 " b = pow(max(b, 0.0), 2.19921875);");
863 case V4L2_XFER_FUNC_DCI_P3:
864 return QString(" r = pow(max(r, 0.0), 2.6);"
865 " g = pow(max(g, 0.0), 2.6);"
866 " b = pow(max(b, 0.0), 2.6);");
867 case V4L2_XFER_FUNC_SMPTE2084:
868 return QString(" float m1 = 1.0 / ((2610.0 / 4096.0) / 4.0);"
869 " float m2 = 1.0 / (128.0 * 2523.0 / 4096.0);"
870 " float c1 = 3424.0 / 4096.0;"
871 " float c2 = 32.0 * 2413.0 / 4096.0;"
872 " float c3 = 32.0 * 2392.0 / 4096.0;"
873 " r = pow(max(r, 0.0), m2);"
874 " g = pow(max(g, 0.0), m2);"
875 " b = pow(max(b, 0.0), m2);"
876 // The factor 100 is because SMPTE-2084 maps to 0-10000 cd/m^2
877 // whereas other transfer functions map to 0-100 cd/m^2.
878 " r = pow(max(r - c1, 0.0) / (c2 - c3 * r), m1) * 100.0;"
879 " g = pow(max(g - c1, 0.0) / (c2 - c3 * g), m1) * 100.0;"
880 " b = pow(max(b - c1, 0.0) / (c2 - c3 * b), m1) * 100.0;");
881 case V4L2_XFER_FUNC_NONE:
882 return "";
883 case V4L2_XFER_FUNC_709:
884 default:
885 // All others use the transfer function specified by REC 709
886 return QString(" r = (r <= -0.081) ? -pow((r - 0.099) / -1.099, 1.0 / 0.45) : "
887 " ((r < 0.081) ? r / 4.5 : pow((r + 0.099) / 1.099, 1.0 / 0.45));"
888 " g = (g <= -0.081) ? -pow((g - 0.099) / -1.099, 1.0 / 0.45) : "
889 " ((g < 0.081) ? g / 4.5 : pow((g + 0.099) / 1.099, 1.0 / 0.45));"
890 " b = (b <= -0.081) ? -pow((b - 0.099) / -1.099, 1.0 / 0.45) : "
891 " ((b < 0.081) ? b / 4.5 : pow((b + 0.099) / 1.099, 1.0 / 0.45));"
892 );
893 }
894 }
895
896 // Convert the given colorspace to the REC 709/sRGB colorspace. All colors are
897 // specified as linear RGB.
codeColorspaceConversion()898 QString CaptureWinGLEngine::codeColorspaceConversion()
899 {
900 switch (m_colorspace) {
901 case V4L2_COLORSPACE_SMPTE170M:
902 case V4L2_COLORSPACE_SMPTE240M:
903 // Current SDTV standard, although slowly being replaced by REC 709.
904 // Uses the SMPTE 170M aka SMPTE-C aka SMPTE RP 145 conversion matrix.
905 return QString(" float rr = 0.939536 * r + 0.050215 * g + 0.001789 * b;"
906 " float gg = 0.017743 * r + 0.965758 * g + 0.016243 * b;"
907 " float bb = -0.001591 * r - 0.004356 * g + 1.005951 * b;"
908 " r = rr; g = gg; b = bb;"
909 );
910 case V4L2_COLORSPACE_470_SYSTEM_M:
911 // Old obsolete NTSC standard. Replaced by REC 709.
912 // Uses the NTSC 1953 conversion matrix and the Bradford method to
913 // compensate for the different whitepoints.
914 return QString(" float rr = 1.4858417 * r - 0.4033361 * g - 0.0825056 * b;"
915 " float gg = -0.0251179 * r + 0.9541568 * g + 0.0709611 * b;"
916 " float bb = -0.0272254 * r - 0.0440815 * g + 1.0713068 * b;"
917 " r = rr; g = gg; b = bb;"
918 );
919 case V4L2_COLORSPACE_470_SYSTEM_BG:
920 // Old obsolete PAL/SECAM standard. Replaced by REC 709.
921 // Uses the EBU Tech. 3213 conversion matrix.
922 return QString(" float rr = 1.0440 * r - 0.0440 * g;"
923 " float bb = -0.0119 * g + 1.0119 * b;"
924 " r = rr; b = bb;"
925 );
926 case V4L2_COLORSPACE_OPRGB:
927 return QString(" float rr = 1.3982832 * r - 0.3982831 * g;"
928 " float bb = -0.0429383 * g + 1.0429383 * b;"
929 " r = rr; b = bb;"
930 );
931 case V4L2_COLORSPACE_DCI_P3:
932 // Uses the Bradford method to compensate for the different whitepoints.
933 return QString(" float rr = 1.1574000 * r - 0.1548597 * g - 0.0025403 * b;"
934 " float gg = -0.0415052 * r + 1.0455684 * g - 0.0040633 * b;"
935 " float bb = -0.0180562 * r - 0.0785993 * g + 1.0966555 * b;"
936 );
937 case V4L2_COLORSPACE_BT2020:
938 return QString(" float rr = 1.6603627 * r - 0.5875400 * g - 0.0728227 * b;"
939 " float gg = -0.1245635 * r + 1.1329114 * g - 0.0083478 * b;"
940 " float bb = -0.0181566 * r - 0.1006017 * g + 1.1187583 * b;"
941 " r = rr; g = gg; b = bb;"
942 );
943 case V4L2_COLORSPACE_REC709:
944 case V4L2_COLORSPACE_SRGB:
945 default:
946 return "";
947 }
948 }
949
950 // Convert linear RGB to non-linear R'G'B', taking into account the
951 // given display colorspace.
codeTransformToNonLinear()952 QString CaptureWinGLEngine::codeTransformToNonLinear()
953 {
954 // Use the sRGB transfer function. Do nothing if the GL_FRAMEBUFFER_SRGB
955 // is available.
956 if (m_haveFramebufferSRGB)
957 return "";
958 return QString(" r = (r < -0.0031308) ? -1.055 * pow(-r, 1.0 / 2.4) + 0.055 : "
959 " ((r <= 0.0031308) ? r * 12.92 : 1.055 * pow(r, 1.0 / 2.4) - 0.055);"
960 " g = (g < -0.0031308) ? -1.055 * pow(-g, 1.0 / 2.4) + 0.055 : "
961 " ((g <= 0.0031308) ? g * 12.92 : 1.055 * pow(g, 1.0 / 2.4) - 0.055);"
962 " b = (b < -0.0031308) ? -1.055 * pow(-b, 1.0 / 2.4) + 0.055 : "
963 " ((b <= 0.0031308) ? b * 12.92 : 1.055 * pow(b, 1.0 / 2.4) - 0.055);"
964 );
965 }
966
967 static const QString codeSuffix(" gl_FragColor = vec4(r, g, b, 0.0);"
968 "}");
969
970 static const QString codeSuffixWithAlpha(" gl_FragColor = vec4(r, g, b, a);"
971 "}");
972
shader_YUV(__u32 format)973 void CaptureWinGLEngine::shader_YUV(__u32 format)
974 {
975 unsigned vdiv = 2, hdiv = 2;
976
977 switch (format) {
978 case V4L2_PIX_FMT_YUV422P:
979 case V4L2_PIX_FMT_YUV422M:
980 case V4L2_PIX_FMT_YVU422M:
981 vdiv = 1;
982 break;
983 case V4L2_PIX_FMT_YUV444M:
984 case V4L2_PIX_FMT_YVU444M:
985 vdiv = hdiv = 1;
986 break;
987 }
988
989 m_screenTextureCount = 3;
990 glGenTextures(m_screenTextureCount, m_screenTexture);
991
992 glActiveTexture(GL_TEXTURE0);
993 configureTexture(0);
994 glTexImage2D(GL_TEXTURE_2D, 0, m_glRed, m_frameWidth, m_frameHeight, 0,
995 m_glRed, GL_UNSIGNED_BYTE, NULL);
996 checkError("YUV shader texture 0");
997
998 glActiveTexture(GL_TEXTURE1);
999 configureTexture(1);
1000 glTexImage2D(GL_TEXTURE_2D, 0, m_glRed, m_frameWidth / hdiv, m_frameHeight / vdiv, 0,
1001 m_glRed, GL_UNSIGNED_BYTE, NULL);
1002 checkError("YUV shader texture 1");
1003
1004 glActiveTexture(GL_TEXTURE2);
1005 configureTexture(2);
1006 glTexImage2D(GL_TEXTURE_2D, 0, m_glRed, m_frameWidth / hdiv, m_frameHeight / vdiv, 0,
1007 m_glRed, GL_UNSIGNED_BYTE, NULL);
1008 checkError("YUV shader texture 2");
1009
1010 QString codeHead = QString("uniform sampler2D ytex;"
1011 "uniform sampler2D utex;"
1012 "uniform sampler2D vtex;"
1013 "uniform float tex_h;"
1014 "void main()"
1015 "{"
1016 " vec2 xy = vec2(gl_TexCoord[0].xy);"
1017 " float ycoord = floor(xy.y * tex_h);");
1018
1019 if (m_field == V4L2_FIELD_SEQ_TB)
1020 codeHead += " xy.y = (mod(ycoord, 2.0) == 0.0) ? xy.y / 2.0 : xy.y / 2.0 + 0.5;";
1021 else if (m_field == V4L2_FIELD_SEQ_BT)
1022 codeHead += " xy.y = (mod(ycoord, 2.0) == 0.0) ? xy.y / 2.0 + 0.5 : xy.y / 2.0;";
1023
1024 codeHead += " float y = texture2D(ytex, xy).r;"
1025 " float u = texture2D(utex, xy).r - 0.5;"
1026 " float v = texture2D(vtex, xy).r - 0.5;";
1027
1028 QString codeTail = codeYUVNormalize() +
1029 codeYUV2RGB() +
1030 codeTransformToLinear() +
1031 codeColorspaceConversion() +
1032 codeTransformToNonLinear() +
1033 codeSuffix;
1034
1035 bool src_c = m_shaderProgram.addShaderFromSourceCode(
1036 #if QT_VERSION < 0x060000
1037 QGLShader::Fragment,
1038 #else
1039 QOpenGLShader::Fragment,
1040 #endif
1041 codeHead + codeTail);
1042
1043 if (!src_c)
1044 fprintf(stderr, "OpenGL Error: YUV shader compilation failed.\n");
1045
1046 m_shaderProgram.bind();
1047 }
1048
render_YUV(__u32 format)1049 void CaptureWinGLEngine::render_YUV(__u32 format)
1050 {
1051 unsigned vdiv = 2, hdiv = 2;
1052 int idxU = 0;
1053 int idxV = 0;
1054
1055 switch (format) {
1056 case V4L2_PIX_FMT_YUV444M:
1057 case V4L2_PIX_FMT_YVU444M:
1058 vdiv = hdiv = 1;
1059 break;
1060 case V4L2_PIX_FMT_YUV422P:
1061 idxU = m_frameWidth * m_frameHeight;
1062 idxV = idxU + (idxU / 2);
1063 vdiv = 1;
1064 break;
1065 case V4L2_PIX_FMT_YUV422M:
1066 case V4L2_PIX_FMT_YVU422M:
1067 vdiv = 1;
1068 break;
1069 case V4L2_PIX_FMT_YUV420:
1070 idxU = m_frameWidth * m_frameHeight;
1071 idxV = idxU + (idxU / 4);
1072 break;
1073 case V4L2_PIX_FMT_YVU420:
1074 idxV = m_frameWidth * m_frameHeight;
1075 idxU = idxV + (idxV / 4);
1076 break;
1077 }
1078
1079 int idx = glGetUniformLocation(m_shaderProgram.programId(), "tex_h"); // Texture height
1080 glUniform1f(idx, m_frameHeight);
1081
1082 glActiveTexture(GL_TEXTURE0);
1083 glBindTexture(GL_TEXTURE_2D, m_screenTexture[0]);
1084 #if QT_VERSION < 0x060000
1085 GLint Y = m_glfunction.glGetUniformLocation(m_shaderProgram.programId(), "ytex");
1086 #else
1087 GLint Y = glGetUniformLocation(m_shaderProgram.programId(), "ytex");
1088 #endif
1089 glUniform1i(Y, 0);
1090 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
1091 m_glRed, GL_UNSIGNED_BYTE, m_frameData);
1092 checkError("YUV paint ytex");
1093
1094 glActiveTexture(GL_TEXTURE1);
1095 glBindTexture(GL_TEXTURE_2D, m_screenTexture[1]);
1096 #if QT_VERSION < 0x060000
1097 GLint U = m_glfunction.glGetUniformLocation(m_shaderProgram.programId(), "utex");
1098 #else
1099 GLint U = glGetUniformLocation(m_shaderProgram.programId(), "utex");
1100 #endif
1101 glUniform1i(U, 1);
1102 switch (format) {
1103 case V4L2_PIX_FMT_YUV422P:
1104 case V4L2_PIX_FMT_YUV420:
1105 case V4L2_PIX_FMT_YVU420:
1106 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth / hdiv, m_frameHeight / vdiv,
1107 m_glRed, GL_UNSIGNED_BYTE, m_frameData == NULL ? NULL : &m_frameData[idxU]);
1108 break;
1109 case V4L2_PIX_FMT_YUV420M:
1110 case V4L2_PIX_FMT_YUV422M:
1111 case V4L2_PIX_FMT_YUV444M:
1112 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth / hdiv, m_frameHeight / vdiv,
1113 m_glRed, GL_UNSIGNED_BYTE, m_frameData2);
1114 break;
1115 case V4L2_PIX_FMT_YVU420M:
1116 case V4L2_PIX_FMT_YVU422M:
1117 case V4L2_PIX_FMT_YVU444M:
1118 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth / hdiv, m_frameHeight / vdiv,
1119 m_glRed, GL_UNSIGNED_BYTE, m_frameData3);
1120 break;
1121 }
1122 checkError("YUV paint utex");
1123
1124 glActiveTexture(GL_TEXTURE2);
1125 glBindTexture(GL_TEXTURE_2D, m_screenTexture[2]);
1126 #if QT_VERSION < 0x060000
1127 GLint V = m_glfunction.glGetUniformLocation(m_shaderProgram.programId(), "vtex");
1128 #else
1129 GLint V = glGetUniformLocation(m_shaderProgram.programId(), "vtex");
1130 #endif
1131 glUniform1i(V, 2);
1132 switch (format) {
1133 case V4L2_PIX_FMT_YUV422P:
1134 case V4L2_PIX_FMT_YUV420:
1135 case V4L2_PIX_FMT_YVU420:
1136 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth / hdiv, m_frameHeight / vdiv,
1137 m_glRed, GL_UNSIGNED_BYTE, m_frameData == NULL ? NULL : &m_frameData[idxV]);
1138 break;
1139 case V4L2_PIX_FMT_YUV420M:
1140 case V4L2_PIX_FMT_YUV422M:
1141 case V4L2_PIX_FMT_YUV444M:
1142 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth / hdiv, m_frameHeight / vdiv,
1143 m_glRed, GL_UNSIGNED_BYTE, m_frameData3);
1144 break;
1145 case V4L2_PIX_FMT_YVU420M:
1146 case V4L2_PIX_FMT_YVU422M:
1147 case V4L2_PIX_FMT_YVU444M:
1148 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth / hdiv, m_frameHeight / vdiv,
1149 m_glRed, GL_UNSIGNED_BYTE, m_frameData2);
1150 break;
1151 }
1152 checkError("YUV paint vtex");
1153 }
1154
shader_NV12_invariant(__u32 format)1155 QString CaptureWinGLEngine::shader_NV12_invariant(__u32 format)
1156 {
1157 switch (format) {
1158 case V4L2_PIX_FMT_NV12:
1159 case V4L2_PIX_FMT_NV12M:
1160 return QString("if (mod(xcoord, 2.0) == 0.0) {"
1161 " u = texture2D(uvtex, xy).r - 0.5;"
1162 " v = texture2D(uvtex, vec2(xy.x + texl_w, xy.y)).r - 0.5;"
1163 "} else {"
1164 " u = texture2D(uvtex, vec2(xy.x - texl_w, xy.y)).r - 0.5;"
1165 " v = texture2D(uvtex, xy).r - 0.5;"
1166 "}"
1167 );
1168
1169 case V4L2_PIX_FMT_NV21:
1170 case V4L2_PIX_FMT_NV21M:
1171 return QString("if (mod(xcoord, 2.0) == 0.0) {"
1172 " u = texture2D(uvtex, vec2(xy.x + texl_w, xy.y)).r - 0.5;"
1173 " v = texture2D(uvtex, xy).r - 0.5;"
1174 "} else {"
1175 " u = texture2D(uvtex, xy).r - 0.5;"
1176 " v = texture2D(uvtex, vec2(xy.x - texl_w, xy.y)).r - 0.5;"
1177 "}"
1178 );
1179
1180 default:
1181 return QString();
1182 }
1183 }
1184
1185
shader_NV12(__u32 format)1186 void CaptureWinGLEngine::shader_NV12(__u32 format)
1187 {
1188 m_screenTextureCount = 2;
1189 glGenTextures(m_screenTextureCount, m_screenTexture);
1190
1191 glActiveTexture(GL_TEXTURE0);
1192 configureTexture(0);
1193 glTexImage2D(GL_TEXTURE_2D, 0, m_glRed, m_frameWidth, m_frameHeight, 0,
1194 m_glRed, GL_UNSIGNED_BYTE, NULL);
1195 checkError("NV12 shader texture 0");
1196
1197 glActiveTexture(GL_TEXTURE1);
1198 configureTexture(1);
1199 glTexImage2D(GL_TEXTURE_2D, 0, m_glRed, m_frameWidth, m_frameHeight / 2, 0,
1200 m_glRed, GL_UNSIGNED_BYTE, NULL);
1201 checkError("NV12 shader texture 1");
1202
1203 QString codeHead = QString("uniform sampler2D ytex;"
1204 "uniform sampler2D uvtex;"
1205 "uniform float texl_w;"
1206 "uniform float tex_w;"
1207 "uniform float tex_h;"
1208 "void main()"
1209 "{"
1210 " vec2 xy = vec2(gl_TexCoord[0].xy);"
1211 " float ycoord = floor(xy.y * tex_h);");
1212
1213 if (m_field == V4L2_FIELD_SEQ_TB)
1214 codeHead += " xy.y = (mod(ycoord, 2.0) == 0.0) ? xy.y / 2.0 : xy.y / 2.0 + 0.5;";
1215 else if (m_field == V4L2_FIELD_SEQ_BT)
1216 codeHead += " xy.y = (mod(ycoord, 2.0) == 0.0) ? xy.y / 2.0 + 0.5 : xy.y / 2.0;";
1217
1218 codeHead += " float u, v;"
1219 " float xcoord = floor(xy.x * tex_w);"
1220 " float y = texture2D(ytex, xy).r;";
1221
1222 QString codeBody = shader_NV12_invariant(format);
1223
1224 QString codeTail = codeYUVNormalize() +
1225 codeYUV2RGB() +
1226 codeTransformToLinear() +
1227 codeColorspaceConversion() +
1228 codeTransformToNonLinear() +
1229 codeSuffix;
1230
1231 bool src_c = m_shaderProgram.addShaderFromSourceCode(
1232 #if QT_VERSION < 0x060000
1233 QGLShader::Fragment,
1234 #else
1235 QOpenGLShader::Fragment,
1236 #endif
1237 QString("%1%2%3").arg(codeHead, codeBody, codeTail));
1238
1239 if (!src_c)
1240 fprintf(stderr, "OpenGL Error: YUV shader compilation failed.\n");
1241
1242 m_shaderProgram.bind();
1243 }
1244
render_NV12(__u32 format)1245 void CaptureWinGLEngine::render_NV12(__u32 format)
1246 {
1247 int idx;
1248
1249 idx = glGetUniformLocation(m_shaderProgram.programId(), "texl_w"); // Texel width
1250 glUniform1f(idx, 1.0 / m_frameWidth);
1251 idx = glGetUniformLocation(m_shaderProgram.programId(), "tex_w"); // Texture width
1252 glUniform1f(idx, m_frameWidth);
1253 idx = glGetUniformLocation(m_shaderProgram.programId(), "tex_h"); // Texture height
1254 glUniform1f(idx, m_frameHeight);
1255
1256 glActiveTexture(GL_TEXTURE0);
1257 glBindTexture(GL_TEXTURE_2D, m_screenTexture[0]);
1258 #if QT_VERSION < 0x060000
1259 GLint Y = m_glfunction.glGetUniformLocation(m_shaderProgram.programId(), "ytex");
1260 #else
1261 GLint Y = glGetUniformLocation(m_shaderProgram.programId(), "ytex");
1262 #endif
1263 glUniform1i(Y, 0);
1264 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
1265 m_glRed, GL_UNSIGNED_BYTE, m_frameData);
1266 checkError("NV12 paint ytex");
1267
1268 glActiveTexture(GL_TEXTURE1);
1269 glBindTexture(GL_TEXTURE_2D, m_screenTexture[1]);
1270 #if QT_VERSION < 0x060000
1271 GLint U = m_glfunction.glGetUniformLocation(m_shaderProgram.programId(), "uvtex");
1272 #else
1273 GLint U = glGetUniformLocation(m_shaderProgram.programId(), "uvtex");
1274 #endif
1275 glUniform1i(U, 1);
1276 switch (format) {
1277 case V4L2_PIX_FMT_NV12:
1278 case V4L2_PIX_FMT_NV21:
1279 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight / 2,
1280 m_glRed, GL_UNSIGNED_BYTE,
1281 m_frameData ? m_frameData + m_frameWidth * m_frameHeight : NULL);
1282 break;
1283 case V4L2_PIX_FMT_NV12M:
1284 case V4L2_PIX_FMT_NV21M:
1285 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight / 2,
1286 m_glRed, GL_UNSIGNED_BYTE, m_frameData2);
1287 break;
1288 }
1289 checkError("NV12 paint uvtex");
1290 }
1291
shader_NV24_invariant(__u32 format)1292 QString CaptureWinGLEngine::shader_NV24_invariant(__u32 format)
1293 {
1294 switch (format) {
1295 case V4L2_PIX_FMT_NV24:
1296 if (m_hasGLRed)
1297 return QString(" u = texture2D(uvtex, xy).r - 0.5;"
1298 " v = texture2D(uvtex, xy).g - 0.5;"
1299 );
1300 return QString(" u = texture2D(uvtex, xy).r - 0.5;"
1301 " v = texture2D(uvtex, xy).a - 0.5;"
1302 );
1303
1304 case V4L2_PIX_FMT_NV42:
1305 if (m_hasGLRed)
1306 return QString(" v = texture2D(uvtex, xy).r - 0.5;"
1307 " u = texture2D(uvtex, xy).g - 0.5;"
1308 );
1309 return QString(" v = texture2D(uvtex, xy).r - 0.5;"
1310 " u = texture2D(uvtex, xy).a - 0.5;"
1311 );
1312
1313 default:
1314 return QString();
1315 }
1316 }
1317
shader_NV24(__u32 format)1318 void CaptureWinGLEngine::shader_NV24(__u32 format)
1319 {
1320 m_screenTextureCount = 2;
1321 glGenTextures(m_screenTextureCount, m_screenTexture);
1322
1323 glActiveTexture(GL_TEXTURE0);
1324 configureTexture(0);
1325 glTexImage2D(GL_TEXTURE_2D, 0, m_glRed, m_frameWidth, m_frameHeight, 0,
1326 m_glRed, GL_UNSIGNED_BYTE, NULL);
1327 checkError("NV24 shader texture 0");
1328
1329 glActiveTexture(GL_TEXTURE1);
1330 configureTexture(1);
1331 glTexImage2D(GL_TEXTURE_2D, 0, m_glRedGreen, m_frameWidth, m_frameHeight, 0,
1332 m_glRedGreen, GL_UNSIGNED_BYTE, NULL);
1333 checkError("NV24 shader texture 1");
1334
1335 QString codeHead = QString("uniform sampler2D ytex;"
1336 "uniform sampler2D uvtex;"
1337 "uniform float tex_w;"
1338 "uniform float tex_h;"
1339 "void main()"
1340 "{"
1341 " vec2 xy = vec2(gl_TexCoord[0].xy);"
1342 " float ycoord = floor(xy.y * tex_h);");
1343
1344 if (m_field == V4L2_FIELD_SEQ_TB)
1345 codeHead += " xy.y = (mod(ycoord, 2.0) == 0.0) ? xy.y / 2.0 : xy.y / 2.0 + 0.5;";
1346 else if (m_field == V4L2_FIELD_SEQ_BT)
1347 codeHead += " xy.y = (mod(ycoord, 2.0) == 0.0) ? xy.y / 2.0 + 0.5 : xy.y / 2.0;";
1348
1349 codeHead += " float u, v;"
1350 " float y = texture2D(ytex, xy).r;";
1351
1352 QString codeBody = shader_NV24_invariant(format);
1353
1354 QString codeTail = codeYUVNormalize() +
1355 codeYUV2RGB() +
1356 codeTransformToLinear() +
1357 codeColorspaceConversion() +
1358 codeTransformToNonLinear() +
1359 codeSuffix;
1360
1361 bool src_c = m_shaderProgram.addShaderFromSourceCode(
1362 #if QT_VERSION < 0x060000
1363 QGLShader::Fragment,
1364 #else
1365 QOpenGLShader::Fragment,
1366 #endif
1367 QString("%1%2%3").arg(codeHead, codeBody, codeTail));
1368
1369 if (!src_c)
1370 fprintf(stderr, "OpenGL Error: YUV shader compilation failed.\n");
1371
1372 m_shaderProgram.bind();
1373 }
1374
render_NV24(__u32 format)1375 void CaptureWinGLEngine::render_NV24(__u32 format)
1376 {
1377 int idx;
1378
1379 idx = glGetUniformLocation(m_shaderProgram.programId(), "tex_w"); // Texture width
1380 glUniform1f(idx, m_frameWidth);
1381 idx = glGetUniformLocation(m_shaderProgram.programId(), "tex_h"); // Texture height
1382 glUniform1f(idx, m_frameHeight);
1383
1384 glActiveTexture(GL_TEXTURE0);
1385 glBindTexture(GL_TEXTURE_2D, m_screenTexture[0]);
1386 #if QT_VERSION < 0x060000
1387 GLint Y = m_glfunction.glGetUniformLocation(m_shaderProgram.programId(), "ytex");
1388 #else
1389 GLint Y = glGetUniformLocation(m_shaderProgram.programId(), "ytex");
1390 #endif
1391 glUniform1i(Y, 0);
1392 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
1393 m_glRed, GL_UNSIGNED_BYTE, m_frameData);
1394 checkError("NV24 paint ytex");
1395
1396 glActiveTexture(GL_TEXTURE1);
1397 glBindTexture(GL_TEXTURE_2D, m_screenTexture[1]);
1398 #if QT_VERSION < 0x060000
1399 GLint U = m_glfunction.glGetUniformLocation(m_shaderProgram.programId(), "uvtex");
1400 #else
1401 GLint U = glGetUniformLocation(m_shaderProgram.programId(), "uvtex");
1402 #endif
1403 glUniform1i(U, 1);
1404 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
1405 m_glRedGreen, GL_UNSIGNED_BYTE,
1406 m_frameData ? m_frameData + m_frameWidth * m_frameHeight : NULL);
1407 checkError("NV24 paint uvtex");
1408 }
1409
shader_NV16_invariant(__u32 format)1410 QString CaptureWinGLEngine::shader_NV16_invariant(__u32 format)
1411 {
1412 switch (format) {
1413 case V4L2_PIX_FMT_NV16:
1414 case V4L2_PIX_FMT_NV16M:
1415 return QString("if (mod(xcoord, 2.0) == 0.0) {"
1416 " u = texture2D(uvtex, xy).r - 0.5;"
1417 " v = texture2D(uvtex, vec2(xy.x + texl_w, xy.y)).r - 0.5;"
1418 "} else {"
1419 " u = texture2D(uvtex, vec2(xy.x - texl_w, xy.y)).r - 0.5;"
1420 " v = texture2D(uvtex, xy).r - 0.5;"
1421 "}"
1422 );
1423
1424 case V4L2_PIX_FMT_NV61:
1425 case V4L2_PIX_FMT_NV61M:
1426 return QString("if (mod(xcoord, 2.0) == 0.0) {"
1427 " u = texture2D(uvtex, vec2(xy.x + texl_w, xy.y)).r - 0.5;"
1428 " v = texture2D(uvtex, xy).r - 0.5;"
1429 "} else {"
1430 " u = texture2D(uvtex, xy).r - 0.5;"
1431 " v = texture2D(uvtex, vec2(xy.x - texl_w, xy.y)).r - 0.5;"
1432 "}"
1433 );
1434
1435 default:
1436 return QString();
1437 }
1438 }
1439
shader_NV16(__u32 format)1440 void CaptureWinGLEngine::shader_NV16(__u32 format)
1441 {
1442 m_screenTextureCount = 2;
1443 glGenTextures(m_screenTextureCount, m_screenTexture);
1444
1445 glActiveTexture(GL_TEXTURE0);
1446 configureTexture(0);
1447 glTexImage2D(GL_TEXTURE_2D, 0, m_glRed, m_frameWidth, m_frameHeight, 0,
1448 m_glRed, GL_UNSIGNED_BYTE, NULL);
1449 checkError("NV16 shader texture 0");
1450
1451 glActiveTexture(GL_TEXTURE1);
1452 configureTexture(1);
1453 glTexImage2D(GL_TEXTURE_2D, 0, m_glRed, m_frameWidth, m_frameHeight, 0,
1454 m_glRed, GL_UNSIGNED_BYTE, NULL);
1455 checkError("NV16 shader texture 1");
1456
1457 QString codeHead = QString("uniform sampler2D ytex;"
1458 "uniform sampler2D uvtex;"
1459 "uniform float texl_w;"
1460 "uniform float tex_w;"
1461 "uniform float tex_h;"
1462 "void main()"
1463 "{"
1464 " vec2 xy = vec2(gl_TexCoord[0].xy);"
1465 " float ycoord = floor(xy.y * tex_h);");
1466
1467 if (m_field == V4L2_FIELD_SEQ_TB)
1468 codeHead += " xy.y = (mod(ycoord, 2.0) == 0.0) ? xy.y / 2.0 : xy.y / 2.0 + 0.5;";
1469 else if (m_field == V4L2_FIELD_SEQ_BT)
1470 codeHead += " xy.y = (mod(ycoord, 2.0) == 0.0) ? xy.y / 2.0 + 0.5 : xy.y / 2.0;";
1471
1472 codeHead += " float u, v;"
1473 " float xcoord = floor(xy.x * tex_w);"
1474 " float y = texture2D(ytex, xy).r;";
1475
1476 QString codeBody = shader_NV16_invariant(format);
1477
1478 QString codeTail = codeYUVNormalize() +
1479 codeYUV2RGB() +
1480 codeTransformToLinear() +
1481 codeColorspaceConversion() +
1482 codeTransformToNonLinear() +
1483 codeSuffix;
1484
1485 bool src_ok = m_shaderProgram.addShaderFromSourceCode(
1486 #if QT_VERSION < 0x060000
1487 QGLShader::Fragment,
1488 #else
1489 QOpenGLShader::Fragment,
1490 #endif
1491 QString("%1%2%3").arg(codeHead, codeBody, codeTail));
1492
1493 if (!src_ok)
1494 fprintf(stderr, "OpenGL Error: NV16 shader compilation failed.\n");
1495
1496 m_shaderProgram.bind();
1497 }
1498
render_NV16(__u32 format)1499 void CaptureWinGLEngine::render_NV16(__u32 format)
1500 {
1501 int idx;
1502 idx = glGetUniformLocation(m_shaderProgram.programId(), "texl_w"); // Texel width
1503 glUniform1f(idx, 1.0 / m_frameWidth);
1504 idx = glGetUniformLocation(m_shaderProgram.programId(), "tex_w"); // Texture width
1505 glUniform1f(idx, m_frameWidth);
1506 idx = glGetUniformLocation(m_shaderProgram.programId(), "tex_h"); // Texture height
1507 glUniform1f(idx, m_frameHeight);
1508
1509 glActiveTexture(GL_TEXTURE0);
1510 glBindTexture(GL_TEXTURE_2D, m_screenTexture[0]);
1511 #if QT_VERSION < 0x060000
1512 GLint Y = m_glfunction.glGetUniformLocation(m_shaderProgram.programId(), "ytex");
1513 #else
1514 GLint Y = glGetUniformLocation(m_shaderProgram.programId(), "ytex");
1515 #endif
1516 glUniform1i(Y, 0);
1517 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
1518 m_glRed, GL_UNSIGNED_BYTE, m_frameData);
1519 checkError("NV16 paint ytex");
1520
1521 glActiveTexture(GL_TEXTURE1);
1522 glBindTexture(GL_TEXTURE_2D, m_screenTexture[1]);
1523 #if QT_VERSION < 0x060000
1524 GLint UV = m_glfunction.glGetUniformLocation(m_shaderProgram.programId(), "uvtex");
1525 #else
1526 GLint UV = glGetUniformLocation(m_shaderProgram.programId(), "uvtex");
1527 #endif
1528 glUniform1i(UV, 1);
1529 switch (format) {
1530 case V4L2_PIX_FMT_NV16:
1531 case V4L2_PIX_FMT_NV61:
1532 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
1533 m_glRed, GL_UNSIGNED_BYTE,
1534 m_frameData ? m_frameData + m_frameWidth * m_frameHeight : NULL);
1535 break;
1536 case V4L2_PIX_FMT_NV16M:
1537 case V4L2_PIX_FMT_NV61M:
1538 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
1539 m_glRed, GL_UNSIGNED_BYTE, m_frameData2);
1540 break;
1541 }
1542 checkError("NV16 paint");
1543 }
1544
shader_YUY2_invariant(__u32 format)1545 QString CaptureWinGLEngine::shader_YUY2_invariant(__u32 format)
1546 {
1547 switch (format) {
1548 case V4L2_PIX_FMT_YUYV:
1549 return QString("if (mod(xcoord, 2.0) == 0.0) {"
1550 " luma_chroma = texture2D(tex, xy);"
1551 " y = luma_chroma.r;"
1552 "} else {"
1553 " luma_chroma = texture2D(tex, vec2(xy.x - texl_w, xy.y));"
1554 " y = luma_chroma.b;"
1555 "}"
1556 "u = luma_chroma.g - 0.5;"
1557 "v = luma_chroma.a - 0.5;"
1558 );
1559
1560 case V4L2_PIX_FMT_YVYU:
1561 return QString("if (mod(xcoord, 2.0) == 0.0) {"
1562 " luma_chroma = texture2D(tex, xy);"
1563 " y = luma_chroma.r;"
1564 "} else {"
1565 " luma_chroma = texture2D(tex, vec2(xy.x - texl_w, xy.y));"
1566 " y = luma_chroma.b;"
1567 "}"
1568 "u = luma_chroma.a - 0.5;"
1569 "v = luma_chroma.g - 0.5;"
1570 );
1571
1572 case V4L2_PIX_FMT_UYVY:
1573 return QString("if (mod(xcoord, 2.0) == 0.0) {"
1574 " luma_chroma = texture2D(tex, xy);"
1575 " y = luma_chroma.g;"
1576 "} else {"
1577 " luma_chroma = texture2D(tex, vec2(xy.x - texl_w, xy.y));"
1578 " y = luma_chroma.a;"
1579 "}"
1580 "u = luma_chroma.r - 0.5;"
1581 "v = luma_chroma.b - 0.5;"
1582 );
1583
1584 case V4L2_PIX_FMT_VYUY:
1585 return QString("if (mod(xcoord, 2.0) == 0.0) {"
1586 " luma_chroma = texture2D(tex, xy);"
1587 " y = luma_chroma.g;"
1588 "} else {"
1589 " luma_chroma = texture2D(tex, vec2(xy.x - texl_w, xy.y));"
1590 " y = luma_chroma.a;"
1591 "}"
1592 "u = luma_chroma.b - 0.5;"
1593 "v = luma_chroma.r - 0.5;"
1594 );
1595
1596 default:
1597 return QString();
1598 }
1599 }
1600
shader_YUY2(__u32 format)1601 void CaptureWinGLEngine::shader_YUY2(__u32 format)
1602 {
1603 m_screenTextureCount = 1;
1604 glGenTextures(m_screenTextureCount, m_screenTexture);
1605 configureTexture(0);
1606 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_frameWidth / 2, m_frameHeight, 0,
1607 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
1608
1609 checkError("YUY2 shader");
1610
1611 QString codeHead = QString("uniform sampler2D tex;"
1612 "uniform float texl_w;"
1613 "uniform float tex_w;"
1614 "uniform float tex_h;"
1615 "void main()"
1616 "{"
1617 " float y, u, v;"
1618 " vec4 luma_chroma;"
1619 " vec2 xy = vec2(gl_TexCoord[0].xy);"
1620 " float xcoord = floor(xy.x * tex_w);"
1621 " float ycoord = floor(xy.y * tex_h);");
1622
1623 if (m_field == V4L2_FIELD_SEQ_TB)
1624 codeHead += " xy.y = (mod(ycoord, 2.0) == 0.0) ? xy.y / 2.0 : xy.y / 2.0 + 0.5;";
1625 else if (m_field == V4L2_FIELD_SEQ_BT)
1626 codeHead += " xy.y = (mod(ycoord, 2.0) == 0.0) ? xy.y / 2.0 + 0.5 : xy.y / 2.0;";
1627
1628 QString codeBody = shader_YUY2_invariant(format);
1629
1630 QString codeTail = codeYUVNormalize() +
1631 codeYUV2RGB() +
1632 codeTransformToLinear() +
1633 codeColorspaceConversion() +
1634 codeTransformToNonLinear() +
1635 codeSuffix;
1636
1637 bool src_ok = m_shaderProgram.addShaderFromSourceCode(
1638 #if QT_VERSION < 0x060000
1639 QGLShader::Fragment,
1640 #else
1641 QOpenGLShader::Fragment,
1642 #endif
1643 QString("%1%2%3").arg(codeHead, codeBody, codeTail));
1644
1645 if (!src_ok)
1646 fprintf(stderr, "OpenGL Error: YUY2 shader compilation failed.\n");
1647
1648 m_shaderProgram.bind();
1649 }
1650
render_YUY2(__u32 format)1651 void CaptureWinGLEngine::render_YUY2(__u32 format)
1652 {
1653 int idx;
1654 idx = glGetUniformLocation(m_shaderProgram.programId(), "texl_w"); // Texel width
1655 glUniform1f(idx, 1.0 / m_frameWidth);
1656 idx = glGetUniformLocation(m_shaderProgram.programId(), "tex_w"); // Texture width
1657 glUniform1f(idx, m_frameWidth);
1658 idx = glGetUniformLocation(m_shaderProgram.programId(), "tex_h"); // Texture height
1659 glUniform1f(idx, m_frameHeight);
1660
1661 glActiveTexture(GL_TEXTURE0);
1662 glBindTexture(GL_TEXTURE_2D, m_screenTexture[0]);
1663 #if QT_VERSION < 0x060000
1664 GLint Y = m_glfunction.glGetUniformLocation(m_shaderProgram.programId(), "tex");
1665 #else
1666 GLint Y = glGetUniformLocation(m_shaderProgram.programId(), "tex");
1667 #endif
1668 glUniform1i(Y, 0);
1669 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth / 2, m_frameHeight,
1670 GL_RGBA, GL_UNSIGNED_BYTE, m_frameData);
1671 checkError("YUY2 paint");
1672 }
1673
shader_RGB(__u32 format)1674 void CaptureWinGLEngine::shader_RGB(__u32 format)
1675 {
1676 bool manualTransform;
1677 bool hasAlpha = false;
1678
1679 m_screenTextureCount = 1;
1680 glGenTextures(m_screenTextureCount, m_screenTexture);
1681 glActiveTexture(GL_TEXTURE0);
1682 configureTexture(0);
1683
1684 manualTransform = m_quantization == V4L2_QUANTIZATION_LIM_RANGE ||
1685 m_xfer_func != V4L2_XFER_FUNC_SRGB ||
1686 format == V4L2_PIX_FMT_BGR666 ||
1687 format == V4L2_PIX_FMT_GREY ||
1688 format == V4L2_PIX_FMT_Z16 ||
1689 format == V4L2_PIX_FMT_INZI ||
1690 format == V4L2_PIX_FMT_Y10 ||
1691 format == V4L2_PIX_FMT_Y12 ||
1692 format == V4L2_PIX_FMT_Y16 ||
1693 format == V4L2_PIX_FMT_Y16_BE ||
1694 format == V4L2_PIX_FMT_HSV24 ||
1695 format == V4L2_PIX_FMT_HSV32;
1696 GLint internalFmt = manualTransform ? GL_RGBA8 : GL_SRGB8_ALPHA8;
1697
1698 switch (format) {
1699 case V4L2_PIX_FMT_ARGB555:
1700 hasAlpha = true;
1701 /* fall-through */
1702 case V4L2_PIX_FMT_RGB555:
1703 case V4L2_PIX_FMT_XRGB555:
1704 glTexImage2D(GL_TEXTURE_2D, 0, internalFmt, m_frameWidth, m_frameHeight, 0,
1705 GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, NULL);
1706 break;
1707
1708 case V4L2_PIX_FMT_ARGB444:
1709 hasAlpha = true;
1710 /* fall-through */
1711 case V4L2_PIX_FMT_RGB444:
1712 case V4L2_PIX_FMT_XRGB444:
1713 glTexImage2D(GL_TEXTURE_2D, 0, internalFmt, m_frameWidth, m_frameHeight, 0,
1714 GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4_REV, NULL);
1715 break;
1716
1717 case V4L2_PIX_FMT_ARGB555X:
1718 hasAlpha = true;
1719 /* fall-through */
1720 case V4L2_PIX_FMT_RGB555X:
1721 case V4L2_PIX_FMT_XRGB555X:
1722 glTexImage2D(GL_TEXTURE_2D, 0, internalFmt, m_frameWidth, m_frameHeight, 0,
1723 GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, NULL);
1724 break;
1725
1726 case V4L2_PIX_FMT_BGR666:
1727 glTexImage2D(GL_TEXTURE_2D, 0, internalFmt, m_frameWidth, m_frameHeight, 0,
1728 GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, NULL);
1729 break;
1730
1731 case V4L2_PIX_FMT_RGB332:
1732 glTexImage2D(GL_TEXTURE_2D, 0, internalFmt, m_frameWidth, m_frameHeight, 0,
1733 GL_RGB, GL_UNSIGNED_BYTE_3_3_2, NULL);
1734 break;
1735
1736 case V4L2_PIX_FMT_RGB565:
1737 case V4L2_PIX_FMT_RGB565X:
1738 glTexImage2D(GL_TEXTURE_2D, 0, internalFmt, m_frameWidth, m_frameHeight, 0,
1739 GL_RGB, GL_UNSIGNED_SHORT_5_6_5, NULL);
1740 break;
1741 case V4L2_PIX_FMT_ARGB32:
1742 hasAlpha = true;
1743 /* fall-through */
1744 case V4L2_PIX_FMT_RGB32:
1745 case V4L2_PIX_FMT_XRGB32:
1746 case V4L2_PIX_FMT_HSV32:
1747 glTexImage2D(GL_TEXTURE_2D, 0, internalFmt, m_frameWidth, m_frameHeight, 0,
1748 GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, NULL);
1749 break;
1750 case V4L2_PIX_FMT_ABGR32:
1751 hasAlpha = true;
1752 /* fall-through */
1753 case V4L2_PIX_FMT_BGR32:
1754 case V4L2_PIX_FMT_XBGR32:
1755 glTexImage2D(GL_TEXTURE_2D, 0, internalFmt, m_frameWidth, m_frameHeight, 0,
1756 GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, NULL);
1757 break;
1758 case V4L2_PIX_FMT_GREY:
1759 glTexImage2D(GL_TEXTURE_2D, 0, m_glRed, m_frameWidth, m_frameHeight, 0,
1760 m_glRed, GL_UNSIGNED_BYTE, NULL);
1761 break;
1762 case V4L2_PIX_FMT_Z16:
1763 case V4L2_PIX_FMT_INZI:
1764 case V4L2_PIX_FMT_Y10:
1765 case V4L2_PIX_FMT_Y12:
1766 case V4L2_PIX_FMT_Y16:
1767 case V4L2_PIX_FMT_Y16_BE:
1768 glTexImage2D(GL_TEXTURE_2D, 0, m_glRed16, m_frameWidth, m_frameHeight, 0,
1769 m_glRed, GL_UNSIGNED_SHORT, NULL);
1770 break;
1771 case V4L2_PIX_FMT_RGB24:
1772 case V4L2_PIX_FMT_BGR24:
1773 case V4L2_PIX_FMT_HSV24:
1774 default:
1775 glTexImage2D(GL_TEXTURE_2D, 0, internalFmt, m_frameWidth, m_frameHeight, 0,
1776 GL_RGB, GL_UNSIGNED_BYTE, NULL);
1777 break;
1778 }
1779
1780 checkError("RGB shader");
1781
1782 QString codeHead = QString("uniform sampler2D tex;"
1783 "uniform float tex_h;"
1784 "void main()"
1785 "{"
1786 " vec2 xy = vec2(gl_TexCoord[0].xy);"
1787 " float ycoord = floor(xy.y * tex_h);");
1788
1789 if (m_field == V4L2_FIELD_SEQ_TB)
1790 codeHead += " xy.y = (mod(ycoord, 2.0) == 0.0) ? xy.y / 2.0 : xy.y / 2.0 + 0.5;";
1791 else if (m_field == V4L2_FIELD_SEQ_BT)
1792 codeHead += " xy.y = (mod(ycoord, 2.0) == 0.0) ? xy.y / 2.0 + 0.5 : xy.y / 2.0;";
1793
1794 codeHead += " vec4 color = texture2D(tex, xy);"
1795 " float a = color.a;";
1796
1797 switch (format) {
1798 case V4L2_PIX_FMT_BGR666:
1799 codeHead += " float ub = floor(color.b * 255.0);"
1800 " float ug = floor(color.g * 255.0);"
1801 " float ur = floor(color.r * 255.0);"
1802 " ur = floor(ur / 64.0) + mod(ug, 16.0) * 4.0;"
1803 " ug = floor(ug / 16.0) + mod(ub, 4.0) * 16.0;"
1804 " ub = floor(ub / 4.0);"
1805 " float b = ub / 63.0;"
1806 " float g = ug / 63.0;"
1807 " float r = ur / 63.0;";
1808 break;
1809 case V4L2_PIX_FMT_BGR24:
1810 codeHead += " float r = color.b;"
1811 " float g = color.g;"
1812 " float b = color.r;";
1813 break;
1814 case V4L2_PIX_FMT_Y10:
1815 codeHead += " float r = color.r * (65535.0 / 1023.0);"
1816 " float g = r;"
1817 " float b = r;";
1818 break;
1819 case V4L2_PIX_FMT_Y12:
1820 codeHead += " float r = color.r * (65535.0 / 4095.0);"
1821 " float g = r;"
1822 " float b = r;";
1823 break;
1824 case V4L2_PIX_FMT_INZI:
1825 codeHead += " float r = color.r * (ycoord < floor(tex_h / 2.0) ? 65535.0 / 1023.0 : 1.0);"
1826 " float g = r;"
1827 " float b = r;";
1828 break;
1829 case V4L2_PIX_FMT_GREY:
1830 case V4L2_PIX_FMT_Z16:
1831 case V4L2_PIX_FMT_Y16:
1832 case V4L2_PIX_FMT_Y16_BE:
1833 codeHead += " float r = color.r;"
1834 " float g = r;"
1835 " float b = r;";
1836 break;
1837 case V4L2_PIX_FMT_HSV24:
1838 case V4L2_PIX_FMT_HSV32:
1839 /* From http://lolengine.net/blog/2013/07/27/rgb-to-hsv-in-glsl */
1840 if (m_ycbcr_enc == V4L2_HSV_ENC_256)
1841 codeHead += " float hue = color.r;";
1842 else
1843 codeHead += " float hue = (color.r * 256.0) / 180.0;";
1844
1845 codeHead += " vec3 c = vec3(hue, color.g, color.b);"
1846 " vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);"
1847 " vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);"
1848 " vec3 ret = c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);"
1849 " float r = ret.x;"
1850 " float g = ret.y;"
1851 " float b = ret.z;";
1852 break;
1853 default:
1854 codeHead += " float r = color.r;"
1855 " float g = color.g;"
1856 " float b = color.b;";
1857 break;
1858 }
1859
1860 QString codeTail;
1861
1862 if (m_quantization == V4L2_QUANTIZATION_LIM_RANGE)
1863 codeTail += codeRGBNormalize();
1864 if (manualTransform)
1865 codeTail += codeTransformToLinear();
1866
1867 codeTail += codeColorspaceConversion() +
1868 codeTransformToNonLinear() +
1869 (hasAlpha ? codeSuffixWithAlpha : codeSuffix);
1870
1871 bool src_ok = m_shaderProgram.addShaderFromSourceCode(
1872 #if QT_VERSION < 0x060000
1873 QGLShader::Fragment,
1874 #else
1875 QOpenGLShader::Fragment,
1876 #endif
1877 QString("%1%2").arg(codeHead, codeTail));
1878
1879 if (!src_ok)
1880 fprintf(stderr, "OpenGL Error: RGB shader compilation failed.\n");
1881
1882 m_shaderProgram.bind();
1883 }
1884
render_RGB(__u32 format)1885 void CaptureWinGLEngine::render_RGB(__u32 format)
1886 {
1887 glActiveTexture(GL_TEXTURE0);
1888 glBindTexture(GL_TEXTURE_2D, m_screenTexture[0]);
1889 #if QT_VERSION < 0x060000
1890 GLint Y = m_glfunction.glGetUniformLocation(m_shaderProgram.programId(), "tex");
1891 #else
1892 GLint Y = glGetUniformLocation(m_shaderProgram.programId(), "tex");
1893 #endif
1894 glUniform1i(Y, 0);
1895 int idx = glGetUniformLocation(m_shaderProgram.programId(), "tex_h"); // Texture height
1896 glUniform1f(idx, m_frameHeight);
1897
1898 switch (format) {
1899 case V4L2_PIX_FMT_RGB332:
1900 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
1901 GL_RGB, GL_UNSIGNED_BYTE_3_3_2, m_frameData);
1902 break;
1903 case V4L2_PIX_FMT_RGB555:
1904 case V4L2_PIX_FMT_XRGB555:
1905 case V4L2_PIX_FMT_ARGB555:
1906 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
1907 GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, m_frameData);
1908 break;
1909
1910 case V4L2_PIX_FMT_RGB444:
1911 case V4L2_PIX_FMT_XRGB444:
1912 case V4L2_PIX_FMT_ARGB444:
1913 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
1914 GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4_REV, m_frameData);
1915 break;
1916
1917 case V4L2_PIX_FMT_GREY:
1918 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
1919 m_glRed, GL_UNSIGNED_BYTE, m_frameData);
1920 break;
1921
1922 case V4L2_PIX_FMT_Y10:
1923 case V4L2_PIX_FMT_Y12:
1924 case V4L2_PIX_FMT_Y16:
1925 case V4L2_PIX_FMT_Z16:
1926 case V4L2_PIX_FMT_INZI:
1927 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
1928 m_glRed, GL_UNSIGNED_SHORT, m_frameData);
1929 break;
1930 case V4L2_PIX_FMT_Y16_BE:
1931 glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_TRUE);
1932 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
1933 m_glRed, GL_UNSIGNED_SHORT, m_frameData);
1934 glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
1935 break;
1936
1937 case V4L2_PIX_FMT_RGB555X:
1938 case V4L2_PIX_FMT_XRGB555X:
1939 case V4L2_PIX_FMT_ARGB555X:
1940 // Note: most likely for big-endian systems SWAP_BYTES should be true
1941 // for the RGB555 format, and false for this format. This would have
1942 // to be tested first, though.
1943 glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_TRUE);
1944 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
1945 GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, m_frameData);
1946 glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
1947 break;
1948
1949 case V4L2_PIX_FMT_RGB565:
1950 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
1951 GL_RGB, GL_UNSIGNED_SHORT_5_6_5, m_frameData);
1952 break;
1953
1954 case V4L2_PIX_FMT_RGB565X:
1955 // Note: most likely for big-endian systems SWAP_BYTES should be true
1956 // for the RGB565 format, and false for this format. This would have
1957 // to be tested first, though.
1958 glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_TRUE);
1959 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
1960 GL_RGB, GL_UNSIGNED_SHORT_5_6_5, m_frameData);
1961 glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
1962 break;
1963
1964 case V4L2_PIX_FMT_RGB32:
1965 case V4L2_PIX_FMT_XRGB32:
1966 case V4L2_PIX_FMT_ARGB32:
1967 case V4L2_PIX_FMT_HSV32:
1968 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
1969 GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, m_frameData);
1970 break;
1971 case V4L2_PIX_FMT_BGR666:
1972 case V4L2_PIX_FMT_BGR32:
1973 case V4L2_PIX_FMT_XBGR32:
1974 case V4L2_PIX_FMT_ABGR32:
1975 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
1976 GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, m_frameData);
1977 break;
1978 case V4L2_PIX_FMT_RGB24:
1979 case V4L2_PIX_FMT_BGR24:
1980 case V4L2_PIX_FMT_HSV24:
1981 default:
1982 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
1983 GL_RGB, GL_UNSIGNED_BYTE, m_frameData);
1984 break;
1985 }
1986 checkError("RGB paint");
1987 }
1988
shader_Bayer(__u32 format)1989 void CaptureWinGLEngine::shader_Bayer(__u32 format)
1990 {
1991 m_screenTextureCount = 1;
1992 glGenTextures(m_screenTextureCount, m_screenTexture);
1993 glActiveTexture(GL_TEXTURE0);
1994 configureTexture(0);
1995
1996 switch (format) {
1997 case V4L2_PIX_FMT_SBGGR8:
1998 case V4L2_PIX_FMT_SGBRG8:
1999 case V4L2_PIX_FMT_SGRBG8:
2000 case V4L2_PIX_FMT_SRGGB8:
2001 glTexImage2D(GL_TEXTURE_2D, 0, m_glRed, m_frameWidth, m_frameHeight, 0,
2002 m_glRed, GL_UNSIGNED_BYTE, NULL);
2003 break;
2004 case V4L2_PIX_FMT_SBGGR10:
2005 case V4L2_PIX_FMT_SGBRG10:
2006 case V4L2_PIX_FMT_SGRBG10:
2007 case V4L2_PIX_FMT_SRGGB10:
2008 case V4L2_PIX_FMT_SBGGR12:
2009 case V4L2_PIX_FMT_SGBRG12:
2010 case V4L2_PIX_FMT_SGRBG12:
2011 case V4L2_PIX_FMT_SRGGB12:
2012 case V4L2_PIX_FMT_SBGGR16:
2013 case V4L2_PIX_FMT_SGBRG16:
2014 case V4L2_PIX_FMT_SGRBG16:
2015 case V4L2_PIX_FMT_SRGGB16:
2016 glTexImage2D(GL_TEXTURE_2D, 0, m_glRed16, m_frameWidth, m_frameHeight, 0,
2017 m_glRed, GL_UNSIGNED_SHORT, NULL);
2018 break;
2019 }
2020
2021 checkError("Bayer shader");
2022
2023 QString codeHead = QString("uniform sampler2D tex;"
2024 "uniform float tex_h;"
2025 "uniform float tex_w;"
2026 "uniform float texl_h;"
2027 "uniform float texl_w;"
2028 "void main()"
2029 "{"
2030 " vec2 xy = vec2(gl_TexCoord[0].xy);"
2031 " float xcoord = floor(xy.x * tex_w);"
2032 " float ycoord = floor(xy.y * tex_h);");
2033
2034 if (m_field == V4L2_FIELD_SEQ_TB)
2035 codeHead += " xy.y = (mod(ycoord, 2.0) == 0.0) ? xy.y / 2.0 : xy.y / 2.0 + 0.5;";
2036 else if (m_field == V4L2_FIELD_SEQ_BT)
2037 codeHead += " xy.y = (mod(ycoord, 2.0) == 0.0) ? xy.y / 2.0 + 0.5 : xy.y / 2.0;";
2038
2039 codeHead += " ycoord = floor(xy.y * tex_h);"
2040 " float r, g, b;"
2041 " vec2 cell;"
2042 " cell.x = (mod(xcoord, 2.0) == 0.0) ? xy.x : xy.x - texl_w;"
2043 " cell.y = (mod(ycoord, 2.0) == 0.0) ? xy.y : xy.y - texl_h;";
2044
2045 /* Poor quality Bayer to RGB conversion, but good enough for now */
2046 switch (format) {
2047 case V4L2_PIX_FMT_SBGGR8:
2048 case V4L2_PIX_FMT_SBGGR10:
2049 case V4L2_PIX_FMT_SBGGR12:
2050 case V4L2_PIX_FMT_SBGGR16:
2051 codeHead += " r = texture2D(tex, vec2(cell.x + texl_w, cell.y + texl_h)).r;"
2052 " g = texture2D(tex, vec2((cell.y == xy.y) ? cell.x + texl_w : cell.x, xy.y)).r;"
2053 " b = texture2D(tex, cell).r;";
2054 break;
2055 case V4L2_PIX_FMT_SGBRG8:
2056 case V4L2_PIX_FMT_SGBRG10:
2057 case V4L2_PIX_FMT_SGBRG12:
2058 case V4L2_PIX_FMT_SGBRG16:
2059 codeHead += " r = texture2D(tex, vec2(cell.x, cell.y + texl_h)).r;"
2060 " g = texture2D(tex, vec2((cell.y == xy.y) ? cell.x : cell.x + texl_w, xy.y)).r;"
2061 " b = texture2D(tex, vec2(cell.x + texl_w, cell.y)).r;";
2062 break;
2063 case V4L2_PIX_FMT_SGRBG8:
2064 case V4L2_PIX_FMT_SGRBG10:
2065 case V4L2_PIX_FMT_SGRBG12:
2066 case V4L2_PIX_FMT_SGRBG16:
2067 codeHead += " r = texture2D(tex, vec2(cell.x + texl_w, cell.y)).r;"
2068 " g = texture2D(tex, vec2((cell.y == xy.y) ? cell.x : cell.x + texl_w, xy.y)).r;"
2069 " b = texture2D(tex, vec2(cell.x, cell.y + texl_h)).r;";
2070 break;
2071 case V4L2_PIX_FMT_SRGGB8:
2072 case V4L2_PIX_FMT_SRGGB10:
2073 case V4L2_PIX_FMT_SRGGB12:
2074 case V4L2_PIX_FMT_SRGGB16:
2075 codeHead += " b = texture2D(tex, vec2(cell.x + texl_w, cell.y + texl_h)).r;"
2076 " g = texture2D(tex, vec2((cell.y == xy.y) ? cell.x + texl_w : cell.x, xy.y)).r;"
2077 " r = texture2D(tex, cell).r;";
2078 break;
2079 }
2080
2081 switch (format) {
2082 case V4L2_PIX_FMT_SBGGR10:
2083 case V4L2_PIX_FMT_SGBRG10:
2084 case V4L2_PIX_FMT_SGRBG10:
2085 case V4L2_PIX_FMT_SRGGB10:
2086 codeHead += " b = b * (65535.0 / 1023.0);"
2087 " g = g * (65535.0 / 1023.0);"
2088 " r = r * (65535.0 / 1023.0);";
2089 break;
2090 case V4L2_PIX_FMT_SBGGR12:
2091 case V4L2_PIX_FMT_SGBRG12:
2092 case V4L2_PIX_FMT_SGRBG12:
2093 case V4L2_PIX_FMT_SRGGB12:
2094 codeHead += " b = b * (65535.0 / 4095.0);"
2095 " g = g * (65535.0 / 4095.0);"
2096 " r = r * (65535.0 / 4095.0);";
2097 break;
2098 }
2099
2100 QString codeTail;
2101
2102 if (m_quantization == V4L2_QUANTIZATION_LIM_RANGE)
2103 codeTail += codeRGBNormalize();
2104
2105 codeTail += codeTransformToLinear() +
2106 codeColorspaceConversion() +
2107 codeTransformToNonLinear() +
2108 codeSuffix;
2109
2110 bool src_ok = m_shaderProgram.addShaderFromSourceCode(
2111 #if QT_VERSION < 0x060000
2112 QGLShader::Fragment,
2113 #else
2114 QOpenGLShader::Fragment,
2115 #endif
2116 QString("%1%2").arg(codeHead, codeTail));
2117
2118 if (!src_ok)
2119 fprintf(stderr, "OpenGL Error: Bayer shader compilation failed.\n");
2120
2121 m_shaderProgram.bind();
2122 }
2123
render_Bayer(__u32 format)2124 void CaptureWinGLEngine::render_Bayer(__u32 format)
2125 {
2126 glActiveTexture(GL_TEXTURE0);
2127 glBindTexture(GL_TEXTURE_2D, m_screenTexture[0]);
2128 #if QT_VERSION < 0x060000
2129 GLint Y = m_glfunction.glGetUniformLocation(m_shaderProgram.programId(), "tex");
2130 #else
2131 GLint Y = glGetUniformLocation(m_shaderProgram.programId(), "tex");
2132 #endif
2133 glUniform1i(Y, 0);
2134 int idx = glGetUniformLocation(m_shaderProgram.programId(), "tex_h"); // Texture height
2135 glUniform1f(idx, m_frameHeight);
2136 idx = glGetUniformLocation(m_shaderProgram.programId(), "tex_w"); // Texture width
2137 glUniform1f(idx, m_frameWidth);
2138 idx = glGetUniformLocation(m_shaderProgram.programId(), "texl_h"); // Texture width
2139 glUniform1f(idx, 1.0 / m_frameHeight);
2140 idx = glGetUniformLocation(m_shaderProgram.programId(), "texl_w"); // Texture width
2141 glUniform1f(idx, 1.0 / m_frameWidth);
2142
2143 switch (format) {
2144 case V4L2_PIX_FMT_SBGGR8:
2145 case V4L2_PIX_FMT_SGBRG8:
2146 case V4L2_PIX_FMT_SGRBG8:
2147 case V4L2_PIX_FMT_SRGGB8:
2148 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
2149 m_glRed, GL_UNSIGNED_BYTE, m_frameData);
2150 break;
2151 case V4L2_PIX_FMT_SBGGR10:
2152 case V4L2_PIX_FMT_SGBRG10:
2153 case V4L2_PIX_FMT_SGRBG10:
2154 case V4L2_PIX_FMT_SRGGB10:
2155 case V4L2_PIX_FMT_SBGGR12:
2156 case V4L2_PIX_FMT_SGBRG12:
2157 case V4L2_PIX_FMT_SGRBG12:
2158 case V4L2_PIX_FMT_SRGGB12:
2159 case V4L2_PIX_FMT_SBGGR16:
2160 case V4L2_PIX_FMT_SGBRG16:
2161 case V4L2_PIX_FMT_SGRBG16:
2162 case V4L2_PIX_FMT_SRGGB16:
2163 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
2164 m_glRed, GL_UNSIGNED_SHORT, m_frameData);
2165 break;
2166 }
2167 checkError("Bayer paint");
2168 }
2169
shader_YUV_packed(__u32 format)2170 void CaptureWinGLEngine::shader_YUV_packed(__u32 format)
2171 {
2172 bool hasAlpha = false;
2173
2174 m_screenTextureCount = 1;
2175 glGenTextures(m_screenTextureCount, m_screenTexture);
2176 glActiveTexture(GL_TEXTURE0);
2177 configureTexture(0);
2178
2179 switch (format) {
2180 case V4L2_PIX_FMT_YUV555:
2181 hasAlpha = true;
2182 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_frameWidth, m_frameHeight, 0,
2183 GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, NULL);
2184 break;
2185
2186 case V4L2_PIX_FMT_YUV444:
2187 hasAlpha = true;
2188 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_frameWidth, m_frameHeight, 0,
2189 GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4_REV, NULL);
2190 break;
2191
2192 case V4L2_PIX_FMT_YUV565:
2193 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_frameWidth, m_frameHeight, 0,
2194 GL_RGB, GL_UNSIGNED_SHORT_5_6_5, NULL);
2195 break;
2196 case V4L2_PIX_FMT_AYUV32:
2197 hasAlpha = true;
2198 // fall-through
2199 case V4L2_PIX_FMT_YUV32:
2200 case V4L2_PIX_FMT_XYUV32:
2201 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_frameWidth, m_frameHeight, 0,
2202 GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, NULL);
2203 break;
2204 case V4L2_PIX_FMT_VUYA32:
2205 hasAlpha = true;
2206 // fall-through
2207 case V4L2_PIX_FMT_VUYX32:
2208 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_frameWidth, m_frameHeight, 0,
2209 GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, NULL);
2210 break;
2211 case V4L2_PIX_FMT_YUVA32:
2212 hasAlpha = true;
2213 // fall-through
2214 case V4L2_PIX_FMT_YUVX32:
2215 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_frameWidth, m_frameHeight, 0,
2216 GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
2217 break;
2218 }
2219
2220 checkError("Packed YUV shader");
2221
2222 QString codeHead = QString("uniform sampler2D tex;"
2223 "uniform float tex_h;"
2224 "void main()"
2225 "{"
2226 " vec2 xy = vec2(gl_TexCoord[0].xy);"
2227 " float ycoord = floor(xy.y * tex_h);");
2228
2229 if (m_field == V4L2_FIELD_SEQ_TB)
2230 codeHead += " xy.y = (mod(ycoord, 2.0) == 0.0) ? xy.y / 2.0 : xy.y / 2.0 + 0.5;";
2231 else if (m_field == V4L2_FIELD_SEQ_BT)
2232 codeHead += " xy.y = (mod(ycoord, 2.0) == 0.0) ? xy.y / 2.0 + 0.5 : xy.y / 2.0;";
2233
2234 codeHead += " vec4 color = texture2D(tex, xy);"
2235 " float a = color.a;";
2236
2237 codeHead += " float y = color.r;"
2238 " float u = color.g - 0.5;"
2239 " float v = color.b - 0.5;";
2240
2241 QString codeTail = codeYUVNormalize() +
2242 codeYUV2RGB() +
2243 codeTransformToLinear() +
2244 codeColorspaceConversion() +
2245 codeTransformToNonLinear() +
2246 (hasAlpha ? codeSuffixWithAlpha : codeSuffix);
2247
2248 bool src_ok = m_shaderProgram.addShaderFromSourceCode(
2249 #if QT_VERSION < 0x060000
2250 QGLShader::Fragment,
2251 #else
2252 QOpenGLShader::Fragment,
2253 #endif
2254 QString("%1%2").arg(codeHead, codeTail));
2255
2256 if (!src_ok)
2257 fprintf(stderr, "OpenGL Error: Packed YUV shader compilation failed.\n");
2258
2259 m_shaderProgram.bind();
2260 }
2261
render_YUV_packed(__u32 format)2262 void CaptureWinGLEngine::render_YUV_packed(__u32 format)
2263 {
2264 glActiveTexture(GL_TEXTURE0);
2265 glBindTexture(GL_TEXTURE_2D, m_screenTexture[0]);
2266 #if QT_VERSION < 0x060000
2267 GLint Y = m_glfunction.glGetUniformLocation(m_shaderProgram.programId(), "tex");
2268 #else
2269 GLint Y = glGetUniformLocation(m_shaderProgram.programId(), "tex");
2270 #endif
2271 glUniform1i(Y, 0);
2272 int idx = glGetUniformLocation(m_shaderProgram.programId(), "tex_h"); // Texture height
2273 glUniform1f(idx, m_frameHeight);
2274
2275 switch (format) {
2276 case V4L2_PIX_FMT_YUV555:
2277 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
2278 GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, m_frameData);
2279 break;
2280
2281 case V4L2_PIX_FMT_YUV444:
2282 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
2283 GL_BGRA, GL_UNSIGNED_SHORT_4_4_4_4_REV, m_frameData);
2284 break;
2285
2286 case V4L2_PIX_FMT_YUV565:
2287 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
2288 GL_RGB, GL_UNSIGNED_SHORT_5_6_5, m_frameData);
2289 break;
2290
2291 case V4L2_PIX_FMT_YUV32:
2292 case V4L2_PIX_FMT_AYUV32:
2293 case V4L2_PIX_FMT_XYUV32:
2294 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
2295 GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, m_frameData);
2296 break;
2297 case V4L2_PIX_FMT_VUYA32:
2298 case V4L2_PIX_FMT_VUYX32:
2299 case V4L2_PIX_FMT_YUVA32:
2300 case V4L2_PIX_FMT_YUVX32:
2301 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_frameWidth, m_frameHeight,
2302 GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, m_frameData);
2303 break;
2304 }
2305 checkError("Packed YUV paint");
2306 }
2307
2308 #endif
2309