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