MythTV  master
videoout_opengl.cpp
Go to the documentation of this file.
1 #include "videoout_opengl.h"
2 #include "mythcontext.h"
3 #include "mythmainwindow.h"
4 #include "mythplayer.h"
5 #include "videooutbase.h"
6 #include "videodisplayprofile.h"
7 #include "filtermanager.h"
8 #include "osd.h"
9 #include "mythuihelper.h"
10 #include "mythrender_opengl.h"
11 #include "mythpainter_ogl.h"
12 #include "mythcodeccontext.h"
13 
14 #define LOC QString("VidOutGL: ")
15 
23  QStringList &cpudeints)
24 {
25  QStringList gldeints;
26  gldeints << "opengllinearblend" <<
27  "openglonefield" <<
28  "openglkerneldeint" <<
29  "openglbobdeint" <<
30  "opengldoubleratelinearblend" <<
31  "opengldoubleratekerneldeint" <<
32  "opengldoubleratefieldorder";
33 
34  QStringList safe;
35  safe << "opengl" << "opengl-lite" << "opengl-yv12" << "opengl-hquyv" << "opengl-rgba";
36 
37  // all profiles can handle all software frames
38  (*opts.safe_renderers)["dummy"].append(safe);
39  (*opts.safe_renderers)["nuppel"].append(safe);
40  if (opts.decoders->contains("ffmpeg"))
41  (*opts.safe_renderers)["ffmpeg"].append(safe);
42  if (opts.decoders->contains("vda"))
43  (*opts.safe_renderers)["vda"].append(safe);
44  if (opts.decoders->contains("crystalhd"))
45  (*opts.safe_renderers)["crystalhd"].append(safe);
46  if (opts.decoders->contains("openmax"))
47  (*opts.safe_renderers)["openmax"].append(safe);
48  if (opts.decoders->contains("mediacodec"))
49  (*opts.safe_renderers)["mediacodec"].append(safe);
50  if (opts.decoders->contains("vaapi2"))
51  (*opts.safe_renderers)["vaapi2"].append(safe);
52 
53  // OpenGL UYVY
54  opts.renderers->append("opengl");
55  opts.deints->insert("opengl", cpudeints + gldeints);
56  (*opts.deints)["opengl"].append("bobdeint");
57  (*opts.osds)["opengl"].append("opengl2");
58  opts.priorities->insert("opengl", 65);
59 
60  // OpenGL HQ UYV
61  opts.renderers->append("opengl-hquyv");
62  opts.deints->insert("opengl-hquyv", cpudeints + gldeints);
63  (*opts.deints)["opengl-hquyv"].append("bobdeint");
64  (*opts.osds)["opengl-hquyv"].append("opengl2");
65  opts.priorities->insert("opengl-hquyv", 60);
66 
67  // OpenGL YV12
68  opts.renderers->append("opengl-yv12");
69  opts.deints->insert("opengl-yv12", cpudeints + gldeints);
70  (*opts.deints)["opengl-yv12"].append("bobdeint");
71  (*opts.osds)["opengl-yv12"].append("opengl2");
72  opts.priorities->insert("opengl-yv12", 65);
73 
74  // lite (YCbCr) profile - no colourspace control, GPU deinterlacing
75  opts.renderers->append("opengl-lite");
76  opts.deints->insert("opengl-lite", cpudeints);
77  (*opts.deints)["opengl-lite"].append("bobdeint");
78  (*opts.osds)["opengl-lite"].append("opengl2");
79  opts.priorities->insert("opengl-lite", 50);
80 
81  // software fallback
82  opts.renderers->append("opengl-rgba");
83  opts.deints->insert("opengl-rgba", cpudeints);
84  (*opts.osds)["opengl-rgba"].append("opengl2");
85  opts.priorities->insert("opengl-rgba", 10);
86 }
87 
89  : VideoOutput(),
90  gl_context_lock(QMutex::Recursive), gl_context(nullptr), gl_valid(true),
91  gl_videochain(nullptr), gl_pipchain_active(nullptr),
92  gl_parent_win(0), gl_painter(nullptr), gl_created_painter(false),
93  gl_opengl_profile(profile),
94  gl_opengl_type(OpenGLVideo::StringToType(profile))
95 {
96  memset(&av_pause_frame, 0, sizeof(av_pause_frame));
97  av_pause_frame.buf = nullptr;
98 
99  if (gCoreContext->GetBoolSetting("UseVideoModes", false))
101 }
102 
104 {
105  gl_context_lock.lock();
106  TearDown();
107 
108  if (gl_context)
109  gl_context->DecrRef();
110  gl_context = nullptr;
111  gl_context_lock.unlock();
112 }
113 
115 {
116  gl_context_lock.lock();
120  gl_context_lock.unlock();
121 }
122 
124 {
125  bool result = CreateBuffers();
126  result &= CreatePauseFrame();
127  return result;
128 }
129 
131 {
132  bool result = SetupContext();
133  if (result)
134  {
135  QSize size = window.GetActualVideoDim();
136  InitDisplayMeasurements(size.width(), size.height(), false);
137  CreatePainter();
138  }
139  return result;
140 }
141 
143 {
144  bool result = SetupOpenGL();
145  MoveResize();
146  return result;
147 }
148 
150 {
151  gl_context_lock.lock();
152  DiscardFrames(true);
154  vbuffers.Reset();
155 
156  if (av_pause_frame.buf)
157  {
158  av_freep(&av_pause_frame.buf);
159  }
161  {
162  av_freep(&av_pause_frame.qscale_table);
163  }
164  gl_context_lock.unlock();
165 }
166 
168 {
169  gl_context_lock.lock();
170  if (gl_context)
172 
173 #ifdef USE_OPENGL_QT5
174  if (gl_created_painter)
175  {
176  QWidget *device = QWidget::find(gl_parent_win);
177  if (device)
178  device->setAttribute(Qt::WA_PaintOnScreen, false);
179  }
180 #endif
181 
182  if (gl_created_painter)
183  {
184  // Hack to ensure that the osd painter is not
185  // deleted while image load thread is still busy
186  // loading images with that painter
187  gl_painter->Teardown();
189  delete invalid_osd_painter;
191  }
192  else if (gl_painter)
193  gl_painter->SetSwapControl(true);
194 
195  gl_painter = nullptr;
196  gl_created_painter = false;
197 
198  if (gl_context)
200 
201  gl_context_lock.unlock();
202 }
203 
205 {
206  gl_context_lock.lock();
207  if (gl_context)
209 
210  if (gl_videochain)
211  {
212  delete gl_videochain;
213  gl_videochain = nullptr;
214  }
215 
216  while (!gl_pipchains.empty())
217  {
218  delete *gl_pipchains.begin();
219  gl_pipchains.erase(gl_pipchains.begin());
220  }
221  gl_pip_ready.clear();
222 
223  if (gl_context)
225  gl_context_lock.unlock();
226 }
227 
228 bool VideoOutputOpenGL::Init(const QSize &video_dim_buf,
229  const QSize &video_dim_disp,
230  float aspect, WId winid,
231  const QRect &win_rect, MythCodecID codec_id)
232 {
233  QMutexLocker locker(&gl_context_lock);
234  bool success = true;
236  gl_parent_win = winid;
237  success &= VideoOutput::Init(video_dim_buf, video_dim_disp,
238  aspect, winid,
239  win_rect, codec_id);
240  SetProfile();
242 
243  success &= CreateCPUResources();
244 
245  if (!gCoreContext->IsUIThread())
246  {
247  LOG(VB_GENERAL, LOG_NOTICE, LOC +
248  "Deferring creation of OpenGL resources");
249  gl_valid = false;
250  }
251  else
252  {
253  success &= CreateGPUResources();
254  success &= CreateVideoResources();
255  }
256 
257  if (!success)
258  TearDown();
259  return success;
260 }
261 
263 {
264  if (db_vdisp_profile)
266 }
267 
268 bool VideoOutputOpenGL::InputChanged(const QSize &video_dim_buf,
269  const QSize &video_dim_disp,
270  float aspect,
271  MythCodecID av_codec_id,
272  void */*codec_private*/,
273  bool &aspect_only)
274 {
275  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("InputChanged(%1,%2,%3) %4->%5")
276  .arg(video_dim_disp.width()).arg(video_dim_disp.height())
277  .arg(aspect)
278  .arg(toString(video_codec_id)).arg(toString(av_codec_id)));
279 
280  QMutexLocker locker(&gl_context_lock);
281 
282  // Ensure we don't lose embedding through program changes. This duplicates
283  // code in VideoOutput::Init but we need start here otherwise the embedding
284  // is lost during window re-initialistion.
285  bool wasembedding = window.IsEmbedding();
286  QRect oldrect;
287  if (wasembedding)
288  {
289  oldrect = window.GetEmbeddingRect();
290  StopEmbedding();
291  }
292 
293  if (!codec_is_std(av_codec_id)
294  && !codec_is_mediacodec(av_codec_id)
295  && !codec_is_vaapi2(av_codec_id))
296  {
297  LOG(VB_GENERAL, LOG_ERR, LOC + "New video codec is not supported.");
299  return false;
300  }
301 
302  bool cid_changed = (video_codec_id != av_codec_id);
303  bool res_changed = video_dim_disp != window.GetActualVideoDim();
304  bool asp_changed = aspect != window.GetVideoAspect();
305 
306  if (!res_changed && !cid_changed)
307  {
308  if (asp_changed)
309  {
310  aspect_only = true;
311  VideoAspectRatioChanged(aspect);
312  MoveResize();
313  }
314  if (wasembedding)
315  EmbedInWidget(oldrect);
316  return true;
317  }
318 
319  if (gCoreContext->IsUIThread())
320  TearDown();
321  else
323 
324  QRect disp = window.GetDisplayVisibleRect();
325  if (Init(video_dim_buf, video_dim_disp,
326  aspect, gl_parent_win, disp, av_codec_id))
327  {
328  if (wasembedding)
329  EmbedInWidget(oldrect);
330  if (gCoreContext->IsUIThread())
331  BestDeint();
332  return true;
333  }
334 
335  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to re-initialise video output.");
337 
338  return false;
339 }
340 
342 {
343  QMutexLocker locker(&gl_context_lock);
344 
345  if (gl_context)
346  {
347  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Re-using context"));
348  return true;
349  }
350 
352  if (!win)
353  {
354  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to get MythMainWindow");
355  return false;
356  }
357 
358  gl_context = dynamic_cast<MythRenderOpenGL*>(win->GetRenderDevice());
359  if (gl_context)
360  {
361  gl_context->IncrRef();
362  LOG(VB_PLAYBACK, LOG_INFO, LOC + "Using main UI render context");
363  return true;
364  }
365 
366  // This code does not work.
367  // Using OpenGL video renderer with QT Theme painter - the moment
368  // the code below calls gl_context->create() the main window disappears
369  // and after that the video renderer complains about rendering on a non
370  // visible window. The window never comes back and you have to kill
371  // the frontend.
372 
373 /*
374  QWidget *device = QWidget::find(gl_parent_win);
375  if (!device)
376  {
377  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to find parent to windowID");
378  return false;
379  }
380 
381  gl_context = MythRenderOpenGL::Create(QString(), device);
382  if (gl_context && gl_context->create())
383  {
384  gl_context->Init();
385  LOG(VB_GENERAL, LOG_INFO, LOC + "Created MythRenderOpenGL device.");
386  return true;
387  }
388 
389  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create MythRenderOpenGL device.");
390  if (gl_context)
391  gl_context->DecrRef();
392  gl_context = nullptr;
393 */
394  LOG(VB_GENERAL, LOG_ERR, LOC + "Unable to use OpenGL when ThemePainter is set to QT.");
395  return false;
396 }
397 
399 {
400  if (!gl_context)
401  return false;
402 
403  QRect dvr = window.GetDisplayVisibleRect();
404 
406  QSize mainSize = mainWin->size();
407 
408  // If the Video screen mode has vertically less pixels
409  // than the GUI screen mode - OpenGL coordinate adjustments
410  // must be made to put the video at the top of the display
411  // area instead of at the bottom.
412  if (dvr.height() < mainSize.height())
413  dvr.setTop(dvr.top()-mainSize.height()+dvr.height());
414 
415  // If the Video screen mode has horizontally less pixels
416  // than the GUI screen mode - OpenGL width must be set
417  // as the higher GUI width so that the Program Guide
418  // invoked from playback is not cut off.
419  if (dvr.width() < mainSize.width())
420  dvr.setWidth(mainSize.width());
421 
423  {
424  gl_context->SetViewPort(QRect(QPoint(),dvr.size()));
425  return true;
426  }
427 
429  {
430  QRect tmprect = QRect(QPoint(0,0), dvr.size());
431  ResizeDisplayWindow(tmprect, true);
432  }
433  bool success = false;
434  OpenGLLocker ctx_lock(gl_context);
435  gl_videochain = new OpenGLVideo();
436  QString options = GetFilters();
440  window.GetVideoDispDim(), dvr,
442  window.GetVideoRect(), true,
443  type, options);
444  if (success)
445  {
446  // check if the profile changed
448  {
451  }
452 
453  bool temp_deinterlacing = m_deinterlacing;
454  if (!m_deintfiltername.isEmpty() &&
455  !m_deintfiltername.contains("opengl"))
456  {
458  }
460  if (!temp_deinterlacing)
461  {
463  }
464  }
465 
466  return success;
467 }
468 
470 {
471  QMutexLocker locker(&gl_context_lock);
472 
473  gl_created_painter = false;
475  if (gl_context && !gl_context->IsShared())
476  {
477  QWidget *device = QWidget::find(gl_parent_win);
478  gl_painter = new MythOpenGLPainter(gl_context, device);
479  if (!gl_painter)
480  {
481  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create painter");
482  return;
483  }
484  gl_created_painter = true;
485 #ifdef USE_OPENGL_QT5
486  if (device)
487  device->setAttribute(Qt::WA_PaintOnScreen);
488 #endif
489  }
490  else
491  {
493  if (!gl_painter)
494  {
495  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to get painter");
496  return;
497  }
498  LOG(VB_PLAYBACK, LOG_INFO, LOC + "Using main UI painter");
499  }
500  gl_painter->SetSwapControl(false);
501 }
502 
504 {
505  QMutexLocker locker(&gl_context_lock);
507  // vbuffers.Init(4, true, 1, 2, 2, 1);
508  vbuffers.Init(8, true, 1, 4, 2, 1);
509  else
510  vbuffers.Init(31, true, 1, 12, 4, 2);
512  window.GetVideoDim().width(),
513  window.GetVideoDim().height());
514 }
515 
517 {
518  int size = buffersize(FMT_YV12,
521  unsigned char *buffer = (unsigned char *)av_malloc(size);
523  buffer,
526  size);
527 
529 
530  if (!av_pause_frame.buf)
531  return false;
532 
534  return true;
535 }
536 
538  FilterChain *filterList,
539  const PIPMap &pipPlayers,
541 {
542  QMutexLocker locker(&gl_context_lock);
543 
544  if (!gl_context)
545  return;
546 
547  if (!gl_valid)
548  {
549  if (!gCoreContext->IsUIThread())
550  {
551  LOG(VB_GENERAL, LOG_ERR, LOC +
552  "ProcessFrame called from wrong thread");
553  }
554  QSize size = window.GetActualVideoDim();
555  InitDisplayMeasurements(size.width(), size.height(), false);
558  BestDeint();
559  gl_valid = true;
560  }
561 
562  bool sw_frame = codec_sw_copy(video_codec_id) &&
564  bool deint_proc = m_deinterlacing && (m_deintFilter != nullptr);
565  OpenGLLocker ctx_lock(gl_context);
566 
567  bool pauseframe = false;
568  if (!frame)
569  {
570  frame = vbuffers.GetScratchFrame();
572  pauseframe = true;
573  }
574 
575  if (sw_frame)
576  {
577  CropToDisplay(frame);
578  }
579 
580  bool dummy = frame->dummy;
581  if (filterList && sw_frame && !dummy)
582  filterList->ProcessFrame(frame);
583 
584  bool safepauseframe = pauseframe && !IsBobDeint();
585  if (sw_frame && deint_proc && m_deinterlaceBeforeOSD &&
586  (!pauseframe || safepauseframe) && !dummy)
587  {
589  }
590 
591  if (!window.IsEmbedding())
592  {
593  gl_pipchain_active = nullptr;
594  ShowPIPs(frame, pipPlayers);
595  }
596 
597  if (sw_frame && (!pauseframe || safepauseframe) &&
598  deint_proc && !m_deinterlaceBeforeOSD && !dummy)
599  {
601  }
602 
603  if (gl_videochain && sw_frame && !dummy)
604  {
605  bool soft_bob = m_deinterlacing && (m_deintfiltername == "bobdeint");
606  gl_videochain->UpdateInputFrame(frame, soft_bob);
607  }
608 }
609 
611  OSD *osd)
612 {
613  if (!gl_context)
614  return;
615 
616  OpenGLLocker ctx_lock(gl_context);
617 
618  if (!buffer)
619  {
620  buffer = vbuffers.GetScratchFrame();
621  if (m_deinterlacing && !IsBobDeint())
623  }
624 
625  gl_context_lock.lock();
626  framesPlayed = buffer->frameNumber + 1;
627  gl_context_lock.unlock();
628 
631  gl_context->SetBackground(127, 127, 127, 255);
632  else
633  gl_context->SetBackground(0, 0, 0, 255);
635 
636  // stereoscopic views
637  QRect main = gl_context->GetViewPort();
638  QRect first = main;
639  QRect second = main;
640  bool twopass = (m_stereo == kStereoscopicModeSideBySide) ||
642 
644  {
645  first = QRect(main.left() / 2, main.top(),
646  main.width() / 2, main.height());
647  second = first.translated(main.width() / 2, 0);
648  }
650  {
651  first = QRect(main.left(), main.top() / 2,
652  main.width(), main.height() / 2);
653  second = first.translated(0, main.height() / 2);
654  }
655 
656  // main UI when embedded
658  if (mwnd && mwnd->GetPaintWindow() && window.IsEmbedding())
659  {
660  if (twopass)
661  gl_context->SetViewPort(first, true);
662  mwnd->GetPaintWindow()->clearMask();
663  // Must force a UI redraw when embedded. If not, when the EPG or
664  // finder screen is popped up over the video and the user then clicks
665  // away from Myth, the UI is left blank.
666  mwnd->GetMainStack()->GetTopScreen()->SetRedraw();
667  mwnd->draw(gl_painter);
668  if (twopass)
669  {
670  gl_context->SetViewPort(second, true);
671  mwnd->GetPaintWindow()->clearMask();
672  mwnd->GetMainStack()->GetTopScreen()->SetRedraw();
673  mwnd->draw(gl_painter);
674  gl_context->SetViewPort(main, true);
675  }
676  }
677 
678  // video
679  if (gl_videochain && !buffer->dummy)
680  {
683  window.GetVideoRect());
686  }
687 
688  // PiPs/PBPs
689  if (gl_pipchains.size())
690  {
691  QMap<MythPlayer*,OpenGLVideo*>::iterator it = gl_pipchains.begin();
692  for (; it != gl_pipchains.end(); ++it)
693  {
694  if (gl_pip_ready[it.key()])
695  {
696  bool active = gl_pipchain_active == *it;
697  if (twopass)
698  gl_context->SetViewPort(first, true);
699  (*it)->PrepareFrame(buffer->top_field_first, t,
701  kStereoscopicModeNone, active);
702  if (twopass)
703  {
704  gl_context->SetViewPort(second, true);
705  (*it)->PrepareFrame(buffer->top_field_first, t,
707  kStereoscopicModeNone, active);
709  }
710  }
711  }
712  }
713 
714  // visualisation
715  if (m_visual && gl_painter && !window.IsEmbedding())
716  {
717  if (twopass)
718  gl_context->SetViewPort(first, true);
720  if (twopass)
721  {
722  gl_context->SetViewPort(second, true);
725  }
726  }
727 
728  // OSD
729  if (osd && gl_painter && !window.IsEmbedding())
730  {
731  if (twopass)
732  gl_context->SetViewPort(first, true);
733  osd->DrawDirect(gl_painter, GetTotalOSDBounds().size(), true);
734  if (twopass)
735  {
736  gl_context->SetViewPort(second, true);
737  osd->DrawDirect(gl_painter, GetTotalOSDBounds().size(), true);
739  }
740  }
741 
742  gl_context->Flush(false);
743 
744  if (vbuffers.GetScratchFrame() == buffer)
746 }
747 
749 {
750  OpenGLLocker ctx_lock(gl_context);
751  if (IsErrored())
752  {
753  LOG(VB_GENERAL, LOG_ERR, LOC + "IsErrored() is true in Show()");
754  return;
755  }
756 
757  if (gl_context)
758  gl_context->swapBuffers();
759 }
760 
770 QStringList VideoOutputOpenGL::GetAllowedRenderers(MythCodecID myth_codec_id, const QSize&)
771 {
772  QStringList list;
773  if (!codec_sw_copy(myth_codec_id) || getenv("NO_OPENGL"))
774  return list;
775 
776  list << "opengl" << "opengl-lite" << "opengl-yv12" << "opengl-hquyv" << "opengl-rgba";
777  return list;
778 }
779 
781 {
782  QMutexLocker locker(&gl_context_lock);
783  VideoOutput::Zoom(direction);
784  MoveResize();
785 }
786 
788 {
789  QMutexLocker locker(&gl_context_lock);
791  if (gl_videochain)
792  {
795  window.GetVideoRect());
796  }
797 }
798 
799 void VideoOutputOpenGL::UpdatePauseFrame(int64_t &disp_timecode)
800 {
801  QMutexLocker locker(&gl_context_lock);
802  VideoFrame *used_frame = vbuffers.Head(kVideoBuffer_used);
803  if (!used_frame)
804  used_frame = vbuffers.GetScratchFrame();
805 
806  CopyFrame(&av_pause_frame, used_frame);
807  disp_timecode = av_pause_frame.disp_timecode;
808 }
809 
811 {
813  return;
814 
821 }
822 
824  int newValue)
825 {
826  if (!gl_context)
827  return -1;
828 
829  return VideoOutput::SetPictureAttribute(attribute, newValue);
830 }
831 
833  bool interlaced, const QString &overridefilter)
834 {
835  if (!gl_videochain || !gl_context)
836  return false;
837 
838  OpenGLLocker ctx_lock(gl_context);
839 
840  if (db_vdisp_profile)
842 
844  return false;
845 
846  if (!m_deintfiltername.contains("opengl"))
847  {
850  VideoOutput::SetupDeinterlace(interlaced, overridefilter);
851  if (m_deinterlacing)
853 
854  return m_deinterlacing;
855  }
856 
857  // clear any non opengl filters
858  if (m_deintFiltMan)
859  {
860  delete m_deintFiltMan;
861  m_deintFiltMan = nullptr;
862  }
863  if (m_deintFilter)
864  {
865  delete m_deintFilter;
866  m_deintFilter = nullptr;
867  }
868 
869  MoveResize();
870  m_deinterlacing = interlaced;
871 
872  if (m_deinterlacing && !m_deintfiltername.isEmpty())
873  {
875  {
877  {
878  LOG(VB_GENERAL, LOG_ERR, LOC +
879  QString("Couldn't load deinterlace filter %1")
880  .arg(m_deintfiltername));
881  m_deinterlacing = false;
882  m_deintfiltername = "";
883  }
884  else
885  {
886  LOG(VB_PLAYBACK, LOG_INFO, LOC +
887  QString("Using deinterlace method %1")
888  .arg(m_deintfiltername));
889  }
890  }
891  }
892 
894 
895  return m_deinterlacing;
896 }
897 
899 {
900  (void) enable;
901 
902  if (!gl_videochain || !gl_context)
903  return false;
904 
905  OpenGLLocker ctx_lock(gl_context);
906 
907  if (enable)
908  {
909  if (m_deintfiltername.isEmpty())
910  return SetupDeinterlace(enable);
911  if (m_deintfiltername.contains("opengl"))
912  {
913  if (gl_videochain->GetDeinterlacer().isEmpty())
914  return SetupDeinterlace(enable);
915  }
916  else if (!m_deintfiltername.contains("opengl"))
917  {
918  // make sure opengl deinterlacing is disabled
920 
921  if (!m_deintFiltMan || !m_deintFilter)
922  return VideoOutput::SetupDeinterlace(enable);
923  }
924  }
925 
926  MoveResize();
928 
929  m_deinterlacing = enable;
930 
931  return m_deinterlacing;
932 }
933 
935  MythPlayer *pipplayer,
936  PIPLocation loc)
937 {
938  if (!pipplayer)
939  return;
940 
941  int pipw, piph;
942  VideoFrame *pipimage = pipplayer->GetCurrentFrame(pipw, piph);
943  const float pipVideoAspect = pipplayer->GetVideoAspect();
944  const QSize pipVideoDim = pipplayer->GetVideoBufferSize();
945  const bool pipActive = pipplayer->IsPIPActive();
946  const bool pipVisible = pipplayer->IsPIPVisible();
947  const uint pipVideoWidth = pipVideoDim.width();
948  const uint pipVideoHeight = pipVideoDim.height();
949 
950  // If PiP is not initialized to values we like, silently ignore the frame.
951  if ((pipVideoAspect <= 0) || !pipimage ||
952  !pipimage->buf || pipimage->codec != FMT_YV12)
953  {
954  pipplayer->ReleaseCurrentFrame(pipimage);
955  return;
956  }
957 
958  if (!pipVisible)
959  {
960  pipplayer->ReleaseCurrentFrame(pipimage);
961  return;
962  }
963 
964  QRect position = GetPIPRect(loc, pipplayer);
965  QRect dvr = window.GetDisplayVisibleRect();
966 
967  gl_pip_ready[pipplayer] = false;
968  OpenGLVideo *gl_pipchain = gl_pipchains[pipplayer];
969  if (!gl_pipchain)
970  {
971  LOG(VB_PLAYBACK, LOG_INFO, LOC + "Initialise PiP.");
972  gl_pipchains[pipplayer] = gl_pipchain = new OpenGLVideo();
973  QString options = GetFilters();
974  bool success = gl_pipchain->Init(gl_context, &videoColourSpace,
975  pipVideoDim, pipVideoDim,
976  dvr, position,
977  QRect(0, 0, pipVideoWidth, pipVideoHeight),
978  false, gl_opengl_type, options);
979  QSize viewport = window.GetDisplayVisibleRect().size();
980  gl_pipchain->SetMasterViewport(viewport);
981  if (!success)
982  {
983  pipplayer->ReleaseCurrentFrame(pipimage);
984  return;
985  }
986  }
987 
988  QSize current = gl_pipchain->GetVideoSize();
989  if ((uint)current.width() != pipVideoWidth ||
990  (uint)current.height() != pipVideoHeight)
991  {
992  LOG(VB_PLAYBACK, LOG_INFO, LOC + "Re-initialise PiP.");
993  delete gl_pipchain;
994  gl_pipchains[pipplayer] = gl_pipchain = new OpenGLVideo();
995  QString options = GetFilters();
996  bool success = gl_pipchain->Init(
998  pipVideoDim, pipVideoDim, dvr, position,
999  QRect(0, 0, pipVideoWidth, pipVideoHeight),
1000  false, gl_opengl_type, options);
1001 
1002  QSize viewport = window.GetDisplayVisibleRect().size();
1003  gl_pipchain->SetMasterViewport(viewport);
1004 
1005  if (!success)
1006  {
1007  pipplayer->ReleaseCurrentFrame(pipimage);
1008  return;
1009  }
1010 
1011  }
1012  gl_pipchain->SetVideoRect(position,
1013  QRect(0, 0, pipVideoWidth, pipVideoHeight));
1014  gl_pipchain->UpdateInputFrame(pipimage);
1015 
1016  gl_pip_ready[pipplayer] = true;
1017 
1018  if (pipActive)
1019  gl_pipchain_active = gl_pipchain;
1020 
1021  pipplayer->ReleaseCurrentFrame(pipimage);
1022 }
1023 
1025 {
1026  if (!gl_pipchains.contains(pipplayer))
1027  return;
1028 
1029  OpenGLLocker ctx_lock(gl_context);
1030 
1031  OpenGLVideo *gl_pipchain = gl_pipchains[pipplayer];
1032  if (gl_pipchain)
1033  delete gl_pipchain;
1034  gl_pip_ready.remove(pipplayer);
1035  gl_pipchains.remove(pipplayer);
1036 }
1037 
1039 {
1040  if (gl_context)
1041  gl_context->MoveResizeWindow(new_rect);
1042 }
1043 
1044 void VideoOutputOpenGL::EmbedInWidget(const QRect &rect)
1045 {
1046  if (!window.IsEmbedding())
1048 
1049  MoveResize();
1050 }
1051 
1053 {
1054  if (!window.IsEmbedding())
1055  return;
1056 
1058  MoveResize();
1059 }
1060 
1061 bool VideoOutputOpenGL::ApproveDeintFilter(const QString& filtername) const
1062 {
1063  // anything OpenGL when using shaders
1064  if (filtername.contains("opengl") &&
1067  {
1068  return true;
1069  }
1070 
1071  // anything software based
1072  if (!filtername.contains("vdpau") && !filtername.contains("vaapi") && (OpenGLVideo::kGLGPU != gl_opengl_type))
1073  return true;
1074 
1075  return VideoOutput::ApproveDeintFilter(filtername);
1076 }
1077 
1079 {
1080  if (gl_context)
1083 }
1084 
1085 //virtual
1087 {
1088  return gl_painter;
1089 }
1090 
1091 // virtual
1093 {
1094  return VideoOutput::CanVisualise(audio, gl_context);
1095 }
1096 
1097 // virtual
1099  MythRender */*render*/, const QString &name)
1100 {
1102 }
static DisplayRes * GetDisplayRes(bool lock=false)
Factory method that returns a DisplayRes singleton.
Definition: DisplayRes.cpp:18
bool Init(const QSize &video_dim_buf, const QSize &video_dim_disp, float aspect, WId winid, const QRect &win_rect, MythCodecID codec_id) override
Performs most of the initialization for VideoOutput.
OpenGLVideo::VideoType gl_opengl_type
bool CreatePauseFrame(void)
void Reset(void)
Resets the class so that Init may be called again.
#define codec_sw_copy(id)
Definition: mythcodecid.h:134
virtual int SetPictureAttribute(PictureAttribute, int newValue)
Sets a specified picture attribute.
virtual void Teardown(void)
Definition: mythpainter.cpp:31
MythPainter * invalid_osd_painter
Definition: videooutbase.h:374
QString m_deintfiltername
Definition: videooutbase.h:351
float GetVideoAspect(void) const
Definition: mythplayer.h:175
void SetVideoRenderer(const QString &video_renderer)
void SetSwapControl(bool swap)
bool SetupDeinterlace(bool interlaced, const QString &overridefilter="") override
Attempts to enable or disable deinterlacing.
bool SetupVisualisation(AudioPlayer *audio, MythRender *render, const QString &name) override
virtual bool CanVisualise(AudioPlayer *audio, MythRender *render)
def scan(profile, smoonURL, gate)
Definition: scan.py:43
void SetLastShownFrameToScratch(void)
void StopEmbedding(void) override
Tells video output to stop embedding video in an existing window.
QMap< MythPlayer *, PIPLocation > PIPMap
Definition: videooutbase.h:37
VERBOSE_PREAMBLE Most true
Definition: verbosedefs.h:91
QMap< MythPlayer *, bool > gl_pip_ready
void UpdateInputFrame(const VideoFrame *frame, bool soft_bob=false)
Update the current input texture using the data from the given YV12 video frame.
bool CanVisualise(AudioPlayer *audio, MythRender *render) override
LetterBoxColour db_letterbox_colour
Definition: videooutbase.h:325
PictureAttributeSupported
QString toString(MarkTypes type)
static bool isCodecDeinterlacer(QString decodername)
void InitPictureAttributes(void) override
virtual bool IsBobDeint(void) const
#define LOC
bool m_deinterlacing
Definition: videooutbase.h:350
virtual void DiscardFrames(bool kf)
Releases all frames not being actively displayed from any queue onto the queue of frames ready for de...
Definition: videooutbase.h:227
MythCodecID
Definition: mythcodecid.h:10
bool IsShared(void) const
Warning: The reference count can be decremented between the call to this function and the use of it's...
VideoColourSpace videoColourSpace
Definition: videooutbase.h:322
void DestroyCPUResources(void)
void SetRedraw(void)
Definition: mythuitype.cpp:318
bool CreateVideoResources(void)
void SetVideoRect(const QRect &dispvidrect, const QRect &vidrect)
RenderType Type(void) const
static pid_list_t::iterator find(const PIDInfoMap &map, pid_list_t &list, pid_list_t::iterator begin, pid_list_t::iterator end, bool find_open)
virtual void TearDown(void)
QString GetFilteredDeint(const QString &override)
static MythMainWindow * getMainWindow(const bool useDB=true)
Return the existing main window, or create one.
QRect GetVideoRect(void) const
virtual bool Init(const QSize &video_dim_buf, const QSize &video_dim_disp, float aspect, WId winid, const QRect &win_rect, MythCodecID codec_id)
Performs most of the initialization for VideoOutput.
QRect GetTotalOSDBounds(void) const
Returns total OSD bounds.
VideoFrame * GetCurrentFrame(int &w, int &h)
QMap< MythPlayer *, OpenGLVideo * > gl_pipchains
void CropToDisplay(VideoFrame *frame)
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 ...
bool CreateGPUResources(void)
unsigned int uint
Definition: compat.h:140
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
void SetSoftwareDeinterlacer(const QString &filter)
virtual void StopEmbedding(void)
Tells video output to stop embedding video in an existing window.
MythScreenStack * GetMainStack()
static QStringList GetAllowedRenderers(MythCodecID myth_codec_id, const QSize &video_dim)
Generate a list of supported OpenGL profiles.
void ProcessFrame(VideoFrame *Frame, FrameScanType scan=kScan_Ignore)
int SetPictureAttribute(PictureAttribute attribute, int newValue) override
Sets a specified picture attribute.
void ProcessFrame(VideoFrame *frame, OSD *osd, FilterChain *filterList, const PIPMap &pipPlayers, FrameScanType scan) override
VideoVisual * m_visual
Definition: videooutbase.h:377
VideoDisplayProfile * db_vdisp_profile
Definition: videooutbase.h:330
virtual void Show(FrameScanType) override
void SetDeinterlacing(bool deinterlacing)
bool CreateCPUResources(void)
unsigned char * qscale_table
Definition: mythframe.h:54
virtual void EmbedInWidget(const QRect &rect)
Tells video output to embed video in an existing window.
void SetBackground(int r, int g, int b, int a)
static void init(VideoFrame *vf, VideoFrameType _codec, unsigned char *_buf, int _width, int _height, int _size, const int *p=nullptr, const int *o=nullptr, float _aspect=-1.0f, double _rate=-1.0f, int _aligned=64)
Definition: mythframe.h:109
long long framesPlayed
Definition: videooutbase.h:361
OpenGLVideo * gl_pipchain_active
bool CreateBuffers(VideoFrameType type, int width, int height, vector< unsigned char * > bufs, vector< YUVInfo > yuvinfo)
void ShowPIP(VideoFrame *frame, MythPlayer *pipplayer, PIPLocation loc) override
Composites PiP image onto a video frame.
void DestroyGPUResources(void)
virtual void ShowPIPs(VideoFrame *frame, const PIPMap &pipPlayers)
This class serves as the base class for all video output methods.
Definition: videooutbase.h:46
virtual ~VideoOutputOpenGL()
QString GetFilters(void) const
void MoveResize(void) override
performs all the calculations for video framing and any resizing.
static void CopyFrame(VideoFrame *to, const VideoFrame *from)
Copies frame data from one VideoFrame to another.
virtual int IncrRef(void)
Increments reference count.
virtual bool CreateBuffers(void)
void Flush(bool use_fence)
VERBOSE_PREAMBLE false
Definition: verbosedefs.h:85
void doneCurrent() override
void PrepareFrame(VideoFrame *buffer, FrameScanType, OSD *osd) override
VideoType GetType()
Definition: openglvideo.h:83
VideoBuffers vbuffers
VideoBuffers instance used to track video output buffers.
Definition: videooutbase.h:357
virtual MythScreenType * GetTopScreen(void) const
static void clear(SettingsMap &cache, SettingsMap &overrides, const QString &myKey)
Definition: mythdb.cpp:830
QSize GetVideoSize(void) const
Definition: openglvideo.h:80
void ReleaseCurrentFrame(VideoFrame *frame)
int height
Definition: mythframe.h:42
MythCodecID video_codec_id
Definition: videooutbase.h:329
QRect GetEmbeddingRect(void) const
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:10
void Zoom(ZoomDirection direction) override
Sets up zooming into to different parts of the video, the zoom is actually applied in MoveResize().
VideoErrorState errorState
Definition: videooutbase.h:360
virtual void BestDeint(void)
Change to the best deinterlacing method.
unsigned char t
Definition: ParseText.cpp:340
QWidget * GetPaintWindow()
virtual int DecrRef(void)
Decrements reference count and deletes on 0.
bool DrawDirect(MythPainter *painter, QSize size, bool repaint=false)
Definition: osd.cpp:671
void InitDisplayMeasurements(uint width, uint height, bool resize)
Init display measurements based on database settings and actual screen parameters.
bool IsEmbedding(void) const
Returns if videooutput is embedding.
long long frameNumber
Definition: mythframe.h:48
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...
OpenGLVideo * gl_videochain
PictureAttribute
Definition: videoouttypes.h:89
QRect vsz_desired_display_rect
Definition: videooutbase.h:343
QSize GetVideoDispDim(void) const
QRect GetDisplayVideoRect(void) const
int top_field_first
1 if top field is first.
Definition: mythframe.h:58
MythPainter * GetCurrentPainter()
#define codec_is_mediacodec(id)
Definition: mythcodecid.h:129
const char * name
Definition: ParseText.cpp:339
virtual void ResizeDisplayWindow(const QRect &, bool)
Resize Display Window.
MythRenderOpenGL * gl_context
void MoveResizeWindow(const QRect &rect)
bool IsErrored() const
Returns true if a fatal error has been encountered.
Definition: videooutbase.h:179
void * av_malloc(unsigned int size)
bool vsz_enabled
Definition: videooutbase.h:342
MythPainter * GetOSDPainter(void) override
bool SetDeinterlacingEnabled(bool) override
Attempts to enable/disable deinterlacing using existing deinterlace method when enabling.
MythRender * GetRenderDevice()
virtual QStringList GetVisualiserList(void)
MythMainWindow * GetMythMainWindow(void)
PIPState GetPIPState(void) const
DisplayRes * display_res
Definition: videooutbase.h:364
A class used to display video frames and associated imagery using the OpenGL API.
Definition: openglvideo.h:19
PIPLocation
Definition: videoouttypes.h:19
VideoFrame * GetScratchFrame(void)
QRect GetViewPort(void)
void makeCurrent() override
VideoOutputOpenGL(const QString &profile=QString())
void SetViewPort(const QRect &rect, bool viewportonly=false)
void EmbedInWidget(const QRect &rect) override
Tells video output to embed video in an existing window.
static MythMainWindow * mainWin
QSize GetActualVideoDim(void) const
QStringList GetVisualiserList(void) override
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
void UpdatePauseFrame(int64_t &disp_timecode) override
Updates frame displayed when video is paused.
QSize GetVideoBufferSize(void) const
Definition: mythplayer.h:173
int64_t disp_timecode
Definition: mythframe.h:50
bool GetBoolSetting(const QString &key, bool defaultval=false)
virtual bool ApproveDeintFilter(const QString &filtername) const
Approves bobdeint filter for XVideo and otherwise defers to VideoOutput::ApproveDeintFilter(const QSt...
virtual void SetProfile(void)
StereoscopicMode m_stereo
Definition: videooutbase.h:380
static QStringList GetVisualiserList(RenderType type)
Definition: videovisual.cpp:16
virtual QRect GetPIPRect(PIPLocation location, MythPlayer *pipplayer=nullptr, bool do_pixel_adj=true) const
returns QRect of PIP based on PIPLocation
VideoFrame * Head(BufferType)
virtual void VideoAspectRatioChanged(float aspect)
Calls SetVideoAspectRatio(float aspect), then calls MoveResize() to apply changes.
virtual void Zoom(ZoomDirection direction)
Sets up zooming into to different parts of the video, the zoom is actually applied in MoveResize().
void SetSupportedAttributes(PictureAttributeSupported supported)
virtual void MoveResize(void)
performs all the calculations for video framing and any resizing.
static void GetRenderOptions(render_opts &opts, QStringList &cpudeints)
Generate the list of available OpenGL profiles.
QString GetDeinterlacer(void) const
Definition: openglvideo.h:68
void draw(MythPainter *painter=nullptr)
Definition: osd.h:132
float GetVideoAspect(void) const
void SetMasterViewport(QSize size)
Definition: openglvideo.h:77
virtual void Draw(const QRect &area, MythPainter *painter, QPaintDevice *device)=0
QRect GetDisplayVisibleRect(void) const
FilterChain * m_deintFilter
Definition: videooutbase.h:353
void DestroyVideoResources(void)
static QString TypeToString(VideoType Type)
#define codec_is_vaapi2(id)
Definition: mythcodecid.h:131
void SetAllowPreviewEPG(bool allowPreviewEPG)
bool InputChanged(const QSize &video_dim_buf, const QSize &video_dim_disp, float aspect, MythCodecID av_codec_id, void *codec_private, bool &aspect_only) override
Tells video output to discard decoded frames and wait for new ones.
QSize GetVideoDim(void) const
void RemovePIP(MythPlayer *pipplayer) override
static uint buffersize(VideoFrameType type, int width, int height, int _aligned=64)
Definition: mythframe.h:291
bool IsPIPVisible(void) const
Definition: mythplayer.h:229
VideoOutWindow window
Definition: videooutbase.h:320
bool m_deinterlaceBeforeOSD
Definition: videooutbase.h:354
FilterManager * m_deintFiltMan
Definition: videooutbase.h:352
bool ApproveDeintFilter(const QString &filtername) const override
Approves bobdeint filter for XVideo and otherwise defers to VideoOutput::ApproveDeintFilter(const QSt...
void Init(uint numdecode, bool extra_for_pause, uint need_free, uint needprebuffer_normal, uint needprebuffer_small, uint keepprebuffer)
Creates buffers and sets various buffer management parameters.
virtual bool SetupDeinterlace(bool interlaced, const QString &overridefilter="")
Attempts to enable or disable deinterlacing.
unsigned char * buf
Definition: mythframe.h:39
ZoomDirection
Definition: videoouttypes.h:28
virtual bool SetupVisualisation(AudioPlayer *audio, MythRender *render, const QString &name)
void DeleteBuffers(void)
void BindFramebuffer(uint fb)
void MoveResizeWindow(QRect new_rect) override
MythOpenGLPainter * gl_painter
bool Init(MythRenderOpenGL *glcontext, VideoColourSpace *colourspace, QSize videoDim, QSize videoDispDim, QRect displayVisibleRect, QRect displayVideoRect, QRect videoRect, bool viewport_control, VideoType type, QString options)
#define codec_is_std(id)
Definition: mythcodecid.h:112
VideoFrame av_pause_frame
bool IsPIPActive(void) const
Definition: mythplayer.h:228
VideoFrameType codec
Definition: mythframe.h:38