MythTV  master
openglvideo.cpp
Go to the documentation of this file.
1 // MythTV headers
2 #include "openglvideo.h"
3 #include "mythcontext.h"
4 #include "tv.h"
5 #include "mythrender_opengl.h"
6 #include "mythavutil.h"
7 
8 #define LOC QString("GLVid: ")
9 #define COLOUR_UNIFORM "m_colourMatrix"
10 #define MYTHTV_YV12 0x8a20
11 
13 {
16 };
17 
19 {
20  public:
21  vector<GLuint> fragmentPrograms;
23  vector<GLuint> frameBuffers;
24  vector<GLuint> frameBufferTextures;
26 };
27 
67  videoType(kGLUYVY),
68  gl_context(nullptr), video_disp_dim(0,0),
69  video_dim(0,0), viewportSize(0,0),
70  masterViewportSize(0,0), display_visible_rect(0,0,0,0),
71  display_video_rect(0,0,0,0), video_rect(0,0,0,0),
72  frameBufferRect(0,0,0,0), hardwareDeinterlacing(false),
73  colourSpace(nullptr), viewportControl(false),
74  inputTextureSize(0,0), currentFrameNum(0),
75  inputUpdated(false), refsNeeded(0),
76  textureRects(false), textureType(GL_TEXTURE_2D),
77  helperTexture(0), defaultUpsize(kGLFilterResize),
78  gl_features(0), forceResize(false)
79 {
80  forceResize = gCoreContext->GetBoolSetting("OpenGLExtraStage", false);
81 }
82 
84 {
85  OpenGLLocker ctx_lock(gl_context);
86  Teardown();
87 }
88 
90 {
91  if (helperTexture)
93  helperTexture = 0;
94 
97 
98  while (!filters.empty())
99  RemoveFilter(filters.begin()->first);
100 }
101 
121  QSize videoDim, QSize videoDispDim,
122  QRect displayVisibleRect,
123  QRect displayVideoRect, QRect videoRect,
124  bool viewport_control,
125  VideoType Type,
126  const QString& options)
127 {
128  if (!glcontext)
129  return false;
130 
131  gl_context = glcontext;
132  OpenGLLocker ctx_lock(gl_context);
133 
134  video_dim = videoDim;
135  video_disp_dim = videoDispDim;
136  display_visible_rect = displayVisibleRect;
137  display_video_rect = displayVideoRect;
138  video_rect = videoRect;
140  frameBufferRect = QRect(QPoint(0,0), video_disp_dim);
142  hardwareDeinterlacing = false;
143  colourSpace = colourspace;
144  viewportControl = viewport_control;
145  inputTextureSize = QSize(0,0);
146  currentFrameNum = -1;
147  inputUpdated = false;
148  videoType = Type;
149 
150  // Set OpenGL feature support
152 
153  if (viewportControl)
154  gl_context->SetFence();
155 
157 
158  bool glsl = (gl_features & kGLSL) != 0U;
159  bool shaders = glsl || ((gl_features & kGLExtFragProg) != 0U);
160  bool fbos = (gl_features & kGLExtFBufObj) != 0U;
161  bool ycbcr = ((gl_features & kGLMesaYCbCr) != 0U) || ((gl_features & kGLAppleYCbCr) != 0U);
162  VideoType fallback = shaders ? (glsl ? (fbos ? kGLUYVY : kGLYV12) : kGLHQUYV) : ycbcr ? kGLYCbCr : kGLRGBA;
163 
164  // check for feature support
165  bool unsupported = (kGLYCbCr == videoType) && !ycbcr;
166  unsupported |= (kGLYV12 == videoType) && !glsl;
167  unsupported |= (kGLUYVY == videoType) && (!shaders || !fbos);
168  unsupported |= (kGLHQUYV == videoType) && !shaders;
169 
170  if (unsupported)
171  {
172  LOG(VB_GENERAL, LOG_WARNING, LOC + QString(
173  "'%1' OpenGLVideo type not available - falling back to '%2'")
174  .arg(TypeToString(videoType)).arg(TypeToString(fallback)));
175  videoType = fallback;
176  }
177 
178  // check picture attributes support - colourspace adjustments require
179  // shaders to operate on YUV textures
180  if (kGLRGBA == videoType || kGLGPU == videoType || kGLYCbCr == videoType)
182 
183  // turn on bicubic filtering
184  if (options.contains("openglbicubic"))
185  {
186  if (shaders && fbos && (gl_features & kGLExtRGBA16))
188  else
189  LOG(VB_PLAYBACK, LOG_ERR, LOC + "No OpenGL feature support for Bicubic filter.");
190  }
191 
192  // decide on best input texture type - GLX surfaces (for VAAPI) and the
193  // bicubic filter do not work with rectangular textures. YV12 now supports
194  // rectangular textures but POT textures are retained for the time being.
195  if ((gl_features & kGLExtRect) && (kGLGPU != videoType) &&
197  {
199  }
200 
201  // Create initial input texture and associated filter stage
203  bool ok = false;
204 
205  if (kGLYV12 == videoType)
206  ok = tex && AddFilter(kGLFilterYV12RGB);
207  else if ((kGLUYVY == videoType) || (kGLHQUYV == videoType) || (kGLYCbCr == videoType))
208  ok = tex && AddFilter(kGLFilterYUV2RGB);
209  else
210  ok = tex && AddFilter(kGLFilterResize);
211 
212  if (ok)
213  {
214  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Using '%1' for OpenGL video type")
215  .arg(TypeToString(videoType)));
216  inputTextures.push_back(tex);
217  }
218  else
219  {
220  Teardown();
221  }
222 
223  if (filters.empty())
224  {
225  bool fatalerror = kGLRGBA == videoType;
226 
227  if (!fatalerror)
228  {
229  LOG(VB_PLAYBACK, LOG_INFO, LOC +
230  "Failed to setup colourspace conversion.\n\t\t\t"
231  "Falling back to software conversion.\n\t\t\t"
232  "Any opengl filters will also be disabled.");
233  GLuint rgba32tex = CreateVideoTexture(video_dim, inputTextureSize);
234 
235  if (rgba32tex && AddFilter(kGLFilterResize))
236  {
237  inputTextures.push_back(rgba32tex);
239  }
240  else
241  {
242  fatalerror = true;
243  }
244  }
245  if (fatalerror)
246  {
247  LOG(VB_GENERAL, LOG_ERR, LOC + "Fatal error");
248  Teardown();
249  return false;
250  }
251  }
252 
253  bool mmx = false;
254  bool neon = false;
255 #ifdef MMX
256  // cppcheck-suppress redundantAssignment
257  mmx = true;
258 #endif
259 #ifdef HAVE_NEON
260  neon = true;
261 #endif
262 
263  CheckResize(false);
264  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("MMX: %1 NEON: %2 PBO: %3 ForceResize: %4 Rects: %5")
265  .arg(mmx).arg(neon).arg((gl_features & kGLExtPBufObj) > 0)
266  .arg(forceResize).arg(textureType != GL_TEXTURE_2D));
267  return true;
268 }
269 
274 void OpenGLVideo::CheckResize(bool deinterlacing, bool allow)
275 {
276  // to improve performance on slower cards when deinterlacing
277  bool resize_up = ((video_disp_dim.height() < display_video_rect.height()) ||
278  (video_disp_dim.width() < display_video_rect.width())) && allow;
279 
280  // to ensure deinterlacing works correctly
281  bool resize_down = (video_disp_dim.height() > display_video_rect.height()) &&
282  deinterlacing && allow;
283 
284  // UYVY packed pixels must be sampled exactly and any overscan settings will
285  // break sampling - so always force an extra stage
286  // TODO optimise this away when 1 for 1 mapping is guaranteed
287  resize_down |= (kGLUYVY == videoType);
288 
289  // we always need at least one filter (i.e. a resize that simply blits the texture
290  // to screen)
291  resize_down |= ((filters.count(kGLFilterYUV2RGB) == 0U) &&
292  (filters.count(kGLFilterYV12RGB) == 0U));
293 
294  // Extra stage needed on Fire Stick 4k, maybe others, because of blank screen when playing.
295  resize_down |= forceResize;
296 
297  if (resize_up && (defaultUpsize == kGLFilterBicubic))
298  {
301  SetFiltering();
302  return;
303  }
304 
305  if ((resize_up && (defaultUpsize == kGLFilterResize)) || resize_down)
306  {
309  SetFiltering();
310  return;
311  }
312 
313  if (!resize_down)
315 
317  OptimiseFilters();
318 }
319 
320 void OpenGLVideo::SetVideoRect(const QRect &dispvidrect, const QRect &vidrect)
321 {
322  if (vidrect == video_rect && dispvidrect == display_video_rect)
323  return;
324 
325  display_video_rect = dispvidrect;
326  video_rect = vidrect;
330 }
331 
338 {
339  glfilt_map_t::reverse_iterator it;
340 
341  // add/remove required frame buffer objects
342  // and link filters
343  uint buffers_needed = 1;
344  bool last_filter = true;
345  for (it = filters.rbegin(); it != filters.rend(); ++it)
346  {
347  if (!last_filter)
348  {
349  it->second->outputBuffer = kFrameBufferObject;
350  uint buffers_have = it->second->frameBuffers.size();
351  int buffers_diff = buffers_needed - buffers_have;
352  if (buffers_diff > 0)
353  {
354  uint tmp_buf, tmp_tex;
355  for (int i = 0; i < buffers_diff; i++)
356  {
357  if (!AddFrameBuffer(tmp_buf, tmp_tex, video_disp_dim))
358  return false;
359  it->second->frameBuffers.push_back(tmp_buf);
360  it->second->frameBufferTextures.push_back(tmp_tex);
361  }
362  }
363  else if (buffers_diff < 0)
364  {
365  for (int i = 0; i > buffers_diff; i--)
366  {
367  OpenGLFilter *filt = it->second;
368 
370  filt->frameBuffers.back());
372  filt->frameBufferTextures.back());
373 
374  filt->frameBuffers.pop_back();
375  filt->frameBufferTextures.pop_back();
376  }
377  }
378  }
379  else
380  {
381  it->second->outputBuffer = kDefaultBuffer;
382  last_filter = false;
383  }
384  buffers_needed = it->second->numInputs;
385  }
386 
387  SetFiltering();
388 
389  return true;
390 }
391 
397 {
398  if (filters.size() < 2)
399  {
400  SetTextureFilters(&inputTextures, GL_LINEAR, GL_CLAMP_TO_EDGE);
401  SetTextureFilters(&referenceTextures, GL_LINEAR, GL_CLAMP_TO_EDGE);
402  return;
403  }
404 
405  SetTextureFilters(&inputTextures, GL_NEAREST, GL_CLAMP_TO_EDGE);
406  SetTextureFilters(&referenceTextures, GL_NEAREST, GL_CLAMP_TO_EDGE);
407 
408  glfilt_map_t::reverse_iterator rit;
409  int last_filter = 0;
410 
411  for (rit = filters.rbegin(); rit != filters.rend(); ++rit)
412  {
413  if (last_filter == 1)
414  {
415  SetTextureFilters(&(rit->second->frameBufferTextures),
416  GL_LINEAR, GL_CLAMP_TO_EDGE);
417  }
418  else if (last_filter > 1)
419  {
420  SetTextureFilters(&(rit->second->frameBufferTextures),
421  GL_NEAREST, GL_CLAMP_TO_EDGE);
422  }
423  ++last_filter;
424  }
425 }
426 
432 {
433  if (filters.count(filter))
434  return true;
435 
436  switch (filter)
437  {
438  case kGLFilterNone:
439  // Nothing to do. Prevents compiler warning.
440  break;
441 
442  case kGLFilterResize:
443  if (!(gl_features & kGLExtFBufObj) && !filters.empty())
444  {
445  LOG(VB_PLAYBACK, LOG_ERR, LOC +
446  "GL_EXT_framebuffer_object not available "
447  "for scaling/resizing filter.");
448  return false;
449  }
450  break;
451 
452  case kGLFilterBicubic:
454  {
455  LOG(VB_PLAYBACK, LOG_ERR, LOC +
456  "Features not available for bicubic filter.");
457  return false;
458  }
459  break;
460 
461  case kGLFilterYUV2RGB:
462  if (!(gl_features & kGLExtFragProg) && !(gl_features & kGLSL))
463  {
464  LOG(VB_PLAYBACK, LOG_ERR, LOC +
465  "No shader support for OpenGL deinterlacing.");
466  return false;
467  }
468  break;
469 
470  case kGLFilterYV12RGB:
471  if (!(gl_features & kGLSL))
472  {
473  LOG(VB_PLAYBACK, LOG_ERR, LOC +
474  "No shader support for OpenGL deinterlacing.");
475  return false;
476  }
477  break;
478  }
479 
480  bool success = true;
481 
482  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Creating %1 filter.")
483  .arg(FilterToString(filter)));
484 
485  OpenGLFilter *temp = new OpenGLFilter();
486 
487  temp->numInputs = 1;
488 
489  if (filter == kGLFilterBicubic)
490  {
491  if (helperTexture)
493 
495  if (!helperTexture)
496  success = false;
497  }
498 
499  if (success &&
500  (((filter != kGLFilterNone) && (filter != kGLFilterResize)) ||
501  ((gl_features & kGLSL) && (filter == kGLFilterResize))))
502  {
503  GLuint program = AddFragmentProgram(filter);
504  if (!program)
505  success = false;
506  else
507  temp->fragmentPrograms.push_back(program);
508  }
509 
510  if (success)
511  {
513  temp->frameBuffers.clear();
514  temp->frameBufferTextures.clear();
515  filters[filter] = temp;
516  temp = nullptr;
517  success &= OptimiseFilters();
518  }
519 
520  if (!success)
521  {
522  RemoveFilter(filter);
523  delete temp;
524  return false;
525  }
526 
527  return true;
528 }
529 
531 {
532  if (!filters.count(filter))
533  return true;
534 
535  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Removing %1 filter")
536  .arg(FilterToString(filter)));
537 
538  vector<GLuint> temp;
539  vector<GLuint>::iterator it;
540 
541  temp = filters[filter]->fragmentPrograms;
542  for (it = temp.begin(); it != temp.end(); ++it)
544  filters[filter]->fragmentPrograms.clear();
545 
546  temp = filters[filter]->frameBuffers;
547  for (it = temp.begin(); it != temp.end(); ++it)
549  filters[filter]->frameBuffers.clear();
550 
551  DeleteTextures(&(filters[filter]->frameBufferTextures));
552 
553  delete filters[filter];
554  filters.erase(filter);
555  return true;
556 }
557 
559 {
560  glfilt_map_t::const_iterator it = filters.cbegin();
561  for ( ; it != filters.cend(); ++it)
562  {
563  if (it->first != kGLFilterYUV2RGB && it->first != kGLFilterYV12RGB)
564  continue;
565 
566  OpenGLFilter *tmp = it->second;
567  while (tmp->fragmentPrograms.size() > 1)
568  {
569  gl_context->DeleteShaderObject(tmp->fragmentPrograms.back());
570  tmp->fragmentPrograms.pop_back();
571  }
572  }
573 
575  refsNeeded = 0;
576 }
577 
585 bool OpenGLVideo::AddDeinterlacer(const QString &deinterlacer)
586 {
587  if (!(gl_features & kGLExtFragProg) && !(gl_features & kGLSL))
588  {
589  LOG(VB_PLAYBACK, LOG_ERR, LOC +
590  "No shader support for OpenGL deinterlacing.");
591  return false;
592  }
593 
594  OpenGLLocker ctx_lock(gl_context);
595 
596  if (filters.end() == filters.find(kGLFilterYUV2RGB) &&
597  filters.end() == filters.find(kGLFilterYV12RGB) )
598  {
599  LOG(VB_PLAYBACK, LOG_ERR, LOC +
600  "No YUV2RGB filter stage for OpenGL deinterlacing.");
601  return false;
602  }
603 
604  if (hardwareDeinterlacer == deinterlacer)
605  return true;
606 
608 
609  bool success = true;
610 
611  uint ref_size = 2;
612 
613  if (deinterlacer == "openglbobdeint" ||
614  deinterlacer == "openglonefield" ||
615  deinterlacer == "opengllinearblend" ||
616  deinterlacer == "opengldoubleratelinearblend" ||
617  deinterlacer == "opengldoubleratefieldorder")
618  {
619  ref_size = 0;
620  }
621 
622  refsNeeded = ref_size;
623  if (ref_size > 0)
624  {
625  for (; ref_size > 0; ref_size--)
626  {
628  if (tex)
629  {
630  referenceTextures.push_back(tex);
631  }
632  else
633  {
634  success = false;
635  }
636  }
637  }
638 
640 
641  uint prog1 = AddFragmentProgram(type, deinterlacer, kScan_Interlaced);
642  uint prog2 = AddFragmentProgram(type, deinterlacer, kScan_Intr2ndField);
643 
644  if (prog1 && prog2)
645  {
646  filters[type]->fragmentPrograms.push_back(prog1);
647  filters[type]->fragmentPrograms.push_back(prog2);
648  }
649  else
650  {
651  success = false;
652  }
653 
654  if (success)
655  {
657  hardwareDeinterlacer = deinterlacer;
658  return true;
659  }
660 
663 
664  return false;
665 }
666 
672  const QString& deint, FrameScanType field)
673 {
674  if (!gl_context)
675  return 0;
676 
677  QString vertex, fragment;
678  if (gl_features & kGLSL)
679  {
680  GetProgramStrings(vertex, fragment, name, deint, field);
681  }
682  else if (gl_features & kGLExtFragProg)
683  {
684  fragment = GetProgramString(name, deint, field);
685  }
686  else
687  {
688  LOG(VB_PLAYBACK, LOG_ERR, LOC + "No OpenGL shader/program support");
689  return 0;
690  }
691 
692  return gl_context->CreateShaderObject(vertex, fragment);
693 }
694 
700  uint &texture, QSize vid_size)
701 {
702  if (!(gl_features & kGLExtFBufObj))
703  {
704  LOG(VB_PLAYBACK, LOG_ERR, LOC + "Framebuffer binding not supported.");
705  return false;
706  }
707 
708  texture = gl_context->CreateTexture(vid_size, false, textureType);
709 
710  bool ok = gl_context->CreateFrameBuffer(framebuffer, texture);
711 
712  if (!ok)
713  gl_context->DeleteTexture(texture);
714 
715  return ok;
716 }
717 
718 void OpenGLVideo::SetViewPort(const QSize &viewPortSize)
719 {
720  uint w = max(viewPortSize.width(), video_disp_dim.width());
721  uint h = max(viewPortSize.height(), video_disp_dim.height());
722 
723  viewportSize = QSize(w, h);
724 
725  if (!viewportControl)
726  return;
727 
728  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Viewport: %1x%2") .arg(w).arg(h));
729  gl_context->SetViewPort(QRect(QPoint(),viewportSize));
730 }
731 
736 uint OpenGLVideo::CreateVideoTexture(QSize size, QSize &tex_size)
737 {
738  uint tmp_tex = 0;
739  bool use_pbo = (gl_features & kGLExtPBufObj) != 0U;
740  if (kGLYCbCr == videoType)
741  {
743  tmp_tex = gl_context->CreateTexture(size, use_pbo, textureType,
745  type, GL_RGBA);
746  }
747  else if (kGLYV12 == videoType)
748  {
749  size.setHeight((3 * size.height() + 1) / 2);
750  tmp_tex = gl_context->CreateTexture(size, use_pbo, textureType,
751  GL_UNSIGNED_BYTE, // data_type
752  GL_LUMINANCE, // data_fmt
753  GL_LUMINANCE // internal_fmt
754  );
755  }
756  else if (kGLUYVY == videoType)
757  {
758  size.setWidth(size.width() >> 1);
759  tmp_tex = gl_context->CreateTexture(size, use_pbo, textureType,
760  GL_UNSIGNED_BYTE, GL_RGBA, GL_RGBA);
761  }
762  else if ((kGLHQUYV == videoType) || (kGLGPU == videoType) || (kGLRGBA == videoType))
763  {
764  tmp_tex = gl_context->CreateTexture(size, use_pbo, textureType);
765  }
766 
767  tex_size = gl_context->GetTextureSize(textureType, size);
768  return tmp_tex;
769 }
770 
771 QSize OpenGLVideo::GetTextureSize(const QSize &size)
772 {
773  if (textureRects)
774  return size;
775 
776  int w = 64;
777  int h = 64;
778 
779  while (w < size.width())
780  {
781  w *= 2;
782  }
783 
784  while (h < size.height())
785  {
786  h *= 2;
787  }
788 
789  return {w, h};
790 }
791 
793 {
794  return inputTextures[0];
795 }
796 
798 {
799  return textureType;
800 }
801 
803 {
804  inputUpdated = true;
805 }
806 
813 void OpenGLVideo::UpdateInputFrame(const VideoFrame *frame, bool soft_bob)
814 {
815  OpenGLLocker ctx_lock(gl_context);
816 
817  if (frame->width != video_dim.width() ||
818  frame->height != video_dim.height() ||
819  frame->width < 1 || frame->height < 1 ||
820  frame->codec != FMT_YV12 || (kGLGPU == videoType))
821  {
822  return;
823  }
825  RotateTextures();
826 
827  // We need to convert frames here to avoid dependencies in MythRenderOpenGL
828  void* buf = gl_context->GetTextureBuffer(inputTextures[0]);
829  if (!buf)
830  return;
831 
832  if (kGLYV12 == videoType)
833  {
835  {
836  // Copy the frame to the pixel buffer which updates the texture
837  copybuffer((uint8_t*)buf, frame, video_dim.width());
838  }
839  else if (video_dim.width() != frame->pitches[0])
840  {
841  // Re-packing is needed
842  copybuffer((uint8_t*)buf, frame, video_dim.width());
843  }
844  else
845  {
846  // UpdateTexture will copy the frame to the texture
847  buf = frame->buf;
848  }
849  }
850  else if ((kGLYCbCr == videoType) || (kGLUYVY == videoType))
851  {
852  AVFrame img_out;
853  m_copyCtx.Copy(&img_out, frame, (unsigned char*)buf, AV_PIX_FMT_UYVY422);
854  }
855  else if (kGLRGBA == videoType)
856  {
857  AVFrame img_out;
858  m_copyCtx.Copy(&img_out, frame, (unsigned char*)buf, AV_PIX_FMT_RGBA);
859  }
860  else if (kGLHQUYV == videoType && frame->interlaced_frame && !soft_bob)
861  {
862  pack_yv12interlaced(frame->buf, (unsigned char*)buf, frame->offsets,
863  frame->pitches, video_dim);
864  }
865  else if (kGLHQUYV == videoType)
866  {
867  pack_yv12progressive(frame->buf, (unsigned char*)buf, frame->offsets,
868  frame->pitches, video_dim);
869  }
870 
872  inputUpdated = true;
873 }
874 
875 void OpenGLVideo::SetDeinterlacing(bool deinterlacing)
876 {
877  hardwareDeinterlacing = deinterlacing;
878  OpenGLLocker ctx_lock(gl_context);
880 }
881 
882 void OpenGLVideo::SetSoftwareDeinterlacer(const QString &filter)
883 {
884  if (softwareDeinterlacer != filter)
885  {
887  CheckResize(false, filter != "bobdeint");
889  }
890  softwareDeinterlacer = filter;
891 }
892 
908  bool softwareDeinterlacing,
909  long long frame, StereoscopicMode stereo,
910  bool draw_border)
911 {
912  if (inputTextures.empty() || filters.empty())
913  return;
914 
915  OpenGLLocker ctx_lock(gl_context);
916 
917  // we need to special case software bobdeint for 1080i
918  bool softwarebob = softwareDeinterlacer == "bobdeint" &&
919  softwareDeinterlacing;
920 
921  vector<GLuint> inputs = inputTextures;
922  QSize inputsize = inputTextureSize;
923  QSize realsize = GetTextureSize(video_disp_dim);
924 
925  glfilt_map_t::iterator it;
926  for (it = filters.begin(); it != filters.end(); ++it)
927  {
928  OpenGLFilterType type = it->first;
929  OpenGLFilter *filter = it->second;
930 
931  bool actual = softwarebob && (filter->outputBuffer == kDefaultBuffer);
932 
933  // texture coordinates
934  float trueheight = (float)(actual ? video_dim.height() :
935  video_disp_dim.height());
936  float width = video_disp_dim.width();
937  if (kGLUYVY == videoType)
938  width /= 2.0F;
939 
940  QRectF trect(QPoint(0, 0), QSize(width, trueheight));
941 
942  // only apply overscan on last filter
943  if (filter->outputBuffer == kDefaultBuffer)
944  trect.setCoords(video_rect.left(), video_rect.top(),
945  video_rect.left() + video_rect.width(),
946  video_rect.top() + video_rect.height());
947 
948  if (!textureRects && (inputsize.height() > 0))
949  trueheight /= inputsize.height();
950 
951  // software bobdeint
952  if (actual)
953  {
954  bool top = (scan == kScan_Intr2ndField && topfieldfirst) ||
955  (scan == kScan_Interlaced && !topfieldfirst);
956  bool bot = (scan == kScan_Interlaced && topfieldfirst) ||
957  (scan == kScan_Intr2ndField && !topfieldfirst);
958  bool first = filters.size() < 2;
959  float bob = (trueheight / (float)video_disp_dim.height()) / 4.0F;
960  if ((top && !first) || (bot && first))
961  {
962  trect.setBottom(trect.bottom() / 2);
963  trect.setTop(trect.top() / 2);
964  trect.adjust(0, bob, 0, bob);
965  }
966  if ((bot && !first) || (top && first))
967  {
968  trect.setTop(static_cast<qreal>(trueheight / 2) + (trect.top() / 2));
969  trect.setBottom(static_cast<qreal>(trueheight / 2) + (trect.bottom() / 2));
970  trect.adjust(0, -bob, 0, -bob);
971  }
972  }
973 
974  // discard stereoscopic fields
975  if (filter->outputBuffer == kDefaultBuffer)
976  {
978  trect = QRectF(trect.left() / 2.0, trect.top(),
979  trect.width() / 2.0, trect.height());
981  trect = QRectF(trect.left(), trect.top() / 2.0,
982  trect.width(), trect.height() / 2.0);
983  }
984 
985  // vertex coordinates
986  QRect display = (filter->outputBuffer == kDefaultBuffer) ?
988  QRect visible = (filter->outputBuffer == kDefaultBuffer) ?
990  QRectF vrect(display);
991 
992  // invert if first filter
993  if (it == filters.begin())
994  {
995  if (filters.size() > 1)
996  {
997  vrect.setTop((visible.height()) - display.top());
998  vrect.setBottom(vrect.top() - (display.height()));
999  }
1000  else
1001  {
1002  vrect.setBottom(display.top());
1003  vrect.setTop(display.top() + (display.height()));
1004  }
1005  }
1006 
1007  // hardware bobdeint
1008  if (filter->outputBuffer == kDefaultBuffer &&
1010  hardwareDeinterlacer == "openglbobdeint")
1011  {
1012  float bob = ((float)display.height() / (float)video_rect.height())
1013  / 2.0F;
1014  float field = kScan_Interlaced ? -1.0F : 1.0F;
1015  bob = bob * (topfieldfirst ? field : -field);
1016  vrect.adjust(0, bob, 0, bob);
1017  }
1018 
1019  uint target = 0;
1020  // bind correct frame buffer (default onscreen) and set viewport
1021  switch (filter->outputBuffer)
1022  {
1023  case kDefaultBuffer:
1025  if (viewportControl)
1026  gl_context->SetViewPort(QRect(QPoint(), display_visible_rect.size()));
1027  else
1028  gl_context->SetViewPort(QRect(QPoint(), masterViewportSize));
1029  break;
1030  case kFrameBufferObject:
1031  if (!filter->frameBuffers.empty())
1032  {
1034  gl_context->SetViewPort(QRect(QPoint(), frameBufferRect.size()));
1035  target = filter->frameBuffers[0];
1036  }
1037  break;
1038 
1039  default:
1040  continue;
1041  }
1042 
1043  if (draw_border && filter->outputBuffer == kDefaultBuffer)
1044  {
1045  QRectF piprectf = vrect.adjusted(-10, -10, +10, +10);
1046  QRect piprect(piprectf.left(), piprectf.top(),
1047  piprectf.width(), piprectf.height());
1048  static const QPen nopen(Qt::NoPen);
1049  static const QBrush redbrush(QBrush(QColor(127, 0, 0, 255)));
1050  gl_context->DrawRect(piprect, redbrush, nopen, 255);
1051  }
1052 
1053  // bind correct textures
1054  uint textures[4]; // NB
1055  uint texture_count = 0;
1056  for (size_t i = 0; i < inputs.size(); i++)
1057  textures[texture_count++] = inputs[i];
1058 
1059  if (!referenceTextures.empty() &&
1062  {
1063  for (size_t i = 0; i < referenceTextures.size(); i++)
1064  textures[texture_count++] = referenceTextures[i];
1065  }
1066 
1068  textures[texture_count++] = helperTexture;
1069 
1070  // enable fragment program and set any environment variables
1071  GLuint program = 0;
1072  if (((type != kGLFilterNone) && (type != kGLFilterResize)) ||
1073  ((gl_features & kGLSL) && (type == kGLFilterResize)))
1074  {
1075  GLuint prog_ref = 0;
1076 
1078  {
1079  if (hardwareDeinterlacing &&
1080  filter->fragmentPrograms.size() == 3 &&
1081  !refsNeeded)
1082  {
1083  if (scan == kScan_Interlaced)
1084  prog_ref = topfieldfirst ? 1 : 2;
1085  else if (scan == kScan_Intr2ndField)
1086  prog_ref = topfieldfirst ? 2 : 1;
1087  }
1088  }
1089  program = filter->fragmentPrograms[prog_ref];
1090  }
1091 
1093  {
1094  gl_context->SetShaderParams(program,
1095  GLMatrix4x4(reinterpret_cast<float*>(colourSpace->GetMatrix())),
1096  COLOUR_UNIFORM);
1097  }
1098 
1099  gl_context->DrawBitmap(textures, texture_count, target, &trect, &vrect,
1100  program);
1101 
1102  inputs = filter->frameBufferTextures;
1103  inputsize = realsize;
1104  }
1105 
1106  currentFrameNum = frame;
1107  inputUpdated = false;
1108 }
1109 
1111 {
1112  if (referenceTextures.size() < 2)
1113  return;
1114 
1115  if (refsNeeded > 0)
1116  refsNeeded--;
1117 
1118  GLuint tmp = referenceTextures[referenceTextures.size() - 1];
1119 
1120  for (uint i = referenceTextures.size() - 1; i > 0; i--)
1122 
1124  inputTextures[0] = tmp;
1125 }
1126 
1127 void OpenGLVideo::DeleteTextures(vector<GLuint> *textures)
1128 {
1129  if ((*textures).empty())
1130  return;
1131 
1132  for (size_t i = 0; i < (*textures).size(); i++)
1133  gl_context->DeleteTexture((*textures)[i]);
1134  (*textures).clear();
1135 }
1136 
1137 void OpenGLVideo::SetTextureFilters(vector<GLuint> *textures,
1138  int filt, int wrap)
1139 {
1140  if (textures->empty())
1141  return;
1142 
1143  for (size_t i = 0; i < textures->size(); i++)
1144  gl_context->SetTextureFilters((*textures)[i], filt, wrap);
1145 }
1146 
1148 {
1150 
1151  if (filter.contains("master"))
1152  ret = kGLFilterYUV2RGB;
1153  else if (filter.contains("resize"))
1154  ret = kGLFilterResize;
1155  else if (filter.contains("bicubic"))
1156  ret = kGLFilterBicubic;
1157  else if (filter.contains("yv12rgb"))
1158  ret = kGLFilterYV12RGB;
1159 
1160  return ret;
1161 }
1162 
1164 {
1165  switch (filt)
1166  {
1167  case kGLFilterNone:
1168  break;
1169  case kGLFilterYUV2RGB:
1170  return "master";
1171  case kGLFilterResize:
1172  return "resize";
1173  case kGLFilterBicubic:
1174  return "bicubic";
1175  case kGLFilterYV12RGB:
1176  return "yv12rgb";
1177  }
1178 
1179  return "";
1180 }
1181 
1183 {
1184  QString type = Type.toLower().trimmed();
1185  if ("opengl-yv12" == type) return kGLYV12;
1186  if ("opengl-hquyv" == type) return kGLHQUYV;
1187  if ("opengl-rgba" == type) return kGLRGBA;
1188  if ("opengl-lite" == type) return kGLYCbCr;
1189  if ("opengl-gpu" == type) return kGLGPU;
1190  return kGLUYVY; // opengl
1191 }
1192 
1194 {
1195  switch (Type)
1196  {
1197  case kGLGPU: return "opengl-gpu";
1198  case kGLYCbCr: return "opengl-lite"; // compatibility with old profiles
1199  case kGLUYVY: return "opengl"; // compatibility with old profiles
1200  case kGLYV12: return "opengl-yv12";
1201  case kGLHQUYV: return "opengl-hquyv";
1202  case kGLRGBA: return "opengl-rgba";
1203  }
1204  return "opengl";
1205 }
1206 
1207 static const QString attrib_fast =
1208 "ATTRIB tex = fragment.texcoord[0];\n"
1209 "PARAM yuv[3] = { program.local[0..2] };\n";
1210 
1211 static const QString tex_fast =
1212 "TEX res, tex, texture[0], %1;\n";
1213 
1214 static const QString var_fast =
1215 "TEMP tmp, res;\n";
1216 
1217 static const QString var_col =
1218 "TEMP col;\n";
1219 
1220 static const QString select_col =
1221 "MUL col, tex.xxxx, %8;\n"
1222 "FRC col, col;\n"
1223 "SUB col, col, 0.5;\n"
1224 "CMP res, col, res.rabg, res.rgba;\n";
1225 
1226 static const QString end_fast =
1227 "DPH tmp.r, res.%SWIZZLE%g, yuv[0];\n"
1228 "DPH tmp.g, res.%SWIZZLE%g, yuv[1];\n"
1229 "DPH tmp.b, res.%SWIZZLE%g, yuv[2];\n"
1230 "MOV tmp.a, 1.0;\n"
1231 "MOV result.color, tmp;\n";
1232 
1233 static const QString var_deint =
1234 "TEMP other, current, mov, prev;\n";
1235 
1236 static const QString field_calc =
1237 "MUL prev, tex.yyyy, %2;\n"
1238 "FRC prev, prev;\n"
1239 "SUB prev, prev, 0.5;\n";
1240 
1241 static const QString bobdeint[2] = {
1242 field_calc +
1243 "ADD other, tex, {0.0, %3, 0.0, 0.0};\n"
1244 "MIN other, other, {10000.0, %9, 10000.0, 10000.0};\n"
1245 "TEX other, other, texture[0], %1;\n"
1246 "CMP res, prev, res, other;\n",
1247 field_calc +
1248 "SUB other, tex, {0.0, %3, 0.0, 0.0};\n"
1249 "TEX other, other, texture[0], %1;\n"
1250 "CMP res, prev, other, res;\n"
1251 };
1252 
1253 static const QString deint_end_top =
1254 "CMP res, prev, current, other;\n";
1255 
1256 static const QString deint_end_bot =
1257 "CMP res, prev, other, current;\n";
1258 
1259 static const QString linearblend[2] = {
1260 "TEX current, tex, texture[0], %1;\n"
1261 "ADD other, tex, {0.0, %3, 0.0, 0.0};\n"
1262 "MIN other, other, {10000.0, %9, 10000.0, 10000.0};\n"
1263 "TEX other, other, texture[0], %1;\n"
1264 "SUB mov, tex, {0.0, %3, 0.0, 0.0};\n"
1265 "TEX mov, mov, texture[0], %1;\n"
1266 "LRP other, 0.5, other, mov;\n"
1268 
1269 "TEX current, tex, texture[0], %1;\n"
1270 "SUB other, tex, {0.0, %3, 0.0, 0.0};\n"
1271 "TEX other, other, texture[0], %1;\n"
1272 "ADD mov, tex, {0.0, %3, 0.0, 0.0};\n"
1273 "TEX mov, mov, texture[0], %1;\n"
1274 "LRP other, 0.5, other, mov;\n"
1276 };
1277 
1278 static const QString kerneldeint[2] = {
1279 "TEX current, tex, texture[1], %1;\n"
1280 "TEX prev, tex, texture[2], %1;\n"
1281 "MUL other, 0.125, prev;\n"
1282 "MAD other, 0.125, current, other;\n"
1283 "ADD prev, tex, {0.0, %3, 0.0, 0.0};\n"
1284 "MIN prev, prev, {10000.0, %9, 10000.0, 10000.0};\n"
1285 "TEX prev, prev, texture[1], %1;\n"
1286 "MAD other, 0.5, prev, other;\n"
1287 "SUB prev, tex, {0.0, %3, 0.0, 0.0};\n"
1288 "TEX prev, prev, texture[1], %1;\n"
1289 "MAD other, 0.5, prev, other;\n"
1290 "ADD prev, tex, {0.0, %4, 0.0, 0.0};\n"
1291 "TEX tmp, prev, texture[1], %1;\n"
1292 "MAD other, -0.0625, tmp, other;\n"
1293 "TEX tmp, prev, texture[2], %1;\n"
1294 "MAD other, -0.0625, tmp, other;\n"
1295 "SUB prev, tex, {0.0, %4, 0.0, 0.0};\n"
1296 "TEX tmp, prev, texture[1], %1;\n"
1297 "MAD other, -0.0625, tmp, other;\n"
1298 "TEX tmp, prev, texture[2], %1;\n"
1299 "MAD other, -0.0625, tmp, other;\n"
1301 
1302 "TEX current, tex, texture[1], %1;\n"
1303 "MUL other, 0.125, res;\n"
1304 "MAD other, 0.125, current, other;\n"
1305 "ADD prev, tex, {0.0, %3, 0.0, 0.0};\n"
1306 "TEX prev, prev, texture[1], %1;\n"
1307 "MAD other, 0.5, prev, other;\n"
1308 "SUB prev, tex, {0.0, %3, 0.0, 0.0};\n"
1309 "TEX prev, prev, texture[1], %1;\n"
1310 "MAD other, 0.5, prev, other;\n"
1311 "ADD prev, tex, {0.0, %4, 0.0, 0.0};\n"
1312 "TEX tmp, prev, texture[1], %1;\n"
1313 "MAD other, -0.0625, tmp, other;\n"
1314 "TEX tmp, prev, texture[0], %1;\n"
1315 "MAD other, -0.0625, tmp, other;\n"
1316 "SUB prev, tex, {0.0, %4, 0.0, 0.0};\n"
1317 "TEX tmp, prev, texture[1], %1;\n"
1318 "MAD other, -0.0625, tmp, other;\n"
1319 "TEX tmp, prev, texture[0], %1;\n"
1320 "MAD other, -0.0625, tmp, other;\n"
1322 };
1323 
1324 static const QString bicubic =
1325 "TEMP coord, coord2, cdelta, parmx, parmy, a, b, c, d;\n"
1326 "MAD coord.xy, fragment.texcoord[0], {%6, 0.0}, {0.5, 0.5};\n"
1327 "MAD coord2.xy, fragment.texcoord[0], {0.0, %7}, {0.5, 0.5};\n"
1328 "TEX parmx, coord.xy, texture[1], 2D;\n"
1329 "TEX parmy, coord2.yx, texture[1], 2D;\n"
1330 "MUL cdelta.xz, parmx.rrgg, {-%5, 0, %5, 0};\n"
1331 "MUL cdelta.yw, parmy.rrgg, {0, -%3, 0, %3};\n"
1332 "ADD coord, fragment.texcoord[0].xyxy, cdelta.xyxw;\n"
1333 "ADD coord2, fragment.texcoord[0].xyxy, cdelta.zyzw;\n"
1334 "TEX a, coord.xyxy, texture[0], 2D;\n"
1335 "TEX b, coord.zwzw, texture[0], 2D;\n"
1336 "TEX c, coord2.xyxy, texture[0], 2D;\n"
1337 "TEX d, coord2.zwzw, texture[0], 2D;\n"
1338 "LRP a, parmy.b, a, b;\n"
1339 "LRP c, parmy.b, c, d;\n"
1340 "LRP result.color, parmx.b, a, c;\n";
1341 
1343  const QString& deint, FrameScanType field)
1344 {
1345  QString ret =
1346  "!!ARBfp1.0\n"
1347  "OPTION ARB_precision_hint_fastest;\n";
1348 
1349  switch (name)
1350  {
1351  case kGLFilterYUV2RGB:
1352  {
1353  bool need_tex = true;
1354  bool packed = (kGLUYVY == videoType);
1355  QString deint_bit = "";
1356  if (deint != "")
1357  {
1358  uint tmp_field = 0;
1359  if (field == kScan_Intr2ndField)
1360  tmp_field = 1;
1361  if (deint == "openglbobdeint" ||
1362  deint == "openglonefield" ||
1363  deint == "opengldoubleratefieldorder")
1364  {
1365  deint_bit = bobdeint[tmp_field];
1366  }
1367  else if (deint == "opengllinearblend" ||
1368  deint == "opengldoubleratelinearblend")
1369  {
1370  deint_bit = linearblend[tmp_field];
1371  if (!tmp_field) { need_tex = false; }
1372  }
1373  else if (deint == "openglkerneldeint" ||
1374  deint == "opengldoubleratekerneldeint")
1375  {
1376  deint_bit = kerneldeint[tmp_field];
1377  if (!tmp_field) { need_tex = false; }
1378  }
1379  else
1380  {
1381  LOG(VB_PLAYBACK, LOG_ERR, LOC +
1382  "Unrecognised OpenGL deinterlacer");
1383  }
1384  }
1385 
1386  ret += attrib_fast;
1387  ret += (deint != "") ? var_deint : "";
1388  ret += packed ? var_col : "";
1389  ret += var_fast + (need_tex ? tex_fast : "");
1390  ret += deint_bit;
1391  ret += packed ? select_col : "";
1392  ret += end_fast;
1393  }
1394  break;
1395 
1396  case kGLFilterNone:
1397  case kGLFilterResize:
1398  break;
1399 
1400  case kGLFilterBicubic:
1401 
1402  ret += bicubic;
1403  break;
1404 
1405  case kGLFilterYV12RGB: // TODO: extend this for opengl1
1406  default:
1407  LOG(VB_PLAYBACK, LOG_ERR, LOC + "Unknown fragment program.");
1408  break;
1409  }
1410 
1412  ret += "END";
1413 
1414  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Created %1 fragment program %2")
1415  .arg(FilterToString(name)).arg(deint));
1416 
1417  return ret;
1418 }
1419 
1421 {
1422  string.replace("%1", textureRects ? "RECT" : "2D");
1423 
1424  if (!textureRects)
1425  {
1426  string.replace("GLSL_SAMPLER", "sampler2D");
1427  string.replace("GLSL_TEXTURE", "texture2D");
1428  }
1429 
1430  float lineHeight = 1.0F;
1431  float colWidth = 1.0F;
1432  float yselect = 1.0F;
1433  float maxwidth = inputTextureSize.width();
1434  float maxheight = inputTextureSize.height();
1435  float yv12height = video_dim.height();
1436  QSize fb_size = GetTextureSize(video_disp_dim);
1437 
1438  if (!textureRects && (inputTextureSize.height() > 0) && (inputTextureSize.width() > 0))
1439  {
1440  lineHeight /= inputTextureSize.height();
1441  colWidth /= inputTextureSize.width();
1442  yselect = (float)inputTextureSize.width();
1443  maxwidth = video_dim.width() / (float)inputTextureSize.width();
1444  maxheight = video_dim.height() / (float)inputTextureSize.height();
1445  yv12height = maxheight;
1446  }
1447 
1448  float fieldSize = 1.0F / (lineHeight * 2.0F);
1449 
1450  string.replace("%2", QString::number(fieldSize, 'f', 8));
1451  string.replace("%3", QString::number(lineHeight, 'f', 8));
1452  string.replace("%4", QString::number(lineHeight * 2.0F, 'f', 8));
1453  string.replace("%5", QString::number(colWidth, 'f', 8));
1454  string.replace("%6", QString::number((float)fb_size.width(), 'f', 1));
1455  string.replace("%7", QString::number((float)fb_size.height(), 'f', 1));
1456  string.replace("%8", QString::number(yselect, 'f', 8));
1457  string.replace("%9", QString::number(maxheight - lineHeight, 'f', 8));
1458  string.replace("%WIDTH%", QString::number(maxwidth, 'f', 8));
1459  string.replace("%HEIGHT%", QString::number(yv12height, 'f', 8));
1460  string.replace("COLOUR_UNIFORM", COLOUR_UNIFORM);
1461  // TODO fix alternative swizzling by changing the YUVA packing code
1462  string.replace("%SWIZZLE%", kGLUYVY == videoType ? "arb" : "abr");
1463 }
1464 
1465 static const QString YUV2RGBVertexShader =
1466 "GLSL_DEFINES"
1467 "attribute vec2 a_position;\n"
1468 "attribute vec2 a_texcoord0;\n"
1469 "varying vec2 v_texcoord0;\n"
1470 "uniform mat4 u_projection;\n"
1471 "void main() {\n"
1472 " gl_Position = u_projection * vec4(a_position, 0.0, 1.0);\n"
1473 " v_texcoord0 = a_texcoord0;\n"
1474 "}\n";
1475 
1476 static const QString SelectColumn =
1477 " if (fract(v_texcoord0.x * %8) < 0.5)\n"
1478 " yuva = yuva.rabg;\n";
1479 
1480 static const QString YUV2RGBFragmentShader =
1481 "GLSL_DEFINES"
1482 "uniform GLSL_SAMPLER s_texture0;\n"
1483 "uniform mat4 COLOUR_UNIFORM;\n"
1484 "varying vec2 v_texcoord0;\n"
1485 "void main(void)\n"
1486 "{\n"
1487 " vec4 yuva = GLSL_TEXTURE(s_texture0, v_texcoord0);\n"
1488 "SELECT_COLUMN"
1489 " gl_FragColor = vec4(yuva.%SWIZZLE%, 1.0) * COLOUR_UNIFORM;\n"
1490 "}\n";
1491 
1492 static const QString OneFieldShader[2] = {
1493 "GLSL_DEFINES"
1494 "uniform GLSL_SAMPLER s_texture0;\n"
1495 "uniform mat4 COLOUR_UNIFORM;\n"
1496 "varying vec2 v_texcoord0;\n"
1497 "void main(void)\n"
1498 "{\n"
1499 " float field = v_texcoord0.y + (step(0.5, fract(v_texcoord0.y * %2)) * %3);\n"
1500 " field = clamp(field, 0.0, %9);\n"
1501 " vec4 yuva = GLSL_TEXTURE(s_texture0, vec2(v_texcoord0.x, field));\n"
1502 "SELECT_COLUMN"
1503 " gl_FragColor = vec4(yuva.%SWIZZLE%, 1.0) * COLOUR_UNIFORM;\n"
1504 "}\n",
1505 
1506 "GLSL_DEFINES"
1507 "uniform GLSL_SAMPLER s_texture0;\n"
1508 "uniform mat4 COLOUR_UNIFORM;\n"
1509 "varying vec2 v_texcoord0;\n"
1510 "void main(void)\n"
1511 "{\n"
1512 " vec2 field = vec2(0.0, step(0.5, 1.0 - fract(v_texcoord0.y * %2)) * %3);\n"
1513 " vec4 yuva = GLSL_TEXTURE(s_texture0, v_texcoord0 + field);\n"
1514 "SELECT_COLUMN"
1515 " gl_FragColor = vec4(yuva.%SWIZZLE%, 1.0) * COLOUR_UNIFORM;\n"
1516 "}\n"
1517 };
1518 
1519 static const QString LinearBlendShader[2] = {
1520 "GLSL_DEFINES"
1521 "uniform GLSL_SAMPLER s_texture0;\n"
1522 "uniform mat4 COLOUR_UNIFORM;\n"
1523 "varying vec2 v_texcoord0;\n"
1524 "void main(void)\n"
1525 "{\n"
1526 " vec4 yuva = GLSL_TEXTURE(s_texture0, v_texcoord0);\n"
1527 " vec4 above = GLSL_TEXTURE(s_texture0, vec2(v_texcoord0.x, min(v_texcoord0.y + %3, %9)));\n"
1528 " vec4 below = GLSL_TEXTURE(s_texture0, vec2(v_texcoord0.x, max(v_texcoord0.y - %3, %3)));\n"
1529 " if (fract(v_texcoord0.y * %2) >= 0.5)\n"
1530 " yuva = mix(above, below, 0.5);\n"
1531 "SELECT_COLUMN"
1532 " gl_FragColor = vec4(yuva.%SWIZZLE%, 1.0) * COLOUR_UNIFORM;\n"
1533 "}\n",
1534 
1535 "GLSL_DEFINES"
1536 "uniform GLSL_SAMPLER s_texture0;\n"
1537 "uniform mat4 COLOUR_UNIFORM;\n"
1538 "varying vec2 v_texcoord0;\n"
1539 "void main(void)\n"
1540 "{\n"
1541 " vec4 yuva = GLSL_TEXTURE(s_texture0, v_texcoord0);\n"
1542 " vec4 above = GLSL_TEXTURE(s_texture0, vec2(v_texcoord0.x, min(v_texcoord0.y + %3, %9)));\n"
1543 " vec4 below = GLSL_TEXTURE(s_texture0, vec2(v_texcoord0.x, max(v_texcoord0.y - %3, %3)));\n"
1544 " if (fract(v_texcoord0.y * %2) < 0.5)\n"
1545 " yuva = mix(above, below, 0.5);\n"
1546 "SELECT_COLUMN"
1547 " gl_FragColor = vec4(yuva.%SWIZZLE%, 1.0) * COLOUR_UNIFORM;\n"
1548 "}\n"
1549 };
1550 
1551 static const QString KernelShader[2] = {
1552 "GLSL_DEFINES"
1553 "uniform GLSL_SAMPLER s_texture1;\n"
1554 "uniform GLSL_SAMPLER s_texture2;\n"
1555 "uniform mat4 COLOUR_UNIFORM;\n"
1556 "varying vec2 v_texcoord0;\n"
1557 "void main(void)\n"
1558 "{\n"
1559 " vec4 yuva = GLSL_TEXTURE(s_texture1, v_texcoord0);\n"
1560 " if (fract(v_texcoord0.y * %2) >= 0.5)\n"
1561 " {\n"
1562 " vec2 oneup = vec2(v_texcoord0.x, max(v_texcoord0.y - %3, %3));\n"
1563 " vec2 twoup = vec2(v_texcoord0.x, max(v_texcoord0.y - %4, %3));\n"
1564 " vec2 onedown = vec2(v_texcoord0.x, min(v_texcoord0.y + %3, %9));\n"
1565 " vec2 twodown = vec2(v_texcoord0.x, min(v_texcoord0.y + %4, %9));\n"
1566 " vec4 line0 = GLSL_TEXTURE(s_texture1, twoup);\n"
1567 " vec4 line1 = GLSL_TEXTURE(s_texture1, oneup);\n"
1568 " vec4 line3 = GLSL_TEXTURE(s_texture1, onedown);\n"
1569 " vec4 line4 = GLSL_TEXTURE(s_texture1, twodown);\n"
1570 " vec4 line00 = GLSL_TEXTURE(s_texture2, twoup);\n"
1571 " vec4 line20 = GLSL_TEXTURE(s_texture2, v_texcoord0);\n"
1572 " vec4 line40 = GLSL_TEXTURE(s_texture2, twodown);\n"
1573 " yuva = (yuva * 0.125);\n"
1574 " yuva = (line20 * 0.125) + yuva;\n"
1575 " yuva = (line1 * 0.5) + yuva;\n"
1576 " yuva = (line3 * 0.5) + yuva;\n"
1577 " yuva = (line0 * -0.0625) + yuva;\n"
1578 " yuva = (line4 * -0.0625) + yuva;\n"
1579 " yuva = (line00 * -0.0625) + yuva;\n"
1580 " yuva = (line40 * -0.0625) + yuva;\n"
1581 " }\n"
1582 "SELECT_COLUMN"
1583 " gl_FragColor = vec4(yuva.%SWIZZLE%, 1.0) * COLOUR_UNIFORM;\n"
1584 "}\n",
1585 
1586 "GLSL_DEFINES"
1587 "uniform GLSL_SAMPLER s_texture0;\n"
1588 "uniform GLSL_SAMPLER s_texture1;\n"
1589 "uniform mat4 COLOUR_UNIFORM;\n"
1590 "varying vec2 v_texcoord0;\n"
1591 "void main(void)\n"
1592 "{\n"
1593 " vec4 yuva = GLSL_TEXTURE(s_texture1, v_texcoord0);\n"
1594 " if (fract(v_texcoord0.y * %2) < 0.5)\n"
1595 " {\n"
1596 " vec2 oneup = vec2(v_texcoord0.x, max(v_texcoord0.y - %3, %3));\n"
1597 " vec2 twoup = vec2(v_texcoord0.x, max(v_texcoord0.y - %4, %3));\n"
1598 " vec2 onedown = vec2(v_texcoord0.x, min(v_texcoord0.y + %3, %9));\n"
1599 " vec2 twodown = vec2(v_texcoord0.x, min(v_texcoord0.y + %4, %9));\n"
1600 " vec4 line0 = GLSL_TEXTURE(s_texture1, twoup);\n"
1601 " vec4 line1 = GLSL_TEXTURE(s_texture1, oneup);\n"
1602 " vec4 line3 = GLSL_TEXTURE(s_texture1, onedown);\n"
1603 " vec4 line4 = GLSL_TEXTURE(s_texture1, twodown);\n"
1604 " vec4 line00 = GLSL_TEXTURE(s_texture0, twoup);\n"
1605 " vec4 line20 = GLSL_TEXTURE(s_texture0, v_texcoord0);\n"
1606 " vec4 line40 = GLSL_TEXTURE(s_texture0, twodown);\n"
1607 " yuva = (yuva * 0.125);\n"
1608 " yuva = (line20 * 0.125) + yuva;\n"
1609 " yuva = (line1 * 0.5) + yuva;\n"
1610 " yuva = (line3 * 0.5) + yuva;\n"
1611 " yuva = (line0 * -0.0625) + yuva;\n"
1612 " yuva = (line4 * -0.0625) + yuva;\n"
1613 " yuva = (line00 * -0.0625) + yuva;\n"
1614 " yuva = (line40 * -0.0625) + yuva;\n"
1615 " }\n"
1616 "SELECT_COLUMN"
1617 " gl_FragColor = vec4(yuva.%SWIZZLE%, 1.0) * COLOUR_UNIFORM;\n"
1618 "}\n"
1619 };
1620 
1621 static const QString BicubicShader =
1622 "GLSL_DEFINES"
1623 "uniform sampler2D s_texture0;\n"
1624 "uniform sampler2D s_texture1;\n"
1625 "varying vec2 v_texcoord0;\n"
1626 "void main(void)\n"
1627 "{\n"
1628 " vec2 coord = (v_texcoord0 * vec2(%6, %7)) - vec2(0.5, 0.5);\n"
1629 " vec4 parmx = texture2D(s_texture1, vec2(coord.x, 0.0));\n"
1630 " vec4 parmy = texture2D(s_texture1, vec2(coord.y, 0.0));\n"
1631 " vec2 e_x = vec2(%5, 0.0);\n"
1632 " vec2 e_y = vec2(0.0, %3);\n"
1633 " vec2 coord10 = v_texcoord0 + parmx.x * e_x;\n"
1634 " vec2 coord00 = v_texcoord0 - parmx.y * e_x;\n"
1635 " vec2 coord11 = coord10 + parmy.x * e_y;\n"
1636 " vec2 coord01 = coord00 + parmy.x * e_y;\n"
1637 " coord10 = coord10 - parmy.y * e_y;\n"
1638 " coord00 = coord00 - parmy.y * e_y;\n"
1639 " vec4 tex00 = texture2D(s_texture0, coord00);\n"
1640 " vec4 tex10 = texture2D(s_texture0, coord10);\n"
1641 " vec4 tex01 = texture2D(s_texture0, coord01);\n"
1642 " vec4 tex11 = texture2D(s_texture0, coord11);\n"
1643 " tex00 = mix(tex00, tex01, parmy.z);\n"
1644 " tex10 = mix(tex10, tex11, parmy.z);\n"
1645 " gl_FragColor = mix(tex00, tex10, parmx.z);\n"
1646 "}\n";
1647 
1648 static const QString DefaultFragmentShader =
1649 "GLSL_DEFINES"
1650 "uniform GLSL_SAMPLER s_texture0;\n"
1651 "varying vec2 v_texcoord0;\n"
1652 "void main(void)\n"
1653 "{\n"
1654 " vec4 color = GLSL_TEXTURE(s_texture0, v_texcoord0);\n"
1655 " gl_FragColor = vec4(color.xyz, 1.0);\n"
1656 "}\n";
1657 
1658 static const QString YV12RGBVertexShader =
1659 "//YV12RGBVertexShader\n"
1660 "GLSL_DEFINES"
1661 "attribute vec2 a_position;\n"
1662 "attribute vec2 a_texcoord0;\n"
1663 "varying vec2 v_texcoord0;\n"
1664 "uniform mat4 u_projection;\n"
1665 "void main() {\n"
1666 " gl_Position = u_projection * vec4(a_position, 0.0, 1.0);\n"
1667 " v_texcoord0 = a_texcoord0;\n"
1668 "}\n";
1669 
1670 #define SAMPLEYVU "\
1671 vec3 sampleYVU(in GLSL_SAMPLER texture, vec2 texcoordY)\n\
1672 {\n\
1673  vec2 texcoordV, texcoordU;\n\
1674  texcoordV = vec2(texcoordY.s / 2.0, %HEIGHT% + texcoordY.t / 4.0);\n\
1675  texcoordU = vec2(texcoordV.s, texcoordV.t + %HEIGHT% / 4.0);\n\
1676  if (fract(texcoordY.t * %2) >= 0.5)\n\
1677  {\n\
1678  texcoordV.s += %WIDTH% / 2.0;\n\
1679  texcoordU.s += %WIDTH% / 2.0;\n\
1680  }\n\
1681  vec3 yvu;\n\
1682  yvu.r = GLSL_TEXTURE(texture, texcoordY).r;\n\
1683  yvu.g = GLSL_TEXTURE(texture, texcoordV).r;\n\
1684  yvu.b = GLSL_TEXTURE(texture, texcoordU).r;\n\
1685  return yvu;\n\
1686 }\n"
1687 
1688 static const QString YV12RGBFragmentShader =
1689 "//YV12RGBFragmentShader\n"
1690 "GLSL_DEFINES"
1691 "uniform GLSL_SAMPLER s_texture0; // 4:1:1 YVU planar\n"
1692 "uniform mat4 COLOUR_UNIFORM;\n"
1693 "varying vec2 v_texcoord0;\n"
1694 SAMPLEYVU
1695 "void main(void)\n"
1696 "{\n"
1697 " vec3 yvu = sampleYVU(s_texture0, v_texcoord0);\n"
1698 " gl_FragColor = vec4(yvu, 1.0) * COLOUR_UNIFORM;\n"
1699 "}\n";
1700 
1701 static const QString YV12RGBOneFieldFragmentShader[2] = {
1702 "//YV12RGBOneFieldFragmentShader 1\n"
1703 "GLSL_DEFINES"
1704 "uniform GLSL_SAMPLER s_texture0;\n"
1705 "uniform mat4 COLOUR_UNIFORM;\n"
1706 "varying vec2 v_texcoord0;\n"
1707 SAMPLEYVU
1708 "void main(void)\n"
1709 "{\n"
1710 " float field = min(v_texcoord0.y + (step(0.5, fract(v_texcoord0.y * %2))) * %3, %HEIGHT% - %3);\n"
1711 " vec3 yvu = sampleYVU(s_texture0, vec2(v_texcoord0.x, field));\n"
1712 " gl_FragColor = vec4(yvu, 1.0) * COLOUR_UNIFORM;\n"
1713 "}\n",
1714 
1715 "//YV12RGBOneFieldFragmentShader 2\n"
1716 "GLSL_DEFINES"
1717 "uniform GLSL_SAMPLER s_texture0;\n"
1718 "uniform mat4 COLOUR_UNIFORM;\n"
1719 "varying vec2 v_texcoord0;\n"
1720 SAMPLEYVU
1721 "void main(void)\n"
1722 "{\n"
1723 " float field = max(v_texcoord0.y + (step(0.5, 1.0 - fract(v_texcoord0.y * %2))) * %3, 0.0);\n"
1724 " vec3 yvu = sampleYVU(s_texture0, vec2(v_texcoord0.x, field));\n"
1725 " gl_FragColor = vec4(yvu, 1.0) * COLOUR_UNIFORM;\n"
1726 "}\n"
1727 };
1728 
1729 static const QString YV12RGBLinearBlendFragmentShader[2] = {
1730 "// YV12RGBLinearBlendFragmentShader - Top\n"
1731 "GLSL_DEFINES"
1732 "uniform GLSL_SAMPLER s_texture0; // 4:1:1 YVU planar\n"
1733 "uniform mat4 COLOUR_UNIFORM;\n"
1734 "varying vec2 v_texcoord0;\n"
1735 SAMPLEYVU
1736 "void main(void)\n"
1737 "{\n"
1738 " vec3 current = sampleYVU(s_texture0, v_texcoord0);\n"
1739 " if (fract(v_texcoord0.y * %2) >= 0.5)\n"
1740 " {\n"
1741 " vec3 above = sampleYVU(s_texture0, vec2(v_texcoord0.x, min(v_texcoord0.y + %3, %HEIGHT% - %3)));\n"
1742 " vec3 below = sampleYVU(s_texture0, vec2(v_texcoord0.x, max(v_texcoord0.y - %3, 0.0)));\n"
1743 " current = mix(above, below, 0.5);\n"
1744 " }\n"
1745 " gl_FragColor = vec4(current, 1.0) * COLOUR_UNIFORM;\n"
1746 "}\n",
1747 
1748 "// YV12RGBLinearBlendFragmentShader - Bottom\n"
1749 "GLSL_DEFINES"
1750 "uniform GLSL_SAMPLER s_texture0; // 4:1:1 YVU planar\n"
1751 "uniform mat4 COLOUR_UNIFORM;\n"
1752 "varying vec2 v_texcoord0;\n"
1753 SAMPLEYVU
1754 "void main(void)\n"
1755 "{\n"
1756 " vec3 current = sampleYVU(s_texture0, v_texcoord0);\n"
1757 " if (fract(v_texcoord0.y * %2) < 0.5)\n"
1758 " {\n"
1759 " vec3 above = sampleYVU(s_texture0, vec2(v_texcoord0.x, min(v_texcoord0.y + %3, %HEIGHT% - %3)));\n"
1760 " vec3 below = sampleYVU(s_texture0, vec2(v_texcoord0.x, max(v_texcoord0.y - %3, 0.0)));\n"
1761 " current = mix(above, below, 0.5);\n"
1762 " }\n"
1763 " gl_FragColor = vec4(current, 1.0) * COLOUR_UNIFORM;\n"
1764 "}\n"};
1765 
1766 #define KERNELYVU "\
1767 vec3 kernelYVU(in vec3 yvu, GLSL_SAMPLER texture1, GLSL_SAMPLER texture2)\n\
1768 {\n\
1769  vec2 twoup = v_texcoord0 - vec2(0.0, %4);\n\
1770  vec2 twodown = v_texcoord0 + vec2(0.0, %4);\n\
1771  twodown.t = min(twodown.t, %HEIGHT% - %3);\n\
1772  vec2 onedown = v_texcoord0 + vec2(0.0, %3);\n\
1773  onedown.t = min(onedown.t, %HEIGHT% - %3);\n\
1774  vec3 line0 = sampleYVU(texture1, twoup);\n\
1775  vec3 line1 = sampleYVU(texture1, v_texcoord0 - vec2(0.0, %3));\n\
1776  vec3 line3 = sampleYVU(texture1, onedown);\n\
1777  vec3 line4 = sampleYVU(texture1, twodown);\n\
1778  vec3 line00 = sampleYVU(texture2, twoup);\n\
1779  vec3 line20 = sampleYVU(texture2, v_texcoord0);\n\
1780  vec3 line40 = sampleYVU(texture2, twodown);\n\
1781  yvu *= 0.125;\n\
1782  yvu += line20 * 0.125;\n\
1783  yvu += line1 * 0.5;\n\
1784  yvu += line3 * 0.5;\n\
1785  yvu += line0 * -0.0625;\n\
1786  yvu += line4 * -0.0625;\n\
1787  yvu += line00 * -0.0625;\n\
1788  yvu += line40 * -0.0625;\n\
1789  return yvu;\n\
1790 }\n"
1791 
1792 static const QString YV12RGBKernelShader[2] = {
1793 "//YV12RGBKernelShader 1\n"
1794 "GLSL_DEFINES"
1795 "uniform GLSL_SAMPLER s_texture1, s_texture2; // 4:1:1 YVU planar\n"
1796 "uniform mat4 COLOUR_UNIFORM;\n"
1797 "varying vec2 v_texcoord0;\n"
1798 SAMPLEYVU
1799 KERNELYVU
1800 "void main(void)\n"
1801 "{\n"
1802 " vec3 yvu = sampleYVU(s_texture1, v_texcoord0);\n"
1803 " if (fract(v_texcoord0.t * %2) >= 0.5)\n"
1804 " yvu = kernelYVU(yvu, s_texture1, s_texture2);\n"
1805 " gl_FragColor = vec4(yvu, 1.0) * COLOUR_UNIFORM;\n"
1806 "}\n",
1807 
1808 "//YV12RGBKernelShader 2\n"
1809 "GLSL_DEFINES"
1810 "uniform GLSL_SAMPLER s_texture0, s_texture1; // 4:1:1 YVU planar\n"
1811 "uniform mat4 COLOUR_UNIFORM;\n"
1812 "varying vec2 v_texcoord0;\n"
1813 SAMPLEYVU
1814 KERNELYVU
1815 "void main(void)\n"
1816 "{\n"
1817 " vec3 yvu = sampleYVU(s_texture1, v_texcoord0);\n"
1818 " if (fract(v_texcoord0.t * %2) < 0.5)\n"
1819 " yvu = kernelYVU(yvu, s_texture1, s_texture0);\n"
1820 " gl_FragColor = vec4(yvu, 1.0) * COLOUR_UNIFORM;\n"
1821 "}\n"
1822 };
1823 
1824 void OpenGLVideo::GetProgramStrings(QString &vertex, QString &fragment,
1825  OpenGLFilterType filter,
1826  const QString& deint, FrameScanType field)
1827 {
1828  uint bottom = field == kScan_Intr2ndField;
1829  vertex = YUV2RGBVertexShader;
1830  switch (filter)
1831  {
1832  case kGLFilterYUV2RGB:
1833  {
1834  if (deint == "openglonefield" || deint == "openglbobdeint")
1835  fragment = OneFieldShader[bottom];
1836  else if (deint == "opengllinearblend" ||
1837  deint == "opengldoubleratelinearblend")
1838  fragment = LinearBlendShader[bottom];
1839  else if (deint == "openglkerneldeint" ||
1840  deint == "opengldoubleratekerneldeint")
1841  fragment = KernelShader[bottom];
1842  else
1843  fragment = YUV2RGBFragmentShader;
1844  fragment.replace("SELECT_COLUMN", (kGLUYVY == videoType) ? SelectColumn : "");
1845  break;
1846  }
1847  case kGLFilterYV12RGB:
1848  vertex = YV12RGBVertexShader;
1849  if (deint == "openglonefield" || deint == "openglbobdeint")
1850  fragment = YV12RGBOneFieldFragmentShader[bottom];
1851  else if (deint == "opengllinearblend" || deint == "opengldoubleratelinearblend")
1852  fragment = YV12RGBLinearBlendFragmentShader[bottom];
1853  else if (deint == "openglkerneldeint" || deint == "opengldoubleratekerneldeint")
1854  fragment = YV12RGBKernelShader[bottom];
1855  else
1856  fragment = YV12RGBFragmentShader;
1857  break;
1858  case kGLFilterNone:
1859  break;
1860  case kGLFilterResize:
1861  fragment = DefaultFragmentShader;
1862  break;
1863  case kGLFilterBicubic:
1864  fragment = BicubicShader;
1865  break;
1866  default:
1867  LOG(VB_PLAYBACK, LOG_ERR, LOC + "Unknown filter");
1868  break;
1869  }
1870  CustomiseProgramString(vertex);
1871  CustomiseProgramString(fragment);
1872 }
static const QString kerneldeint[2]
int pitches[3]
Y, U, & V pitches.
Definition: mythframe.h:63
void GetProgramStrings(QString &vertex, QString &fragment, OpenGLFilterType filter, const QString &deint=QString(), FrameScanType field=kScan_Progressive)
static const QString select_col
virtual void SetShaderParams(uint prog, const QMatrix4x4 &m, const char *uniform)=0
static const QString bicubic
def scan(profile, smoonURL, gate)
Definition: scan.py:46
static void copybuffer(VideoFrame *dst, uint8_t *buffer, int pitch, VideoFrameType type=FMT_YV12)
Definition: mythframe.h:324
void CustomiseProgramString(QString &string)
static const QString YV12RGBLinearBlendFragmentShader[2]
VERBOSE_PREAMBLE Most true
Definition: verbosedefs.h:91
void DeleteTexture(uint tex)
int Copy(VideoFrame *dst, const VideoFrame *src)
Definition: mythavutil.cpp:199
QRect frameBufferRect
Rect version of video_disp_dim.
Definition: openglvideo.h:124
void UpdateInputFrame(const VideoFrame *frame, bool soft_bob=false)
Update the current input texture using the data from the given YV12 video frame.
bool Init(MythRenderOpenGL *glcontext, VideoColourSpace *colourspace, QSize videoDim, QSize videoDispDim, QRect displayVisibleRect, QRect displayVideoRect, QRect videoRect, bool viewport_control, VideoType type, const QString &options)
vector< GLuint > fragmentPrograms
Definition: openglvideo.cpp:21
static const QString var_deint
QRect video_rect
Sub-rect of video_disp_dim to display (after zoom adjustments etc)
Definition: openglvideo.h:123
struct AVFrame AVFrame
void SetVideoRect(const QRect &dispvidrect, const QRect &vidrect)
QRect display_visible_rect
Total useful, visible rectangle.
Definition: openglvideo.h:121
uint GetInputTexture(void) const
uint helperTexture
Extra texture for bicubic filter.
Definition: openglvideo.h:139
QSize video_dim
Total video frame size e.g. 1920x1088.
Definition: openglvideo.h:118
static const QString YUV2RGBVertexShader
DisplayBuffer
Definition: openglvideo.cpp:12
static const QString var_col
FrameScanType
Definition: videoouttypes.h:80
bool AddDeinterlacer(const QString &deinterlacer)
Extends the functionality of the basic YUV->RGB filter stage to include deinterlacing (combining the ...
unsigned int uint
Definition: compat.h:140
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
void SetSoftwareDeinterlacer(const QString &filter)
glfilt_map_t filters
Filter stages to be applied to frame.
Definition: openglvideo.h:133
QString GetProgramString(OpenGLFilterType name, const QString &deint=QString(), FrameScanType field=kScan_Progressive)
bool textureRects
OpenGLVideo is using rectangular textures.
Definition: openglvideo.h:137
static guint32 * tmp
Definition: goom_core.c:35
static const QString bobdeint[2]
void SetDeinterlacing(bool deinterlacing)
uint GetTextureType(void) const
static QSize GetTextureSize(uint type, const QSize &size)
#define SAMPLEYVU
void * GetMatrix(void)
QSize GetTextureSize(const QSize &size)
MythRenderOpenGL * gl_context
Definition: openglvideo.h:116
vector< GLuint > frameBuffers
Definition: openglvideo.cpp:23
void DrawBitmap(uint tex, uint target, const QRect *src, const QRect *dst, uint prog, int alpha=255, int red=255, int green=255, int blue=255)
virtual uint CreateShaderObject(const QString &vert, const QString &frag)=0
static const QString BicubicShader
int offsets[3]
Y, U, & V offsets.
Definition: mythframe.h:64
static const QString YUV2RGBFragmentShader
static OpenGLFilterType StringToFilter(const QString &filter)
VERBOSE_PREAMBLE false
Definition: verbosedefs.h:85
static const QString LinearBlendShader[2]
void doneCurrent() override
#define GL_YCBCR_MESA
int refsNeeded
Number of reference textures expected.
Definition: openglvideo.h:136
QRect display_video_rect
Sub-rect of display_visible_rect for video.
Definition: openglvideo.h:122
uint CreateVideoTexture(QSize size, QSize &tex_size)
Create and initialise an OpenGL texture suitable for a YV12 video frame of the given size.
int height
Definition: mythframe.h:42
void SetTextureFilters(uint tex, uint filt, uint wrap)
vector< GLuint > inputTextures
Textures with raw video data.
Definition: openglvideo.h:131
vector< GLuint > referenceTextures
Up to 3 reference textures for filters.
Definition: openglvideo.h:130
static const QString KernelShader[2]
void SetViewPort(const QSize &viewPortSize)
bool inputUpdated
Input texture has been refreshed with new data.
Definition: openglvideo.h:135
void DeleteFrameBuffer(uint fb)
uint gl_features
OR'd list of GLFeatures in use.
Definition: openglvideo.h:141
uint textureType
Texture type (e.g. GL_TEXTURE_2D or GL_TEXTURE_RECT)
Definition: openglvideo.h:138
static QString FilterToString(OpenGLFilterType filter)
void PrepareFrame(bool topfieldfirst, FrameScanType scan, bool softwareDeinterlacing, long long frame, StereoscopicMode stereo, bool draw_border=false)
Render the contents of the current input texture to the framebuffer using the currently enabled filte...
MythAVCopy m_copyCtx
Conversion context for YV12 to UYVY.
Definition: openglvideo.h:142
static const QString deint_end_top
static const QString DefaultFragmentShader
QSize viewportSize
Can be removed.
Definition: openglvideo.h:119
uint CreateHelperTexture(void)
void DrawRect(const QRect &area, const QBrush &fillBrush, const QPen &linePen, int alpha)
void UpdateTexture(uint tex, void *buf)
bool forceResize
Global setting to force a resize stage.
Definition: openglvideo.h:143
const char * name
Definition: ParseText.cpp:328
QSize inputTextureSize
Actual size of input texture(s)
Definition: openglvideo.h:132
#define COLOUR_UNIFORM
Definition: openglvideo.cpp:9
vector< GLuint > frameBufferTextures
Definition: openglvideo.cpp:24
QString hardwareDeinterlacer
Definition: openglvideo.h:126
void pack_yv12progressive(const unsigned char *source, const unsigned char *dest, const int *offsets, const int *pitches, const QSize &size)
void * GetTextureBuffer(uint tex, bool create_buffer=true)
void makeCurrent() override
bool CreateFrameBuffer(uint &fb, uint tex)
void SetViewPort(const QRect &rect, bool viewportonly=false)
static const QString YV12RGBFragmentShader
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
static const QString var_fast
static const QString SelectColumn
StereoscopicMode
bool GetBoolSetting(const QString &key, bool defaultval=false)
bool AddFilter(const QString &filter)
Public interface to AddFilter(OpenGLFilterType filter)
Definition: openglvideo.h:61
static const QString field_calc
QString softwareDeinterlacer
Definition: openglvideo.h:125
void Teardown(void)
Definition: openglvideo.cpp:89
static const QString tex_fast
QSize video_disp_dim
Useful video frame size e.g. 1920x1080.
Definition: openglvideo.h:117
void DeleteTextures(vector< GLuint > *textures)
void SetInputUpdated(void)
#define GL_YCBCR_422_APPLE
#define GL_RGBA
static const QString deint_end_bot
void SetSupportedAttributes(PictureAttributeSupported supported)
int GetTextureType(bool &rect)
VideoColourSpace * colourSpace
Definition: openglvideo.h:128
QSize masterViewportSize
Current viewport into which OpenGL is rendered.
Definition: openglvideo.h:120
#define GL_UNSIGNED_SHORT_8_8_MESA
bool viewportControl
Video has control over view port.
Definition: openglvideo.h:129
static QString TypeToString(VideoType Type)
bool OptimiseFilters(void)
Ensure the current chain of OpenGLFilters is logically correct and has the resources required to comp...
void CheckResize(bool deinterlacing, bool allow=true)
Determine if the output is to be scaled at all and create or destroy the appropriate filter as necess...
bool AddFrameBuffer(uint &framebuffer, uint &texture, QSize vid_size)
Add a FrameBuffer object of the correct size to the given texture.
static const QString OneFieldShader[2]
uint CreateTexture(QSize act_size, bool use_pbo, uint type, uint data_type=GL_UNSIGNED_BYTE, uint data_fmt=GL_RGBA, uint internal_fmt=GL_RGBA8, uint filter=GL_LINEAR, uint wrap=GL_CLAMP_TO_EDGE)
void SetFiltering(void)
Set the OpenGL texture mapping functions to optimise speed and quality.
int interlaced_frame
1 if interlaced.
Definition: mythframe.h:57
#define LOC
Definition: openglvideo.cpp:8
GLMatrix4x4 is a helper class to convert between QT and GT 4x4 matrices.
bool RemoveFilter(const QString &filter)
Definition: openglvideo.h:63
static const QString linearblend[2]
static const QString YV12RGBOneFieldFragmentShader[2]
static const QString YV12RGBVertexShader
unsigned char * buf
Definition: mythframe.h:39
static const QString end_fast
void BindFramebuffer(uint fb)
long long currentFrameNum
Can be removed.
Definition: openglvideo.h:134
virtual void DeleteShaderObject(uint obj)=0
static const QString attrib_fast
VideoType videoType
Definition: openglvideo.h:115
void SetTextureFilters(vector< GLuint > *textures, int filt, int wrap)
uint AddFragmentProgram(OpenGLFilterType name, const QString &deint=QString(), FrameScanType field=kScan_Progressive)
Create the correct fragment program for the given filter type.
void RotateTextures(void)
void pack_yv12interlaced(const unsigned char *source, unsigned char *dest, const int offsets[3], const int pitches[3], const QSize &size)
void TearDownDeinterlacer(void)
OpenGLFilterType defaultUpsize
Regular or bicubic upsizing.
Definition: openglvideo.h:140
#define KERNELYVU
static VideoType StringToType(const QString &Type)
DisplayBuffer outputBuffer
Definition: openglvideo.cpp:25
VideoFrameType codec
Definition: mythframe.h:38
OpenGLVideo()
Create a new OpenGLVideo instance that must be initialised with a call to OpenGLVideo::Init()
Definition: openglvideo.cpp:66
static const QString YV12RGBKernelShader[2]
bool hardwareDeinterlacing
OpenGL deinterlacing is enabled.
Definition: openglvideo.h:127