MythTV  master
mythvideooutopengl.cpp
Go to the documentation of this file.
1 // C/C++
2 #include <utility>
3 
4 // MythTV
5 #include "mythcontext.h"
6 #include "mythmainwindow.h"
7 #include "mythplayer.h"
8 #include "videodisplayprofile.h"
9 #include "osd.h"
10 #include "mythuihelper.h"
11 #include "opengl/mythopenglperf.h"
14 #include "mythcodeccontext.h"
15 #include "mythopenglinterop.h"
16 #include "mythvideooutopengl.h"
17 
18 #define LOC QString("VidOutGL: ")
19 
27 {
28  QStringList safe;
29  safe << "opengl" << "opengl-yv12";
30 
31  // all profiles can handle all software frames
32  (*Options.safe_renderers)["dummy"].append(safe);
33  (*Options.safe_renderers)["nuppel"].append(safe);
34  if (Options.decoders->contains("ffmpeg"))
35  (*Options.safe_renderers)["ffmpeg"].append(safe);
36  if (Options.decoders->contains("mediacodec-dec"))
37  (*Options.safe_renderers)["mediacodec-dec"].append(safe);
38  if (Options.decoders->contains("vaapi-dec"))
39  (*Options.safe_renderers)["vaapi-dec"].append(safe);
40  if (Options.decoders->contains("vdpau-dec"))
41  (*Options.safe_renderers)["vdpau-dec"].append(safe);
42  if (Options.decoders->contains("nvdec-dec"))
43  (*Options.safe_renderers)["nvdec-dec"].append(safe);
44  if (Options.decoders->contains("vtb-dec"))
45  (*Options.safe_renderers)["vtb-dec"].append(safe);
46  if (Options.decoders->contains("v4l2-dec"))
47  (*Options.safe_renderers)["v4l2-dec"].append(safe);
48  if (Options.decoders->contains("mmal-dec"))
49  (*Options.safe_renderers)["mmal-dec"].append(safe);
50 
51  // OpenGL UYVY
52  Options.renderers->append("opengl");
53  Options.priorities->insert("opengl", 65);
54 
55  // OpenGL YV12
56  Options.renderers->append("opengl-yv12");
57  Options.priorities->insert("opengl-yv12", 65);
58 
59 #if defined(USING_VAAPI) || defined (USING_VTB) || defined (USING_MEDIACODEC) || defined (USING_VDPAU) || defined (USING_NVDEC) || defined (USING_MMAL) || defined (USING_V4L2PRIME) || defined (USING_EGL)
60  Options.renderers->append("opengl-hw");
61  (*Options.safe_renderers)["dummy"].append("opengl-hw");
62  (*Options.safe_renderers)["nuppel"].append("opengl-hw");
63  Options.priorities->insert("opengl-hw", 110);
64 #endif
65 #ifdef USING_VAAPI
66  if (Options.decoders->contains("vaapi"))
67  (*Options.safe_renderers)["vaapi"].append("opengl-hw");
68 #endif
69 #ifdef USING_VTB
70  if (Options.decoders->contains("vtb"))
71  (*Options.safe_renderers)["vtb"].append("opengl-hw");
72 #endif
73 #ifdef USING_MEDIACODEC
74  if (Options.decoders->contains("mediacodec"))
75  (*Options.safe_renderers)["mediacodec"].append("opengl-hw");
76 #endif
77 #ifdef USING_VDPAU
78  if (Options.decoders->contains("vdpau"))
79  (*Options.safe_renderers)["vdpau"].append("opengl-hw");
80 #endif
81 #ifdef USING_NVDEC
82  if (Options.decoders->contains("nvdec"))
83  (*Options.safe_renderers)["nvdec"].append("opengl-hw");
84 #endif
85 #ifdef USING_MMAL
86  if (Options.decoders->contains("mmal"))
87  (*Options.safe_renderers)["mmal"].append("opengl-hw");
88 #endif
89 #ifdef USING_V4L2PRIME
90  if (Options.decoders->contains("v4l2"))
91  (*Options.safe_renderers)["v4l2"].append("opengl-hw");
92 #endif
93 #ifdef USING_EGL
94  if (Options.decoders->contains("drmprime"))
95  (*Options.safe_renderers)["drmprime"].append("opengl-hw");
96 #endif
97 }
98 
100  : m_videoProfile(std::move(Profile))
101 {
102  // Retrieve render context
104  if (!m_render)
105  {
106  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to retrieve OpenGL context");
107  return;
108  }
109 
110  // Retain and lock
111  m_render->IncrRef();
112  OpenGLLocker locker(m_render);
113 
114  // enable performance monitoring if requested
115  // will report the execution time for the key GL code blocks
116  // N.B. 'Upload' should always be zero when using hardware decoding and direct
117  // rendering. Any copy cost for direct rendering will be included within 'Render'
118  if (VERBOSE_LEVEL_CHECK(VB_GPUVIDEO, LOG_INFO))
119  {
120  m_openGLPerf = new MythOpenGLPerf("GLVidPerf: ", { "Upload:", "Clear:", "Render:", "Flush:", "Swap:" });
121  if (!m_openGLPerf->isCreated())
122  {
123  delete m_openGLPerf;
124  m_openGLPerf = nullptr;
125  }
126  }
127 
128  // Disallow unsupported video texturing on GLES2/GL1.X
131 
132  // Retrieve OpenGL painter
134  m_openGLPainter = dynamic_cast<MythOpenGLPainter*>(win->GetCurrentPainter());
135  if (!m_openGLPainter)
136  {
137  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to get painter");
138  return;
139  }
140 
141  // we need to control buffer swapping
143 
144  // Create OpenGLVideo
145  QRect dvr = GetDisplayVisibleRect();
149 
150  // Connect VideoOutWindow to OpenGLVideo
155 }
156 
158 {
160  while (!m_openGLVideoPiPs.empty())
161  {
162  delete *m_openGLVideoPiPs.begin();
163  m_openGLVideoPiPs.erase(m_openGLVideoPiPs.begin());
164  }
165  m_openGLVideoPiPsReady.clear();
166  if (m_openGLPainter)
168  delete m_openGLVideo;
169  if (m_render)
170  {
172  delete m_openGLPerf;
174  m_render->DecrRef();
175  }
176  m_render = nullptr;
177 }
178 
180 {
184  m_buffersCreated = false;
185 }
186 
187 bool MythVideoOutputOpenGL::Init(const QSize &VideoDim, const QSize &VideoDispDim, float Aspect,
188  MythDisplay *Display, const QRect &DisplayVisibleRect, MythCodecID CodecId)
189 {
191  return false;
192 
193  if (!gCoreContext->IsUIThread())
194  {
195  LOG(VB_GENERAL, LOG_ERR, LOC + "Cannot initialise OpenGL video from this thread");
196  return false;
197  }
198 
199  OpenGLLocker ctx_lock(m_render);
200 
201  // if we are the main video player then free up as much video memory
202  // as possible at startup
203  PIPState pip = m_window.GetPIPState();
204  if ((kCodec_NONE == m_newCodecId) && ((kPIPOff == pip) || (kPBPLeft == pip)))
206 
207  // Default initialisation - mainly VideoOutWindow
208  if (!MythVideoOutput::Init(VideoDim, VideoDispDim, Aspect, Display, DisplayVisibleRect, CodecId))
209  return false;
210 
211  // Ensure any new profile preferences are handled after a stream change
212  if (m_dbDisplayProfile)
214 
215  // Set default support for picture attributes
217 
218  // Setup display
219  QSize size = m_window.GetVideoDim();
220 
221  // Set the display mode if required
223  ResizeForVideo(size);
225 
226  // Create buffers
227  if (!CreateBuffers(CodecId, m_window.GetVideoDim()))
228  return false;
229 
230  // Adjust visible rect for embedding
231  QRect dvr = GetDisplayVisibleRect();
233  {
234  m_render->SetViewPort(QRect(QPoint(), dvr.size()));
235  return true;
236  }
237 
239  {
240  QRect tmprect = QRect(QPoint(0,0), dvr.size());
241  ResizeDisplayWindow(tmprect, true);
242  }
243 
244  // Reset OpenGLVideo
245  if (m_openGLVideo->IsValid())
247 
248  // This works around an issue with VDPAU direct rendering using legacy drivers
249  m_render->Flush();
250 
251  return true;
252 }
253 
255 {
256  if (!m_dbDisplayProfile)
257  return;
258 
259  if (qFuzzyCompare(m_dbDisplayProfile->GetOutput() + 1.0F, NewRate + 1.0F))
260  return;
261 
262  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Video frame rate changed: %1->%2")
263  .arg(static_cast<double>(m_dbDisplayProfile->GetOutput())).arg(static_cast<double>(NewRate)));
264  m_dbDisplayProfile->SetOutput(NewRate);
265  m_newFrameRate = true;
266 }
267 
268 bool MythVideoOutputOpenGL::InputChanged(const QSize &VideoDim, const QSize &VideoDispDim,
269  float Aspect, MythCodecID CodecId, bool &AspectOnly,
270  MythMultiLocker* /*Locks*/, int ReferenceFrames,
271  bool ForceChange)
272 {
273  QSize currentvideodim = m_window.GetVideoDim();
274  QSize currentvideodispdim = m_window.GetVideoDispDim();
275  MythCodecID currentcodec = m_videoCodecID;
276  float currentaspect = m_window.GetVideoAspect();
277 
278  if (m_newCodecId != kCodec_NONE)
279  {
280  // InputChanged has been called twice in quick succession without a call to ProcessFrame
281  currentvideodim = m_newVideoDim;
282  currentvideodispdim = m_newVideoDispDim;
283  currentcodec = m_newCodecId;
284  currentaspect = m_newAspect;
285  }
286 
287  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Video changed: %1x%2 (%3x%4) '%5' (Aspect %6 Refs %13)"
288  "-> %7x%8 (%9x%10) '%11' (Aspect %12 Refs %14)")
289  .arg(currentvideodispdim.width()).arg(currentvideodispdim.height())
290  .arg(currentvideodim.width()).arg(currentvideodim.height())
291  .arg(toString(currentcodec)).arg(static_cast<double>(currentaspect))
292  .arg(VideoDispDim.width()).arg(VideoDispDim.height())
293  .arg(VideoDim.width()).arg(VideoDim.height())
294  .arg(toString(CodecId)).arg(static_cast<double>(Aspect))
295  .arg(m_maxReferenceFrames).arg(ReferenceFrames));
296 
297  bool cidchanged = (CodecId != currentcodec);
298  bool reschanged = (VideoDispDim != currentvideodispdim);
299  bool refschanged = m_maxReferenceFrames != ReferenceFrames;
300 
301  // aspect ratio changes are a no-op as changes are handled at display time
302  if (!(cidchanged || reschanged || refschanged || ForceChange))
303  {
304  AspectOnly = true;
305  return true;
306  }
307 
308  // N.B. We no longer check for interop support for the new codec as it is a
309  // poor substitute for a full check of decoder capabilities etc. Better to let
310  // hardware decoding fail if necessary - which should at least fallback to
311  // software decoding rather than bailing out here.
312 
313  // delete and recreate the buffers and flag that the input has changed
314  m_maxReferenceFrames = ReferenceFrames;
316  DestroyBuffers();
317  m_buffersCreated = CreateBuffers(CodecId, VideoDim);
319  if (!m_buffersCreated)
320  return false;
321 
322  m_newCodecId= CodecId;
323  m_newVideoDim = VideoDim;
324  m_newVideoDispDim = VideoDispDim;
325  m_newAspect = Aspect;
326  return true;
327 }
328 
330 {
331  QRect dvr = m_window.GetDisplayVisibleRect();
332 
333  MythMainWindow *mainwin = GetMythMainWindow();
334  if (!mainwin)
335  return dvr;
336  QSize size = mainwin->size();
337 
338  // may be called before m_window is initialised fully
339  if (dvr.isEmpty())
340  dvr = QRect(QPoint(0, 0), size);
341 
342  // If the Video screen mode has vertically less pixels
343  // than the GUI screen mode - OpenGL coordinate adjustments
344  // must be made to put the video at the top of the display
345  // area instead of at the bottom.
346  if (dvr.height() < size.height())
347  dvr.setTop(dvr.top() - size.height() + dvr.height());
348 
349  // If the Video screen mode has horizontally less pixels
350  // than the GUI screen mode - OpenGL width must be set
351  // as the higher GUI width so that the Program Guide
352  // invoked from playback is not cut off.
353  if (dvr.width() < size.width())
354  dvr.setWidth(size.width());
355 
356  return dvr;
357 }
358 
360 {
361  if (m_buffersCreated)
362  return true;
363 
364  if (codec_is_copyback(CodecID))
365  {
367  return m_videoBuffers.CreateBuffers(FMT_YV12, Size.width(), Size.height());
368  }
369 
370  if (codec_is_mediacodec(CodecID))
371  return m_videoBuffers.CreateBuffers(FMT_MEDIACODEC, Size, false, 1, 2, 2);
372  if (codec_is_vaapi(CodecID))
373  return m_videoBuffers.CreateBuffers(FMT_VAAPI, Size, false, 2, 1, 4, m_maxReferenceFrames);
374  if (codec_is_vtb(CodecID))
375  return m_videoBuffers.CreateBuffers(FMT_VTB, Size, false, 1, 4, 2);
376  if (codec_is_vdpau(CodecID))
377  return m_videoBuffers.CreateBuffers(FMT_VDPAU, Size, false, 2, 1, 4, m_maxReferenceFrames);
378  if (codec_is_nvdec(CodecID))
379  return m_videoBuffers.CreateBuffers(FMT_NVDEC, Size, false, 2, 1, 4);
380  if (codec_is_mmal(CodecID))
381  return m_videoBuffers.CreateBuffers(FMT_MMAL, Size, false, 2, 1, 4);
382  if (codec_is_v4l2(CodecID) || codec_is_drmprime(CodecID))
383  return m_videoBuffers.CreateBuffers(FMT_DRMPRIME, Size, false, 2, 1, 4);
384 
385  return m_videoBuffers.CreateBuffers(FMT_YV12, Size, false, 1, 8, 4, m_maxReferenceFrames);
386 }
387 
389  const PIPMap &PiPPlayers,
390  FrameScanType Scan)
391 {
392  if (!m_render)
393  return;
394 
395  OpenGLLocker ctx_lock(m_render);
396 
397  // start the first timer
398  if (m_openGLPerf)
400 
401  // Process input changes
402  if (m_newCodecId != kCodec_NONE)
403  {
404  // Ensure we don't lose embedding through program changes.
405  bool wasembedding = m_window.IsEmbedding();
406  QRect oldrect;
407  if (wasembedding)
408  {
409  oldrect = m_window.GetEmbeddingRect();
410  StopEmbedding();
411  }
412 
413  // Note - we don't call the default VideoOutput::InputChanged method as
414  // the OpenGL implementation is asynchronous.
415  // So we need to update the video display profile here. It is a little
416  // circular as we need to set the video dimensions first which are then
417  // reset in Init.
418  // All told needs a cleanup - not least because the use of codecName appears
419  // to be inconsistent.
421  AVCodecID avCodecId = myth2av_codecid(m_newCodecId);
422  AVCodec *codec = avcodec_find_decoder(avCodecId);
423  QString codecName;
424  if (codec)
425  codecName = codec->name;
426  if (m_dbDisplayProfile)
428 
432  m_newVideoDim = QSize();
433  m_newVideoDispDim = QSize();
434  m_newAspect = 0.0F;
435  m_newFrameRate = false;
436 
437  if (wasembedding && ok)
438  EmbedInWidget(oldrect);
439 
440  if (!ok)
441  return;
442  }
443  else if (m_newFrameRate)
444  {
445  // If we are switching mode purely for a refresh rate change, then there
446  // is no need to recreate buffers etc etc
447  ResizeForVideo();
448  m_newFrameRate = false;
449  }
450 
451  if (Frame)
452  m_window.SetRotation(Frame->rotation);
453 
454  if (VERBOSE_LEVEL_CHECK(VB_GPU, LOG_INFO))
455  m_render->logDebugMarker(LOC + "PROCESS_FRAME_START");
456 
457  bool swframe = Frame ? !format_is_hw(Frame->codec) : false;
458  bool dummy = Frame ? Frame->dummy : false;
459 
460  // software deinterlacing
461  if (!dummy && swframe)
463 
464  if (!m_window.IsEmbedding())
465  {
466  m_openGLVideoPiPActive = nullptr;
467  ShowPIPs(Frame, PiPPlayers);
468  }
469 
470  if (m_openGLVideo && swframe && !dummy)
472 
473  // time texture update
474  if (m_openGLPerf)
476 
477  if (VERBOSE_LEVEL_CHECK(VB_GPU, LOG_INFO))
478  m_render->logDebugMarker(LOC + "PROCESS_FRAME_END");
479 }
480 
482 {
483  if (!m_render)
484  return;
485 
486  if (m_newCodecId != kCodec_NONE)
487  return; // input changes need to be handled in ProcessFrame
488 
489  OpenGLLocker ctx_lock(m_render);
490 
491  if (VERBOSE_LEVEL_CHECK(VB_GPU, LOG_INFO))
492  m_render->logDebugMarker(LOC + "PREPARE_FRAME_START");
493 
494  bool dummy = false;
495  int topfieldfirst = 0;
496  if (Frame)
497  {
498  m_framesPlayed = Frame->frameNumber + 1;
499  topfieldfirst = Frame->interlaced_reversed ? !Frame->top_field_first : Frame->top_field_first;
500  dummy = Frame->dummy;
501  }
502  else
503  {
504  // see VideoOutputOpenGL::DoneDisplayingFrame
505  // we only retain pause frames for hardware formats
508  }
509 
510  // if process frame has not been called (double rate hardware deint), then
511  // we need to start the first 2 performance timers here
512  if (m_openGLPerf)
513  {
515  {
518  }
519  }
520 
521  m_render->BindFramebuffer(nullptr);
522 
523  if (VERBOSE_LEVEL_CHECK(VB_GPU, LOG_INFO))
524  m_render->logDebugMarker(LOC + "CLEAR_START");
525 
526  int gray = m_dbLetterboxColour == kLetterBoxColour_Gray25 ? 64 : 0;
527  bool useclear = !Frame || dummy || m_render->GetExtraFeatures() & kGLTiled;
528 #if QT_VERSION < QT_VERSION_CHECK(5, 8, 0)
529  // Qt < 5.8 uses a different QRegion API. Just clear and remove this code
530  // when 5.8 is standard
531  useclear = true;
532 #endif
533 
534  if (useclear)
535  {
536  m_render->SetBackground(gray, gray, gray, 255);
538  }
539 #if QT_VERSION >= QT_VERSION_CHECK(5, 8, 0)
540  // avoid clearing the framebuffer if it will be entirely overwritten by video
541  else if (!m_window.VideoIsFullScreen())
542  {
543  if (m_window.IsEmbedding())
544  {
545  // use MythRenderOpenGL rendering as it will clear to the appropriate 'black level'
546  m_render->ClearRect(nullptr, m_window.GetWindowRect(), gray);
547  }
548  else
549  {
550  // in the vast majority of cases it is significantly quicker to just
551  // clear the unused portions of the screen
552  QRegion toclear = m_window.GetBoundingRegion();
553  foreach (auto rect, toclear)
554  m_render->ClearRect(nullptr, rect, gray);
555  }
556  }
557 #endif
558 
559  if (VERBOSE_LEVEL_CHECK(VB_GPU, LOG_INFO))
560  m_render->logDebugMarker(LOC + "CLEAR_END");
561 
562  // time framebuffer clearing
563  if (m_openGLPerf)
565 
566  // stereoscopic views
567  QRect main = m_render->GetViewPort();
568  QRect first = main;
569  QRect second = main;
571 
573  {
574  first = QRect(main.left() / 2, main.top(), main.width() / 2, main.height());
575  second = first.translated(main.width() / 2, 0);
576  }
578  {
579  first = QRect(main.left(), main.top() / 2, main.width(), main.height() / 2);
580  second = first.translated(0, main.height() / 2);
581  }
582 
583  // main UI when embedded
584  if (m_window.IsEmbedding())
585  {
587  if (win && win->GetPaintWindow())
588  {
589  if (twopass)
590  m_render->SetViewPort(first, true);
591  win->GetPaintWindow()->clearMask();
592  win->draw(m_openGLPainter);
593  if (twopass)
594  {
595  m_render->SetViewPort(second, true);
596  win->GetPaintWindow()->clearMask();
597  win->draw(m_openGLPainter);
598  m_render->SetViewPort(main, true);
599  }
600  }
601  }
602 
603  // video
604  if (m_openGLVideo && !dummy)
605  {
606  m_openGLVideo->PrepareFrame(Frame, topfieldfirst, Scan, m_stereo);
607  // dummy streams need the viewport updated in case we have resized the window
608  }
609  else if (dummy)
610  {
612  }
613 
614  // PiPs/PBPs
615  if (!m_openGLVideoPiPs.empty())
616  {
617  for (auto it = m_openGLVideoPiPs.begin(); it != m_openGLVideoPiPs.end(); ++it)
618  {
619  if (m_openGLVideoPiPsReady[it.key()])
620  {
621  bool active = m_openGLVideoPiPActive == *it;
622  if (twopass)
623  m_render->SetViewPort(first, true);
624  (*it)->PrepareFrame(nullptr, topfieldfirst, Scan, kStereoscopicModeNone, active);
625  if (twopass)
626  {
627  m_render->SetViewPort(second, true);
628  (*it)->PrepareFrame(nullptr, topfieldfirst, Scan, kStereoscopicModeNone, active);
630  }
631  }
632  }
633  }
634 
635  // visualisation
637  {
638  if (twopass)
639  m_render->SetViewPort(first, true);
641  if (twopass)
642  {
643  m_render->SetViewPort(second, true);
646  }
647  }
648 
649  // OSD
650  if (Osd && m_openGLPainter && !m_window.IsEmbedding())
651  {
652  if (twopass)
653  m_render->SetViewPort(first, true);
654  Osd->Draw(m_openGLPainter, GetTotalOSDBounds().size(), true);
655  if (twopass)
656  {
657  m_render->SetViewPort(second, true);
658  Osd->Draw(m_openGLPainter, GetTotalOSDBounds().size(), true);
660  }
661  }
662 
663  // time rendering
664  if (m_openGLPerf)
666 
667  m_render->Flush();
668 
669  // time flush
670  if (m_openGLPerf)
672 
673  if (VERBOSE_LEVEL_CHECK(VB_GPU, LOG_INFO))
674  m_render->logDebugMarker(LOC + "PREPARE_FRAME_END");
675 }
676 
689 {
690  if (!Frame)
691  return;
692 
693  bool retain = format_is_hw(Frame->codec);
694 
697  {
699  if (!retain || (retain && (frame != Frame)))
701  }
702 
703  if (retain)
704  {
708  }
709  else
710  {
712  }
714 }
715 
722 void MythVideoOutputOpenGL::DiscardFrames(bool KeyFrame, bool Flushed)
723 {
724  if (Flushed)
725  {
727  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("(%1): %2").arg(KeyFrame).arg(m_videoBuffers.GetStatus()));
731  }
732 
733  MythVideoOutput::DiscardFrames(KeyFrame, Flushed);
734 }
735 
737 {
738  // Complete list of formats supported for OpenGL 2.0 and higher and OpenGL ES3.X
739  static VideoFrameType s_AllFormats[] =
745  FMT_NONE };
746 
747  // OpenGL ES 2.0 and OpenGL1.X only allow luminance textures
748  static VideoFrameType s_LegacyFormats[] =
750 
751  static VideoFrameType* s_formats[2] = { s_AllFormats, s_LegacyFormats };
752  return s_formats[m_textureFormats];
753 }
754 
756 {
757  m_window.SetWindowSize(Size);
759 }
760 
762 {
763  if (m_render && !IsErrored())
764  {
766  if (VERBOSE_LEVEL_CHECK(VB_GPU, LOG_INFO))
767  m_render->logDebugMarker(LOC + "SHOW");
769  if (m_openGLPerf)
770  {
771  // time buffer swap and log
772  // Results will normally be available on the next pass - and we will typically
773  // test every other frame as a result to avoid blocking in the driver.
774  // With the default of averaging over 30 samples this should give a 30 sample
775  // average over 60 frames
778  }
780  }
781 }
782 
784 {
785  if (m_openGLVideo)
788 }
789 
799 QStringList MythVideoOutputOpenGL::GetAllowedRenderers(MythCodecID CodecId, const QSize& /*VideoDim*/)
800 {
801  QStringList allowed;
802  if (getenv("NO_OPENGL"))
803  return allowed;
804 
805  if (codec_sw_copy(CodecId))
806  {
807  allowed << "opengl" << "opengl-yv12";
808  return allowed;
809  }
810 
811  VideoFrameType format = FMT_NONE;
812  if (codec_is_vaapi(CodecId))
813  format = FMT_VAAPI;
814  else if (codec_is_vdpau(CodecId))
815  format = FMT_VDPAU;
816  else if (codec_is_nvdec(CodecId))
817  format = FMT_NVDEC;
818  else if (codec_is_vtb(CodecId))
819  format = FMT_VTB;
820  else if (codec_is_mmal(CodecId))
821  format = FMT_MMAL;
822  else if (codec_is_v4l2(CodecId) || codec_is_drmprime(CodecId))
823  format = FMT_DRMPRIME;
824  else if (codec_is_mediacodec(CodecId))
825  format = FMT_MEDIACODEC;
826 
827  if (FMT_NONE == format)
828  return allowed;
829 
830  allowed += MythOpenGLInterop::GetAllowedRenderers(format);
831  return allowed;
832 }
833 
834 void MythVideoOutputOpenGL::UpdatePauseFrame(int64_t &DisplayTimecode, FrameScanType Scan)
835 {
838  if (used)
839  {
840  if (format_is_hw(used->codec))
841  {
842  DoneDisplayingFrame(used);
843  }
844  else
845  {
847  m_deinterlacer.Filter(used, Scan, m_dbDisplayProfile, true);
848  m_openGLVideo->ProcessFrame(used, Scan);
849  }
850  DisplayTimecode = used->disp_timecode;
851  }
852  else
853  {
854  LOG(VB_PLAYBACK, LOG_WARNING, LOC + "Could not update pause frame");
855  }
857 }
858 
860 {
862 }
863 
864 void MythVideoOutputOpenGL::ShowPIP(VideoFrame* /*Frame*/, MythPlayer *PiPPlayer, PIPLocation Location)
865 {
866  if (!PiPPlayer)
867  return;
868 
869  int pipw = 0;
870  int piph = 0;
871  VideoFrame *pipimage = PiPPlayer->GetCurrentFrame(pipw, piph);
872  const QSize pipvideodim = PiPPlayer->GetVideoBufferSize();
873  QRect pipvideorect = QRect(QPoint(0, 0), pipvideodim);
874 
875  if ((PiPPlayer->GetVideoAspect() <= 0.0F) || !pipimage || !pipimage->buf ||
876  (pipimage->codec != FMT_YV12) || !PiPPlayer->IsPIPVisible())
877  {
878  PiPPlayer->ReleaseCurrentFrame(pipimage);
879  return;
880  }
881 
882  QRect position = GetPIPRect(Location, PiPPlayer);
883  QRect dvr = m_window.GetDisplayVisibleRect();
884 
885  m_openGLVideoPiPsReady[PiPPlayer] = false;
886  MythOpenGLVideo *gl_pipchain = m_openGLVideoPiPs[PiPPlayer];
887  if (!gl_pipchain)
888  {
889  LOG(VB_PLAYBACK, LOG_INFO, LOC + "Initialise PiP");
890  auto *colourspace = new VideoColourSpace(&m_videoColourSpace);
891  m_openGLVideoPiPs[PiPPlayer] = gl_pipchain = new MythOpenGLVideo(m_render, colourspace,
892  pipvideodim, pipvideodim,
893  dvr, position, pipvideorect,
894  false, m_videoProfile);
895 
896  colourspace->DecrRef();
897  if (!gl_pipchain->IsValid())
898  {
899  PiPPlayer->ReleaseCurrentFrame(pipimage);
900  return;
901  }
902  gl_pipchain->SetMasterViewport(dvr.size());
903  }
904 
905  if (gl_pipchain->GetVideoSize() != pipvideodim)
906  {
907  LOG(VB_PLAYBACK, LOG_INFO, LOC + "Re-initialise PiP.");
908  delete gl_pipchain;
909  auto *colourspace = new VideoColourSpace(&m_videoColourSpace);
910  m_openGLVideoPiPs[PiPPlayer] = gl_pipchain = new MythOpenGLVideo(m_render, colourspace,
911  pipvideodim, pipvideodim,
912  dvr, position, pipvideorect,
913  false, m_videoProfile);
914  colourspace->DecrRef();
915  if (!gl_pipchain->IsValid())
916  {
917  PiPPlayer->ReleaseCurrentFrame(pipimage);
918  return;
919  }
920  gl_pipchain->SetMasterViewport(dvr.size());
921  }
922 
923  if (gl_pipchain->IsValid())
924  {
925  gl_pipchain->SetVideoRects(position, pipvideorect);
926  gl_pipchain->ProcessFrame(pipimage);
927  }
928 
929  m_openGLVideoPiPsReady[PiPPlayer] = true;
930  if (PiPPlayer->IsPIPActive())
931  m_openGLVideoPiPActive = gl_pipchain;
932  PiPPlayer->ReleaseCurrentFrame(pipimage);
933 }
934 
936 {
937  if (m_openGLVideoPiPs.contains(PiPPlayer))
938  {
940  delete m_openGLVideoPiPs.take(PiPPlayer);
941  m_openGLVideoPiPsReady.remove(PiPPlayer);
942  m_openGLVideoPiPs.remove(PiPPlayer);
944  }
945 }
946 
948 {
949  if (m_render)
952 }
953 
955 {
956  return m_openGLPainter;
957 }
958 
960 {
962 }
963 
964 bool MythVideoOutputOpenGL::SetupVisualisation(AudioPlayer *Audio, MythRender* /*Render*/, const QString &Name)
965 {
967 }
QRegion GetBoundingRegion(void) const
Return the region of DisplayVisibleRect that lies outside of DisplayVideoRect.
int GetExtraFeatures(void) const
static MythMainWindow * getMainWindow(bool useDB=true)
Return the existing main window, or create one.
void Reset(void)
Resets the class so that Init may be called again.
#define codec_sw_copy(id)
Definition: mythcodecid.h:349
void SetVideoRects(const QRect &DisplayVideoRect, const QRect &VideoRect)
void FreeResources(void) override
QMap< MythPlayer *, PIPLocation > PIPMap
Definition: mythvideoout.h:32
VideoColourSpace contains a QMatrix4x4 that can convert YCbCr data to RGB.
AVCodecID myth2av_codecid(MythCodecID codec_id)
virtual void ResizeDisplayWindow(const QRect &Rect, bool SaveVisible)
Resize Display Window.
float GetVideoAspect(void) const
Definition: mythplayer.h:209
void SetInput(const QSize &Size, float Framerate=0, const QString &CodecName=QString())
MythCodecID m_videoCodecID
Definition: mythvideoout.h:164
#define codec_is_mmal(id)
Definition: mythcodecid.h:341
MythRenderOpenGL * m_render
VideoColourSpace m_videoColourSpace
Definition: mythvideoout.h:160
static QStringList GetAllowedRenderers(MythCodecID CodecId, const QSize &VideoDim)
Generate a list of supported OpenGL profiles.
unsigned char * buf
Definition: mythframe.h:139
QString GetStatus(uint Num=0) const
virtual QStringList GetVisualiserList(void)
uint Size(BufferType Type) const
QString toString(MarkTypes type)
void DoneDisplayingFrame(VideoFrame *Frame) override
Release a video frame back into the decoder pool.
MythDeinterlacer m_deinterlacer
Definition: mythvideoout.h:173
QRect GetTotalOSDBounds(void) const
void VideoRectsChanged(const QRect &DisplayVideoRect, const QRect &VideoRect)
void SetOutput(float Framerate)
MythCodecID
Definition: mythcodecid.h:10
virtual bool CanVisualise(AudioPlayer *Audio, MythRender *Render)
VideoFrame * Dequeue(BufferType Type)
void PrepareFrame(VideoFrame *Frame, FrameScanType Scan, OSD *Osd) override
VideoDisplayProfile * m_dbDisplayProfile
Definition: mythvideoout.h:166
VideoVisual * m_visual
Definition: mythvideoout.h:170
void BindFramebuffer(QOpenGLFramebufferObject *Framebuffer)
RenderType Type(void) const
float GetOutput(void) const
bool Contains(BufferType Type, VideoFrame *Frame) const
VideoFrameType codec
Definition: mythframe.h:138
bool IsValid(void) const
QRect GetVideoRect(void) const
void WindowResized(const QSize &Size) override
#define codec_is_vdpau(id)
Definition: mythcodecid.h:298
void SetSwapControl(bool Swap)
VideoFrame * GetCurrentFrame(int &w, int &h)
Definition: mythplayer.cpp:964
QStringList GetVisualiserList(void) override
#define codec_is_copyback(id)
Definition: mythcodecid.h:344
void logDebugMarker(const QString &Message)
FrameScanType
Definition: videoouttypes.h:78
VideoFrameType
Definition: mythframe.h:23
void SetVideoDimensions(const QSize &VideoDim, const QSize &VideoDispDim)
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
bool CreateBuffers(MythCodecID CodecID, QSize Size)
void DoneDisplayingFrame(VideoFrame *Frame)
Removes frame from used queue and adds it to the available list.
MythVideoOutputOpenGL(QString Profile=QString())
MythOpenGLVideo * m_openGLVideo
#define LOC
QSize GetVideoSize(void) const
void Init(uint NumDecode, bool ExtraForPause, uint NeedFree, uint NeedprebufferNormal, uint NeedPrebufferSmall)
Creates buffers and sets various buffer management parameters.
static QStringList GetAllowedRenderers(VideoFrameType Format)
TextureFormats m_textureFormats
void WindowRectChanged(const QRect &WindowRect)
virtual void ClearAfterSeek(void)
Tells video output to toss decoded buffers due to a seek.
void SetBackground(int r, int g, int b, int a)
void RecordSample(void)
VideoFrameType * DirectRenderFormats(void) override
bool CanVisualise(AudioPlayer *Audio, MythRender *Render) override
int already_deinterlaced
temporary? TODO move scan detection/tracking into decoder
Definition: mythframe.h:170
QMap< QString, QStringList > * safe_renderers
virtual bool UsingVideoModes(void)
Definition: mythdisplay.h:29
#define codec_is_vaapi(id)
Definition: mythcodecid.h:311
QMap< MythPlayer *, MythOpenGLVideo * > m_openGLVideoPiPs
LetterBoxColour m_dbLetterboxColour
Definition: mythvideoout.h:163
virtual bool Init(const QSize &VideoDim, const QSize &VideoDispDim, float VideoAspect, MythDisplay *Display, const QRect &WindowRect, MythCodecID CodecID)
void OutputChanged(QSize VideoDim, QSize VideoDispDim, float)
MythOpenGLVideo * m_openGLVideoPiPActive
virtual int IncrRef(void)
Increments reference count.
VideoOutWindow m_window
Definition: mythvideoout.h:159
QStringList * renderers
#define VERBOSE_LEVEL_CHECK(_MASK_, _LEVEL_)
Definition: mythlogging.h:24
void DiscardFrames(bool KeyFrame, bool Flushed) override
Discard video frames.
void ReleaseCurrentFrame(VideoFrame *frame)
Definition: mythplayer.cpp:987
void Remove(BufferType Type, VideoFrame *Frame)
VideoBuffers m_videoBuffers
Definition: mythvideoout.h:167
static int format_is_hw(VideoFrameType Type)
Definition: mythframe.h:72
void SetWindowSize(QSize Size)
QRect GetEmbeddingRect(void) const
virtual void EmbedInWidget(const QRect &EmbedRect)
Tells video output to embed video in an existing window.
MythDisplay * m_display
Definition: mythvideoout.h:158
QWidget * GetPaintWindow()
bool IsErrored() const
virtual int DecrRef(void)
Decrements reference count and deletes on 0.
MythPainter * GetOSDPainter(void) override
void Show(FrameScanType Scan) override
virtual void StopEmbedding(void)
void DiscardFrame(VideoFrame *Frame)
Frame is ready to be reused by decoder.
bool IsEmbedding(void) const
frame_queue_t::iterator BeginLock(BufferType Type)
QSize GetVideoDispDim(void) const
void Filter(VideoFrame *Frame, FrameScanType Scan, VideoDisplayProfile *Profile, bool Force=false)
Deinterlace Frame if needed.
void ResetFrameFormat(void)
bool CreateBuffers(VideoFrameType Type, QSize Size, bool ExtraForPause, uint NeedFree, uint NeedprebufferNormal, uint NeedPrebufferSmall, int MaxReferenceFrames=16)
virtual void ResizeForVideo(QSize Size=QSize())
QRect GetDisplayVideoRect(void) const
#define ALL_PICTURE_ATTRIBUTES
MythPainter * GetCurrentPainter()
#define codec_is_mediacodec(id)
Definition: mythcodecid.h:323
bool Draw(MythPainter *Painter, QSize Size, bool Repaint=false)
Definition: osd.cpp:633
void RemovePIP(MythPlayer *PiPPlayer) override
void ResetTextures(void)
Clear reference frames after a seek as they will contain old images.
static void GetRenderOptions(RenderOptions &Options)
Generate the list of available OpenGL profiles.
int GetTimersRunning(void)
void ShowPIP(VideoFrame *Frame, MythPlayer *PiPPlayer, PIPLocation Location) override
virtual void DiscardFrames(bool KeyFrame, bool Flushed)
Releases all frames not being actively displayed from any queue onto the queue of frames ready for de...
bool VideoIsFullScreen(void) const
Check whether the video display rect covers the entire window/framebuffer.
QStringList * decoders
long long m_framesPlayed
Definition: mythvideoout.h:169
MythMainWindow * GetMythMainWindow(void)
PIPState GetPIPState(void) const
QMap< MythPlayer *, bool > m_openGLVideoPiPsReady
PIPLocation
Definition: videoouttypes.h:17
int64_t disp_timecode
Definition: mythframe.h:150
QRect GetViewPort(void)
void SetSupportedAttributes(PictureAttributeSupported Supported)
Enable the given set of picture attributes.
void ProcessFrame(VideoFrame *Frame, FrameScanType Scan=kScan_Progressive)
Update the current input texture using the data from the given video frame.
#define codec_is_vtb(id)
Definition: mythcodecid.h:333
void SetViewPort(const QRect &rect, bool viewportonly=false)
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
QSize GetVideoBufferSize(void) const
Definition: mythplayer.h:207
virtual void ShowPIPs(VideoFrame *Frame, const PIPMap &PiPPlayers)
static uint GetNumBuffers(int PixelFormat, int MaxReferenceFrames=16, bool Decoder=false)
void ClearAfterSeek(void) override
Tells video output to toss decoded buffers due to a seek.
PIPState
Definition: videoouttypes.h:8
void SetViewportRect(const QRect &DisplayVisibleRect)
virtual QRect GetPIPRect(PIPLocation Location, MythPlayer *PiPPlayer=nullptr, bool DoPixelAdj=true) const
returns QRect of PIP based on PIPLocation
static QStringList GetVisualiserList(RenderType type)
Definition: videovisual.cpp:14
static MythRenderOpenGL * GetOpenGLRender(void)
A simple overload of QOpenGLTimeMonitor to record and log OpenGL execution intervals.
bool SetupVisualisation(AudioPlayer *Audio, MythRender *Render, const QString &Name) override
void UpdatePauseFrame(int64_t &DisplayTimecode, FrameScanType Scan=kScan_Progressive) override
void VideoSizeChanged(const QSize &VideoDim, const QSize &VideoDispDim)
void draw(MythPainter *painter=nullptr)
void SetProfile(const QString &Profile)
Definition: osd.h:131
float GetVideoAspect(void) const
virtual void Draw(const QRect &area, MythPainter *painter, QPaintDevice *device)=0
QRect GetDisplayVisibleRect(void) const
QMap< QString, uint > * priorities
QString GetVideoRenderer(void) const
void LogSamples(void)
QRect GetWindowRect(void) const
QSize GetVideoDim(void) const
virtual bool SetupVisualisation(AudioPlayer *Audio, MythRender *Render, const QString &Name)
MythOpenGLPerf * m_openGLPerf
#define codec_is_nvdec(id)
Definition: mythcodecid.h:328
bool Init(const QSize &VideoDim, const QSize &VideoDispDim, float Aspect, MythDisplay *Display, const QRect &DisplayVisibleRect, MythCodecID CodecId) override
void InputChanged(const QSize &VideoDim, const QSize &VideoDispDim, float Aspect)
Tells video output to discard decoded frames and wait for new ones.
bool IsPIPVisible(void) const
Definition: mythplayer.h:258
void ClearRect(QOpenGLFramebufferObject *Target, const QRect &Area, int Color)
An optimised method to clear a QRect to the given color.
bool is_interlaced(FrameScanType Scan)
#define codec_is_drmprime(id)
Definition: mythcodecid.h:296
void SetVideoFrameRate(float NewRate) override
void SetMasterViewport(QSize Size)
VideoFrame * Head(BufferType Type)
StereoscopicMode m_stereo
Definition: mythvideoout.h:171
void Enqueue(BufferType Type, VideoFrame *Frame)
VideoFrame * Tail(BufferType Type)
void SetRotation(int Rotation)
Set the rotation in degrees.
virtual void DoneDisplayingFrame(VideoFrame *Frame)
Releases frame returned from GetLastShownFrame() onto the queue of frames ready for decoding onto.
void DeleteBuffers(void)
void InitDisplayMeasurements(void)
Initialise display measurement.
#define codec_is_v4l2(id)
Definition: mythcodecid.h:338
bool InputChanged(const QSize &VideoDim, const QSize &VideoDispDim, float Aspect, MythCodecID CodecId, bool &AspectOnly, MythMultiLocker *Locks, int ReferenceFrames, bool ForceChange) override
Tells video output to discard decoded frames and wait for new ones.
void ClearFramebuffer(void)
MythOpenGLVideo is responsible for displaying video frames on screen using OpenGL.
MythOpenGLPainter * m_openGLPainter
bool IsPIPActive(void) const
Definition: mythplayer.h:257
void PrepareFrame(VideoFrame *Frame, bool TopFieldFirst, FrameScanType Scan, StereoscopicMode Stereo, bool DrawBorder=false)
void InitPictureAttributes(void) override
void ProcessFrame(VideoFrame *Frame, OSD *Osd, const PIPMap &PiPPlayers, FrameScanType Scan) override