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 & /*video_dim*/)
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
307  m_render.ShowFormats(port, LOG_DEBUG);
308 #endif
309  }
310 
311  if (OMX_ErrorNone != m_imagefx.Init(OMX_IndexParamImageInit))
312  return;
313 
314  if (!m_imagefx.IsValid())
315  return;
316 
317  // Show default port definitions and formats supported
318  for (unsigned port = 0; port < m_imagefx.Ports(); ++port)
319  {
320  m_imagefx.ShowPortDef(port, LOG_DEBUG);
321 #if 0
322  m_imagefx.ShowFormats(port, LOG_DEBUG);
323 #endif
324  }
325 }
326 
327 // virtual
329 {
330  // Must shutdown the OMX components now before our state becomes invalid.
331  // When the component's dtor is called our state has already been destroyed.
333  m_render.Shutdown();
334 
335  DeleteBuffers();
336 
337 #ifdef OSD_EGL
338  if (m_osdpainter)
339  delete m_osdpainter, m_osdpainter = nullptr;
340  if (m_context)
341  m_context->DecrRef(), m_context = nullptr;
342  if (m_glOsdThread)
343  {
344  m_glOsdThread->shutdown();
345  delete m_glOsdThread;
346  m_glOsdThread = nullptr;
347  }
348  if (m_threaded_osdpainter)
349  delete m_threaded_osdpainter, m_threaded_osdpainter = nullptr;
350 #endif
351 
352  if (m_backgroundscreen)
353  {
355  m_backgroundscreen = nullptr;
357  }
358 }
359 
360 // virtual
361 bool VideoOutputOMX::Init( // Return true if successful
362  const QSize &video_dim_buf, // video buffer size
363  const QSize &video_dim_disp, // video display size
364  float aspect, // w/h of presented video
365  WId winid, // "video playback window" widget winId()
366  const QRect &win_rect, // playback rect on "video playback window"
367  MythCodecID codec_id ) // video codec
368 {
369  LOG(VB_PLAYBACK, LOG_INFO, LOC + __func__ +
370  QString(" vbuf=%1x%2 vdisp=%3x%4 aspect=%5 win=%6,%7,%8x%9 codec=%10")
371  .arg(video_dim_buf.width()).arg(video_dim_buf.height())
372  .arg(video_dim_disp.width()).arg(video_dim_disp.height())
373  .arg(aspect).arg(win_rect.x()).arg(win_rect.y())
374  .arg(win_rect.width()).arg(win_rect.height())
375  .arg(toString(codec_id)) );
376 
377  if (!codec_is_std(codec_id))
378  {
379  LOG(VB_GENERAL, LOG_ERR, LOC +
380  QString("Cannot create VideoOutput for codec %1")
381  .arg(toString(codec_id)));
383  return false;
384  }
385 
386  if (getenv("NO_OPENMAX"))
387  {
388  LOG(VB_PLAYBACK, LOG_NOTICE, LOC + __func__ + " OpenMAX disabled");
390  return false;
391  }
392 
393  if (!m_render.IsValid())
394  {
395  LOG(VB_GENERAL, LOG_ERR, LOC + __func__ + " No video render");
397  return false;
398  }
399  if (!m_imagefx.IsValid())
400  LOG(VB_GENERAL, LOG_WARNING, LOC + "Hardware deinterlace unavailable");
401 
403 
404  if (!VideoOutput::Init(video_dim_buf, video_dim_disp,
405  aspect, winid, win_rect, codec_id))
406  {
407  LOG(VB_GENERAL, LOG_ERR, LOC + __func__ + ": VideoOutput::Init failed");
408  return false;
409  }
410 
411  if (db_vdisp_profile)
413 
414  // Set resolution/measurements
415  InitDisplayMeasurements(video_dim_disp.width(), video_dim_disp.height(), false);
416 
417  if (OMX_ErrorNone != SetImageFilter(OMX_ImageFilterNone))
418  return false;
419 
420  // Setup video buffers
421  static const int kBuffers = std::max(
422  gCoreContext->GetNumSetting("OmxVideoBuffers", kNumBuffers), kMinBuffers);
423  vbuffers.Init(std::max(kBuffers, int(m_render.PortDef().nBufferCountMin)),
424  true, kNeedFreeFrames,
427 
428  // Allocate video buffers
429  if (!CreateBuffers(video_dim_buf, video_dim_disp))
430  return false;
431 
432  bool osdIsSet = false;
433 #ifdef OSD_EGL
434  if (GetOSDRenderer() == "opengl")
435  {
436  MythRenderEGL *render = new MythRenderEGL();
437  if (render->create())
438  {
439  render->Init();
440  m_context = render;
441  MythOpenGLPainter *p = new MythOpenGLPainter(m_context);
442  p->SetSwapControl(false);
443  m_osdpainter = p;
444  LOG(VB_GENERAL, LOG_INFO, LOC + __func__ +
445  ": OSD display uses opengl");
446  osdIsSet = true;
447  }
448  else
449  {
450  LOG(VB_GENERAL, LOG_ERR, LOC + __func__ +
451  ": failed to create MythRenderEGL");
452  render->DecrRef();
453  m_context = nullptr;
454  m_osdpainter = nullptr;
455  }
456  }
457  if (GetOSDRenderer() == "threaded")
458  {
459  m_glOsdThread = new GlOsdThread();
460  m_glOsdThread->start();
461  // Wait until set up
462  m_glOsdThread->m_lock.lock();
463  m_glOsdThread->m_lock.unlock();
464  if (m_glOsdThread->isValid())
465  osdIsSet = true;
466  }
467 #endif
468 
469  if (!osdIsSet)
470  LOG(VB_GENERAL, LOG_INFO, LOC + __func__ +
471  ": OSD display uses softblend");
472 
473  MoveResize();
474 
475  m_disp_rect = m_vid_rect = QRect();
477  return false;
478 
479  if (!Start())
480  return false;
481 
482  LOG(VB_PLAYBACK, LOG_DEBUG, LOC + __func__ + " done");
483  return true;
484 }
485 
486 // virtual
487 bool VideoOutputOMX::InputChanged( // Return true if successful
488  const QSize &video_dim_buf, // video buffer size
489  const QSize &video_dim_disp, // video display size
490  float aspect, // w/h of presented video
491  MythCodecID av_codec_id, // video codec
492  void *codec_private,
493  bool &aspect_only ) // Out: true if aspect only changed
494 {
495  QSize cursize = window.GetActualVideoDim();
496 
497  LOG(VB_PLAYBACK, LOG_INFO, LOC + __func__ +
498  QString(" from %1: %2x%3 aspect %4 to %5: %6x%7 aspect %9")
499  .arg(toString(video_codec_id)).arg(cursize.width())
500  .arg(cursize.height()).arg(window.GetVideoAspect())
501  .arg(toString(av_codec_id)).arg(video_dim_disp.width())
502  .arg(video_dim_disp.height()).arg(aspect));
503 
504  if (!codec_is_std(av_codec_id))
505  {
506  LOG(VB_GENERAL, LOG_ERR, LOC + "New video codec is not supported.");
508  return false;
509  }
510 
511  bool cid_changed = (video_codec_id != av_codec_id);
512  bool res_changed = video_dim_disp != cursize;
513  bool asp_changed = aspect != window.GetVideoAspect();
514 
515  if (!res_changed && !cid_changed)
516  {
517  if (asp_changed)
518  {
519  aspect_only = true;
520  VideoAspectRatioChanged(aspect);
521  MoveResize();
522  }
523  return true;
524  }
525 
526  VideoOutput::InputChanged(video_dim_buf, video_dim_disp,
527  aspect, av_codec_id, codec_private,
528  aspect_only);
529 
531  m_render.Shutdown();
532 
533  DeleteBuffers();
534  if (!CreateBuffers(video_dim_buf, video_dim_disp))
535  return false;
536 
537  MoveResize();
538 
539  m_disp_rect = m_vid_rect = QRect();
541  return false;
542 
543  if (!Start())
544  return false;
545 
546  if (db_vdisp_profile)
548 
549  LOG(VB_PLAYBACK, LOG_DEBUG, LOC + __func__ + " done");
550  return true;
551 }
552 
553 // virtual
554 bool VideoOutputOMX::ApproveDeintFilter(const QString& filtername) const
555 {
556  if (filtername.contains(kName))
557  return true;
558 
559  return VideoOutput::ApproveDeintFilter(filtername);
560 }
561 
562 // virtual
564 {
565  return SetupDeinterlace(interlaced);
566 }
567 
568 // virtual
569 bool VideoOutputOMX::SetupDeinterlace(bool interlaced, const QString &overridefilter)
570 {
571  if (!m_imagefx.IsValid())
572  return VideoOutput::SetupDeinterlace(interlaced, overridefilter);
573 
574  QString deintfiltername;
575  if (db_vdisp_profile)
576  deintfiltername = db_vdisp_profile->GetFilteredDeint(overridefilter);
577 
578  if (!deintfiltername.contains(kName))
579  {
580  if (m_deinterlacing && m_deintfiltername.contains(kName))
581  SetImageFilter(OMX_ImageFilterNone);
582  return VideoOutput::SetupDeinterlace(interlaced, overridefilter);
583  }
584 
585  if (m_deinterlacing == interlaced && deintfiltername == m_deintfiltername)
586  return m_deinterlacing;
587 
588  m_deintfiltername = deintfiltername;
589  m_deinterlacing = interlaced;
590 
591  // Remove non-openmax filters
592  delete m_deintFiltMan, m_deintFiltMan = nullptr;
593  delete m_deintFilter, m_deintFilter = nullptr;
594 
595  LOG(VB_PLAYBACK, LOG_INFO, LOC + __func__ + " switching " +
596  (interlaced ? "on" : "off") + " '" + deintfiltername + "'");
597 
598  OMX_IMAGEFILTERTYPE type;
599  if (!m_deinterlacing || m_deintfiltername.isEmpty())
600  type = OMX_ImageFilterNone;
601 #ifdef USING_BROADCOM
602  else if (m_deintfiltername.contains("advanced"))
603  type = OMX_ImageFilterDeInterlaceAdvanced;
604  else if (m_deintfiltername.contains("fast"))
605  type = OMX_ImageFilterDeInterlaceFast;
606  else if (m_deintfiltername.contains("linedouble"))
607  type = OMX_ImageFilterDeInterlaceLineDouble;
608 #endif
609  else
610  {
611  LOG(VB_GENERAL, LOG_ERR, LOC + __func__ + " Unknown type: '" +
612  m_deintfiltername + "'");
613 #ifdef USING_BROADCOM
614  type = OMX_ImageFilterDeInterlaceFast;
615 #else
616  type = OMX_ImageFilterNone;
617 #endif
618  }
619 
620  (void)SetImageFilter(type);
621 
622  return m_deinterlacing;
623 }
624 
625 OMX_ERRORTYPE VideoOutputOMX::SetImageFilter(OMX_IMAGEFILTERTYPE type)
626 {
627  LOG(VB_PLAYBACK, LOG_DEBUG, LOC + __func__ + " " + Filter2String(type));
628 
629 #ifdef USING_BROADCOM
630  OMX_INDEXTYPE index = OMX_IndexConfigCommonImageFilterParameters;
631  OMX_CONFIG_IMAGEFILTERPARAMSTYPE image_filter;
632  OMX_DATA_INIT(image_filter);
633  switch (type)
634  {
635  case OMX_ImageFilterDeInterlaceAdvanced:
636  image_filter.nNumParams = 1;
637  image_filter.nParams[0] = 3;
638  break;
639 
640  case OMX_ImageFilterDeInterlaceFast:
641  case OMX_ImageFilterDeInterlaceLineDouble:
642  case OMX_ImageFilterNone:
643  break;
644 
645  default:
646  break;
647  }
648 
649 #else
650  OMX_INDEXTYPE index = OMX_IndexConfigCommonImageFilter;
651  OMX_CONFIG_IMAGEFILTERTYPE image_filter;
652  OMX_DATA_INIT(image_filter);
653 #endif //def USING_BROADCOM
654 
655  if (!m_imagefx.IsValid())
656  return (type != OMX_ImageFilterNone) ? OMX_ErrorInvalidState : OMX_ErrorNone;
657 
658  image_filter.nPortIndex = m_imagefx.Base() + 1;
659  image_filter.eImageFilter = type;
660  OMX_ERRORTYPE e = m_imagefx.SetConfig(index, &image_filter);
661  if (e != OMX_ErrorNone)
662  LOG(VB_PLAYBACK, LOG_ERR, LOC + QString(
663  "SetConfig CommonImageFilter error %1")
664  .arg(Error2String(e)));
665  return e;
666 }
667 
668 // virtual
669 void VideoOutputOMX::EmbedInWidget(const QRect &rect)
670 {
671  if (!window.IsEmbedding())
673 }
674 
675 // virtual
677 {
678  if (window.IsEmbedding())
680 }
681 
682 // virtual
684 {
685  VideoOutput::Zoom(direction);
686  MoveResize();
687 }
688 
689 // virtual
691  PIPLocation location, MythPlayer *pipplayer, bool do_pixel_adj) const
692 {
693  QRect r = VideoOutput::GetPIPRect(location, pipplayer, do_pixel_adj);
694 
695  const QRect display_video_rect = window.GetDisplayVideoRect();
696  const QRect video_rect = window.GetVideoRect();
697  const QRect display_visible_rect = window.GetDisplayVisibleRect();
698 
699  // Transform PIP rect from DisplayVisibleRect to VideoRect
700  qreal s = qreal(display_video_rect.width()) / display_visible_rect.width();
701  s /= qreal(display_video_rect.height()) / display_visible_rect.height();
702  r = QTransform()
703  .scale( (s * video_rect.width()) / display_video_rect.width(),
704  (s * video_rect.height()) / display_video_rect.height() )
705  .mapRect(r);
706 
707  r.setRect(r.x() & ~1, r.y() & ~1, r.width() & ~1, r.height() & ~1);
708  return r;
709 }
710 
712 {
713  delete [] av_pause_frame.buf;
714  av_pause_frame.buf = nullptr;
715 
716  VideoFrame *scratch = vbuffers.GetScratchFrame();
717 
718  init(&av_pause_frame, FMT_YV12, new unsigned char[scratch->size + 128],
719  scratch->width, scratch->height, scratch->size);
720 
722 
724 
725  // Need two pause frames for OMX video_render.
726  // 1st is held by EmptyBuffer until next frame is sent.
727  // Need additional pause frame for advanced deinterlacer
728  while (vbuffers.Size(kVideoBuffer_pause) < 3)
730 }
731 
732 // pure virtual
733 void VideoOutputOMX::UpdatePauseFrame(int64_t &disp_timecode)
734 {
735  if (!av_pause_frame.buf)
736  {
737  LOG(VB_GENERAL, LOG_ERR, LOC + __func__ + " - no buffers?");
738  return;
739  }
740 
741  // Try used frame first, then fall back to scratch frame.
743 
744  VideoFrame *used_frame = (vbuffers.Size(kVideoBuffer_used) > 0) ?
745  vbuffers.Head(kVideoBuffer_used) : nullptr;
746  if (used_frame)
747  CopyFrame(&av_pause_frame, used_frame);
748 
749  vbuffers.end_lock();
750 
751  if (!used_frame)
752  {
753  used_frame = vbuffers.Tail(kVideoBuffer_pause);
754  used_frame->frameNumber = framesPlayed - 1;
755  CopyFrame(&av_pause_frame, used_frame);
756  }
757 
758  // Suppress deinterlace while paused to prevent the jiggles.
761 
762  disp_timecode = av_pause_frame.disp_timecode;
763 }
764 
768 // pure virtual
770  FilterChain *filterList,
771  const PIPMap &pipPlayers,
773 {
774  if (IsErrored())
775  {
776  LOG(VB_GENERAL, LOG_ERR, LOC + __func__ + " IsErrored is true");
777  return;
778  }
779 
780  m_videoPaused = false;
781  if (!frame)
782  {
783  // Rotate pause frames
784  m_videoPaused = true;
786  frame = vbuffers.GetScratchFrame();
787  CopyFrame(frame, &av_pause_frame);
788  }
789 
790  CropToDisplay(frame);
791 
792  if (filterList)
793  filterList->ProcessFrame(frame);
794 
797 
798  ShowPIPs(frame, pipPlayers);
799  if (osd && !window.IsEmbedding())
800  DisplayOSD(frame, osd);
801 
804 }
805 
806 // tells show what frame to be show, do other last minute stuff
807 // pure virtual
808 void VideoOutputOMX::PrepareFrame(VideoFrame *buffer, FrameScanType /*scan*/, OSD */*osd*/)
809 {
810  if (IsErrored())
811  {
812  LOG(VB_GENERAL, LOG_ERR, LOC + __func__ + " IsErrored is true");
813  return;
814  }
815 
816  if (!buffer)
817  {
818  buffer = vbuffers.GetScratchFrame();
820  }
821 
822  framesPlayed = buffer->frameNumber + 1;
823 
824  // PGB Set up a background window to prevent bleed through
825  // of theme when playing a video smaller than the play area
826  if (m_backgroundscreen == nullptr)
827  {
828  MythMainWindow *mainWindow = GetMythMainWindow();
829  MythScreenStack *mainStack = mainWindow->GetMainStack();
830  m_backgroundscreen = new MythScreenType(mainStack,"VideoBackground");
831 
832  if (XMLParseBase::CopyWindowFromBase("videobackground",
834  {
835  mainStack->AddScreen(m_backgroundscreen, false);
836  GetMythUI()->AddCurrentLocation("Playback");
837  if (mainWindow->GetPaintWindow())
838  mainWindow->GetPaintWindow()->update();
839  qApp->processEvents();
840  }
841  }
842 
845  window.GetVideoRect() );
846 }
847 
848 // BLT the last prepared frame to the screen as quickly as possible.
849 // pure virtual
851 {
852  if (IsErrored())
853  {
854  LOG(VB_GENERAL, LOG_ERR, LOC + __func__ + " IsErrored is true");
855  return;
856  }
857 
858  VideoFrame *frame = GetLastShownFrame();
859  if (!frame)
860  {
861  LOG(VB_GENERAL, LOG_ERR, LOC + __func__ + " No LastShownFrame");
862  return;
863  }
864 
865  OMX_BUFFERHEADERTYPE *hdr = FRAME2HDR(frame);
866  if (!hdr)
867  {
868  LOG(VB_GENERAL, LOG_ERR, LOC + __func__ + " Frame has no buffer header");
869  return;
870  }
871 
872  assert(hdr->nSize == sizeof(OMX_BUFFERHEADERTYPE));
873  assert(hdr->nVersion.nVersion == OMX_VERSION);
874  assert(hdr->pBuffer == frame->buf);
875 
876  if (hdr->nFilledLen)
877  {
878  LOG(VB_GENERAL, LOG_WARNING, LOC + __func__ + " Frame in use");
879  return; // Pending empty callback
880  }
881 
882  assert(frame->codec == FMT_YV12);
883 
884  hdr->nFilledLen = frame->offsets[2] + (frame->offsets[1] >> 2);
885  hdr->nFlags = OMX_BUFFERFLAG_ENDOFFRAME;
886 #ifdef OMX_BUFFERFLAG_INTERLACED
887  if (frame->interlaced_frame)
888  hdr->nFlags |= OMX_BUFFERFLAG_INTERLACED;
889 #endif
890 #ifdef OMX_BUFFERFLAG_TOP_FIELD_FIRST
891  if (frame->top_field_first)
892  hdr->nFlags |= OMX_BUFFERFLAG_TOP_FIELD_FIRST;
893 #endif
895  // Paused - do not display anything unless softblend set
896  if (m_videoPaused && GetOSDRenderer() != "softblend")
897  {
898  // fake out that the buffer was already emptied
899  EmptyBufferDone(cmpnt, hdr);
900  return;
901  }
902  OMX_ERRORTYPE e = OMX_EmptyThisBuffer(cmpnt.Handle(), hdr);
903  if (e != OMX_ErrorNone)
904  {
905  LOG(VB_PLAYBACK, LOG_ERR, LOC + QString(
906  "OMX_EmptyThisBuffer error %1").arg(Error2String(e)) );
907  hdr->nFlags = 0;
908  hdr->nFilledLen = 0;
909  }
910 }
911 
912 // pure virtual
913 void VideoOutputOMX::MoveResizeWindow(QRect /*new_rect*/)
914 {
915 }
916 
917 // virtual
919 {
920 #ifdef OSD_EGL
921  if (GetOSDRenderer() == "opengl"
922  && m_context && m_osdpainter)
923  return true;
924  if (GetOSDRenderer() == "threaded"
925  && m_glOsdThread && m_glOsdThread->isValid())
926  return true;
927 #endif
929 }
930 
931 // virtual
933 {
934 #ifdef OSD_EGL
935  if (GetOSDRenderer() == "opengl")
936  return m_osdpainter;
937  if (GetOSDRenderer() == "threaded")
938  return m_threaded_osdpainter;
939 #endif
941 }
942 
943 // virtual
945 {
946 #ifdef OSD_EGL
947  if (GetOSDRenderer() == "opengl"
948  && m_context && m_osdpainter)
949  {
950  m_context->makeCurrent();
951  m_context->BindFramebuffer(0);
952 
953  QRect bounds = GetTotalOSDBounds();
954  bool redraw = false;
955  if (m_visual)
956  {
957  m_visual->Draw(bounds, m_osdpainter, nullptr);
958  redraw = true;
959  }
960 
961  if (osd)
962  redraw |= osd->DrawDirect(m_osdpainter, bounds.size(), redraw);
963 
964  if (redraw)
965  {
966  m_context->swapBuffers();
967  m_context->SetBackground(0, 0, 0, 0);
968  m_context->ClearFramebuffer();
969  }
970 
971  m_context->doneCurrent();
972  return true;
973  }
974 
975  if (GetOSDRenderer() == "threaded"
976  && m_glOsdThread && m_glOsdThread->isValid())
977  {
978  if (!m_threaded_osdpainter)
979  {
980  m_threaded_osdpainter = new MythQImagePainter();
981  if (!m_threaded_osdpainter)
982  return false;
983  }
984  QSize osd_size = GetTotalOSDBounds().size();
985  if (m_glOsdThread->m_osdImage && (m_glOsdThread->m_osdImage->size() != osd_size))
986  {
987  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("OSD size changed."));
988  m_glOsdThread->m_osdImage->DecrRef();
989  m_glOsdThread->m_osdImage = nullptr;
990  }
991  if (!m_glOsdThread->m_osdImage)
992  {
993  m_glOsdThread->m_osdImage = m_threaded_osdpainter->GetFormatImage();
994  if (m_glOsdThread->m_osdImage)
995  {
996  QImage blank = QImage(osd_size,
997  QImage::Format_ARGB32_Premultiplied);
998  m_glOsdThread->m_osdImage->Assign(blank);
999  m_threaded_osdpainter->Clear(m_glOsdThread->m_osdImage,
1000  QRegion(QRect(QPoint(0,0), osd_size)));
1001  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Created OSD QImage."));
1002  }
1003  else {
1004  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Unable to create OSD QImage."));
1005  return false;
1006  }
1007  }
1008  if (m_visual)
1009  {
1010  LOG(VB_GENERAL, LOG_ERR, LOC + "Visualiser not supported here");
1011  m_visual->Draw(QRect(), nullptr, nullptr);
1012  }
1013 
1014  if (m_glOsdThread->m_lock.tryLock(0)) {
1015  QRegion dirty = QRegion();
1016  QRegion visible = osd->Draw(m_threaded_osdpainter,
1017  m_glOsdThread->m_osdImage, osd_size, dirty);
1018  m_changed = m_changed || !dirty.isEmpty();
1019  m_glOsdThread->m_osdImage->SetChanged(m_changed);
1020  m_glOsdThread->m_bounds = GetTotalOSDBounds();
1021  m_glOsdThread->m_lock.unlock();
1022  if (m_changed) {
1023  m_glOsdThread->m_wait.wakeAll();
1024  m_changed = false;
1025  }
1026  }
1027  return true;
1028  }
1029 #endif
1030  return VideoOutput::DisplayOSD(frame, osd);
1031 }
1032 
1033 // virtual
1035 {
1036  (void)sync;
1037 }
1038 
1039 // virtual
1041 {
1042 #ifdef OSD_EGL
1043  return VideoOutput::CanVisualise(audio, m_context ? m_context : render);
1044 #else
1045  return VideoOutput::CanVisualise(audio, render);
1046 #endif
1047 }
1048 
1049 // virtual
1051  const QString &name)
1052 {
1053 #ifdef OSD_EGL
1054  return VideoOutput::SetupVisualisation(audio,
1055  m_context ? m_context : render, name);
1056 #else
1057  return VideoOutput::SetupVisualisation(audio, render, name);
1058 #endif
1059 }
1060 
1061 // virtual
1063 {
1064 #ifdef OSD_EGL
1065  return m_context ?
1066  VideoVisual::GetVisualiserList(m_context->Type()) :
1068 #else
1070 #endif
1071 }
1072 
1074  const QSize &video_dim_buf, // video buffer size
1075  const QSize &video_dim_disp) // video display size
1076 {
1078 
1079  // Set the video dimensions
1080  OMX_S32 nStride = ROUNDUP(video_dim_buf.width(), 32);
1081  OMX_U32 nSliceHeight = ROUNDUP(video_dim_buf.height(), 16);
1082  OMX_PARAM_PORTDEFINITIONTYPE def = cmpnt.PortDef();
1083  assert(vbuffers.Size() >= def.nBufferCountMin);
1084  def.nBufferCountActual = vbuffers.Size();
1085  def.nBufferSize = 0;
1086  def.bBuffersContiguous = OMX_FALSE;
1087  def.nBufferAlignment = sizeof(int);
1088  def.eDomain = OMX_PortDomainVideo;
1089  def.format.video.cMIMEType = nullptr;
1090  def.format.video.pNativeRender = nullptr;
1091  def.format.video.nFrameWidth = video_dim_disp.width();
1092  def.format.video.nFrameHeight = video_dim_disp.height();
1093  def.format.video.nStride = nStride;
1094  def.format.video.nSliceHeight = nSliceHeight;
1095  def.format.video.nBitrate = 0;
1096  def.format.video.xFramerate = 0;
1097  def.format.video.bFlagErrorConcealment = OMX_FALSE;
1098  def.format.video.eCompressionFormat = OMX_VIDEO_CodingUnused;
1099  def.format.video.eColorFormat = OMX_COLOR_FormatYUV420PackedPlanar;
1100  def.format.video.pNativeWindow = nullptr;
1101  OMX_ERRORTYPE e = cmpnt.SetParameter(OMX_IndexParamPortDefinition, &def);
1102  if (e != OMX_ErrorNone)
1103  {
1104  LOG(VB_PLAYBACK, LOG_ERR, LOC + QString(
1105  "SetParameter PortDefinition error %1")
1106  .arg(Error2String(e)));
1107  return false;
1108  }
1109 
1110  // Update port status with revised buffer size etc
1111  if (OMX_ErrorNone != cmpnt.GetPortDef())
1112  return false;
1113 
1114  // Setup image_fx output
1115  if (m_imagefx.IsValid())
1116  {
1117  def = m_imagefx.PortDef(1);
1118  def.nBufferCountActual = 1 + std::max(def.nBufferCountMin,
1119  m_render.PortDef().nBufferCountMin);
1120  def.nBufferSize = 0;
1121  assert(def.eDomain == OMX_PortDomainImage);
1122  def.format.image.nFrameWidth = video_dim_disp.width();
1123  def.format.image.nFrameHeight = video_dim_disp.height();
1124  def.format.image.nStride = nStride;
1125  def.format.image.nSliceHeight = nSliceHeight;
1126  e = m_imagefx.SetParameter(OMX_IndexParamPortDefinition, &def);
1127  if (e != OMX_ErrorNone)
1128  {
1129  LOG(VB_PLAYBACK, LOG_ERR, LOC + QString(
1130  "SetParameter image_fx output PortDefinition error %1")
1131  .arg(Error2String(e)));
1132  return false;
1133  }
1134 
1135  if (OMX_ErrorNone != m_imagefx.GetPortDef(1))
1136  return false;
1137  }
1138 
1139  int pitches[3], offsets[3];
1140  pitches[0] = nStride;
1141  pitches[1] = pitches[2] = nStride >> 1;
1142  offsets[0] = 0;
1143  offsets[1] = nStride * nSliceHeight;
1144  offsets[2] = offsets[1] + (offsets[1] >> 2);
1145  uint nBufferSize = buffersize(FMT_YV12, nStride, nSliceHeight);
1146 
1147  std::vector<unsigned char*> bufs;
1148  std::vector<YUVInfo> yuvinfo;
1149  for (uint i = 0; i < vbuffers.Size(); ++i)
1150  {
1151  yuvinfo.emplace_back(video_dim_disp.width(), video_dim_disp.height(),
1152  nBufferSize, pitches, offsets);
1153  void *buf = av_malloc(nBufferSize + 64);
1154  if (!buf)
1155  {
1156  LOG(VB_GENERAL, LOG_ERR, LOC + "Out of memory");
1158  return false;
1159  }
1160  m_bufs.push_back(buf);
1161  bufs.push_back((unsigned char *)buf);
1162  }
1163  if (!vbuffers.CreateBuffers(FMT_YV12, video_dim_disp.width(),
1164  video_dim_disp.height(), bufs, yuvinfo))
1165  {
1166  LOG(VB_GENERAL, LOG_ERR, LOC + "CreateBuffers failed");
1168  return false;
1169  }
1170 
1171  CreatePauseFrame();
1172 
1173  return true;
1174 }
1175 
1177 {
1178  delete [] av_pause_frame.buf;
1179  init(&av_pause_frame, FMT_YV12, nullptr, 0, 0, 0);
1180 
1182 
1183  while (!m_bufs.empty())
1184  {
1185  av_free(m_bufs.back());
1186  m_bufs.pop_back();
1187  }
1188 }
1189 
1191 {
1192  if (m_imagefx.IsValid())
1193  {
1194  // Setup a tunnel between image_fx & video_render
1195  OMX_ERRORTYPE e;
1196  e = OMX_SetupTunnel(m_imagefx.Handle(), m_imagefx.Base() + 1,
1197  m_render.Handle(), m_render.Base());
1198  if (e != OMX_ErrorNone)
1199  {
1200  LOG(VB_PLAYBACK, LOG_ERR, LOC + QString("OMX_SetupTunnel error %1")
1201  .arg(Error2String(e)));
1202  return false;
1203  }
1204 
1205  // Disable image_fx input port.
1206  // A disabled port is not populated with buffers on a transition to IDLE
1207  if (m_imagefx.PortDisable(0, 500) != OMX_ErrorNone)
1208  return false;
1209 
1210  // Goto OMX_StateIdle
1211  if (m_imagefx.SetState(OMX_StateIdle, 500) != OMX_ErrorNone)
1212  return false;
1213 
1214  if (m_render.SetState(OMX_StateIdle, 500) != OMX_ErrorNone)
1215  return false;
1216 
1217  // Enable image_fx input port and populate buffers
1219  if (m_imagefx.PortEnable(0, 500, &cb) != OMX_ErrorNone)
1220  return false;
1221 
1222  // Goto OMX_StateExecuting
1223  if (m_imagefx.SetState(OMX_StateExecuting, 500) != OMX_ErrorNone)
1224  return false;
1225  }
1226  else
1227  {
1228  if (m_render.PortDisable(0, 500) != OMX_ErrorNone)
1229  return false;
1230 
1231  if (m_render.SetState(OMX_StateIdle, 500) != OMX_ErrorNone)
1232  return false;
1233 
1235  if (m_render.PortEnable(0, 500, &cb) != OMX_ErrorNone)
1236  return false;
1237  }
1238 
1239  return m_render.SetState(OMX_StateExecuting, 500) == OMX_ErrorNone;
1240 }
1241 
1242 bool VideoOutputOMX::SetVideoRect(const QRect &d_rect, const QRect &vid_rect)
1243 {
1244  // Translate display rect to screen coordinates
1245  QRect disp_rect = d_rect.translated(GetMythMainWindow()->geometry().topLeft());
1246 
1247  if (disp_rect == m_disp_rect && vid_rect == m_vid_rect)
1248  return true;
1249 
1250  LOG(VB_PLAYBACK, LOG_INFO, LOC + __func__ + QString(
1251  " display=%1,%2,%3x%4 (%9) video=%5,%6,%7x%8 (%10)")
1252  .arg(disp_rect.x()).arg(disp_rect.y())
1253  .arg(disp_rect.width()).arg(disp_rect.height())
1254  .arg(vid_rect.x()).arg(vid_rect.y())
1255  .arg(vid_rect.width()).arg(vid_rect.height())
1257 
1258 #ifdef USING_BROADCOM
1259  OMX_CONFIG_DISPLAYREGIONTYPE dregion;
1260  OMX_DATA_INIT(dregion);
1261  dregion.nPortIndex = m_render.Base();
1262  dregion.set = OMX_DISPLAYSETTYPE( OMX_DISPLAY_SET_FULLSCREEN |
1263  OMX_DISPLAY_SET_TRANSFORM |
1264  OMX_DISPLAY_SET_DEST_RECT | OMX_DISPLAY_SET_SRC_RECT |
1265  OMX_DISPLAY_SET_MODE |
1266  OMX_DISPLAY_SET_PIXEL |
1267  OMX_DISPLAY_SET_NOASPECT |
1268  OMX_DISPLAY_SET_LAYER );
1269  dregion.fullscreen = OMX_FALSE;
1270  dregion.transform = OMX_DISPLAY_ROT0;
1271  dregion.dest_rect.x_offset = disp_rect.x();
1272  dregion.dest_rect.y_offset = disp_rect.y();
1273  dregion.dest_rect.width = disp_rect.width();
1274  dregion.dest_rect.height = disp_rect.height();
1275  dregion.src_rect.x_offset = vid_rect.x();
1276  dregion.src_rect.y_offset = vid_rect.y();
1277  dregion.src_rect.width = vid_rect.width();
1278  dregion.src_rect.height = vid_rect.height();
1279  dregion.noaspect = OMX_TRUE;
1280  dregion.mode = OMX_DISPLAY_MODE_FILL; //OMX_DISPLAY_MODE_LETTERBOX;
1281  dregion.pixel_x = dregion.pixel_y = 0;
1282  // NB Qt EGLFS uses layer 1 - See createDispmanxLayer() in
1283  // mkspecs/devices/linux-rasp-pi-g++/qeglfshooks_pi.cpp.
1284  // Therefore to view video must select layer >= 1
1285  dregion.layer = 2;
1286 
1287  OMX_ERRORTYPE e = m_render.SetConfig(OMX_IndexConfigDisplayRegion, &dregion);
1288  if (e != OMX_ErrorNone)
1289  {
1290  LOG(VB_PLAYBACK, LOG_ERR, LOC + QString(
1291  "SetConfig DisplayRegion error %1")
1292  .arg(Error2String(e)));
1293  return false;
1294  }
1295 #endif // USING_BROADCOM
1296 
1297 #ifdef OSD_EGL
1298  if (m_context
1299  || ( m_glOsdThread && m_glOsdThread->isValid() ) )
1300  {
1301  QRect displayRect = window.GetDisplayVisibleRect();
1302  QRect mainRect = GetMythMainWindow()->geometry();
1303  uint32_t maxwidth = 0, maxheight = 0;
1304  graphics_get_display_size(DISPMANX_ID_MAIN_LCD, &maxwidth, &maxheight);
1305  QRect glRect(mainRect.x(), // left
1306  maxheight-mainRect.bottom(), // top
1307  0,0);
1308  glRect.setRight(mainRect.right());
1309  glRect.setBottom(glRect.top()+mainRect.height());
1310  if (m_context)
1311  {
1312  m_context->SetViewPort(displayRect);
1313  m_context->SetViewPort(glRect,true);
1314  }
1315  if (m_glOsdThread && m_glOsdThread->isValid()) {
1316  m_glOsdThread->setRects(displayRect,glRect);
1317  }
1318  }
1319 #endif
1320 
1321  m_disp_rect = disp_rect;
1322  m_vid_rect = vid_rect;
1323 
1324  return true;
1325 }
1326 
1327 // virtual
1329  OMXComponent& /*cmpnt*/, OMX_BUFFERHEADERTYPE *hdr)
1330 {
1331  assert(hdr->nSize == sizeof(OMX_BUFFERHEADERTYPE));
1332  assert(hdr->nVersion.nVersion == OMX_VERSION);
1333  hdr->nFilledLen = 0;
1334  hdr->nFlags = 0;
1335  return OMX_ErrorNone;
1336 }
1337 
1338 // Shutdown OMX_StateIdle -> OMX_StateLoaded callback
1339 // virtual
1341 {
1343  if(cmpnt.Handle() == c.Handle())
1344  FreeBuffersCB();
1345 }
1346 
1347 // Use frame buffers
1348 OMX_ERRORTYPE VideoOutputOMX::UseBuffersCB()
1349 {
1351  const OMX_PARAM_PORTDEFINITIONTYPE &def = cmpnt.PortDef();
1352  assert(vbuffers.Size() >= def.nBufferCountActual);
1353 
1354  LOG(VB_PLAYBACK, LOG_DEBUG, LOC + QString("Use %1 of %2 byte buffer(s)")
1355  .arg(def.nBufferCountActual).arg(def.nBufferSize));
1356 
1357  OMX_ERRORTYPE e = OMX_ErrorNone;
1358 
1359  for (uint i = 0; i < vbuffers.Size(); ++i)
1360  {
1361  VideoFrame *vf = vbuffers.At(i);
1362  assert(vf);
1363  assert(OMX_U32(vf->size) >= def.nBufferSize);
1364  assert(vf->buf);
1365  if (i >= def.nBufferCountActual)
1366  continue;
1367 
1368  OMX_BUFFERHEADERTYPE *hdr;
1369  e = OMX_UseBuffer(cmpnt.Handle(), &hdr, def.nPortIndex, vf,
1370  def.nBufferSize, vf->buf);
1371  if (e != OMX_ErrorNone)
1372  {
1373  LOG(VB_PLAYBACK, LOG_ERR, LOC + QString(
1374  "OMX_UseBuffer error %1").arg(Error2String(e)) );
1375  break;
1376  }
1377  if (hdr->nSize != sizeof(OMX_BUFFERHEADERTYPE))
1378  {
1379  LOG(VB_PLAYBACK, LOG_ERR, LOC + "OMX_UseBuffer header mismatch");
1380  OMX_FreeBuffer(cmpnt.Handle(), def.nPortIndex, hdr);
1381  e = OMX_ErrorVersionMismatch;
1382  break;
1383  }
1384  if (hdr->nVersion.nVersion != OMX_VERSION)
1385  {
1386  LOG(VB_PLAYBACK, LOG_ERR, LOC + "OMX_UseBuffer version mismatch");
1387  OMX_FreeBuffer(cmpnt.Handle(), def.nPortIndex, hdr);
1388  e = OMX_ErrorVersionMismatch;
1389  break;
1390  }
1391  assert(vf == HDR2FRAME(hdr));
1392  FRAMESETHDR(vf, hdr);
1393  hdr->nFilledLen = 0;
1394  hdr->nOffset = 0;
1395  }
1396 
1397  return e;
1398 }
1399 
1400 // Free all OMX buffers
1401 // OMX_CommandPortDisable callback
1402 OMX_ERRORTYPE VideoOutputOMX::FreeBuffersCB()
1403 {
1405 #ifndef NDEBUG
1406  const OMX_PARAM_PORTDEFINITIONTYPE &def = cmpnt.PortDef();
1407  assert(vbuffers.Size() >= def.nBufferCountActual);
1408 #endif
1409 
1410  for (uint i = 0; i < vbuffers.Size(); ++i)
1411  {
1412  VideoFrame *vf = vbuffers.At(i);
1413  assert(vf);
1414  OMX_BUFFERHEADERTYPE *hdr = FRAME2HDR(vf);
1415  if (!hdr)
1416  continue;
1417  assert(hdr->nSize == sizeof(OMX_BUFFERHEADERTYPE));
1418  assert(hdr->nVersion.nVersion == OMX_VERSION);
1419  assert(vf == HDR2FRAME(hdr));
1420  FRAMESETHDRNONE(vf);
1421 
1422  OMX_ERRORTYPE e = OMX_FreeBuffer(cmpnt.Handle(), cmpnt.Base(), hdr);
1423  if (e != OMX_ErrorNone)
1424  {
1425  LOG(VB_PLAYBACK, LOG_ERR, LOC + QString(
1426  "OMX_FreeBuffer 0x%1 error %2")
1427  .arg(quintptr(hdr),0,16).arg(Error2String(e)));
1428  }
1429  }
1430  return OMX_ErrorNone;
1431 }
1432 
1433 #ifdef OSD_EGL
1434 MythRenderEGL::MythRenderEGL() :
1436  m_display(EGL_NO_DISPLAY),
1437  m_context(EGL_NO_CONTEXT),
1438  m_window(nullptr),
1439  m_surface(EGL_NO_SURFACE)
1440 {
1441  // Disable flush to get performance improvement
1442  m_flushEnabled = false;
1443  // get an EGL display connection
1444  m_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
1445  if (m_display == EGL_NO_DISPLAY)
1446  {
1447  LOG(VB_GENERAL, LOG_ERR, "eglGetDisplay => EGL_NO_DISPLAY");
1448  return;
1449  }
1450 
1451  // initialize the EGL display connection
1452  EGLint major, minor;
1453  EGLBoolean b = eglInitialize(m_display, &major, &minor);
1454  if (!b)
1455  {
1456  LOG(VB_GENERAL, LOG_ERR, "eglInitialize failed");
1457  return;
1458  }
1459  LOG(VB_PLAYBACK, LOG_INFO, QString("EGL runtime version %1.%2")
1460  .arg(major).arg(minor));
1461 
1462  // get an appropriate EGL frame buffer configuration
1463  static EGLint const attribute_list[] = {
1464  EGL_RED_SIZE, 8,
1465  EGL_GREEN_SIZE, 8,
1466  EGL_BLUE_SIZE, 8,
1467  EGL_ALPHA_SIZE, 8,
1468  EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
1469  EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, // ES2 required for GLSL
1470  EGL_NONE
1471  };
1472  EGLConfig config;
1473  EGLint num_config;
1474  b = eglChooseConfig(m_display, attribute_list, &config, 1, &num_config);
1475  if (!b)
1476  {
1477  LOG(VB_GENERAL, LOG_ERR, "eglChooseConfig failed");
1478  return;
1479  }
1480 
1481  // create an EGL rendering context
1482  static EGLint const ctx_attribute_list[] = {
1483  EGL_CONTEXT_CLIENT_VERSION, 2, // ES2 required for GLSL
1484  EGL_NONE
1485  };
1486  m_context = eglCreateContext(m_display, config, EGL_NO_CONTEXT, ctx_attribute_list);
1487  if (m_context == EGL_NO_CONTEXT)
1488  {
1489  LOG(VB_GENERAL, LOG_ERR, "eglCreateContext failed");
1490  return;
1491  }
1492 
1493 #ifdef USE_OPENGL_QT5
1494  QVariant v;
1495  v.setValue(QEGLNativeContext(m_context, m_display));
1496  setNativeHandle(v);
1497 #endif
1498 
1499  m_window = createNativeWindow();
1500 
1501  m_surface = eglCreateWindowSurface(m_display, config, m_window, nullptr);
1502  if (m_context == EGL_NO_SURFACE)
1503  {
1504  LOG(VB_GENERAL, LOG_ERR, "eglCreateWindowSurface failed");
1505  return;
1506  }
1507 
1508  // connect the context to the surface
1509  b = eglMakeCurrent(m_display, m_surface, m_surface, m_context);
1510  if (!b)
1511  {
1512  LOG(VB_GENERAL, LOG_ERR, "eglMakeCurrent failed");
1513  return;
1514  }
1515 
1516  // clear the color buffer
1517  glClearColor(0, 0, 0, 0); // RGBA
1518  glClear(GL_COLOR_BUFFER_BIT);
1519  glFlush();
1520  b = eglSwapBuffers(m_display, m_surface);
1521  if (!b)
1522  LOG(VB_GENERAL, LOG_ERR, "eglSwapBuffers failed");
1523 
1524  b = eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
1525  if (!b)
1526  LOG(VB_GENERAL, LOG_ERR, "eglMakeCurrent EGL_NO_SURFACE failed");
1527 
1528 #ifndef USE_OPENGL_QT5
1529  setValid(true);
1530 #endif
1531 }
1532 
1533 MythRenderEGL::~MythRenderEGL()
1534 {
1535 #ifndef USE_OPENGL_QT5
1536  setValid(false);
1537 #endif
1538 
1539  if (m_display == EGL_NO_DISPLAY)
1540  return;
1541 
1542  EGLBoolean b;
1543  if (m_context != EGL_NO_CONTEXT)
1544  {
1545  b = eglMakeCurrent(m_display, m_surface, m_surface, m_context);
1546  assert(b == EGL_TRUE);
1547  }
1548 
1549  if (m_surface != EGL_NO_SURFACE)
1550  {
1551  b = eglDestroySurface(m_display, m_surface);
1552  assert(b == EGL_TRUE);
1553  m_surface = EGL_NO_SURFACE;
1554  }
1555 
1556  destroyNativeWindow();
1557 
1558  if (m_context != EGL_NO_CONTEXT)
1559  {
1560  b = eglDestroyContext(m_display, m_context);
1561  assert(b == EGL_TRUE);
1562  m_context = EGL_NO_CONTEXT;
1563  }
1564 
1565 #if 0 // This causes Qt to throw a segv
1566  b = eglTerminate(m_display);
1567  assert(b == EGL_TRUE);
1568 #endif
1569  m_display = EGL_NO_DISPLAY;
1570  DeleteOpenGLResources();
1571 
1572 #ifdef NDEBUG
1573  Q_UNUSED(b);
1574 #endif
1575 }
1576 
1577 EGLNativeWindowType MythRenderEGL::createNativeWindow()
1578 {
1579 #ifdef USING_BROADCOM
1580  uint32_t width = 0, height = 0;
1581  int32_t ret = graphics_get_display_size(DISPMANX_ID_MAIN_LCD, &width, &height);
1582  assert(ret >= 0);
1583 
1584  m_dispman_display = vc_dispmanx_display_open(DISPMANX_ID_MAIN_LCD);
1585  assert(m_dispman_display != DISPMANX_NO_HANDLE);
1586 
1587  DISPMANX_UPDATE_HANDLE_T update = vc_dispmanx_update_start(0);
1588  assert(update != DISPMANX_NO_HANDLE);
1589 
1590  VC_RECT_T dst_rect;
1591  dst_rect.x = 0;
1592  dst_rect.y = 0;
1593  dst_rect.width = width;
1594  dst_rect.height = height;
1595 
1596  VC_RECT_T src_rect;
1597  src_rect.x = 0;
1598  src_rect.y = 0;
1599  src_rect.width = width << 16;
1600  src_rect.height = height << 16;
1601 
1602  VC_DISPMANX_ALPHA_T alpha = {
1603  DISPMANX_FLAGS_ALPHA_T(
1604  DISPMANX_FLAGS_ALPHA_FROM_SOURCE |
1605  (0&DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS) |
1606  (0&DISPMANX_FLAGS_ALPHA_FIXED_NON_ZERO) |
1607  (0&DISPMANX_FLAGS_ALPHA_FIXED_EXCEED_0X07) |
1608  (~0&DISPMANX_FLAGS_ALPHA_PREMULT) |
1609  (0&DISPMANX_FLAGS_ALPHA_MIX)
1610  ), // flags
1611  0, // opacity(alpha) 0->255
1612  0 // DISPMANX_RESOURCE_HANDLE_T mask
1613  };
1614 
1615  DISPMANX_ELEMENT_HANDLE_T dispman_element = vc_dispmanx_element_add(
1616  update, m_dispman_display, 3/*layer*/, &dst_rect,
1617  DISPMANX_RESOURCE_HANDLE_T(0) /*src*/, &src_rect,
1618  DISPMANX_PROTECTION_NONE, &alpha, nullptr /*clamp*/, DISPMANX_NO_ROTATE);
1619  assert(dispman_element != DISPMANX_NO_HANDLE);
1620 
1621  gNativewindow.element = dispman_element;
1622  gNativewindow.width = width;
1623  gNativewindow.height = height;
1624 
1625  vc_dispmanx_update_submit_sync(update);
1626  return &gNativewindow;
1627 #ifdef NDEBUG
1628  Q_UNUSED(ret);
1629 #endif
1630 #else
1631  return 0;
1632 #endif
1633 }
1634 
1635 void MythRenderEGL::destroyNativeWindow()
1636 {
1637 #ifdef USING_BROADCOM
1638  if (m_dispman_display != DISPMANX_NO_HANDLE)
1639  {
1640  int ret;
1641  if (DISPMANX_NO_HANDLE != gNativewindow.element)
1642  {
1643  DISPMANX_UPDATE_HANDLE_T update = vc_dispmanx_update_start(0);
1644  assert(update != DISPMANX_NO_HANDLE);
1645 
1646  ret = vc_dispmanx_element_remove(update, gNativewindow.element);
1647  assert(ret >= 0);
1648 
1649  ret = vc_dispmanx_update_submit_sync(update);
1650  assert(ret >= 0);
1651 
1652  gNativewindow.element = DISPMANX_NO_HANDLE;
1653  }
1654 
1655  ret = vc_dispmanx_display_close(m_dispman_display);
1656  assert(ret >= 0);
1657  m_dispman_display = DISPMANX_NO_HANDLE;
1658 #ifdef NDEBUG
1659  Q_UNUSED(ret);
1660 #endif
1661  }
1662 #endif //def USING_BROADCOM
1663 }
1664 
1665 // virtual
1666 void MythRenderEGL::makeCurrent()
1667 {
1668  assert(m_lock_level >= 0);
1669  if (++m_lock_level == 1)
1670  eglMakeCurrent(m_display, m_surface, m_surface, m_context);
1671 }
1672 
1673 // virtual
1674 void MythRenderEGL::doneCurrent()
1675 {
1676  assert(m_lock_level > 0);
1677  if (--m_lock_level == 0)
1678  eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
1679 }
1680 
1681 // virtual
1682 #ifdef USE_OPENGL_QT5
1683 void MythRenderEGL::swapBuffers()
1684 #else
1685 void MythRenderEGL::swapBuffers() const
1686 #endif
1687 {
1688  eglSwapBuffers(m_display, m_surface);
1689 }
1690 #endif //def OSD_EGL
1691 // 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:297
VideoFrame * At(uint i)
Definition: videobuffers.h:90
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.
void AddCurrentLocation(const QString &location)
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:329
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:309
#define FRAME2HDR(f)
unsigned char b
Definition: ParseText.cpp:329
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:218
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:457
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:787
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:672
void InitDisplayMeasurements(uint width, uint height, bool resize)
Init display measurements based on database settings and actual screen parameters.
bool IsEmbedding(void) const
Returns if videooutput is embedding.
long long frameNumber
Definition: mythframe.h:48
void end_lock()
Definition: videobuffers.h:100
void Shutdown()
Definition: omxcontext.cpp:185
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:328
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
bool SetVideoRect(const QRect &d_rect, const QRect &vid_rect)
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:14
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
static void init(VideoFrame *vf, VideoFrameType _codec, unsigned char *_buf, int _width, int _height, int _size, const int *p=nullptr, const int *o=nullptr, float _aspect=-1.0F, double _rate=-1.0F, int _aligned=64)
Definition: mythframe.h:115
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:297
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:274
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:127
unsigned Ports() const
Definition: omxcontext.h:49
void ShowFormats(unsigned index=0, LogLevel_t=LOG_INFO, uint64_t=VB_PLAYBACK) const
Definition: omxcontext.cpp:438
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