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  if (opts.decoders->contains("nvdec"))
53  (*opts.safe_renderers)["nvdec"].append(safe);
54 
55  // OpenGL UYVY
56  opts.renderers->append("opengl");
57  opts.deints->insert("opengl", cpudeints + gldeints);
58  (*opts.deints)["opengl"].append("bobdeint");
59  (*opts.osds)["opengl"].append("opengl2");
60  opts.priorities->insert("opengl", 65);
61 
62  // OpenGL HQ UYV
63  opts.renderers->append("opengl-hquyv");
64  opts.deints->insert("opengl-hquyv", cpudeints + gldeints);
65  (*opts.deints)["opengl-hquyv"].append("bobdeint");
66  (*opts.osds)["opengl-hquyv"].append("opengl2");
67  opts.priorities->insert("opengl-hquyv", 60);
68 
69  // OpenGL YV12
70  opts.renderers->append("opengl-yv12");
71  opts.deints->insert("opengl-yv12", cpudeints + gldeints);
72  (*opts.deints)["opengl-yv12"].append("bobdeint");
73  (*opts.osds)["opengl-yv12"].append("opengl2");
74  opts.priorities->insert("opengl-yv12", 65);
75 
76  // lite (YCbCr) profile - no colourspace control, GPU deinterlacing
77  opts.renderers->append("opengl-lite");
78  opts.deints->insert("opengl-lite", cpudeints);
79  (*opts.deints)["opengl-lite"].append("bobdeint");
80  (*opts.osds)["opengl-lite"].append("opengl2");
81  opts.priorities->insert("opengl-lite", 50);
82 
83  // software fallback
84  opts.renderers->append("opengl-rgba");
85  opts.deints->insert("opengl-rgba", cpudeints);
86  (*opts.osds)["opengl-rgba"].append("opengl2");
87  opts.priorities->insert("opengl-rgba", 10);
88 }
89 
91  : gl_context_lock(QMutex::Recursive), gl_context(nullptr), gl_valid(true),
92  gl_videochain(nullptr), gl_pipchain_active(nullptr),
93  gl_parent_win(0), gl_painter(nullptr), gl_created_painter(false),
94  gl_opengl_profile(profile),
95  gl_opengl_type(OpenGLVideo::StringToType(profile))
96 {
97  memset(&av_pause_frame, 0, sizeof(av_pause_frame));
98  av_pause_frame.buf = nullptr;
99 
100  if (gCoreContext->GetBoolSetting("UseVideoModes", false))
102 }
103 
105 {
106  gl_context_lock.lock();
108 
109  if (gl_context)
110  gl_context->DecrRef();
111  gl_context = nullptr;
112  gl_context_lock.unlock();
113 }
114 
116 {
117  gl_context_lock.lock();
121  gl_context_lock.unlock();
122 }
123 
125 {
126  bool result = CreateBuffers();
127  result &= CreatePauseFrame();
128  return result;
129 }
130 
132 {
133  bool result = SetupContext();
134  if (result)
135  {
136  QSize size = window.GetActualVideoDim();
137  InitDisplayMeasurements(size.width(), size.height(), false);
138  CreatePainter();
139  }
140  return result;
141 }
142 
144 {
145  bool result = SetupOpenGL();
146  MoveResize();
147  return result;
148 }
149 
151 {
152  gl_context_lock.lock();
153  DiscardFrames(true);
155  vbuffers.Reset();
156 
157  if (av_pause_frame.buf)
158  {
159  av_freep(&av_pause_frame.buf);
160  }
162  {
163  av_freep(&av_pause_frame.qscale_table);
164  }
165  gl_context_lock.unlock();
166 }
167 
169 {
170  gl_context_lock.lock();
171  if (gl_context)
173 
174 #ifdef USE_OPENGL_QT5
175  if (gl_created_painter)
176  {
177  QWidget *device = QWidget::find(gl_parent_win);
178  if (device)
179  device->setAttribute(Qt::WA_PaintOnScreen, false);
180  }
181 #endif
182 
183  if (gl_created_painter)
184  {
185  // Hack to ensure that the osd painter is not
186  // deleted while image load thread is still busy
187  // loading images with that painter
188  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  && !codec_is_nvdec(av_codec_id))
297  {
298  LOG(VB_GENERAL, LOG_ERR, LOC + "New video codec is not supported.");
300  return false;
301  }
302 
303  bool cid_changed = (video_codec_id != av_codec_id);
304  bool res_changed = video_dim_disp != window.GetActualVideoDim();
305  bool asp_changed = aspect != window.GetVideoAspect();
306 
307  if (!res_changed && !cid_changed)
308  {
309  if (asp_changed)
310  {
311  aspect_only = true;
312  VideoAspectRatioChanged(aspect);
313  MoveResize();
314  }
315  if (wasembedding)
316  EmbedInWidget(oldrect);
317  return true;
318  }
319 
320  if (gCoreContext->IsUIThread())
321  TearDown();
322  else
324 
325  QRect disp = window.GetDisplayVisibleRect();
326  if (Init(video_dim_buf, video_dim_disp,
327  aspect, gl_parent_win, disp, av_codec_id))
328  {
329  if (wasembedding)
330  EmbedInWidget(oldrect);
331  if (gCoreContext->IsUIThread())
332  BestDeint();
333  return true;
334  }
335 
336  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to re-initialise video output.");
338 
339  return false;
340 }
341 
343 {
344  QMutexLocker locker(&gl_context_lock);
345 
346  if (gl_context)
347  {
348  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Re-using context"));
349  return true;
350  }
351 
353  if (!win)
354  {
355  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to get MythMainWindow");
356  return false;
357  }
358 
359  gl_context = dynamic_cast<MythRenderOpenGL*>(win->GetRenderDevice());
360  if (gl_context)
361  {
362  gl_context->IncrRef();
363  LOG(VB_PLAYBACK, LOG_INFO, LOC + "Using main UI render context");
364  return true;
365  }
366 
367  // This code does not work.
368  // Using OpenGL video renderer with QT Theme painter - the moment
369  // the code below calls gl_context->create() the main window disappears
370  // and after that the video renderer complains about rendering on a non
371  // visible window. The window never comes back and you have to kill
372  // the frontend.
373 
374 /*
375  QWidget *device = QWidget::find(gl_parent_win);
376  if (!device)
377  {
378  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to find parent to windowID");
379  return false;
380  }
381 
382  gl_context = MythRenderOpenGL::Create(QString(), device);
383  if (gl_context && gl_context->create())
384  {
385  gl_context->Init();
386  LOG(VB_GENERAL, LOG_INFO, LOC + "Created MythRenderOpenGL device.");
387  return true;
388  }
389 
390  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create MythRenderOpenGL device.");
391  if (gl_context)
392  gl_context->DecrRef();
393  gl_context = nullptr;
394 */
395  LOG(VB_GENERAL, LOG_ERR, LOC + "Unable to use OpenGL when ThemePainter is set to QT.");
396  return false;
397 }
398 
400 {
401  if (!gl_context)
402  return false;
403 
404  QRect dvr = window.GetDisplayVisibleRect();
405 
407  QSize mainSize = mainWin->size();
408 
409  // If the Video screen mode has vertically less pixels
410  // than the GUI screen mode - OpenGL coordinate adjustments
411  // must be made to put the video at the top of the display
412  // area instead of at the bottom.
413  if (dvr.height() < mainSize.height())
414  dvr.setTop(dvr.top()-mainSize.height()+dvr.height());
415 
416  // If the Video screen mode has horizontally less pixels
417  // than the GUI screen mode - OpenGL width must be set
418  // as the higher GUI width so that the Program Guide
419  // invoked from playback is not cut off.
420  if (dvr.width() < mainSize.width())
421  dvr.setWidth(mainSize.width());
422 
424  {
425  gl_context->SetViewPort(QRect(QPoint(),dvr.size()));
426  return true;
427  }
428 
430  {
431  QRect tmprect = QRect(QPoint(0,0), dvr.size());
432  ResizeDisplayWindow(tmprect, true);
433  }
434  bool success = false;
435  OpenGLLocker ctx_lock(gl_context);
436  gl_videochain = new OpenGLVideo();
437  QString options = GetFilters();
441  window.GetVideoDispDim(), dvr,
443  window.GetVideoRect(), true,
444  type, options);
445  if (success)
446  {
447  // check if the profile changed
449  {
452  }
453 
454  bool temp_deinterlacing = m_deinterlacing;
455  if (!m_deintfiltername.isEmpty() &&
456  !m_deintfiltername.contains("opengl"))
457  {
459  }
461  if (!temp_deinterlacing)
462  {
464  }
465  }
466 
467  return success;
468 }
469 
471 {
472  QMutexLocker locker(&gl_context_lock);
473 
474  gl_created_painter = false;
476  if (gl_context && !gl_context->IsShared())
477  {
478  QWidget *device = QWidget::find(gl_parent_win);
479  gl_painter = new MythOpenGLPainter(gl_context, device);
480  if (!gl_painter)
481  {
482  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create painter");
483  return;
484  }
485  gl_created_painter = true;
486 #ifdef USE_OPENGL_QT5
487  if (device)
488  device->setAttribute(Qt::WA_PaintOnScreen);
489 #endif
490  }
491  else
492  {
494  if (!gl_painter)
495  {
496  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to get painter");
497  return;
498  }
499  LOG(VB_PLAYBACK, LOG_INFO, LOC + "Using main UI painter");
500  }
501  gl_painter->SetSwapControl(false);
502 }
503 
505 {
506  QMutexLocker locker(&gl_context_lock);
508  // vbuffers.Init(4, true, 1, 2, 2, 1);
509  vbuffers.Init(8, true, 1, 4, 2, 1);
510  else
511  vbuffers.Init(31, true, 1, 12, 4, 2);
513  window.GetVideoDim().width(),
514  window.GetVideoDim().height());
515 }
516 
518 {
519  int size = buffersize(FMT_YV12,
522  unsigned char *buffer = (unsigned char *)av_malloc(size);
524  buffer,
527  size);
528 
530 
531  if (!av_pause_frame.buf)
532  return false;
533 
535  return true;
536 }
537 
539  FilterChain *filterList,
540  const PIPMap &pipPlayers,
542 {
543  QMutexLocker locker(&gl_context_lock);
544 
545  if (!gl_context)
546  return;
547 
548  if (!gl_valid)
549  {
550  if (!gCoreContext->IsUIThread())
551  {
552  LOG(VB_GENERAL, LOG_ERR, LOC +
553  "ProcessFrame called from wrong thread");
554  }
555  QSize size = window.GetActualVideoDim();
556  InitDisplayMeasurements(size.width(), size.height(), false);
559  BestDeint();
560  gl_valid = true;
561  }
562 
563  bool sw_frame = codec_sw_copy(video_codec_id) &&
565  bool deint_proc = m_deinterlacing && (m_deintFilter != nullptr);
566  OpenGLLocker ctx_lock(gl_context);
567 
568  bool pauseframe = false;
569  if (!frame)
570  {
571  frame = vbuffers.GetScratchFrame();
573  pauseframe = true;
574  }
575 
576  if (sw_frame)
577  {
578  CropToDisplay(frame);
579  }
580 
581  bool dummy = frame->dummy;
582  if (filterList && sw_frame && !dummy)
583  filterList->ProcessFrame(frame);
584 
585  bool safepauseframe = pauseframe && !IsBobDeint();
586  if (sw_frame && deint_proc && m_deinterlaceBeforeOSD &&
587  (!pauseframe || safepauseframe) && !dummy)
588  {
590  }
591 
592  if (!window.IsEmbedding())
593  {
594  gl_pipchain_active = nullptr;
595  ShowPIPs(frame, pipPlayers);
596  }
597 
598  if (sw_frame && (!pauseframe || safepauseframe) &&
599  deint_proc && !m_deinterlaceBeforeOSD && !dummy)
600  {
602  }
603 
604  if (gl_videochain && sw_frame && !dummy)
605  {
606  bool soft_bob = m_deinterlacing && (m_deintfiltername == "bobdeint");
607  gl_videochain->UpdateInputFrame(frame, soft_bob);
608  }
609 }
610 
612  OSD *osd)
613 {
614  if (!gl_context)
615  return;
616 
617  OpenGLLocker ctx_lock(gl_context);
618 
619  bool dummy = false;
620  gl_context_lock.lock();
621  if (buffer)
622  {
623  framesPlayed = buffer->frameNumber + 1;
624  dummy = buffer->dummy;
625  }
626  gl_context_lock.unlock();
627 
628  if (!buffer)
629  {
630  buffer = vbuffers.GetScratchFrame();
631  if (m_deinterlacing && !IsBobDeint())
633  }
634 
637  gl_context->SetBackground(127, 127, 127, 255);
638  else
639  gl_context->SetBackground(0, 0, 0, 255);
641 
642  // stereoscopic views
643  QRect main = gl_context->GetViewPort();
644  QRect first = main;
645  QRect second = main;
646  bool twopass = (m_stereo == kStereoscopicModeSideBySide) ||
648 
650  {
651  first = QRect(main.left() / 2, main.top(),
652  main.width() / 2, main.height());
653  second = first.translated(main.width() / 2, 0);
654  }
656  {
657  first = QRect(main.left(), main.top() / 2,
658  main.width(), main.height() / 2);
659  second = first.translated(0, main.height() / 2);
660  }
661 
662  // main UI when embedded
664  if (mwnd && mwnd->GetPaintWindow() && window.IsEmbedding())
665  {
666  if (twopass)
667  gl_context->SetViewPort(first, true);
668  mwnd->GetPaintWindow()->clearMask();
669  // Must force a UI redraw when embedded. If not, when the EPG or
670  // finder screen is popped up over the video and the user then clicks
671  // away from Myth, the UI is left blank.
672  mwnd->GetMainStack()->GetTopScreen()->SetRedraw();
673  mwnd->draw(gl_painter);
674  if (twopass)
675  {
676  gl_context->SetViewPort(second, true);
677  mwnd->GetPaintWindow()->clearMask();
678  mwnd->GetMainStack()->GetTopScreen()->SetRedraw();
679  mwnd->draw(gl_painter);
680  gl_context->SetViewPort(main, true);
681  }
682  }
683 
684  // video
685  if (gl_videochain && !dummy)
686  {
689  window.GetVideoRect());
692  }
693 
694  // PiPs/PBPs
695  if (!gl_pipchains.empty())
696  {
697  QMap<MythPlayer*,OpenGLVideo*>::iterator it = gl_pipchains.begin();
698  for (; it != gl_pipchains.end(); ++it)
699  {
700  if (gl_pip_ready[it.key()])
701  {
702  bool active = gl_pipchain_active == *it;
703  if (twopass)
704  gl_context->SetViewPort(first, true);
705  (*it)->PrepareFrame(buffer->top_field_first, t,
707  kStereoscopicModeNone, active);
708  if (twopass)
709  {
710  gl_context->SetViewPort(second, true);
711  (*it)->PrepareFrame(buffer->top_field_first, t,
713  kStereoscopicModeNone, active);
715  }
716  }
717  }
718  }
719 
720  // visualisation
721  if (m_visual && gl_painter && !window.IsEmbedding())
722  {
723  if (twopass)
724  gl_context->SetViewPort(first, true);
726  if (twopass)
727  {
728  gl_context->SetViewPort(second, true);
731  }
732  }
733 
734  // OSD
735  if (osd && gl_painter && !window.IsEmbedding())
736  {
737  if (twopass)
738  gl_context->SetViewPort(first, true);
739  osd->DrawDirect(gl_painter, GetTotalOSDBounds().size(), true);
740  if (twopass)
741  {
742  gl_context->SetViewPort(second, true);
743  osd->DrawDirect(gl_painter, GetTotalOSDBounds().size(), true);
745  }
746  }
747 
748  gl_context->Flush(false);
749 }
750 
752 {
753  OpenGLLocker ctx_lock(gl_context);
754  if (IsErrored())
755  {
756  LOG(VB_GENERAL, LOG_ERR, LOC + "IsErrored() is true in Show()");
757  return;
758  }
759 
760  if (gl_context)
761  gl_context->swapBuffers();
762 }
763 
773 QStringList VideoOutputOpenGL::GetAllowedRenderers(MythCodecID myth_codec_id, const QSize& /*video_dim*/)
774 {
775  QStringList list;
776  if (!codec_sw_copy(myth_codec_id) || getenv("NO_OPENGL"))
777  return list;
778 
779  list << "opengl" << "opengl-lite" << "opengl-yv12" << "opengl-hquyv" << "opengl-rgba";
780  return list;
781 }
782 
784 {
785  QMutexLocker locker(&gl_context_lock);
786  VideoOutput::Zoom(direction);
787  MoveResize();
788 }
789 
791 {
792  QMutexLocker locker(&gl_context_lock);
794  if (gl_videochain)
795  {
798  window.GetVideoRect());
799  }
800 }
801 
802 void VideoOutputOpenGL::UpdatePauseFrame(int64_t &disp_timecode)
803 {
804  QMutexLocker locker(&gl_context_lock);
805  VideoFrame *used_frame = vbuffers.Head(kVideoBuffer_used);
806  if (!used_frame)
807  used_frame = vbuffers.GetScratchFrame();
808 
809  CopyFrame(&av_pause_frame, used_frame);
810  disp_timecode = av_pause_frame.disp_timecode;
811 }
812 
814 {
816  return;
817 
824 }
825 
827  int newValue)
828 {
829  if (!gl_context)
830  return -1;
831 
832  return VideoOutput::SetPictureAttribute(attribute, newValue);
833 }
834 
836  bool interlaced, const QString &overridefilter)
837 {
838  if (!gl_videochain || !gl_context)
839  return false;
840 
841  OpenGLLocker ctx_lock(gl_context);
842 
843  if (db_vdisp_profile)
845 
847  return false;
848 
849  if (!m_deintfiltername.contains("opengl"))
850  {
853  VideoOutput::SetupDeinterlace(interlaced, overridefilter);
854  if (m_deinterlacing)
856 
857  return m_deinterlacing;
858  }
859 
860  // clear any non opengl filters
861  if (m_deintFiltMan)
862  {
863  delete m_deintFiltMan;
864  m_deintFiltMan = nullptr;
865  }
866  if (m_deintFilter)
867  {
868  delete m_deintFilter;
869  m_deintFilter = nullptr;
870  }
871 
872  MoveResize();
873  m_deinterlacing = interlaced;
874 
875  if (m_deinterlacing && !m_deintfiltername.isEmpty())
876  {
878  {
880  {
881  LOG(VB_GENERAL, LOG_ERR, LOC +
882  QString("Couldn't load deinterlace filter %1")
883  .arg(m_deintfiltername));
884  m_deinterlacing = false;
885  m_deintfiltername = "";
886  }
887  else
888  {
889  LOG(VB_PLAYBACK, LOG_INFO, LOC +
890  QString("Using deinterlace method %1")
891  .arg(m_deintfiltername));
892  }
893  }
894  }
895 
897 
898  return m_deinterlacing;
899 }
900 
902 {
903  (void) enable;
904 
905  if (!gl_videochain || !gl_context)
906  return false;
907 
908  OpenGLLocker ctx_lock(gl_context);
909 
910  if (enable)
911  {
912  if (m_deintfiltername.isEmpty())
913  return SetupDeinterlace(enable);
914  if (m_deintfiltername.contains("opengl"))
915  {
916  if (gl_videochain->GetDeinterlacer().isEmpty())
917  return SetupDeinterlace(enable);
918  }
919  else if (!m_deintfiltername.contains("opengl"))
920  {
921  // make sure opengl deinterlacing is disabled
923 
924  if (!m_deintFiltMan || !m_deintFilter)
925  return VideoOutput::SetupDeinterlace(enable);
926  }
927  }
928 
929  MoveResize();
931 
932  m_deinterlacing = enable;
933 
934  return m_deinterlacing;
935 }
936 
938  MythPlayer *pipplayer,
939  PIPLocation loc)
940 {
941  if (!pipplayer)
942  return;
943 
944  int pipw, piph;
945  VideoFrame *pipimage = pipplayer->GetCurrentFrame(pipw, piph);
946  const float pipVideoAspect = pipplayer->GetVideoAspect();
947  const QSize pipVideoDim = pipplayer->GetVideoBufferSize();
948  const bool pipActive = pipplayer->IsPIPActive();
949  const bool pipVisible = pipplayer->IsPIPVisible();
950  const uint pipVideoWidth = pipVideoDim.width();
951  const uint pipVideoHeight = pipVideoDim.height();
952 
953  // If PiP is not initialized to values we like, silently ignore the frame.
954  if ((pipVideoAspect <= 0) || !pipimage ||
955  !pipimage->buf || pipimage->codec != FMT_YV12)
956  {
957  pipplayer->ReleaseCurrentFrame(pipimage);
958  return;
959  }
960 
961  if (!pipVisible)
962  {
963  pipplayer->ReleaseCurrentFrame(pipimage);
964  return;
965  }
966 
967  QRect position = GetPIPRect(loc, pipplayer);
968  QRect dvr = window.GetDisplayVisibleRect();
969 
970  gl_pip_ready[pipplayer] = false;
971  OpenGLVideo *gl_pipchain = gl_pipchains[pipplayer];
972  if (!gl_pipchain)
973  {
974  LOG(VB_PLAYBACK, LOG_INFO, LOC + "Initialise PiP.");
975  gl_pipchains[pipplayer] = gl_pipchain = new OpenGLVideo();
976  QString options = GetFilters();
977  bool success = gl_pipchain->Init(gl_context, &videoColourSpace,
978  pipVideoDim, pipVideoDim,
979  dvr, position,
980  QRect(0, 0, pipVideoWidth, pipVideoHeight),
981  false, gl_opengl_type, options);
982  QSize viewport = window.GetDisplayVisibleRect().size();
983  gl_pipchain->SetMasterViewport(viewport);
984  if (!success)
985  {
986  pipplayer->ReleaseCurrentFrame(pipimage);
987  return;
988  }
989  }
990 
991  QSize current = gl_pipchain->GetVideoSize();
992  if ((uint)current.width() != pipVideoWidth ||
993  (uint)current.height() != pipVideoHeight)
994  {
995  LOG(VB_PLAYBACK, LOG_INFO, LOC + "Re-initialise PiP.");
996  delete gl_pipchain;
997  gl_pipchains[pipplayer] = gl_pipchain = new OpenGLVideo();
998  QString options = GetFilters();
999  bool success = gl_pipchain->Init(
1001  pipVideoDim, pipVideoDim, dvr, position,
1002  QRect(0, 0, pipVideoWidth, pipVideoHeight),
1003  false, gl_opengl_type, options);
1004 
1005  QSize viewport = window.GetDisplayVisibleRect().size();
1006  gl_pipchain->SetMasterViewport(viewport);
1007 
1008  if (!success)
1009  {
1010  pipplayer->ReleaseCurrentFrame(pipimage);
1011  return;
1012  }
1013 
1014  }
1015  gl_pipchain->SetVideoRect(position,
1016  QRect(0, 0, pipVideoWidth, pipVideoHeight));
1017  gl_pipchain->UpdateInputFrame(pipimage);
1018 
1019  gl_pip_ready[pipplayer] = true;
1020 
1021  if (pipActive)
1022  gl_pipchain_active = gl_pipchain;
1023 
1024  pipplayer->ReleaseCurrentFrame(pipimage);
1025 }
1026 
1028 {
1029  if (!gl_pipchains.contains(pipplayer))
1030  return;
1031 
1032  OpenGLLocker ctx_lock(gl_context);
1033 
1034  OpenGLVideo *gl_pipchain = gl_pipchains[pipplayer];
1035  delete gl_pipchain;
1036  gl_pip_ready.remove(pipplayer);
1037  gl_pipchains.remove(pipplayer);
1038 }
1039 
1041 {
1042  if (gl_context)
1043  gl_context->MoveResizeWindow(new_rect);
1044 }
1045 
1046 void VideoOutputOpenGL::EmbedInWidget(const QRect &rect)
1047 {
1048  if (!window.IsEmbedding())
1050 
1051  MoveResize();
1052 }
1053 
1055 {
1056  if (!window.IsEmbedding())
1057  return;
1058 
1060  MoveResize();
1061 }
1062 
1063 bool VideoOutputOpenGL::ApproveDeintFilter(const QString& filtername) const
1064 {
1065  // anything OpenGL when using shaders
1066  if (filtername.contains("opengl") &&
1069  {
1070  return true;
1071  }
1072 
1073  // anything software based
1074  if (!filtername.contains("vdpau") && !filtername.contains("vaapi") && (OpenGLVideo::kGLGPU != gl_opengl_type))
1075  return true;
1076 
1077  return VideoOutput::ApproveDeintFilter(filtername);
1078 }
1079 
1081 {
1082  if (gl_context)
1085 }
1086 
1087 //virtual
1089 {
1090  return gl_painter;
1091 }
1092 
1093 // virtual
1095 {
1096  return VideoOutput::CanVisualise(audio, gl_context);
1097 }
1098 
1099 // virtual
1101  MythRender */*render*/, const QString &name)
1102 {
1104 }
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:151
virtual int SetPictureAttribute(PictureAttribute, int newValue)
Sets a specified picture attribute.
virtual void Teardown(void)
Definition: mythpainter.cpp:29
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 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
static bool isCodecDeinterlacer(const QString &decodername)
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)
void InitPictureAttributes(void) override
bool Init(MythRenderOpenGL *glcontext, VideoColourSpace *colourspace, QSize videoDim, QSize videoDispDim, QRect displayVisibleRect, QRect displayVideoRect, QRect videoRect, bool viewport_control, VideoType type, const QString &options)
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:295
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)
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)
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:329
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:672
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:144
const char * name
Definition: ParseText.cpp:328
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:14
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 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:115
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:146
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
#define codec_is_nvdec(id)
Definition: mythcodecid.h:148
void RemovePIP(MythPlayer *pipplayer) override
static uint buffersize(VideoFrameType type, int width, int height, int _aligned=64)
Definition: mythframe.h:297
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
#define codec_is_std(id)
Definition: mythcodecid.h:127
VideoFrame av_pause_frame
bool IsPIPActive(void) const
Definition: mythplayer.h:228
VideoFrameType codec
Definition: mythframe.h:38