MythTV  master
videoout_omx.cpp
Go to the documentation of this file.
1 
2 #include "videoout_omx.h"
3 
4 #ifdef OSD_EGL /* includes QJson with enum value named Bool, must go before EGL/egl.h */
5 # include "mythpainter_ogl.h"
6 # include "mythpainter_qimage.h"
7 #endif //def OSD_EGL
8 
9 /* must go before X11/X.h due to #define None 0L */
10 #include "privatedecoder_omx.h" // For PrivateDecoderOMX::s_name
11 
12 #include <cstddef>
13 #include <cassert>
14 #include <algorithm> // max/min
15 #include <vector>
16 
17 #include <QTransform>
18 
19 #include <OMX_Core.h>
20 #include <OMX_Video.h>
21 #ifdef USING_BROADCOM
22 #include <OMX_Broadcom.h>
23 #include <bcm_host.h>
24 #endif
25 
26 #ifdef OSD_EGL
27 #include <EGL/egl.h>
28 #include <QtGlobal>
29 #endif
30 
31 // MythTV
32 #ifdef OSD_EGL
33 # define LOC QString("EGL: ")
34 # include "mythrender_opengl2es.h"
35 # undef LOC
36 # if 0 /* moved to top so it goes before X11/Xlib.h which is included via EGL/egl.h on Raspbian */
37 # include "mythpainter_ogl.h"
38 # endif
39 #endif //def OSD_EGL
40 
41 #include "mythmainwindow.h"
42 #include "mythuihelper.h"
43 #include "mythcorecontext.h"
44 
45 #include "filtermanager.h"
46 #include "videodisplayprofile.h"
47 #include "videobuffers.h"
48 
49 #include "omxcontext.h"
50 using namespace omxcontext;
51 
52 
53 /*
54  * Macros
55  */
56 #define LOC QString("VideoOutputOMX: ")
57 
58 // Roundup a value: y = ROUNDUP(x,4)
59 #define ROUNDUP( _x,_z) ((_x) + ((-(_x)) & ((_z) -1)) )
60 
61 // VideoFrame <> OMX_BUFFERHEADERTYPE
62 #define FRAMESETHDR(f,h) ((f)->priv[3] = reinterpret_cast<unsigned char* >(h))
63 #define FRAMESETHDRNONE(f) ((f)->priv[3] = nullptr)
64 #define FRAME2HDR(f) ((OMX_BUFFERHEADERTYPE*)((f)->priv[3]))
65 #define HDR2FRAME(h) ((VideoFrame*)((h)->pAppPrivate))
66 
67 // Component names
68 #ifdef USING_BELLAGIO
69 # define VIDEO_RENDER "xvideosink"
70 # define IMAGE_FX "" // Not implemented
71 #else
72 # define VIDEO_RENDER "video_render"
73 # define IMAGE_FX "image_fx"
74 #endif
75 
76 
77 /*
78  * Types
79  */
80 #ifdef OSD_EGL
81 class MythRenderEGL : public MythRenderOpenGL2ES
82 {
83  // No copying
84  MythRenderEGL(MythRenderEGL&);
85  MythRenderEGL& operator =(MythRenderEGL &rhs);
86 
87  public:
88  MythRenderEGL();
89 
90  void makeCurrent() override; // MythRenderOpenGL
91  void doneCurrent() override; // MythRenderOpenGL
92 #ifdef USE_OPENGL_QT5
93  void swapBuffers() override; // MythRenderOpenGL
94 #else
95  void swapBuffers() const override; // QGLContext
96  bool create(const QGLContext * = nullptr) override // QGLContext
97  { return isValid(); }
98 #endif
99 
100  protected:
101  virtual ~MythRenderEGL(); // Use MythRenderOpenGL2ES::DecrRef to delete
102 
103  EGLNativeWindowType createNativeWindow();
104  void destroyNativeWindow();
105 
106  EGLDisplay m_display;
107  EGLContext m_context;
108  EGLNativeWindowType m_window;
109  EGLSurface m_surface;
110 
111 #ifdef USING_BROADCOM
112 private:
113  EGL_DISPMANX_WINDOW_T gNativewindow;
114  DISPMANX_DISPLAY_HANDLE_T m_dispman_display;
115 #endif
116 };
117 
118 class GlOsdThread : public MThread
119 {
120  public:
121  GlOsdThread() :
122  MThread("GlOsdThread")
123  {
124  isRunning = true;
125  m_osdImage = nullptr;
126  m_EGLRender = nullptr;
127  m_Painter = nullptr;
128  rectsChanged = false;
129  m_lock.lock();
130  }
131  void run() override // MThread
132  {
133  RunProlog();
134  m_EGLRender = new MythRenderEGL();
135  if (m_EGLRender->create())
136  {
137  m_EGLRender->Init();
138  m_Painter = new MythOpenGLPainter(m_EGLRender);
139  m_Painter->SetSwapControl(false);
140  LOG(VB_GENERAL, LOG_INFO, LOC + __func__ +
141  ": OSD display uses threaded opengl");
142 
143  }
144  else
145  {
146  LOG(VB_GENERAL, LOG_ERR, LOC + __func__ +
147  ": failed to create MythRenderEGL for OSD");
148  m_EGLRender = nullptr;
149  m_Painter = nullptr;
150  isRunning = false;
151  }
152  m_lock.unlock();
153  while (isRunning)
154  {
155  m_lock.lock();
156  m_wait.wait(&m_lock);
157  if (!isRunning) {
158  m_lock.unlock();
159  break;
160  }
161 
162  if (rectsChanged)
163  {
164  m_EGLRender->SetViewPort(m_displayRect);
165  m_EGLRender->SetViewPort(m_glRect,true);
166  rectsChanged = false;
167  }
168  m_EGLRender->makeCurrent();
169  m_EGLRender->BindFramebuffer(0);
170  m_Painter->DrawImage(m_bounds, m_osdImage,
171  m_bounds, 255);
172  m_EGLRender->swapBuffers();
173  m_EGLRender->SetBackground(0, 0, 0, 0);
174  m_EGLRender->ClearFramebuffer();
175  m_Painter->DeleteTextures();
176  m_EGLRender->doneCurrent();
177 
178  m_lock.unlock();
179  }
180  if (m_osdImage)
181  m_osdImage->DecrRef(), m_osdImage = nullptr;
182  if (m_Painter)
183  delete m_Painter, m_Painter = nullptr;
184  if (m_EGLRender)
185  m_EGLRender->DecrRef(), m_EGLRender = nullptr;
186  RunEpilog();
187  }
188  // All of the below methods are called from another thread
189  void shutdown()
190  {
191  isRunning=false;
192  m_lock.tryLock(2000);
193  m_wait.wakeAll();
194  m_lock.unlock();
195  wait(2000);
196  }
197  bool isValid() {
198  return isRunning;
199  }
200  void setRects(const QRect &displayRect,const QRect &glRect)
201  {
202  m_displayRect = displayRect;
203  m_glRect = glRect;
204  rectsChanged = true;
205  }
206  private:
207  MythRenderEGL *m_EGLRender;
208  MythOpenGLPainter *m_Painter;
209  bool isRunning;
210  QRect m_displayRect;
211  QRect m_glRect;
212  bool rectsChanged;
213  public:
214  QMutex m_lock;
215  QWaitCondition m_wait;
216  MythImage *m_osdImage;
217  QRect m_bounds;
218 };
219 
220 #endif //def OSD_EGL
221 
222 /*
223  * Constants
224  */
225 const int kNumBuffers = 11; // +1 if extra_for_pause
226 const int kMinBuffers = 5;
227 const int kNeedFreeFrames = 1;
229 const int kPrebufferFramesSmall = 1;
230 const int kKeepPrebuffer = 1;
231 
232 QString const VideoOutputOMX::kName ="openmax";
233 
234 
235 /*
236  * Functions
237  */
238 // static
240  QStringList &cpudeints)
241 {
242  opts.renderers->append(kName);
243 
244  opts.deints->insert(kName, cpudeints);
245 #ifdef USING_BROADCOM
246  (*opts.deints)[kName].append(kName + "advanced");
247  (*opts.deints)[kName].append(kName + "fast");
248  (*opts.deints)[kName].append(kName + "linedouble");
249 #endif
250 #ifdef OSD_EGL
251  (*opts.osds)[kName].append("opengl");
252  (*opts.osds)[kName].append("threaded");
253 #endif
254  (*opts.osds)[kName].append("softblend");
255 
256  (*opts.safe_renderers)["dummy"].append(kName);
257  (*opts.safe_renderers)["nuppel"].append(kName);
258  if (opts.decoders->contains("ffmpeg"))
259  (*opts.safe_renderers)["ffmpeg"].append(kName);
260  if (opts.decoders->contains("crystalhd"))
261  (*opts.safe_renderers)["crystalhd"].append(kName);
262  if (opts.decoders->contains(PrivateDecoderOMX::s_name))
263  (*opts.safe_renderers)[PrivateDecoderOMX::s_name].append(kName);
264 
265  opts.priorities->insert(kName, 70);
266 }
267 
268 // static
270  MythCodecID myth_codec_id, const QSize &)
271 {
272  QStringList list;
273  if (codec_is_std(myth_codec_id))
274  list += kName;
275 
276  return list;
277 }
278 
280  m_render(gCoreContext->GetSetting("OMXVideoRender", VIDEO_RENDER), *this),
281  m_imagefx(gCoreContext->GetSetting("OMXVideoFilter", IMAGE_FX), *this),
282  m_backgroundscreen(nullptr), m_videoPaused(false)
283 {
284 #ifdef OSD_EGL
285  m_context = nullptr;
286  m_osdpainter = nullptr;
287  m_threaded_osdpainter = nullptr;
288  m_glOsdThread = nullptr;
289  m_changed = false;
290 #endif
291  init(&av_pause_frame, FMT_YV12, nullptr, 0, 0, 0);
292 
293  if (gCoreContext->GetBoolSetting("UseVideoModes", false))
295 
296  if (OMX_ErrorNone != m_render.Init(OMX_IndexParamVideoInit))
297  return;
298 
299  if (!m_render.IsValid())
300  return;
301 
302  // Show default port definitions and video formats supported
303  for (unsigned port = 0; port < m_render.Ports(); ++port)
304  {
305  m_render.ShowPortDef(port, LOG_DEBUG);
306  if (0) m_render.ShowFormats(port, LOG_DEBUG);
307  }
308 
309  if (OMX_ErrorNone != m_imagefx.Init(OMX_IndexParamImageInit))
310  return;
311 
312  if (!m_imagefx.IsValid())
313  return;
314 
315  // Show default port definitions and formats supported
316  for (unsigned port = 0; port < m_imagefx.Ports(); ++port)
317  {
318  m_imagefx.ShowPortDef(port, LOG_DEBUG);
319  if (0) m_imagefx.ShowFormats(port, LOG_DEBUG);
320  }
321 }
322 
323 // virtual
325 {
326  // Must shutdown the OMX components now before our state becomes invalid.
327  // When the component's dtor is called our state has already been destroyed.
329  m_render.Shutdown();
330 
331  DeleteBuffers();
332 
333 #ifdef OSD_EGL
334  if (m_osdpainter)
335  delete m_osdpainter, m_osdpainter = nullptr;
336  if (m_context)
337  m_context->DecrRef(), m_context = nullptr;
338  if (m_glOsdThread)
339  {
340  m_glOsdThread->shutdown();
341  delete m_glOsdThread;
342  m_glOsdThread = nullptr;
343  }
344  if (m_threaded_osdpainter)
345  delete m_threaded_osdpainter, m_threaded_osdpainter = nullptr;
346 #endif
347 
348  if (m_backgroundscreen)
349  {
351  m_backgroundscreen = nullptr;
353  }
354 }
355 
356 // virtual
357 bool VideoOutputOMX::Init( // Return true if successful
358  const QSize &video_dim_buf, // video buffer size
359  const QSize &video_dim_disp, // video display size
360  float aspect, // w/h of presented video
361  WId winid, // "video playback window" widget winId()
362  const QRect &win_rect, // playback rect on "video playback window"
363  MythCodecID codec_id ) // video codec
364 {
365  LOG(VB_PLAYBACK, LOG_INFO, LOC + __func__ +
366  QString(" vbuf=%1x%2 vdisp=%3x%4 aspect=%5 win=%6,%7,%8x%9 codec=%10")
367  .arg(video_dim_buf.width()).arg(video_dim_buf.height())
368  .arg(video_dim_disp.width()).arg(video_dim_disp.height())
369  .arg(aspect).arg(win_rect.x()).arg(win_rect.y())
370  .arg(win_rect.width()).arg(win_rect.height())
371  .arg(toString(codec_id)) );
372 
373  if (!codec_is_std(codec_id))
374  {
375  LOG(VB_GENERAL, LOG_ERR, LOC +
376  QString("Cannot create VideoOutput for codec %1")
377  .arg(toString(codec_id)));
379  return false;
380  }
381 
382  if (getenv("NO_OPENMAX"))
383  {
384  LOG(VB_PLAYBACK, LOG_NOTICE, LOC + __func__ + " OpenMAX disabled");
386  return false;
387  }
388 
389  if (!m_render.IsValid())
390  {
391  LOG(VB_GENERAL, LOG_ERR, LOC + __func__ + " No video render");
393  return false;
394  }
395  if (!m_imagefx.IsValid())
396  LOG(VB_GENERAL, LOG_WARNING, LOC + "Hardware deinterlace unavailable");
397 
399 
400  if (!VideoOutput::Init(video_dim_buf, video_dim_disp,
401  aspect, winid, win_rect, codec_id))
402  {
403  LOG(VB_GENERAL, LOG_ERR, LOC + __func__ + ": VideoOutput::Init failed");
404  return false;
405  }
406 
407  if (db_vdisp_profile)
409 
410  // Set resolution/measurements
411  InitDisplayMeasurements(video_dim_disp.width(), video_dim_disp.height(), false);
412 
413  if (OMX_ErrorNone != SetImageFilter(OMX_ImageFilterNone))
414  return false;
415 
416  // Setup video buffers
417  static const int kBuffers = std::max(
418  gCoreContext->GetNumSetting("OmxVideoBuffers", kNumBuffers), kMinBuffers);
419  vbuffers.Init(std::max(kBuffers, int(m_render.PortDef().nBufferCountMin)),
420  true, kNeedFreeFrames,
423 
424  // Allocate video buffers
425  if (!CreateBuffers(video_dim_buf, video_dim_disp))
426  return false;
427 
428  bool osdIsSet = false;
429 #ifdef OSD_EGL
430  if (GetOSDRenderer() == "opengl")
431  {
432  MythRenderEGL *render = new MythRenderEGL();
433  if (render->create())
434  {
435  render->Init();
436  m_context = render;
437  MythOpenGLPainter *p = new MythOpenGLPainter(m_context);
438  p->SetSwapControl(false);
439  m_osdpainter = p;
440  LOG(VB_GENERAL, LOG_INFO, LOC + __func__ +
441  ": OSD display uses opengl");
442  osdIsSet = true;
443  }
444  else
445  {
446  LOG(VB_GENERAL, LOG_ERR, LOC + __func__ +
447  ": failed to create MythRenderEGL");
448  render->DecrRef();
449  m_context = nullptr;
450  m_osdpainter = nullptr;
451  }
452  }
453  if (GetOSDRenderer() == "threaded")
454  {
455  m_glOsdThread = new GlOsdThread();
456  m_glOsdThread->start();
457  // Wait until set up
458  m_glOsdThread->m_lock.lock();
459  m_glOsdThread->m_lock.unlock();
460  if (m_glOsdThread->isValid())
461  osdIsSet = true;
462  }
463 #endif
464 
465  if (!osdIsSet)
466  LOG(VB_GENERAL, LOG_INFO, LOC + __func__ +
467  ": OSD display uses softblend");
468 
469  MoveResize();
470 
471  m_disp_rect = m_vid_rect = QRect();
473  return false;
474 
475  if (!Start())
476  return false;
477 
478  LOG(VB_PLAYBACK, LOG_DEBUG, LOC + __func__ + " done");
479  return true;
480 }
481 
482 // virtual
483 bool VideoOutputOMX::InputChanged( // Return true if successful
484  const QSize &video_dim_buf, // video buffer size
485  const QSize &video_dim_disp, // video display size
486  float aspect, // w/h of presented video
487  MythCodecID av_codec_id, // video codec
488  void *codec_private,
489  bool &aspect_only ) // Out: true if aspect only changed
490 {
491  QSize cursize = window.GetActualVideoDim();
492 
493  LOG(VB_PLAYBACK, LOG_INFO, LOC + __func__ +
494  QString(" from %1: %2x%3 aspect %4 to %5: %6x%7 aspect %9")
495  .arg(toString(video_codec_id)).arg(cursize.width())
496  .arg(cursize.height()).arg(window.GetVideoAspect())
497  .arg(toString(av_codec_id)).arg(video_dim_disp.width())
498  .arg(video_dim_disp.height()).arg(aspect));
499 
500  if (!codec_is_std(av_codec_id))
501  {
502  LOG(VB_GENERAL, LOG_ERR, LOC + "New video codec is not supported.");
504  return false;
505  }
506 
507  bool cid_changed = (video_codec_id != av_codec_id);
508  bool res_changed = video_dim_disp != cursize;
509  bool asp_changed = aspect != window.GetVideoAspect();
510 
511  if (!res_changed && !cid_changed)
512  {
513  if (asp_changed)
514  {
515  aspect_only = true;
516  VideoAspectRatioChanged(aspect);
517  MoveResize();
518  }
519  return true;
520  }
521 
522  VideoOutput::InputChanged(video_dim_buf, video_dim_disp,
523  aspect, av_codec_id, codec_private,
524  aspect_only);
525 
527  m_render.Shutdown();
528 
529  DeleteBuffers();
530  if (!CreateBuffers(video_dim_buf, video_dim_disp))
531  return false;
532 
533  MoveResize();
534 
535  m_disp_rect = m_vid_rect = QRect();
537  return false;
538 
539  if (!Start())
540  return false;
541 
542  if (db_vdisp_profile)
544 
545  LOG(VB_PLAYBACK, LOG_DEBUG, LOC + __func__ + " done");
546  return true;
547 }
548 
549 // virtual
550 bool VideoOutputOMX::ApproveDeintFilter(const QString& filtername) const
551 {
552  if (filtername.contains(kName))
553  return true;
554 
555  return VideoOutput::ApproveDeintFilter(filtername);
556 }
557 
558 // virtual
560 {
561  return SetupDeinterlace(interlaced);
562 }
563 
564 // virtual
565 bool VideoOutputOMX::SetupDeinterlace(bool interlaced, const QString &overridefilter)
566 {
567  if (!m_imagefx.IsValid())
568  return VideoOutput::SetupDeinterlace(interlaced, overridefilter);
569 
570  QString deintfiltername;
571  if (db_vdisp_profile)
572  deintfiltername = db_vdisp_profile->GetFilteredDeint(overridefilter);
573 
574  if (!deintfiltername.contains(kName))
575  {
576  if (m_deinterlacing && m_deintfiltername.contains(kName))
577  SetImageFilter(OMX_ImageFilterNone);
578  return VideoOutput::SetupDeinterlace(interlaced, overridefilter);
579  }
580 
581  if (m_deinterlacing == interlaced && deintfiltername == m_deintfiltername)
582  return m_deinterlacing;
583 
584  m_deintfiltername = deintfiltername;
585  m_deinterlacing = interlaced;
586 
587  // Remove non-openmax filters
588  delete m_deintFiltMan, m_deintFiltMan = nullptr;
589  delete m_deintFilter, m_deintFilter = nullptr;
590 
591  LOG(VB_PLAYBACK, LOG_INFO, LOC + __func__ + " switching " +
592  (interlaced ? "on" : "off") + " '" + deintfiltername + "'");
593 
594  OMX_IMAGEFILTERTYPE type;
595  if (!m_deinterlacing || m_deintfiltername.isEmpty())
596  type = OMX_ImageFilterNone;
597 #ifdef USING_BROADCOM
598  else if (m_deintfiltername.contains("advanced"))
599  type = OMX_ImageFilterDeInterlaceAdvanced;
600  else if (m_deintfiltername.contains("fast"))
601  type = OMX_ImageFilterDeInterlaceFast;
602  else if (m_deintfiltername.contains("linedouble"))
603  type = OMX_ImageFilterDeInterlaceLineDouble;
604 #endif
605  else
606  {
607  LOG(VB_GENERAL, LOG_ERR, LOC + __func__ + " Unknown type: '" +
608  m_deintfiltername + "'");
609 #ifdef USING_BROADCOM
610  type = OMX_ImageFilterDeInterlaceFast;
611 #else
612  type = OMX_ImageFilterNone;
613 #endif
614  }
615 
616  (void)SetImageFilter(type);
617 
618  return m_deinterlacing;
619 }
620 
621 OMX_ERRORTYPE VideoOutputOMX::SetImageFilter(OMX_IMAGEFILTERTYPE type)
622 {
623  LOG(VB_PLAYBACK, LOG_DEBUG, LOC + __func__ + " " + Filter2String(type));
624 
625 #ifdef USING_BROADCOM
626  OMX_INDEXTYPE index = OMX_IndexConfigCommonImageFilterParameters;
627  OMX_CONFIG_IMAGEFILTERPARAMSTYPE image_filter;
628  OMX_DATA_INIT(image_filter);
629  switch (type)
630  {
631  case OMX_ImageFilterDeInterlaceAdvanced:
632  image_filter.nNumParams = 1;
633  image_filter.nParams[0] = 3;
634  break;
635 
636  case OMX_ImageFilterDeInterlaceFast:
637  case OMX_ImageFilterDeInterlaceLineDouble:
638  case OMX_ImageFilterNone:
639  break;
640 
641  default:
642  break;
643  }
644 
645 #else
646  OMX_INDEXTYPE index = OMX_IndexConfigCommonImageFilter;
647  OMX_CONFIG_IMAGEFILTERTYPE image_filter;
648  OMX_DATA_INIT(image_filter);
649 #endif //def USING_BROADCOM
650 
651  if (!m_imagefx.IsValid())
652  return (type != OMX_ImageFilterNone) ? OMX_ErrorInvalidState : OMX_ErrorNone;
653 
654  image_filter.nPortIndex = m_imagefx.Base() + 1;
655  image_filter.eImageFilter = type;
656  OMX_ERRORTYPE e = m_imagefx.SetConfig(index, &image_filter);
657  if (e != OMX_ErrorNone)
658  LOG(VB_PLAYBACK, LOG_ERR, LOC + QString(
659  "SetConfig CommonImageFilter error %1")
660  .arg(Error2String(e)));
661  return e;
662 }
663 
664 // virtual
665 void VideoOutputOMX::EmbedInWidget(const QRect &rect)
666 {
667  if (!window.IsEmbedding())
669 }
670 
671 // virtual
673 {
674  if (window.IsEmbedding())
676 }
677 
678 // virtual
680 {
681  VideoOutput::Zoom(direction);
682  MoveResize();
683 }
684 
685 // virtual
687  PIPLocation location, MythPlayer *pipplayer, bool do_pixel_adj) const
688 {
689  QRect r = VideoOutput::GetPIPRect(location, pipplayer, do_pixel_adj);
690 
691  const QRect display_video_rect = window.GetDisplayVideoRect();
692  const QRect video_rect = window.GetVideoRect();
693  const QRect display_visible_rect = window.GetDisplayVisibleRect();
694 
695  // Transform PIP rect from DisplayVisibleRect to VideoRect
696  qreal s = qreal(display_video_rect.width()) / display_visible_rect.width();
697  s /= qreal(display_video_rect.height()) / display_visible_rect.height();
698  r = QTransform()
699  .scale( (s * video_rect.width()) / display_video_rect.width(),
700  (s * video_rect.height()) / display_video_rect.height() )
701  .mapRect(r);
702 
703  r.setRect(r.x() & ~1, r.y() & ~1, r.width() & ~1, r.height() & ~1);
704  return r;
705 }
706 
708 {
709  delete [] av_pause_frame.buf;
710  av_pause_frame.buf = nullptr;
711 
712  VideoFrame *scratch = vbuffers.GetScratchFrame();
713 
714  init(&av_pause_frame, FMT_YV12, new unsigned char[scratch->size + 128],
715  scratch->width, scratch->height, scratch->size);
716 
718 
720 
721  // Need two pause frames for OMX video_render.
722  // 1st is held by EmptyBuffer until next frame is sent.
723  // Need additional pause frame for advanced deinterlacer
724  while (vbuffers.Size(kVideoBuffer_pause) < 3)
726 }
727 
728 // pure virtual
729 void VideoOutputOMX::UpdatePauseFrame(int64_t &disp_timecode)
730 {
731  if (!av_pause_frame.buf)
732  {
733  LOG(VB_GENERAL, LOG_ERR, LOC + __func__ + " - no buffers?");
734  return;
735  }
736 
737  // Try used frame first, then fall back to scratch frame.
739 
740  VideoFrame *used_frame = (vbuffers.Size(kVideoBuffer_used) > 0) ?
741  vbuffers.Head(kVideoBuffer_used) : nullptr;
742  if (used_frame)
743  CopyFrame(&av_pause_frame, used_frame);
744 
745  vbuffers.end_lock();
746 
747  if (!used_frame)
748  {
749  used_frame = vbuffers.Tail(kVideoBuffer_pause);
750  used_frame->frameNumber = framesPlayed - 1;
751  CopyFrame(&av_pause_frame, used_frame);
752  }
753 
754  // Suppress deinterlace while paused to prevent the jiggles.
757 
758  disp_timecode = av_pause_frame.disp_timecode;
759 }
760 
764 // pure virtual
766  FilterChain *filterList,
767  const PIPMap &pipPlayers,
769 {
770  if (IsErrored())
771  {
772  LOG(VB_GENERAL, LOG_ERR, LOC + __func__ + " IsErrored is true");
773  return;
774  }
775 
776  m_videoPaused = false;
777  if (!frame)
778  {
779  // Rotate pause frames
780  m_videoPaused = true;
782  frame = vbuffers.GetScratchFrame();
783  CopyFrame(frame, &av_pause_frame);
784  }
785 
786  CropToDisplay(frame);
787 
788  if (filterList)
789  filterList->ProcessFrame(frame);
790 
793 
794  ShowPIPs(frame, pipPlayers);
795  if (osd && !window.IsEmbedding())
796  DisplayOSD(frame, osd);
797 
800 }
801 
802 // tells show what frame to be show, do other last minute stuff
803 // pure virtual
804 void VideoOutputOMX::PrepareFrame(VideoFrame *buffer, FrameScanType /*scan*/, OSD */*osd*/)
805 {
806  if (IsErrored())
807  {
808  LOG(VB_GENERAL, LOG_ERR, LOC + __func__ + " IsErrored is true");
809  return;
810  }
811 
812  if (!buffer)
813  {
814  buffer = vbuffers.GetScratchFrame();
816  }
817 
818  framesPlayed = buffer->frameNumber + 1;
819 
820  // PGB Set up a background window to prevent bleed through
821  // of theme when playing a video smaller than the play area
822  if (m_backgroundscreen == nullptr)
823  {
824  MythMainWindow *mainWindow = GetMythMainWindow();
825  MythScreenStack *mainStack = mainWindow->GetMainStack();
826  m_backgroundscreen = new MythScreenType(mainStack,"VideoBackground");
827 
828  if (XMLParseBase::CopyWindowFromBase("videobackground",
830  {
831  mainStack->AddScreen(m_backgroundscreen, false);
832  GetMythUI()->AddCurrentLocation("Playback");
833  if (mainWindow->GetPaintWindow())
834  mainWindow->GetPaintWindow()->update();
835  qApp->processEvents();
836  }
837  }
838 
841  window.GetVideoRect() );
842 }
843 
844 // BLT the last prepared frame to the screen as quickly as possible.
845 // pure virtual
847 {
848  if (IsErrored())
849  {
850  LOG(VB_GENERAL, LOG_ERR, LOC + __func__ + " IsErrored is true");
851  return;
852  }
853 
854  VideoFrame *frame = GetLastShownFrame();
855  if (!frame)
856  {
857  LOG(VB_GENERAL, LOG_ERR, LOC + __func__ + " No LastShownFrame");
858  return;
859  }
860 
861  OMX_BUFFERHEADERTYPE *hdr = FRAME2HDR(frame);
862  if (!hdr)
863  {
864  LOG(VB_GENERAL, LOG_ERR, LOC + __func__ + " Frame has no buffer header");
865  return;
866  }
867 
868  assert(hdr->nSize == sizeof(OMX_BUFFERHEADERTYPE));
869  assert(hdr->nVersion.nVersion == OMX_VERSION);
870  assert(hdr->pBuffer == frame->buf);
871 
872  if (hdr->nFilledLen)
873  {
874  LOG(VB_GENERAL, LOG_WARNING, LOC + __func__ + " Frame in use");
875  return; // Pending empty callback
876  }
877 
878  assert(frame->codec == FMT_YV12);
879 
880  hdr->nFilledLen = frame->offsets[2] + (frame->offsets[1] >> 2);
881  hdr->nFlags = OMX_BUFFERFLAG_ENDOFFRAME;
882 #ifdef OMX_BUFFERFLAG_INTERLACED
883  if (frame->interlaced_frame)
884  hdr->nFlags |= OMX_BUFFERFLAG_INTERLACED;
885 #endif
886 #ifdef OMX_BUFFERFLAG_TOP_FIELD_FIRST
887  if (frame->top_field_first)
888  hdr->nFlags |= OMX_BUFFERFLAG_TOP_FIELD_FIRST;
889 #endif
891  // Paused - do not display anything unless softblend set
892  if (m_videoPaused && GetOSDRenderer() != "softblend")
893  {
894  // fake out that the buffer was already emptied
895  EmptyBufferDone(cmpnt, hdr);
896  return;
897  }
898  OMX_ERRORTYPE e = OMX_EmptyThisBuffer(cmpnt.Handle(), hdr);
899  if (e != OMX_ErrorNone)
900  {
901  LOG(VB_PLAYBACK, LOG_ERR, LOC + QString(
902  "OMX_EmptyThisBuffer error %1").arg(Error2String(e)) );
903  hdr->nFlags = 0;
904  hdr->nFilledLen = 0;
905  }
906 }
907 
908 // pure virtual
910 {
911 }
912 
913 // virtual
915 {
916 #ifdef OSD_EGL
917  if (GetOSDRenderer() == "opengl"
918  && m_context && m_osdpainter)
919  return true;
920  if (GetOSDRenderer() == "threaded"
921  && m_glOsdThread && m_glOsdThread->isValid())
922  return true;
923 #endif
925 }
926 
927 // virtual
929 {
930 #ifdef OSD_EGL
931  if (GetOSDRenderer() == "opengl")
932  return m_osdpainter;
933  if (GetOSDRenderer() == "threaded")
934  return m_threaded_osdpainter;
935 #endif
937 }
938 
939 // virtual
941 {
942 #ifdef OSD_EGL
943  if (GetOSDRenderer() == "opengl"
944  && m_context && m_osdpainter)
945  {
946  m_context->makeCurrent();
947  m_context->BindFramebuffer(0);
948 
949  QRect bounds = GetTotalOSDBounds();
950  bool redraw = false;
951  if (m_visual)
952  {
953  m_visual->Draw(bounds, m_osdpainter, nullptr);
954  redraw = true;
955  }
956 
957  if (osd)
958  redraw |= osd->DrawDirect(m_osdpainter, bounds.size(), redraw);
959 
960  if (redraw)
961  {
962  m_context->swapBuffers();
963  m_context->SetBackground(0, 0, 0, 0);
964  m_context->ClearFramebuffer();
965  }
966 
967  m_context->doneCurrent();
968  return true;
969  }
970 
971  if (GetOSDRenderer() == "threaded"
972  && m_glOsdThread && m_glOsdThread->isValid())
973  {
974  if (!m_threaded_osdpainter)
975  {
976  m_threaded_osdpainter = new MythQImagePainter();
977  if (!m_threaded_osdpainter)
978  return false;
979  }
980  QSize osd_size = GetTotalOSDBounds().size();
981  if (m_glOsdThread->m_osdImage && (m_glOsdThread->m_osdImage->size() != osd_size))
982  {
983  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("OSD size changed."));
984  m_glOsdThread->m_osdImage->DecrRef();
985  m_glOsdThread->m_osdImage = nullptr;
986  }
987  if (!m_glOsdThread->m_osdImage)
988  {
989  m_glOsdThread->m_osdImage = m_threaded_osdpainter->GetFormatImage();
990  if (m_glOsdThread->m_osdImage)
991  {
992  QImage blank = QImage(osd_size,
993  QImage::Format_ARGB32_Premultiplied);
994  m_glOsdThread->m_osdImage->Assign(blank);
995  m_threaded_osdpainter->Clear(m_glOsdThread->m_osdImage,
996  QRegion(QRect(QPoint(0,0), osd_size)));
997  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Created OSD QImage."));
998  }
999  else {
1000  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Unable to create OSD QImage."));
1001  return false;
1002  }
1003  }
1004  if (m_visual)
1005  {
1006  LOG(VB_GENERAL, LOG_ERR, LOC + "Visualiser not supported here");
1007  m_visual->Draw(QRect(), nullptr, nullptr);
1008  }
1009 
1010  if (m_glOsdThread->m_lock.tryLock(0)) {
1011  QRegion dirty = QRegion();
1012  QRegion visible = osd->Draw(m_threaded_osdpainter,
1013  m_glOsdThread->m_osdImage, osd_size, dirty);
1014  m_changed = m_changed || !dirty.isEmpty();
1015  m_glOsdThread->m_osdImage->SetChanged(m_changed);
1016  m_glOsdThread->m_bounds = GetTotalOSDBounds();
1017  m_glOsdThread->m_lock.unlock();
1018  if (m_changed) {
1019  m_glOsdThread->m_wait.wakeAll();
1020  m_changed = false;
1021  }
1022  }
1023  return true;
1024  }
1025 #endif
1026  return VideoOutput::DisplayOSD(frame, osd);
1027 }
1028 
1029 // virtual
1031 {
1032  (void)sync;
1033 }
1034 
1035 // virtual
1037 {
1038 #ifdef OSD_EGL
1039  return VideoOutput::CanVisualise(audio, m_context ? m_context : render);
1040 #else
1041  return VideoOutput::CanVisualise(audio, render);
1042 #endif
1043 }
1044 
1045 // virtual
1047  const QString &name)
1048 {
1049 #ifdef OSD_EGL
1050  return VideoOutput::SetupVisualisation(audio,
1051  m_context ? m_context : render, name);
1052 #else
1053  return VideoOutput::SetupVisualisation(audio, render, name);
1054 #endif
1055 }
1056 
1057 // virtual
1059 {
1060 #ifdef OSD_EGL
1061  return m_context ?
1062  VideoVisual::GetVisualiserList(m_context->Type()) :
1064 #else
1066 #endif
1067 }
1068 
1070  const QSize &video_dim_buf, // video buffer size
1071  const QSize &video_dim_disp) // video display size
1072 {
1074 
1075  // Set the video dimensions
1076  OMX_S32 nStride = ROUNDUP(video_dim_buf.width(), 32);
1077  OMX_U32 nSliceHeight = ROUNDUP(video_dim_buf.height(), 16);
1078  OMX_PARAM_PORTDEFINITIONTYPE def = cmpnt.PortDef();
1079  assert(vbuffers.Size() >= def.nBufferCountMin);
1080  def.nBufferCountActual = vbuffers.Size();
1081  def.nBufferSize = 0;
1082  def.bBuffersContiguous = OMX_FALSE;
1083  def.nBufferAlignment = sizeof(int);
1084  def.eDomain = OMX_PortDomainVideo;
1085  def.format.video.cMIMEType = nullptr;
1086  def.format.video.pNativeRender = nullptr;
1087  def.format.video.nFrameWidth = video_dim_disp.width();
1088  def.format.video.nFrameHeight = video_dim_disp.height();
1089  def.format.video.nStride = nStride;
1090  def.format.video.nSliceHeight = nSliceHeight;
1091  def.format.video.nBitrate = 0;
1092  def.format.video.xFramerate = 0;
1093  def.format.video.bFlagErrorConcealment = OMX_FALSE;
1094  def.format.video.eCompressionFormat = OMX_VIDEO_CodingUnused;
1095  def.format.video.eColorFormat = OMX_COLOR_FormatYUV420PackedPlanar;
1096  def.format.video.pNativeWindow = nullptr;
1097  OMX_ERRORTYPE e = cmpnt.SetParameter(OMX_IndexParamPortDefinition, &def);
1098  if (e != OMX_ErrorNone)
1099  {
1100  LOG(VB_PLAYBACK, LOG_ERR, LOC + QString(
1101  "SetParameter PortDefinition error %1")
1102  .arg(Error2String(e)));
1103  return false;
1104  }
1105 
1106  // Update port status with revised buffer size etc
1107  if (OMX_ErrorNone != cmpnt.GetPortDef())
1108  return false;
1109 
1110  // Setup image_fx output
1111  if (m_imagefx.IsValid())
1112  {
1113  def = m_imagefx.PortDef(1);
1114  def.nBufferCountActual = 1 + std::max(def.nBufferCountMin,
1115  m_render.PortDef().nBufferCountMin);
1116  def.nBufferSize = 0;
1117  assert(def.eDomain == OMX_PortDomainImage);
1118  def.format.image.nFrameWidth = video_dim_disp.width();
1119  def.format.image.nFrameHeight = video_dim_disp.height();
1120  def.format.image.nStride = nStride;
1121  def.format.image.nSliceHeight = nSliceHeight;
1122  e = m_imagefx.SetParameter(OMX_IndexParamPortDefinition, &def);
1123  if (e != OMX_ErrorNone)
1124  {
1125  LOG(VB_PLAYBACK, LOG_ERR, LOC + QString(
1126  "SetParameter image_fx output PortDefinition error %1")
1127  .arg(Error2String(e)));
1128  return false;
1129  }
1130 
1131  if (OMX_ErrorNone != m_imagefx.GetPortDef(1))
1132  return false;
1133  }
1134 
1135  int pitches[3], offsets[3];
1136  pitches[0] = nStride;
1137  pitches[1] = pitches[2] = nStride >> 1;
1138  offsets[0] = 0;
1139  offsets[1] = nStride * nSliceHeight;
1140  offsets[2] = offsets[1] + (offsets[1] >> 2);
1141  uint nBufferSize = buffersize(FMT_YV12, nStride, nSliceHeight);
1142 
1143  std::vector<unsigned char*> bufs;
1144  std::vector<YUVInfo> yuvinfo;
1145  for (uint i = 0; i < vbuffers.Size(); ++i)
1146  {
1147  yuvinfo.push_back(YUVInfo(video_dim_disp.width(),
1148  video_dim_disp.height(), nBufferSize, pitches, offsets));
1149  void *buf = av_malloc(nBufferSize + 64);
1150  if (!buf)
1151  {
1152  LOG(VB_GENERAL, LOG_ERR, LOC + "Out of memory");
1154  return false;
1155  }
1156  m_bufs.push_back(buf);
1157  bufs.push_back((unsigned char *)buf);
1158  }
1159  if (!vbuffers.CreateBuffers(FMT_YV12, video_dim_disp.width(),
1160  video_dim_disp.height(), bufs, yuvinfo))
1161  {
1162  LOG(VB_GENERAL, LOG_ERR, LOC + "CreateBuffers failed");
1164  return false;
1165  }
1166 
1167  CreatePauseFrame();
1168 
1169  return true;
1170 }
1171 
1173 {
1174  delete [] av_pause_frame.buf;
1175  init(&av_pause_frame, FMT_YV12, nullptr, 0, 0, 0);
1176 
1178 
1179  while (!m_bufs.empty())
1180  {
1181  av_free(m_bufs.back());
1182  m_bufs.pop_back();
1183  }
1184 }
1185 
1187 {
1188  if (m_imagefx.IsValid())
1189  {
1190  // Setup a tunnel between image_fx & video_render
1191  OMX_ERRORTYPE e;
1192  e = OMX_SetupTunnel(m_imagefx.Handle(), m_imagefx.Base() + 1,
1193  m_render.Handle(), m_render.Base());
1194  if (e != OMX_ErrorNone)
1195  {
1196  LOG(VB_PLAYBACK, LOG_ERR, LOC + QString("OMX_SetupTunnel error %1")
1197  .arg(Error2String(e)));
1198  return false;
1199  }
1200 
1201  // Disable image_fx input port.
1202  // A disabled port is not populated with buffers on a transition to IDLE
1203  if (m_imagefx.PortDisable(0, 500) != OMX_ErrorNone)
1204  return false;
1205 
1206  // Goto OMX_StateIdle
1207  if (m_imagefx.SetState(OMX_StateIdle, 500) != OMX_ErrorNone)
1208  return false;
1209 
1210  if (m_render.SetState(OMX_StateIdle, 500) != OMX_ErrorNone)
1211  return false;
1212 
1213  // Enable image_fx input port and populate buffers
1215  if (m_imagefx.PortEnable(0, 500, &cb) != OMX_ErrorNone)
1216  return false;
1217 
1218  // Goto OMX_StateExecuting
1219  if (m_imagefx.SetState(OMX_StateExecuting, 500) != OMX_ErrorNone)
1220  return false;
1221  }
1222  else
1223  {
1224  if (m_render.PortDisable(0, 500) != OMX_ErrorNone)
1225  return false;
1226 
1227  if (m_render.SetState(OMX_StateIdle, 500) != OMX_ErrorNone)
1228  return false;
1229 
1231  if (m_render.PortEnable(0, 500, &cb) != OMX_ErrorNone)
1232  return false;
1233  }
1234 
1235  if (m_render.SetState(OMX_StateExecuting, 500) != OMX_ErrorNone)
1236  return false;
1237 
1238  return true;
1239 }
1240 
1241 bool VideoOutputOMX::SetVideoRect(const QRect &d_rect, const QRect &vid_rect)
1242 {
1243  // Translate display rect to screen coordinates
1244  QRect disp_rect = d_rect.translated(GetMythMainWindow()->geometry().topLeft());
1245 
1246  if (disp_rect == m_disp_rect && vid_rect == m_vid_rect)
1247  return true;
1248 
1249  LOG(VB_PLAYBACK, LOG_INFO, LOC + __func__ + QString(
1250  " display=%1,%2,%3x%4 (%9) video=%5,%6,%7x%8 (%10)")
1251  .arg(disp_rect.x()).arg(disp_rect.y())
1252  .arg(disp_rect.width()).arg(disp_rect.height())
1253  .arg(vid_rect.x()).arg(vid_rect.y())
1254  .arg(vid_rect.width()).arg(vid_rect.height())
1256 
1257 #ifdef USING_BROADCOM
1258  OMX_CONFIG_DISPLAYREGIONTYPE dregion;
1259  OMX_DATA_INIT(dregion);
1260  dregion.nPortIndex = m_render.Base();
1261  dregion.set = OMX_DISPLAYSETTYPE( OMX_DISPLAY_SET_FULLSCREEN |
1262  OMX_DISPLAY_SET_TRANSFORM |
1263  OMX_DISPLAY_SET_DEST_RECT | OMX_DISPLAY_SET_SRC_RECT |
1264  OMX_DISPLAY_SET_MODE |
1265  OMX_DISPLAY_SET_PIXEL |
1266  OMX_DISPLAY_SET_NOASPECT |
1267  OMX_DISPLAY_SET_LAYER );
1268  dregion.fullscreen = OMX_FALSE;
1269  dregion.transform = OMX_DISPLAY_ROT0;
1270  dregion.dest_rect.x_offset = disp_rect.x();
1271  dregion.dest_rect.y_offset = disp_rect.y();
1272  dregion.dest_rect.width = disp_rect.width();
1273  dregion.dest_rect.height = disp_rect.height();
1274  dregion.src_rect.x_offset = vid_rect.x();
1275  dregion.src_rect.y_offset = vid_rect.y();
1276  dregion.src_rect.width = vid_rect.width();
1277  dregion.src_rect.height = vid_rect.height();
1278  dregion.noaspect = OMX_TRUE;
1279  dregion.mode = OMX_DISPLAY_MODE_FILL; //OMX_DISPLAY_MODE_LETTERBOX;
1280  dregion.pixel_x = dregion.pixel_y = 0;
1281  // NB Qt EGLFS uses layer 1 - See createDispmanxLayer() in
1282  // mkspecs/devices/linux-rasp-pi-g++/qeglfshooks_pi.cpp.
1283  // Therefore to view video must select layer >= 1
1284  dregion.layer = 2;
1285 
1286  OMX_ERRORTYPE e = m_render.SetConfig(OMX_IndexConfigDisplayRegion, &dregion);
1287  if (e != OMX_ErrorNone)
1288  {
1289  LOG(VB_PLAYBACK, LOG_ERR, LOC + QString(
1290  "SetConfig DisplayRegion error %1")
1291  .arg(Error2String(e)));
1292  return false;
1293  }
1294 #endif // USING_BROADCOM
1295 
1296 #ifdef OSD_EGL
1297  if (m_context
1298  || ( m_glOsdThread && m_glOsdThread->isValid() ) )
1299  {
1300  QRect displayRect = window.GetDisplayVisibleRect();
1301  QRect mainRect = GetMythMainWindow()->geometry();
1302  uint32_t maxwidth = 0, maxheight = 0;
1303  graphics_get_display_size(DISPMANX_ID_MAIN_LCD, &maxwidth, &maxheight);
1304  QRect glRect(mainRect.x(), // left
1305  maxheight-mainRect.bottom(), // top
1306  0,0);
1307  glRect.setRight(mainRect.right());
1308  glRect.setBottom(glRect.top()+mainRect.height());
1309  if (m_context)
1310  {
1311  m_context->SetViewPort(displayRect);
1312  m_context->SetViewPort(glRect,true);
1313  }
1314  if (m_glOsdThread && m_glOsdThread->isValid()) {
1315  m_glOsdThread->setRects(displayRect,glRect);
1316  }
1317  }
1318 #endif
1319 
1320  m_disp_rect = disp_rect;
1321  m_vid_rect = vid_rect;
1322 
1323  return true;
1324 }
1325 
1326 // virtual
1328  OMXComponent&, OMX_BUFFERHEADERTYPE *hdr)
1329 {
1330  assert(hdr->nSize == sizeof(OMX_BUFFERHEADERTYPE));
1331  assert(hdr->nVersion.nVersion == OMX_VERSION);
1332  hdr->nFilledLen = 0;
1333  hdr->nFlags = 0;
1334  return OMX_ErrorNone;
1335 }
1336 
1337 // Shutdown OMX_StateIdle -> OMX_StateLoaded callback
1338 // virtual
1340 {
1342  if(cmpnt.Handle() == c.Handle())
1343  FreeBuffersCB();
1344 }
1345 
1346 // Use frame buffers
1347 OMX_ERRORTYPE VideoOutputOMX::UseBuffersCB()
1348 {
1350  const OMX_PARAM_PORTDEFINITIONTYPE &def = cmpnt.PortDef();
1351  assert(vbuffers.Size() >= def.nBufferCountActual);
1352 
1353  LOG(VB_PLAYBACK, LOG_DEBUG, LOC + QString("Use %1 of %2 byte buffer(s)")
1354  .arg(def.nBufferCountActual).arg(def.nBufferSize));
1355 
1356  OMX_ERRORTYPE e = OMX_ErrorNone;
1357 
1358  for (uint i = 0; i < vbuffers.Size(); ++i)
1359  {
1360  VideoFrame *vf = vbuffers.At(i);
1361  assert(vf);
1362  assert(OMX_U32(vf->size) >= def.nBufferSize);
1363  assert(vf->buf);
1364  if (i >= def.nBufferCountActual)
1365  continue;
1366 
1367  OMX_BUFFERHEADERTYPE *hdr;
1368  e = OMX_UseBuffer(cmpnt.Handle(), &hdr, def.nPortIndex, vf,
1369  def.nBufferSize, vf->buf);
1370  if (e != OMX_ErrorNone)
1371  {
1372  LOG(VB_PLAYBACK, LOG_ERR, LOC + QString(
1373  "OMX_UseBuffer error %1").arg(Error2String(e)) );
1374  break;
1375  }
1376  if (hdr->nSize != sizeof(OMX_BUFFERHEADERTYPE))
1377  {
1378  LOG(VB_PLAYBACK, LOG_ERR, LOC + "OMX_UseBuffer header mismatch");
1379  OMX_FreeBuffer(cmpnt.Handle(), def.nPortIndex, hdr);
1380  e = OMX_ErrorVersionMismatch;
1381  break;
1382  }
1383  if (hdr->nVersion.nVersion != OMX_VERSION)
1384  {
1385  LOG(VB_PLAYBACK, LOG_ERR, LOC + "OMX_UseBuffer version mismatch");
1386  OMX_FreeBuffer(cmpnt.Handle(), def.nPortIndex, hdr);
1387  e = OMX_ErrorVersionMismatch;
1388  break;
1389  }
1390  assert(vf == HDR2FRAME(hdr));
1391  FRAMESETHDR(vf, hdr);
1392  hdr->nFilledLen = 0;
1393  hdr->nOffset = 0;
1394  }
1395 
1396  return e;
1397 }
1398 
1399 // Free all OMX buffers
1400 // OMX_CommandPortDisable callback
1401 OMX_ERRORTYPE VideoOutputOMX::FreeBuffersCB()
1402 {
1404 #ifndef NDEBUG
1405  const OMX_PARAM_PORTDEFINITIONTYPE &def = cmpnt.PortDef();
1406  assert(vbuffers.Size() >= def.nBufferCountActual);
1407 #endif
1408 
1409  for (uint i = 0; i < vbuffers.Size(); ++i)
1410  {
1411  VideoFrame *vf = vbuffers.At(i);
1412  assert(vf);
1413  OMX_BUFFERHEADERTYPE *hdr = FRAME2HDR(vf);
1414  if (!hdr)
1415  continue;
1416  assert(hdr->nSize == sizeof(OMX_BUFFERHEADERTYPE));
1417  assert(hdr->nVersion.nVersion == OMX_VERSION);
1418  assert(vf == HDR2FRAME(hdr));
1419  FRAMESETHDRNONE(vf);
1420 
1421  OMX_ERRORTYPE e = OMX_FreeBuffer(cmpnt.Handle(), cmpnt.Base(), hdr);
1422  if (e != OMX_ErrorNone)
1423  {
1424  LOG(VB_PLAYBACK, LOG_ERR, LOC + QString(
1425  "OMX_FreeBuffer 0x%1 error %2")
1426  .arg(quintptr(hdr),0,16).arg(Error2String(e)));
1427  }
1428  }
1429  return OMX_ErrorNone;
1430 }
1431 
1432 #ifdef OSD_EGL
1433 MythRenderEGL::MythRenderEGL() :
1435  m_display(EGL_NO_DISPLAY),
1436  m_context(EGL_NO_CONTEXT),
1437  m_window(nullptr),
1438  m_surface(EGL_NO_SURFACE)
1439 {
1440  // Disable flush to get performance improvement
1441  m_flushEnabled = false;
1442  // get an EGL display connection
1443  m_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
1444  if (m_display == EGL_NO_DISPLAY)
1445  {
1446  LOG(VB_GENERAL, LOG_ERR, "eglGetDisplay => EGL_NO_DISPLAY");
1447  return;
1448  }
1449 
1450  // initialize the EGL display connection
1451  EGLint major, minor;
1452  EGLBoolean b = eglInitialize(m_display, &major, &minor);
1453  if (!b)
1454  {
1455  LOG(VB_GENERAL, LOG_ERR, "eglInitialize failed");
1456  return;
1457  }
1458  LOG(VB_PLAYBACK, LOG_INFO, QString("EGL runtime version %1.%2")
1459  .arg(major).arg(minor));
1460 
1461  // get an appropriate EGL frame buffer configuration
1462  static EGLint const attribute_list[] = {
1463  EGL_RED_SIZE, 8,
1464  EGL_GREEN_SIZE, 8,
1465  EGL_BLUE_SIZE, 8,
1466  EGL_ALPHA_SIZE, 8,
1467  EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
1468  EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, // ES2 required for GLSL
1469  EGL_NONE
1470  };
1471  EGLConfig config;
1472  EGLint num_config;
1473  b = eglChooseConfig(m_display, attribute_list, &config, 1, &num_config);
1474  if (!b)
1475  {
1476  LOG(VB_GENERAL, LOG_ERR, "eglChooseConfig failed");
1477  return;
1478  }
1479 
1480  // create an EGL rendering context
1481  static EGLint const ctx_attribute_list[] = {
1482  EGL_CONTEXT_CLIENT_VERSION, 2, // ES2 required for GLSL
1483  EGL_NONE
1484  };
1485  m_context = eglCreateContext(m_display, config, EGL_NO_CONTEXT, ctx_attribute_list);
1486  if (m_context == EGL_NO_CONTEXT)
1487  {
1488  LOG(VB_GENERAL, LOG_ERR, "eglCreateContext failed");
1489  return;
1490  }
1491 
1492 #ifdef USE_OPENGL_QT5
1493  QVariant v;
1494  v.setValue(QEGLNativeContext(m_context, m_display));
1495  setNativeHandle(v);
1496 #endif
1497 
1498  m_window = createNativeWindow();
1499 
1500  m_surface = eglCreateWindowSurface(m_display, config, m_window, nullptr);
1501  if (m_context == EGL_NO_SURFACE)
1502  {
1503  LOG(VB_GENERAL, LOG_ERR, "eglCreateWindowSurface failed");
1504  return;
1505  }
1506 
1507  // connect the context to the surface
1508  b = eglMakeCurrent(m_display, m_surface, m_surface, m_context);
1509  if (!b)
1510  {
1511  LOG(VB_GENERAL, LOG_ERR, "eglMakeCurrent failed");
1512  return;
1513  }
1514 
1515  // clear the color buffer
1516  glClearColor(0, 0, 0, 0); // RGBA
1517  glClear(GL_COLOR_BUFFER_BIT);
1518  glFlush();
1519  b = eglSwapBuffers(m_display, m_surface);
1520  if (!b)
1521  LOG(VB_GENERAL, LOG_ERR, "eglSwapBuffers failed");
1522 
1523  b = eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
1524  if (!b)
1525  LOG(VB_GENERAL, LOG_ERR, "eglMakeCurrent EGL_NO_SURFACE failed");
1526 
1527 #ifndef USE_OPENGL_QT5
1528  setValid(true);
1529 #endif
1530 }
1531 
1532 MythRenderEGL::~MythRenderEGL()
1533 {
1534 #ifndef USE_OPENGL_QT5
1535  setValid(false);
1536 #endif
1537 
1538  if (m_display == EGL_NO_DISPLAY)
1539  return;
1540 
1541  EGLBoolean b;
1542  if (m_context != EGL_NO_CONTEXT)
1543  {
1544  b = eglMakeCurrent(m_display, m_surface, m_surface, m_context);
1545  assert(b == EGL_TRUE);
1546  }
1547 
1548  if (m_surface != EGL_NO_SURFACE)
1549  {
1550  b = eglDestroySurface(m_display, m_surface);
1551  assert(b == EGL_TRUE);
1552  m_surface = EGL_NO_SURFACE;
1553  }
1554 
1555  destroyNativeWindow();
1556 
1557  if (m_context != EGL_NO_CONTEXT)
1558  {
1559  b = eglDestroyContext(m_display, m_context);
1560  assert(b == EGL_TRUE);
1561  m_context = EGL_NO_CONTEXT;
1562  }
1563 
1564 #if 0 // This causes Qt to throw a segv
1565  b = eglTerminate(m_display);
1566  assert(b == EGL_TRUE);
1567 #endif
1568  m_display = EGL_NO_DISPLAY;
1569  DeleteOpenGLResources();
1570 
1571 #ifdef NDEBUG
1572  Q_UNUSED(b);
1573 #endif
1574 }
1575 
1576 EGLNativeWindowType MythRenderEGL::createNativeWindow()
1577 {
1578 #ifdef USING_BROADCOM
1579  uint32_t width = 0, height = 0;
1580  int32_t ret = graphics_get_display_size(DISPMANX_ID_MAIN_LCD, &width, &height);
1581  assert(ret >= 0);
1582 
1583  m_dispman_display = vc_dispmanx_display_open(DISPMANX_ID_MAIN_LCD);
1584  assert(m_dispman_display != DISPMANX_NO_HANDLE);
1585 
1586  DISPMANX_UPDATE_HANDLE_T update = vc_dispmanx_update_start(0);
1587  assert(update != DISPMANX_NO_HANDLE);
1588 
1589  VC_RECT_T dst_rect;
1590  dst_rect.x = 0;
1591  dst_rect.y = 0;
1592  dst_rect.width = width;
1593  dst_rect.height = height;
1594 
1595  VC_RECT_T src_rect;
1596  src_rect.x = 0;
1597  src_rect.y = 0;
1598  src_rect.width = width << 16;
1599  src_rect.height = height << 16;
1600 
1601  VC_DISPMANX_ALPHA_T alpha = {
1602  DISPMANX_FLAGS_ALPHA_T(
1603  DISPMANX_FLAGS_ALPHA_FROM_SOURCE |
1604  (0&DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS) |
1605  (0&DISPMANX_FLAGS_ALPHA_FIXED_NON_ZERO) |
1606  (0&DISPMANX_FLAGS_ALPHA_FIXED_EXCEED_0X07) |
1607  (~0&DISPMANX_FLAGS_ALPHA_PREMULT) |
1608  (0&DISPMANX_FLAGS_ALPHA_MIX)
1609  ), // flags
1610  0, // opacity(alpha) 0->255
1611  0 // DISPMANX_RESOURCE_HANDLE_T mask
1612  };
1613 
1614  DISPMANX_ELEMENT_HANDLE_T dispman_element = vc_dispmanx_element_add(
1615  update, m_dispman_display, 3/*layer*/, &dst_rect,
1616  DISPMANX_RESOURCE_HANDLE_T(0) /*src*/, &src_rect,
1617  DISPMANX_PROTECTION_NONE, &alpha, nullptr /*clamp*/, DISPMANX_NO_ROTATE);
1618  assert(dispman_element != DISPMANX_NO_HANDLE);
1619 
1620  gNativewindow.element = dispman_element;
1621  gNativewindow.width = width;
1622  gNativewindow.height = height;
1623 
1624  vc_dispmanx_update_submit_sync(update);
1625  return &gNativewindow;
1626 #ifdef NDEBUG
1627  Q_UNUSED(ret);
1628 #endif
1629 #else
1630  return 0;
1631 #endif
1632 }
1633 
1634 void MythRenderEGL::destroyNativeWindow()
1635 {
1636 #ifdef USING_BROADCOM
1637  if (m_dispman_display != DISPMANX_NO_HANDLE)
1638  {
1639  int ret;
1640  if (DISPMANX_NO_HANDLE != gNativewindow.element)
1641  {
1642  DISPMANX_UPDATE_HANDLE_T update = vc_dispmanx_update_start(0);
1643  assert(update != DISPMANX_NO_HANDLE);
1644 
1645  ret = vc_dispmanx_element_remove(update, gNativewindow.element);
1646  assert(ret >= 0);
1647 
1648  ret = vc_dispmanx_update_submit_sync(update);
1649  assert(ret >= 0);
1650 
1651  gNativewindow.element = DISPMANX_NO_HANDLE;
1652  }
1653 
1654  ret = vc_dispmanx_display_close(m_dispman_display);
1655  assert(ret >= 0);
1656  m_dispman_display = DISPMANX_NO_HANDLE;
1657 #ifdef NDEBUG
1658  Q_UNUSED(ret);
1659 #endif
1660  }
1661 #endif //def USING_BROADCOM
1662 }
1663 
1664 // virtual
1665 void MythRenderEGL::makeCurrent()
1666 {
1667  assert(m_lock_level >= 0);
1668  if (++m_lock_level == 1)
1669  eglMakeCurrent(m_display, m_surface, m_surface, m_context);
1670 }
1671 
1672 // virtual
1673 void MythRenderEGL::doneCurrent()
1674 {
1675  assert(m_lock_level > 0);
1676  if (--m_lock_level == 0)
1677  eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
1678 }
1679 
1680 // virtual
1681 #ifdef USE_OPENGL_QT5
1682 void MythRenderEGL::swapBuffers()
1683 #else
1684 void MythRenderEGL::swapBuffers() const
1685 #endif
1686 {
1687  eglSwapBuffers(m_display, m_surface);
1688 }
1689 #endif //def OSD_EGL
1690 // EOF
static DisplayRes * GetDisplayRes(bool lock=false)
Factory method that returns a DisplayRes singleton.
Definition: DisplayRes.cpp:18
#define VIDEO_RENDER
void UpdatePauseFrame(int64_t &) override
Updates frame displayed when video is paused.
void Zoom(ZoomDirection) override
Sets up zooming into to different parts of the video, the zoom is actually applied in MoveResize().
QRect GetPIPRect(PIPLocation, MythPlayer *=nullptr, bool=true) const override
returns QRect of PIP based on PIPLocation
virtual ~VideoOutputOMX()
QString m_deintfiltername
Definition: videooutbase.h:351
const int kPrebufferFramesSmall
#define LOC
void SetVideoRenderer(const QString &video_renderer)
#define IMAGE_FX
This is a wrapper around QThread that does several additional things.
Definition: mthread.h:46
bool SetupVisualisation(AudioPlayer *, MythRender *, const QString &) override
void SetSwapControl(bool swap)
virtual bool CanVisualise(AudioPlayer *audio, MythRender *render)
def scan(profile, smoonURL, gate)
Definition: scan.py:43
void SetLastShownFrameToScratch(void)
QMap< MythPlayer *, PIPLocation > PIPMap
Definition: videooutbase.h:37
virtual bool DisplayOSD(VideoFrame *frame, OSD *osd)
If the OSD has changed, this will convert the OSD buffer to the OSDSurface's color format.
QString toString(MarkTypes type)
bool m_deinterlacing
Definition: videooutbase.h:350
MythCodecID
Definition: mythcodecid.h:10
const int kNeedFreeFrames
#define ROUNDUP(_x, _z)
OMX_U32 Base() const
Definition: omxcontext.h:48
QString GetFilteredDeint(const QString &override)
QRect GetVideoRect(void) const
bool IsValid() const
Definition: omxcontext.h:43
OMX_ERRORTYPE SetConfig(OMX_INDEXTYPE type, OMX_PTR p)
Definition: omxcontext.h:71
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.
const OMX_PARAM_PORTDEFINITIONTYPE & PortDef(unsigned index=0) const
Definition: omxcontext.cpp:299
VideoFrame * At(uint i)
Definition: videobuffers.h:90
void AddCurrentLocation(QString location)
QRect GetTotalOSDBounds(void) const
Returns total OSD bounds.
void CropToDisplay(VideoFrame *frame)
FrameScanType
Definition: videoouttypes.h:80
bool SetupDeinterlace(bool interlaced, const QString &overridefilter="") override
Attempts to enable or disable deinterlacing.
unsigned int uint
Definition: compat.h:140
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
virtual void StopEmbedding(void)
Tells video output to stop embedding video in an existing window.
static int shutdown()
MythScreenStack * GetMainStack()
virtual QString GetOSDRenderer(void) const
\ brief return OSD renderer type for this videoOutput
void MoveResizeWindow(QRect) override
void ProcessFrame(VideoFrame *Frame, FrameScanType scan=kScan_Ignore)
void PrepareFrame(VideoFrame *, FrameScanType, OSD *) override
VideoVisual * m_visual
Definition: videooutbase.h:377
bool DisplayOSD(VideoFrame *frame, OSD *osd) override
If the OSD has changed, this will convert the OSD buffer to the OSDSurface's color format.
VideoDisplayProfile * db_vdisp_profile
Definition: videooutbase.h:330
MythScreenType * m_backgroundscreen
Definition: videoout_omx.h:97
uint Size(BufferType type) const
const int kPrebufferFramesNormal
bool CanVisualise(AudioPlayer *, MythRender *) override
float GetDisplayAspect(void) const
Returns current display aspect ratio.
OMX_ERRORTYPE SetImageFilter(OMX_IMAGEFILTERTYPE)
unsigned char r
Definition: ParseText.cpp:340
bool SetVideoRect(const QRect &disp_rect, const QRect &vid_rect)
virtual void EmbedInWidget(const QRect &rect)
Tells video output to embed video in an existing window.
void ShowPortDef(unsigned index=0, LogLevel_t=LOG_INFO, uint64_t=VB_PLAYBACK) const
Definition: omxcontext.cpp:311
#define FRAME2HDR(f)
unsigned char b
Definition: ParseText.cpp:340
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
bool CreateBuffers(VideoFrameType type, int width, int height, vector< unsigned char * > bufs, vector< YUVInfo > yuvinfo)
void Show(FrameScanType) override
virtual void Close()
virtual void ShowPIPs(VideoFrame *frame, const PIPMap &pipPlayers)
int offsets[3]
Y, U, & V offsets.
Definition: mythframe.h:64
VideoFrame * Dequeue(BufferType)
void ProcessFrame(VideoFrame *, OSD *, FilterChain *, const PIPMap &, FrameScanType) override
Draw OSD, apply filters and deinterlacing,.
static int run(MythMediaDevice *dev=nullptr, bool startRandomShow=false)
ComponentCB UseBuffersCB
Definition: videoout_omx.h:76
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
OMX_ERRORTYPE PortEnable(unsigned index=0, int ms=-1, OMXComponentAbstractCB *cb=nullptr)
Definition: omxcontext.h:76
static void CopyFrame(VideoFrame *to, const VideoFrame *from)
Copies frame data from one VideoFrame to another.
static bool isRunning(const char *program)
Returns true if a program containing the specified string is running on this machine.
VERBOSE_PREAMBLE false
Definition: verbosedefs.h:85
MythPainter * GetOSDPainter(void) override
OMXComponent m_imagefx
Definition: videoout_omx.h:86
VideoBuffers vbuffers
VideoBuffers instance used to track video output buffers.
Definition: videooutbase.h:357
OMX_ERRORTYPE Init(OMX_INDEXTYPE)
Definition: omxcontext.cpp:220
static void clear(SettingsMap &cache, SettingsMap &overrides, const QString &myKey)
Definition: mythdb.cpp:830
OMX_ERRORTYPE SetState(OMX_STATETYPE state, int ms=-1, OMXComponentAbstractCB *cb=nullptr)
Definition: omxcontext.cpp:459
const int kKeepPrebuffer
static QString const s_name
int height
Definition: mythframe.h:42
MythCodecID video_codec_id
Definition: videooutbase.h:329
static bool CopyWindowFromBase(const QString &windowname, MythScreenType *win)
QRegion Draw(MythPainter *painter, QPaintDevice *device, QSize size, QRegion &changed, int alignx=0, int aligny=0)
Definition: osd.cpp:786
bool SetDeinterlacingEnabled(bool interlaced) override
Attempts to enable/disable deinterlacing using existing deinterlace method when enabling.
VideoErrorState errorState
Definition: videooutbase.h:360
bool InputChanged(const QSize &, const QSize &, float, MythCodecID, void *, bool &) override
Tells video output to discard decoded frames and wait for new ones.
#define FRAMESETHDRNONE(f)
QWidget * GetPaintWindow()
#define minor(X)
Definition: compat.h:138
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 end_lock()
Definition: videobuffers.h:100
void Shutdown()
Definition: omxcontext.cpp:187
QRect vsz_desired_display_rect
Definition: videooutbase.h:343
class QGLFormat MythRenderFormat
void OMX_DATA_INIT(T &s)
Definition: omxcontext.h:162
QRect GetDisplayVideoRect(void) const
int top_field_first
1 if top field is first.
Definition: mythframe.h:58
const char * name
Definition: ParseText.cpp:339
bool IsErrored() const
Returns true if a fatal error has been encountered.
Definition: videooutbase.h:179
void * av_malloc(unsigned int size)
OMX_ERRORTYPE PortDisable(unsigned index=0, int ms=-1, OMXComponentAbstractCB *cb=nullptr)
Definition: omxcontext.h:79
MythUIHelper * GetMythUI()
bool vsz_enabled
Definition: videooutbase.h:342
static QString const kName
Definition: videoout_omx.h:30
#define HDR2FRAME(h)
virtual QStringList GetVisualiserList(void)
VideoFrame * Tail(BufferType)
#define FRAMESETHDR(f, h)
static QStringList GetAllowedRenderers(MythCodecID, const QSize &)
const int kNumBuffers
MythMainWindow * GetMythMainWindow(void)
const int kMinBuffers
DisplayRes * display_res
Definition: videooutbase.h:364
const char * Filter2String(OMX_IMAGEFILTERTYPE eType)
static void GetRenderOptions(render_opts &opts, QStringList &cpudeints)
virtual bool hasFullScreenOSD(void) const
Definition: videooutbase.h:309
PIPLocation
Definition: videoouttypes.h:19
VideoFrame * GetScratchFrame(void)
virtual bool InputChanged(const QSize &video_dim_buf, const QSize &video_dim_disp, float aspect, MythCodecID myth_codec_id, void *codec_private, bool &aspect_changed)
Tells video output to discard decoded frames and wait for new ones.
int GetNumSetting(const QString &key, int defaultval=0)
QSize GetActualVideoDim(void) const
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
void StopEmbedding(void) override
Tells video output to stop embedding video in an existing window.
int64_t disp_timecode
Definition: mythframe.h:50
#define assert(x)
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...
OMX_ERRORTYPE SetParameter(OMX_INDEXTYPE type, OMX_PTR p)
Definition: omxcontext.h:66
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
QString RemoveCurrentLocation(void)
VideoFrame * Head(BufferType)
virtual VideoFrame * GetLastShownFrame(void)
Returns frame from the head of the ready to be displayed queue, if StartDisplayingFrame has been call...
Definition: videooutbase.h:239
void EmbedInWidget(const QRect &) override
Tells video output to embed video in an existing window.
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 DrawUnusedRects(bool) override
Draws non-video portions of the screen.
const char * Error2String(OMX_ERRORTYPE eError)
virtual void MoveResize(void)
performs all the calculations for video framing and any resizing.
float GetOverridenVideoAspect(void) const
Definition: osd.h:132
float GetVideoAspect(void) const
bool IsEmbedding(void)
Returns if videooutput is embedding.
virtual void Draw(const QRect &area, MythPainter *painter, QPaintDevice *device)=0
QRect GetDisplayVisibleRect(void) const
FilterChain * m_deintFilter
Definition: videooutbase.h:353
void Enqueue(BufferType, VideoFrame *)
bool Init(const QSize &, const QSize &, float, WId, const QRect &, MythCodecID) override
Performs most of the initialization for VideoOutput.
void SetAllowPreviewEPG(bool allowPreviewEPG)
void av_free(void *ptr)
OMXComponent m_render
Definition: videoout_omx.h:86
static uint buffersize(VideoFrameType type, int width, int height, int _aligned=64)
Definition: mythframe.h:291
VideoOutWindow window
Definition: videooutbase.h:320
Screen in which all other widgets are contained and rendered.
int interlaced_frame
1 if interlaced.
Definition: mythframe.h:57
virtual MythPainter * GetOSDPainter(void)
Definition: videooutbase.h:268
QVector< void * > m_bufs
Definition: videoout_omx.h:89
bool m_deinterlaceBeforeOSD
Definition: videooutbase.h:354
FilterManager * m_deintFiltMan
Definition: videooutbase.h:352
ComponentCB FreeBuffersCB
Definition: videoout_omx.h:76
bool CreateBuffers(const QSize &, const QSize &)
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.
frame_queue_t::iterator begin_lock(BufferType)
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
VideoFrame av_pause_frame
Definition: videoout_omx.h:87
virtual bool SetupVisualisation(AudioPlayer *audio, MythRender *render, const QString &name)
OMX_ERRORTYPE GetPortDef(unsigned index=0)
Definition: omxcontext.cpp:276
QStringList GetVisualiserList(void) override
bool ApproveDeintFilter(const QString &) const override
Approves bobdeint filter for XVideo and otherwise defers to VideoOutput::ApproveDeintFilter(const QSt...
void DeleteBuffers(void)
OMX_ERRORTYPE EmptyBufferDone(OMXComponent &, OMX_BUFFERHEADERTYPE *) override
bool hasFullScreenOSD(void) const override
#define codec_is_std(id)
Definition: mythcodecid.h:112
unsigned Ports() const
Definition: omxcontext.h:49
void ShowFormats(unsigned index=0, LogLevel_t=LOG_INFO, uint64_t=VB_PLAYBACK) const
Definition: omxcontext.cpp:440
void CreatePauseFrame(void)
#define OMX_VERSION
Definition: omxcontext.h:158
OMX_HANDLETYPE Handle() const
Definition: omxcontext.h:44
VideoFrameType codec
Definition: mythframe.h:38
void ReleaseBuffers(OMXComponent &) override