MythTV  master
videoout_openglvaapi.cpp
Go to the documentation of this file.
1 #include "videoout_openglvaapi.h"
2 #include "mythrender_opengl.h"
3 #include "openglvideo.h"
4 #include "vaapicontext.h"
5 #include "mythpainter.h"
6 #ifdef USING_OPENGLES
7 #include "mythrender_opengl2es.h"
8 #include "mythmainwindow.h"
9 #endif
10 #include <QGuiApplication>
11 
12 #define LOC QString("VidOutGLVAAPI: ")
13 #define ERR QString("VidOutGLVAAPI Error: ")
14 
16 {
17  opts.renderers->append("openglvaapi");
18 
19  (*opts.deints)["openglvaapi"].append("vaapionefield");
20  (*opts.deints)["openglvaapi"].append("vaapibobdeint");
21  (*opts.deints)["openglvaapi"].append("none");
22  (*opts.osds)["openglvaapi"].append("opengl2");
23 
24  if (opts.decoders->contains("vaapi"))
25  (*opts.safe_renderers)["vaapi"].append("openglvaapi");
26 
27  if (opts.decoders->contains("ffmpeg"))
28  (*opts.safe_renderers)["ffmpeg"].append("openglvaapi");
29 
30  (*opts.safe_renderers)["dummy"].append("openglvaapi");
31  (*opts.safe_renderers)["nuppel"].append("openglvaapi");
32 
33  opts.priorities->insert("openglvaapi", 110);
34 }
35 
37  : m_ctx(nullptr), m_pauseBuffer(nullptr)
38 {
39 }
40 
42 {
44 }
45 
47 {
49 }
50 
51 bool VideoOutputOpenGLVAAPI::InputChanged(const QSize &video_dim_buf,
52  const QSize &video_dim_disp,
53  float aspect,
54  MythCodecID av_codec_id, void *codec_private,
55  bool &aspect_only)
56 {
57  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("InputChanged(%1,%2,%3) %4->%5")
58  .arg(video_dim_disp.width()).arg(video_dim_disp.height())
59  .arg(aspect)
60  .arg(toString(video_codec_id)).arg(toString(av_codec_id)));
61 
62  if (!codec_is_vaapi(av_codec_id))
63  return VideoOutputOpenGL::InputChanged(video_dim_buf, video_dim_disp,
64  aspect, av_codec_id,
65  codec_private, aspect_only);
66 
67  QMutexLocker locker(&gl_context_lock);
68 
69  bool wasembedding = window.IsEmbedding();
70  QRect oldrect;
71  if (wasembedding)
72  {
73  oldrect = window.GetEmbeddingRect();
74  StopEmbedding();
75  }
76 
77  bool cid_changed = (video_codec_id != av_codec_id);
78  bool res_changed = video_dim_disp != window.GetActualVideoDim();
79  bool asp_changed = aspect != window.GetVideoAspect();
80 
81  if (!res_changed && !cid_changed)
82  {
83  if (asp_changed)
84  {
85  aspect_only = true;
87  MoveResize();
88  if (wasembedding)
89  EmbedInWidget(oldrect);
90  }
91  return true;
92  }
93 
94  if (gCoreContext->IsUIThread())
95  TearDown();
96  else
98 
99  QRect disp = window.GetDisplayVisibleRect();
100  if (Init(video_dim_buf, video_dim_disp,
101  aspect, gl_parent_win, disp, av_codec_id))
102  {
103  if (wasembedding)
104  EmbedInWidget(oldrect);
105  if (gCoreContext->IsUIThread())
106  BestDeint();
107  return true;
108  }
109 
110  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to re-initialise video output.");
112 
113  return false;
114 }
115 
116 bool VideoOutputOpenGLVAAPI::Init(const QSize &video_dim_buf,
117  const QSize &video_dim_disp,
118  float aspect,
119  WId winid, const QRect &win_rect,
120  MythCodecID codec_id)
121 {
122  bool ok = VideoOutputOpenGL::Init(video_dim_buf, video_dim_disp,
123  aspect, winid,
124  win_rect, codec_id);
125  if (ok && codec_is_vaapi(video_codec_id))
127  return ok;
128 }
129 
131 {
132  // FIXME During a video stream change this is called from the decoder
133  // thread - which breaks all other efforts to remove non-UI thread
134  // access to the OpenGL context. There is no obvious fix however - if we
135  // don't delete and re-create the VAAPI decoder context immediately then
136  // the decoder fails and playback exits.
137 
138  // lvr 27-oct-13
139  // in 0.27 if m_ctx->CreateDisplay is called outside of the UI thread then
140  // it fails, which then causes subsequent unbalanced calls to doneCurrent
141  // which results in Qt aborting. So just fail if non-UI.
142  if (!gCoreContext->IsUIThread())
143  {
144  LOG(VB_GENERAL, LOG_ERR, LOC +
145  "CreateVAAPIContext called from non-UI thread");
146  return false;
147  }
148 
149  OpenGLLocker ctx_lock(gl_context);
150 
151  if (m_ctx)
153 
155  if (m_ctx && m_ctx->CreateDisplay(size) && m_ctx->CreateBuffers())
156  {
157  int num_buffers = m_ctx->GetNumBuffers();
158  const QSize video_dim = window.GetActualVideoDim();
159 
160  bool ok = true;
161  for (int i = 0; i < num_buffers; i++)
162  {
163  ok &= vbuffers.CreateBuffer(video_dim.width(),
164  video_dim.height(), i,
166  FMT_VAAPI);
167  }
169  return ok;
170  }
171 
172  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create VAAPI context.");
174  return false;
175 }
176 
178 {
179  QMutexLocker locker(&gl_context_lock);
180  delete m_ctx;
181  m_ctx = nullptr;
182 }
183 
185 {
186  QMutexLocker locker(&gl_context_lock);
188  {
189  vbuffers.Init(24, true, 2, 1, 4, 1);
190  return true;
191  }
193 }
194 
195 void* VideoOutputOpenGLVAAPI::GetDecoderContext(unsigned char* buf, uint8_t*& id)
196 {
197  if (m_ctx)
198  {
199  id = GetSurfaceIDPointer(buf);
200  return &m_ctx->m_ctx;
201  }
202  return nullptr;
203 }
204 
206 {
207  if (m_ctx)
208  return m_ctx->GetSurfaceIDPointer(buf);
209  return nullptr;
210 }
211 
213 {
214  if (db_vdisp_profile)
215  db_vdisp_profile->SetVideoRenderer("openglvaapi");
216 }
217 
218 bool VideoOutputOpenGLVAAPI::ApproveDeintFilter(const QString &filtername) const
219 {
220  return filtername.contains("vaapi");
221 }
222 
224 {
225  m_deinterlacing = enable;
226  SetupDeinterlace(enable);
227  return m_deinterlacing;
228 }
229 
230 bool VideoOutputOpenGLVAAPI::SetupDeinterlace(bool interlaced, const QString& overridefilter)
231 {
232  if (db_vdisp_profile)
234  m_deinterlacing = m_deintfiltername.contains("vaapi") ? interlaced : false;
235  return m_deinterlacing;
236 }
237 
239 {
241  {
242  if (m_ctx)
244  return;
245  }
247 }
248 
250  int newValue)
251 {
252  int val = newValue;
254  val = m_ctx->SetPictureAttribute(attribute, newValue);
255  return VideoOutputOpenGL::SetPictureAttribute(attribute, val);
256 }
257 
258 void VideoOutputOpenGLVAAPI::UpdatePauseFrame(int64_t &disp_timecode)
259 {
261  {
263  return;
264  }
265 
268  {
270  CopyFrame(&av_pause_frame, frame);
271  m_pauseBuffer = frame->buf;
272  disp_timecode = frame->disp_timecode;
273  }
274  else
275  LOG(VB_PLAYBACK, LOG_WARNING, LOC +
276  "Could not update pause frame - no used frames.");
277 
278  vbuffers.end_lock();
279 }
280 
282 {
283  {
284  QMutexLocker locker(&gl_context_lock);
286  {
288  m_ctx->CopySurfaceToTexture(frame ? frame->buf : m_pauseBuffer,
293  }
294  }
296 }
297 
299  MythCodecID myth_codec_id, const QSize &video_dim)
300 {
301  (void) video_dim;
302  QStringList list;
303  if ((codec_is_std(myth_codec_id) || (codec_is_vaapi(myth_codec_id))) &&
304  !getenv("NO_VAAPI") && AllowVAAPIDisplay())
305  {
306  list += "openglvaapi";
307  }
308  return list;
309 }
310 
312  uint width, uint height, const QString &decoder,
313  uint stream_type, bool no_acceleration,
314  AVPixelFormat &pix_fmt)
315 {
316  QSize size(width, height);
317  bool use_cpu = no_acceleration;
318  AVPixelFormat fmt = AV_PIX_FMT_YUV420P;
319  MythCodecID test_cid = (MythCodecID)(kCodec_MPEG1_VAAPI + (stream_type - 1));
320  if (codec_is_vaapi(test_cid) && decoder == "vaapi" && !getenv("NO_VAAPI") && AllowVAAPIDisplay())
321  use_cpu |= !VAAPIContext::IsFormatAccelerated(size, test_cid, fmt);
322  else
323  use_cpu = true;
324 
325  if (use_cpu)
326  return (MythCodecID)(kCodec_MPEG1 + (stream_type - 1));
327 
328  pix_fmt = fmt;
329  return test_cid;
330 }
331 
332 // We currently (v30) only support rendering to a GLX surface.
333 // Disallow OpenGL ES (crashes hard) and EGL (fails to initialise) with Intel.
334 // This needs extending when EGL etc support is added and also generalising
335 // for other video output classes.
337 {
338  if (qApp->platformName().contains("egl", Qt::CaseInsensitive))
339  {
340  LOG(VB_GENERAL, LOG_INFO, "Disabling VAAPI display with EGL");
341  return false;
342  }
343 
344 #ifdef USING_OPENGLES
346  if (win)
347  {
348  MythRender *render = win->GetRenderDevice();
349  if (static_cast<MythRenderOpenGL2ES*>(render))
350  {
351  LOG(VB_GENERAL, LOG_INFO, "Disabling VAAPI display with OpenGLES");
352  return false;
353  }
354  }
355 #endif
356  return true;
357 }
bool CopySurfaceToTexture(const void *buf, uint texture, uint texture_type, FrameScanType scan)
bool Init(const QSize &video_dim_buf, const QSize &video_dim_disp, float aspect, WId winid, const QRect &win_rect, MythCodecID codec_id) override
Performs most of the initialization for VideoOutput.
void TearDown(void) override
int SetPictureAttribute(PictureAttribute attribute, int newValue) override
Sets a specified picture attribute.
QString m_deintfiltername
Definition: videooutbase.h:351
static MythCodecID GetBestSupportedCodec(uint width, uint height, const QString &decoder, uint stream_type, bool no_acceleration, AVPixelFormat &pix_fmt)
void SetVideoRenderer(const QString &video_renderer)
void PrepareFrame(VideoFrame *frame, FrameScanType scan, OSD *osd) override
def scan(profile, smoonURL, gate)
Definition: scan.py:46
bool Init(const QSize &video_dim_buf, const QSize &video_dim_disp, float aspect, WId winid, const QRect &win_rect, MythCodecID codec_id) override
Performs most of the initialization for VideoOutput.
void StopEmbedding(void) override
Tells video output to stop embedding video in an existing window.
static bool IsFormatAccelerated(QSize size, MythCodecID codec, AVPixelFormat &pix_fmt)
bool SetupDeinterlace(bool interlaced, const QString &overridefilter="") override
Attempts to enable or disable deinterlacing.
QString toString(MarkTypes type)
void InitPictureAttributes(void) override
bool m_deinterlacing
Definition: videooutbase.h:350
MythCodecID
Definition: mythcodecid.h:10
VideoColourSpace videoColourSpace
Definition: videooutbase.h:322
void DestroyCPUResources(void)
QString GetFilteredDeint(const QString &override)
uint8_t * GetSurfaceIDPointer(void *buf)
static MythMainWindow * getMainWindow(const bool useDB=true)
Return the existing main window, or create one.
uint GetInputTexture(void) const
bool CreateVAAPIContext(QSize size)
void UpdatePauseFrame(int64_t &disp_timecode) override
Updates frame displayed when video is paused.
#define LOC
FrameScanType
Definition: videoouttypes.h:80
unsigned int uint
Definition: compat.h:140
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
int SetPictureAttribute(PictureAttribute attribute, int newValue) override
Sets a specified picture attribute.
VideoDisplayProfile * db_vdisp_profile
Definition: videooutbase.h:330
uint Size(BufferType type) const
uint GetTextureType(void) const
bool CreateDisplay(QSize size, bool noreuse=false)
vaapi_context m_ctx
Definition: vaapicontext.h:62
#define codec_is_vaapi(id)
Definition: mythcodecid.h:134
void MoveResize(void) override
performs all the calculations for video framing and any resizing.
static void CopyFrame(VideoFrame *to, const VideoFrame *from)
Copies frame data from one VideoFrame to another.
virtual bool CreateBuffers(void)
void doneCurrent() override
void PrepareFrame(VideoFrame *buffer, FrameScanType, OSD *osd) override
static void GetRenderOptions(render_opts &opts)
VideoBuffers vbuffers
VideoBuffers instance used to track video output buffers.
Definition: videooutbase.h:357
bool CreateBuffers(void) override
MythCodecID video_codec_id
Definition: videooutbase.h:329
QRect GetEmbeddingRect(void) const
VideoErrorState errorState
Definition: videooutbase.h:360
virtual void BestDeint(void)
Change to the best deinterlacing method.
bool CreateBuffers(void)
uint8_t * GetSurfaceIDPointer(void *buf)
bool CreateBuffer(int width, int height, uint num, void *data, VideoFrameType fmt)
bool IsEmbedding(void) const
Returns if videooutput is embedding.
void end_lock()
Definition: videobuffers.h:100
OpenGLVideo * gl_videochain
PictureAttribute
Definition: videoouttypes.h:89
MythRenderOpenGL * gl_context
bool ApproveDeintFilter(const QString &filtername) const override
Approves bobdeint filter for XVideo and otherwise defers to VideoOutput::ApproveDeintFilter(const QSt...
MythRender * GetRenderDevice()
void InitPictureAttributes(void) override
void InitPictureAttributes(VideoColourSpace &colourspace)
void makeCurrent() override
void EmbedInWidget(const QRect &rect) override
Tells video output to embed video in an existing window.
QSize GetActualVideoDim(void) const
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
bool SetDeinterlacingEnabled(bool enable) override
Attempts to enable/disable deinterlacing using existing deinterlace method when enabling.
void UpdatePauseFrame(int64_t &disp_timecode) override
Updates frame displayed when video is paused.
int64_t disp_timecode
Definition: mythframe.h:50
void * GetDecoderContext(unsigned char *buf, uint8_t *&id) override
void SetInputUpdated(void)
VideoFrame * Head(BufferType)
virtual void VideoAspectRatioChanged(float aspect)
Calls SetVideoAspectRatio(float aspect), then calls MoveResize() to apply changes.
Definition: osd.h:132
float GetVideoAspect(void) const
void SetProfile(void) override
QRect GetDisplayVisibleRect(void) const
bool InputChanged(const QSize &video_dim_buf, const QSize &video_dim_disp, float aspect, MythCodecID av_codec_id, void *codec_private, bool &aspect_only) override
Tells video output to discard decoded frames and wait for new ones.
static QStringList GetAllowedRenderers(MythCodecID myth_codec_id, const QSize &video_dim)
VideoOutWindow window
Definition: videooutbase.h:320
int SetPictureAttribute(PictureAttribute attribute, int newValue)
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.
void * GetVideoSurface(int i)
frame_queue_t::iterator begin_lock(BufferType)
unsigned char * buf
Definition: mythframe.h:39
int GetNumBuffers(void) const
Definition: vaapicontext.h:42
bool InputChanged(const QSize &video_dim_buf, const QSize &video_dim_disp, float aspect, MythCodecID av_codec_id, void *codec_private, bool &aspect_only) override
Tells video output to discard decoded frames and wait for new ones.
#define codec_is_std(id)
Definition: mythcodecid.h:127
VideoFrame av_pause_frame