MythTV  master
mythvaapicontext.cpp
Go to the documentation of this file.
1 // Qt
2 #include <QCoreApplication>
3 #include <QWaitCondition>
4 
5 // Mythtv
6 #include "mythcontext.h"
7 #include "mythmainwindow.h"
8 #include "mythlogging.h"
11 #include "videobuffers.h"
12 #include "mythvaapiinterop.h"
13 #include "mythvaapicontext.h"
14 
15 extern "C" {
16 #include "libavutil/hwcontext_vaapi.h"
17 #include "libavutil/pixdesc.h"
18 #include "libavfilter/buffersink.h"
19 }
20 
21 #define LOC QString("VAAPIDec: ")
22 
32  : MythCodecContext(Parent, CodecID)
33 {
34 }
35 
37 {
39 }
40 
41 VAProfile MythVAAPIContext::VAAPIProfileForCodec(const AVCodecContext *Codec)
42 {
43  if (!Codec)
44  return VAProfileNone;
45 
46  switch (Codec->codec_id)
47  {
48  case AV_CODEC_ID_MPEG2VIDEO:
49  switch (Codec->profile)
50  {
51  case FF_PROFILE_MPEG2_SIMPLE: return VAProfileMPEG2Simple;
52  case FF_PROFILE_MPEG2_MAIN: return VAProfileMPEG2Main;
53  default: break;
54  }
55  break;
56  case AV_CODEC_ID_H263: return VAProfileH263Baseline;
57  case AV_CODEC_ID_MPEG4:
58  switch (Codec->profile)
59  {
60  case FF_PROFILE_MPEG4_SIMPLE: return VAProfileMPEG4Simple;
61  case FF_PROFILE_MPEG4_ADVANCED_SIMPLE: return VAProfileMPEG4AdvancedSimple;
62  case FF_PROFILE_MPEG4_MAIN: return VAProfileMPEG4Main;
63  default: break;
64  }
65  break;
66  case AV_CODEC_ID_H264:
67  switch (Codec->profile)
68  {
69  case FF_PROFILE_H264_CONSTRAINED_BASELINE: return VAProfileH264ConstrainedBaseline;
70  case FF_PROFILE_H264_MAIN: return VAProfileH264Main;
71  case FF_PROFILE_H264_HIGH: return VAProfileH264High;
72  default: break;
73  }
74  break;
75  case AV_CODEC_ID_HEVC:
76 #if VA_CHECK_VERSION(0, 37, 0)
77  switch (Codec->profile)
78  {
79  case FF_PROFILE_HEVC_MAIN: return VAProfileHEVCMain;
80  case FF_PROFILE_HEVC_MAIN_10: return VAProfileHEVCMain10;
81  default: break;
82  }
83 #endif
84  break;
85  case AV_CODEC_ID_MJPEG: return VAProfileJPEGBaseline;
86  case AV_CODEC_ID_WMV3:
87  case AV_CODEC_ID_VC1:
88  switch (Codec->profile)
89  {
90  case FF_PROFILE_VC1_SIMPLE: return VAProfileVC1Simple;
91  case FF_PROFILE_VC1_MAIN: return VAProfileVC1Main;
92  case FF_PROFILE_VC1_ADVANCED:
93  case FF_PROFILE_VC1_COMPLEX: return VAProfileVC1Advanced;
94  default: break;
95  }
96  break;
97  case AV_CODEC_ID_VP8: return VAProfileVP8Version0_3;
98  case AV_CODEC_ID_VP9:
99  switch (Codec->profile)
100  {
101 #if VA_CHECK_VERSION(0, 38, 0)
102  case FF_PROFILE_VP9_0: return VAProfileVP9Profile0;
103 #endif
104 #if VA_CHECK_VERSION(0, 39, 0)
105  case FF_PROFILE_VP9_2: return VAProfileVP9Profile2;
106 #endif
107  default: break;
108  }
109  break;
110  default: break;
111  }
112 
113  return VAProfileNone;
114 }
115 
116 inline AVPixelFormat MythVAAPIContext::FramesFormat(AVPixelFormat Format)
117 {
118  switch (Format)
119  {
120  case AV_PIX_FMT_YUV420P10: return AV_PIX_FMT_P010;
121  case AV_PIX_FMT_YUV420P12:
122  case AV_PIX_FMT_YUV420P14:
123  case AV_PIX_FMT_YUV420P16: return AV_PIX_FMT_P016;
124  default: return AV_PIX_FMT_NV12;
125  }
126 }
127 
131  AVCodec ** /*Codec*/,
132  const QString &Decoder,
133  uint StreamType)
134 {
135  bool decodeonly = Decoder == "vaapi-dec";
136  auto success = static_cast<MythCodecID>((decodeonly ? kCodec_MPEG1_VAAPI_DEC : kCodec_MPEG1_VAAPI) + (StreamType - 1));
137  auto failure = static_cast<MythCodecID>(kCodec_MPEG1 + (StreamType - 1));
138  QString vendor = HaveVAAPI();
139  if (!Decoder.startsWith("vaapi") || vendor.isEmpty() || getenv("NO_VAAPI"))
140  return failure;
141 
142  QString codec = ff_codec_id_string((*Context)->codec_id);
143  QString profile = avcodec_profile_name((*Context)->codec_id, (*Context)->profile);
144  QString pixfmt = av_get_pix_fmt_name((*Context)->pix_fmt);
145 
146  // Simple check for known profile
147  VAProfile desired = VAAPIProfileForCodec(*Context);
148  if (desired == VAProfileNone)
149  {
150  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("VAAPI does not support decoding '%1 %2 %3'")
151  .arg(codec).arg(profile).arg(pixfmt));
152  return failure;
153  }
154 
155  // Check for ironlake decode only - which won't work due to FFmpeg frame format
156  // constraints. May apply to other platforms.
157  if (decodeonly)
158  {
159  if (vendor.contains("ironlake", Qt::CaseInsensitive))
160  {
161  LOG(VB_GENERAL, LOG_WARNING, LOC + "Disallowing VAAPI decode only for Ironlake");
162  return failure;
163  }
164  }
165  else
166  {
167  // If called from outside of the main thread, we need a MythPlayer instance to
168  // process the interop check callback - which may fail otherwise (depending
169  // on whether the result is cached).
170  MythPlayer* player = nullptr;
171  if (!gCoreContext->IsUIThread())
172  {
173  auto *decoder = reinterpret_cast<AvFormatDecoder*>((*Context)->opaque);
174  if (decoder)
175  player = decoder->GetPlayer();
176  }
177 
178  // Direct rendering needs interop support
180  return failure;
181  }
182 
183  // Check profile support
184  bool ok = false;
185  const VAAPIProfiles& profiles = MythVAAPIContext::GetProfiles();
186  MythCodecContext::CodecProfile mythprofile =
187  MythCodecContext::FFmpegToMythProfile((*Context)->codec_id, (*Context)->profile);
188  auto haveprofile = [=](MythCodecContext::CodecProfile Profile, QSize Size)
189  {
190  foreach (auto vaprofile, profiles)
191  {
192  if (vaprofile.first == Profile &&
193  vaprofile.second.first.width() <= Size.width() &&
194  vaprofile.second.first.height() <= Size.height() &&
195  vaprofile.second.second.width() >= Size.width() &&
196  vaprofile.second.second.height() >= Size.height())
197  {
198  return true;
199  }
200  }
201  return false;
202  };
203 
204  ok = haveprofile(mythprofile, QSize((*Context)->width, (*Context)->height));
205  // use JPEG support as a proxy for MJPEG (full range YUV)
206  if (ok && (AV_PIX_FMT_YUVJ420P == (*Context)->pix_fmt || AV_PIX_FMT_YUVJ422P == (*Context)->pix_fmt ||
207  AV_PIX_FMT_YUVJ444P == (*Context)->pix_fmt))
208  {
209  ok = haveprofile(MythCodecContext::MJPEG, QSize());
210  }
211 
212  QString desc = QString("'%1 %2 %3 %4x%5'")
213  .arg(codec).arg(profile).arg(pixfmt).arg((*Context)->width).arg((*Context)->height);
214 
215  if (ok)
216  {
217  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("VAAPI supports decoding %1").arg(desc));
218  (*Context)->pix_fmt = AV_PIX_FMT_VAAPI;
219  return success;
220  }
221 
222  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("VAAPI does NOT support %1").arg(desc));
223  return failure;
224 }
225 
226 AVPixelFormat MythVAAPIContext::GetFormat(AVCodecContext *Context, const AVPixelFormat *PixFmt)
227 {
228  while (*PixFmt != AV_PIX_FMT_NONE)
229  {
230  if (*PixFmt == AV_PIX_FMT_VAAPI)
232  return AV_PIX_FMT_VAAPI;
233  PixFmt++;
234  }
235  return AV_PIX_FMT_NONE;
236 }
237 
238 AVPixelFormat MythVAAPIContext::GetFormat2(AVCodecContext *Context, const AVPixelFormat *PixFmt)
239 {
240  while (*PixFmt != AV_PIX_FMT_NONE)
241  {
242  if (*PixFmt == AV_PIX_FMT_VAAPI)
243  if (InitialiseContext2(Context) >= 0)
244  return AV_PIX_FMT_VAAPI;
245  PixFmt++;
246  }
247  return AV_PIX_FMT_NONE;
248 }
249 
253 {
254  if (!Context || !gCoreContext->IsUIThread())
255  return -1;
256 
257  // We need a render device
259  if (!render)
260  return -1;
261 
262  // The interop must have a reference to the player so it can be deleted
263  // from the main thread.
264  MythPlayer *player = nullptr;
265  auto *decoder = reinterpret_cast<AvFormatDecoder*>(Context->opaque);
266  if (decoder)
267  player = decoder->GetPlayer();
268  if (!player)
269  return -1;
270 
271  // Check interop support
274  return -1;
275 
276  // Create interop
277  MythVAAPIInterop *interop = MythVAAPIInterop::Create(render, type);
278  if (!interop)
279  return -1;
280  if (!interop->GetDisplay())
281  {
282  interop->DecrRef();
283  return -1;
284  }
285 
286  // Set the player required to process interop release
287  interop->SetPlayer(player);
288 
289  // Create hardware device context
290  AVBufferRef* hwdeviceref = av_hwdevice_ctx_alloc(AV_HWDEVICE_TYPE_VAAPI);
291  if (!hwdeviceref || (hwdeviceref && !hwdeviceref->data))
292  {
293  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create VAAPI hardware device context");
294  return -1;
295  }
296 
297  auto* hwdevicecontext = reinterpret_cast<AVHWDeviceContext*>(hwdeviceref->data);
298  if (!hwdevicecontext || (hwdevicecontext && !hwdevicecontext->hwctx))
299  return -1;
300  auto *vaapidevicectx = reinterpret_cast<AVVAAPIDeviceContext*>(hwdevicecontext->hwctx);
301  if (!vaapidevicectx)
302  return -1;
303 
304  // Set the display
305  vaapidevicectx->display = interop->GetDisplay();
306 
307  // Initialise hardware device context
308  int res = av_hwdevice_ctx_init(hwdeviceref);
309  if (res < 0)
310  {
311  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to initialise VAAPI hardware context");
312  av_buffer_unref(&hwdeviceref);
313  interop->DecrRef();
314  return res;
315  }
316 
317  // Allocate the hardware frames context for FFmpeg
318  Context->hw_frames_ctx = av_hwframe_ctx_alloc(hwdeviceref);
319  if (!Context->hw_frames_ctx)
320  {
321  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create VAAPI hardware frames context");
322  av_buffer_unref(&hwdeviceref);
323  interop->DecrRef();
324  return -1;
325  }
326 
327  // Setup the frames context
328  auto* hw_frames_ctx = reinterpret_cast<AVHWFramesContext*>(Context->hw_frames_ctx->data);
329  auto* vaapi_frames_ctx = reinterpret_cast<AVVAAPIFramesContext*>(hw_frames_ctx->hwctx);
330 
331  // Workarounds for specific drivers, surface formats and codecs
332  // NV12 seems to work best across GPUs and codecs with the exception of
333  // MPEG2 on Ironlake where it seems to return I420 labelled as NV12. I420 is
334  // buggy on Sandybridge (stride?) and produces a mixture of I420/NV12 frames
335  // for H.264 on Ironlake.
336  int format = VA_FOURCC_NV12;
337  QString vendor = interop->GetVendor();
338  if (vendor.contains("ironlake", Qt::CaseInsensitive))
339  if (CODEC_IS_MPEG(Context->codec_id))
340  format = VA_FOURCC_I420;
341 
342  if (format != VA_FOURCC_NV12)
343  {
344  auto vaapiid = static_cast<MythCodecID>(kCodec_MPEG1_VAAPI + (mpeg_version(Context->codec_id) - 1));
345  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Forcing surface format for %1 and %2 with driver '%3'")
346  .arg(toString(vaapiid)).arg(MythOpenGLInterop::TypeToString(type)).arg(vendor));
347  }
348 
349  VASurfaceAttrib prefs[3] = {
350  { VASurfaceAttribPixelFormat, VA_SURFACE_ATTRIB_SETTABLE, { VAGenericValueTypeInteger, { format } } },
351  { VASurfaceAttribUsageHint, VA_SURFACE_ATTRIB_SETTABLE, { VAGenericValueTypeInteger, { VA_SURFACE_ATTRIB_USAGE_HINT_DISPLAY } } },
352  { VASurfaceAttribMemoryType, VA_SURFACE_ATTRIB_SETTABLE, { VAGenericValueTypeInteger, { VA_SURFACE_ATTRIB_MEM_TYPE_VA} } } };
353  vaapi_frames_ctx->attributes = prefs;
354  vaapi_frames_ctx->nb_attributes = 3;
355  hw_frames_ctx->sw_format = FramesFormat(Context->sw_pix_fmt);
356  int referenceframes = AvFormatDecoder::GetMaxReferenceFrames(Context);
357  hw_frames_ctx->initial_pool_size = static_cast<int>(VideoBuffers::GetNumBuffers(FMT_VAAPI, referenceframes, true));
358  hw_frames_ctx->format = AV_PIX_FMT_VAAPI;
359  hw_frames_ctx->width = Context->coded_width;
360  hw_frames_ctx->height = Context->coded_height;
361  // The frames context now holds the reference to MythVAAPIInterop
362  hw_frames_ctx->user_opaque = interop;
363  // Set the callback to ensure it is released
364  hw_frames_ctx->free = &MythCodecContext::FramesContextFinished;
365 
366  // Initialise hardwar frames context
367  res = av_hwframe_ctx_init(Context->hw_frames_ctx);
368  if (res < 0)
369  {
370  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to initialise VAAPI frames context");
371  av_buffer_unref(&hwdeviceref);
372  av_buffer_unref(&(Context->hw_frames_ctx));
373  return res;
374  }
375 
376  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("VAAPI FFmpeg buffer pool created with %1 %2x%3 surfaces (%4 references)")
377  .arg(vaapi_frames_ctx->nb_surfaces).arg(Context->coded_width).arg(Context->coded_height)
378  .arg(referenceframes));
379  av_buffer_unref(&hwdeviceref);
380 
382 
383  return 0;
384 }
385 
394 {
395  if (!Context)
396  return -1;
397 
398  AVBufferRef *device = MythCodecContext::CreateDevice(AV_HWDEVICE_TYPE_VAAPI, nullptr,
399  gCoreContext->GetSetting("VAAPIDevice"));
400  Context->hw_frames_ctx = av_hwframe_ctx_alloc(device);
401  if (!Context->hw_frames_ctx)
402  {
403  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create VAAPI hardware frames context");
404  av_buffer_unref(&device);
405  return -1;
406  }
407 
408  int referenceframes = AvFormatDecoder::GetMaxReferenceFrames(Context);
409  auto* hw_frames_ctx = reinterpret_cast<AVHWFramesContext*>(Context->hw_frames_ctx->data);
410  auto* vaapi_frames_ctx = reinterpret_cast<AVVAAPIFramesContext*>(hw_frames_ctx->hwctx);
411  hw_frames_ctx->sw_format = FramesFormat(Context->sw_pix_fmt);
412  hw_frames_ctx->format = AV_PIX_FMT_VAAPI;
413  hw_frames_ctx->width = Context->coded_width;
414  hw_frames_ctx->height = Context->coded_height;
415  hw_frames_ctx->initial_pool_size = static_cast<int>(VideoBuffers::GetNumBuffers(FMT_VAAPI, referenceframes));
416  hw_frames_ctx->free = &MythCodecContext::FramesContextFinished;
417  if (av_hwframe_ctx_init(Context->hw_frames_ctx) < 0)
418  {
419  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to initialise VAAPI frames context");
420  av_buffer_unref(&device);
421  av_buffer_unref(&(Context->hw_frames_ctx));
422  return -1;
423  }
424 
425  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("VAAPI FFmpeg buffer pool created with %1 %2x%3 surfaces (%4 references)")
426  .arg(vaapi_frames_ctx->nb_surfaces).arg(Context->coded_width).arg(Context->coded_height)
427  .arg(referenceframes));
428  av_buffer_unref(&device);
429 
431 
432  return 0;
433 }
434 
442 QString MythVAAPIContext::HaveVAAPI(bool ReCheck /*= false*/)
443 {
444  static QString s_vendor;
445  static bool s_checked = false;
446  if (s_checked && !ReCheck)
447  return s_vendor;
448  s_checked = true;
449 
450  AVBufferRef *context = MythCodecContext::CreateDevice(AV_HWDEVICE_TYPE_VAAPI, nullptr,
451  gCoreContext->GetSetting("VAAPIDevice"));
452  if (context)
453  {
454  auto *hwdevice = reinterpret_cast<AVHWDeviceContext*>(context->data);
455  auto *hwctx = reinterpret_cast<AVVAAPIDeviceContext*>(hwdevice->hwctx);
456  s_vendor = QString(vaQueryVendorString(hwctx->display));
457  if (s_vendor.contains("vdpau", Qt::CaseInsensitive))
458  {
459  s_vendor = QString();
460  LOG(VB_GENERAL, LOG_INFO, LOC + "VAAPI is using a VDPAU backend - ignoring VAAPI");
461  }
462  else if (s_vendor.isEmpty())
463  {
464  LOG(VB_GENERAL, LOG_INFO, LOC + "Unknown VAAPI vendor - ignoring VAAPI");
465  }
466  else
467  {
468  LOG(VB_GENERAL, LOG_INFO, LOC + "Supported/available VAAPI decoders:");
469  const VAAPIProfiles& profiles = MythVAAPIContext::GetProfiles();
470  foreach (auto profile, profiles)
471  {
472  if (profile.first != MythCodecContext::MJPEG)
473  {
474  LOG(VB_GENERAL, LOG_INFO, LOC +
476  }
477  }
478  }
479  av_buffer_unref(&context);
480  }
481  else
482  {
483  LOG(VB_GENERAL, LOG_INFO, LOC + "VAAPI functionality checked failed");
484  }
485 
486  return s_vendor;
487 }
488 
490 {
491  static QMutex lock(QMutex::Recursive);
492  static bool s_initialised = false;
493  static VAAPIProfiles s_profiles;
494 
495  QMutexLocker locker(&lock);
496  if (s_initialised)
497  return s_profiles;
498  s_initialised = true;
499 
500  auto VAToMythProfile = [](VAProfile Profile)
501  {
502  switch (Profile)
503  {
504  case VAProfileMPEG2Simple: return MythCodecContext::MPEG2Simple;
505  case VAProfileMPEG2Main: return MythCodecContext::MPEG2Main;
506  case VAProfileMPEG4Simple: return MythCodecContext::MPEG4Simple;
507  case VAProfileMPEG4AdvancedSimple: return MythCodecContext::MPEG4AdvancedSimple;
508  case VAProfileMPEG4Main: return MythCodecContext::MPEG4Main;
509  case VAProfileH263Baseline: return MythCodecContext::H263;
510  case VAProfileH264ConstrainedBaseline: return MythCodecContext::H264ConstrainedBaseline;
511  case VAProfileH264Main: return MythCodecContext::H264Main;
512  case VAProfileH264High: return MythCodecContext::H264High;
513  case VAProfileVC1Simple: return MythCodecContext::VC1Simple;
514  case VAProfileVC1Main: return MythCodecContext::VC1Main;
515  case VAProfileVC1Advanced: return MythCodecContext::VC1Advanced;
516  case VAProfileVP8Version0_3: return MythCodecContext::VP8;
517  #if VA_CHECK_VERSION(0, 38, 0)
518  case VAProfileVP9Profile0: return MythCodecContext::VP9_0;
519  #endif
520  #if VA_CHECK_VERSION(0, 39, 0)
521  case VAProfileVP9Profile2: return MythCodecContext::VP9_2;
522  #endif
523  #if VA_CHECK_VERSION(0, 37, 0)
524  case VAProfileHEVCMain: return MythCodecContext::HEVCMain;
525  case VAProfileHEVCMain10: return MythCodecContext::HEVCMain10;
526  #endif
527  case VAProfileJPEGBaseline: return MythCodecContext::MJPEG;
528  default: break;
529  }
531  };
532 
533  AVBufferRef *hwdevicectx = MythCodecContext::CreateDevice(AV_HWDEVICE_TYPE_VAAPI, nullptr,
534  gCoreContext->GetSetting("VAAPIDevice"));
535  if(!hwdevicectx)
536  return s_profiles;
537 
538  auto *device = reinterpret_cast<AVHWDeviceContext*>(hwdevicectx->data);
539  auto *hwctx = reinterpret_cast<AVVAAPIDeviceContext*>(device->hwctx);
540 
541  int profilecount = vaMaxNumProfiles(hwctx->display);
542  auto *profilelist = static_cast<VAProfile*>(av_malloc_array(static_cast<size_t>(profilecount), sizeof(VAProfile)));
543  if (vaQueryConfigProfiles(hwctx->display, profilelist, &profilecount) == VA_STATUS_SUCCESS)
544  {
545  for (int i = 0; i < profilecount; ++i)
546  {
547  VAProfile profile = profilelist[i];
548  if (profile == VAProfileNone || profile == VAProfileH264StereoHigh || profile == VAProfileH264MultiviewHigh)
549  continue;
550  int count = 0;
551  int entrysize = vaMaxNumEntrypoints(hwctx->display);
552  auto *entrylist = static_cast<VAEntrypoint*>(av_malloc_array(static_cast<size_t>(entrysize), sizeof(VAEntrypoint)));
553  if (vaQueryConfigEntrypoints(hwctx->display, profile, entrylist, &count) == VA_STATUS_SUCCESS)
554  {
555  for (int j = 0; j < count; ++j)
556  {
557  if (entrylist[j] != VAEntrypointVLD)
558  continue;
559 
560  QSize minsize;
561  QSize maxsize;
562  VAConfigID config = 0;
563  if (vaCreateConfig(hwctx->display, profile, VAEntrypointVLD, nullptr, 0, &config) != VA_STATUS_SUCCESS)
564  continue;
565 
566  uint attrcount = 0;
567  if (vaQuerySurfaceAttributes(hwctx->display, config, nullptr, &attrcount) == VA_STATUS_SUCCESS)
568  {
569  VASurfaceAttrib *attrlist = static_cast<VASurfaceAttrib*>(av_malloc(attrcount * sizeof(*attrlist)));
570  if (vaQuerySurfaceAttributes(hwctx->display, config, attrlist, &attrcount) == VA_STATUS_SUCCESS)
571  {
572  for (uint k = 0; k < attrcount; ++k)
573  {
574  if (attrlist[k].type == VASurfaceAttribMaxWidth)
575  maxsize.setWidth(attrlist[k].value.value.i);
576  if (attrlist[k].type == VASurfaceAttribMaxHeight)
577  maxsize.setHeight(attrlist[k].value.value.i);
578  if (attrlist[k].type == VASurfaceAttribMinWidth)
579  minsize.setWidth(attrlist[k].value.value.i);
580  if (attrlist[k].type == VASurfaceAttribMinHeight)
581  minsize.setHeight(attrlist[k].value.value.i);
582  }
583  }
584  av_freep(&attrlist);
585  }
586  vaDestroyConfig(hwctx->display, config);
587  s_profiles.append(VAAPIProfile(VAToMythProfile(profile), QPair<QSize,QSize>(minsize, maxsize)));
588  }
589  }
590  av_freep(&entrylist);
591  }
592  }
593  av_freep(&profilelist);
594  av_buffer_unref(&hwdevicectx);
595 
596  // Once only check for EGL support for best performance
598  if (!s_profiles.isEmpty() && render)
599  {
600  if (render->IsEGL())
601  {
602  LOG(VB_GENERAL, LOG_INFO, LOC + "EGL DMABUF available for best VAAPI performance");
603  }
604  else
605  {
606  LOG(VB_GENERAL, LOG_WARNING, LOC + "No EGL support. VAAPI performance will be reduced");
607  LOG(VB_GENERAL, LOG_WARNING, LOC + "Consider setting MYTHTV_FORCE_EGL=1 to try and enable");
608  }
609  }
610  return s_profiles;
611 }
612 
613 void MythVAAPIContext::GetDecoderList(QStringList &Decoders)
614 {
615  const VAAPIProfiles& profiles = MythVAAPIContext::GetProfiles();
616  if (profiles.isEmpty())
617  return;
618  Decoders.append("VAAPI:");
619  foreach (auto profile, profiles)
620  if (profile.first != MythCodecContext::MJPEG)
621  Decoders.append(MythCodecContext::GetProfileDescription(profile.first, profile.second.second));
622 }
623 
624 void MythVAAPIContext::InitVideoCodec(AVCodecContext *Context, bool SelectedStream, bool &DirectRendering)
625 {
627  {
628  Context->get_buffer2 = MythCodecContext::GetBuffer;
629  Context->get_format = MythVAAPIContext::GetFormat;
630  Context->slice_flags = SLICE_FLAG_CODED_ORDER | SLICE_FLAG_ALLOW_FIELD;
631  return;
632  }
634  {
636  Context->slice_flags = SLICE_FLAG_CODED_ORDER | SLICE_FLAG_ALLOW_FIELD;
637  DirectRendering = false;
638  return;
639  }
640 
641  MythCodecContext::InitVideoCodec(Context, SelectedStream, DirectRendering);
642 }
643 
644 bool MythVAAPIContext::RetrieveFrame(AVCodecContext* /*unused*/, VideoFrame *Frame, AVFrame *AvFrame)
645 {
646  if (AvFrame->format != AV_PIX_FMT_VAAPI)
647  return false;
649  return RetrieveHWFrame(Frame, AvFrame);
650  return false;
651 }
652 
662 {
663  int ret = 0;
664 
665  while (true)
666  {
667  if (m_filterGraph && ((m_filterWidth != Context->coded_width) || (m_filterHeight != Context->coded_height)))
668  {
669  LOG(VB_GENERAL, LOG_WARNING, LOC + "Input changed - deleting filter");
671  }
672 
673  if (m_filterGraph)
674  {
675  ret = av_buffersink_get_frame(m_filterSink, Frame);
676  if (ret >= 0)
677  {
679  {
680  Frame->pts = m_filterPriorPTS[1] + (m_filterPriorPTS[1] - m_filterPriorPTS[0]) / 2;
681  Frame->scte_cc_len = 0;
682  Frame->atsc_cc_len = 0;
683  av_frame_remove_side_data(Frame, AV_FRAME_DATA_A53_CC);
684  }
685  else
686  {
687  Frame->pts = m_filterPriorPTS[1];
689  }
690  }
691  if (ret != AVERROR(EAGAIN))
692  break;
693  }
694 
695  // EAGAIN or no filter graph
696  ret = avcodec_receive_frame(Context, Frame);
697  if (ret == 0)
698  {
699  // preserve interlaced flags
700  m_lastInterlaced = Frame->interlaced_frame;
701  m_lastTopFieldFirst = Frame->top_field_first;
702  }
703 
704  if (ret < 0)
705  break;
706 
707  // some streams with missing timestamps break frame timing when doublerate
708  // so replace with dts if available
709  int64_t pts = Frame->pts;
710  if (pts == AV_NOPTS_VALUE && Frame->pkt_dts != AV_NOPTS_VALUE && m_deinterlacer2x)
711  pts = Frame->pkt_dts;
713  m_filterPriorPTS[1] = pts;
714 
715  if (!m_filterGraph)
716  break;
717 
718  ret = av_buffersrc_add_frame(m_filterSource, Frame);
719  if (ret < 0)
720  break;
721  }
722 
723  return ret;
724 }
725 
727 {
728  if (!Frame || !codec_is_vaapi_dec(m_codecID) || !Context->hw_frames_ctx)
729  return;
730 
731  // if VAAPI driver deints are errored or not available (older boards), then
732  // allow CPU/GLSL
733  if (m_filterError)
734  {
735  Frame->deinterlace_allowed = Frame->deinterlace_allowed & ~DEINT_DRIVER;
736  return;
737  }
740  {
741  // enabling VPP deinterlacing with these codecs breaks decoding for some reason.
742  // HEVC interlacing is not currently detected by FFmpeg and I can't find
743  // any interlaced VP8/9 material. Shaders and/or CPU deints will be available
744  // as appropriate
745  m_filterError = true;
746  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Disabling VAAPI VPP deinterlacer for %1")
747  .arg(toString(m_codecID)));
748  return;
749  }
750 
751  // if this frame has already been deinterlaced, then flag the deinterlacer and
752  // that the frame has already been deinterlaced.
753  // the FFmpeg vaapi deint filter will mark frames as progressive, so restore the
754  // interlaced flags to ensure auto deinterlacing continues to work
755  if (m_deinterlacer)
756  {
757  Frame->interlaced_frame = m_lastInterlaced;
758  Frame->top_field_first = m_lastTopFieldFirst;
759  Frame->deinterlace_inuse = m_deinterlacer | DEINT_DRIVER;
760  Frame->deinterlace_inuse2x = m_deinterlacer2x;
761  Frame->already_deinterlaced = 1;
762  }
763 
764  // N.B. this picks up the scan tracking in MythPlayer. So we can
765  // auto enable deinterlacing etc and override Progressive/Interlaced - but
766  // no reversed interlaced.
767  MythDeintType vaapideint = DEINT_NONE;
770  bool doublerate = true;
771  bool other = false;
772 
773  // For decode only, a CPU or shader deint may also be used/preferred
774  if (doublepref)
775  vaapideint = doublepref;
777  other = true;
778 
779  if (!vaapideint && !other && singlepref)
780  {
781  doublerate = false;
782  vaapideint = singlepref;
783  }
784 
785  // nothing to see
786  if (vaapideint == DEINT_NONE)
787  {
788  if (m_deinterlacer)
790  return;
791  }
792 
793  // already setup
794  if ((m_deinterlacer == vaapideint) && (m_deinterlacer2x == doublerate))
795  return;
796 
797  // Start from scratch
799  m_framesCtx = av_buffer_ref(Context->hw_frames_ctx);
800  if (!MythVAAPIInterop::SetupDeinterlacer(vaapideint, doublerate, Context->hw_frames_ctx,
801  Context->coded_width, Context->coded_height,
803  {
804  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Failed to create deinterlacer %1 - disabling")
805  .arg(DeinterlacerName(vaapideint | DEINT_DRIVER, doublerate, FMT_VAAPI)));
807  m_filterError = true;
808  }
809  else
810  {
811  m_deinterlacer = vaapideint;
812  m_deinterlacer2x = doublerate;
813  m_filterWidth = Context->coded_width;
814  m_filterHeight = Context->coded_height;
815  }
816 }
817 
818 bool MythVAAPIContext::IsDeinterlacing(bool &DoubleRate, bool StreamChange)
819 {
820  // the VAAPI deinterlacer can be turned on and off, so on stream changes
821  // return false to ensure auto deint works for the new format (the deinterlacer
822  // refers to the current format)
823  if (m_deinterlacer && !StreamChange)
824  {
825  DoubleRate = m_deinterlacer2x;
826  return true;
827  }
828  DoubleRate = false;
829  return false;
830 }
831 
833 {
834  // HEVC appears to be OK
835  return kCodec_H264_VAAPI == m_codecID;
836 }
837 
839 {
840  // Only MPEG2 tested so far
842 }
843 
845 {
846  if (m_filterGraph)
847  LOG(VB_GENERAL, LOG_INFO, LOC + "Destroying VAAPI deinterlacer");
848  avfilter_graph_free(&m_filterGraph);
849  m_filterGraph = nullptr;
850  m_filterSink = nullptr;
851  m_filterSource = nullptr;
852  m_filterPTSUsed = 0;
853  m_filterPriorPTS[0] = 0;
854  m_filterPriorPTS[1] = 0;
855  m_filterWidth = 0;
856  m_filterHeight = 0;
857  if (m_framesCtx)
858  av_buffer_unref(&m_framesCtx);
860  m_deinterlacer2x = false;
861 }
QPair< MythCodecContext::CodecProfile, QPair< QSize, QSize > > VAAPIProfile
static enum AVPixelFormat GetFormat(AVCodecContext *Context, const AVPixelFormat *PixFmt)
void SetPlayer(MythPlayer *Player)
MythDeintType GetDoubleRateOption(const VideoFrame *Frame, MythDeintType Type, MythDeintType Override)
Definition: mythframe.cpp:854
bool RetrieveFrame(AVCodecContext *Context, VideoFrame *Frame, AVFrame *AvFrame) override
#define CODEC_IS_MPEG(id)
Definition: mythcodecid.h:359
static void GetDecoderList(QStringList &Decoders)
QHash< QString, Action * > Context
Definition: action.h:77
QList< VAAPIProfile > VAAPIProfiles
bool DecoderWillResetOnFlush(void) override
QString toString(MarkTypes type)
static Type GetInteropType(VideoFrameType Format, MythPlayer *Player)
Check whether we support direct rendering for the given VideoFrameType.
MythCodecID
Definition: mythcodecid.h:10
#define LOC
static enum AVPixelFormat GetFormat2(AVCodecContext *Context, const AVPixelFormat *PixFmt)
static AVPixelFormat FramesFormat(AVPixelFormat Format)
void PostProcessFrame(AVCodecContext *Context, VideoFrame *Frame) override
static int InitialiseDecoder(AVCodecContext *Context, CreateHWDecoder Callback, const QString &Debug)
Initialise a hardware decoder that is expected to use AVHWFramesContext.
AVFilterContext * m_filterSink
bool DecoderWillResetOnAspect(void) override
static VAProfile VAAPIProfileForCodec(const AVCodecContext *Codec)
static QString GetProfileDescription(CodecProfile Profile, QSize Size, VideoFrameType Format=FMT_NONE, uint ColorDepth=0)
struct AVFrame AVFrame
AVBufferRef * m_framesCtx
static int GetBuffer(struct AVCodecContext *Context, AVFrame *Frame, int Flags)
A generic hardware buffer initialisation method when using AVHWFramesContext.
QString GetVendor(void)
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
static int GetMaxReferenceFrames(AVCodecContext *Context)
MythCodecID m_codecID
MythDeintType
Definition: mythframe.h:120
QString DeinterlacerName(MythDeintType Deint, bool DoubleRate, VideoFrameType Format)
Return a user friendly description of the given deinterlacer.
Definition: mythavutil.cpp:114
void InitVideoCodec(AVCodecContext *Context, bool SelectedStream, bool &DirectRendering) override
#define codec_is_vaapi(id)
Definition: mythcodecid.h:311
static const VAAPIProfiles & GetProfiles(void)
virtual void InitVideoCodec(AVCodecContext *Context, bool SelectedStream, bool &DirectRendering)
QString GetSetting(const QString &key, const QString &defaultval="")
#define codec_is_vaapi_dec(id)
Definition: mythcodecid.h:313
virtual int DecrRef(void)
Decrements reference count and deletes on 0.
unsigned int uint
Definition: compat.h:140
static int InitialiseContext(AVCodecContext *Context)
Create a VAAPI hardware context with appropriate OpenGL interop.
static CodecProfile FFmpegToMythProfile(AVCodecID CodecID, int Profile)
void * av_malloc(unsigned int size)
static void FramesContextFinished(AVHWFramesContext *Context)
uint mpeg_version(int codec_id)
static MythVAAPIInterop * Create(MythRenderOpenGL *Context, Type InteropType)
MythDeintType m_deinterlacer
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
static uint GetNumBuffers(int PixelFormat, int MaxReferenceFrames=16, bool Decoder=false)
int64_t m_filterPriorPTS[2]
int FilteredReceiveFrame(AVCodecContext *Context, AVFrame *Frame) override
Retrieve decoded frame and optionally deinterlace.
static MythRenderOpenGL * GetOpenGLRender(void)
AVFilterContext * m_filterSource
bool IsDeinterlacing(bool &DoubleRate, bool StreamChange=false) override
MythVAAPIContext(DecoderBase *Parent, MythCodecID CodecID)
~MythVAAPIContext() override
static void NewHardwareFramesContext(void)
Track the number of concurrent frames contexts.
static QString HaveVAAPI(bool ReCheck=false)
Check whether VAAPI is available and not emulated via VDPAU.
static bool SetupDeinterlacer(MythDeintType Deinterlacer, bool DoubleRate, AVBufferRef *FramesContext, int Width, int Height, AVFilterGraph *&Graph, AVFilterContext *&Source, AVFilterContext *&Sink)
virtual bool RetrieveHWFrame(VideoFrame *Frame, AVFrame *AvFrame)
VADisplay GetDisplay(void)
static int InitialiseContext2(AVCodecContext *Context)
Create a VAAPI hardware context without OpenGL interop.
bool IsEGL(void)
Definition: mythegl.cpp:29
void DestroyDeinterlacer(void)
AVFilterGraph * m_filterGraph
MythDeintType GetSingleRateOption(const VideoFrame *Frame, MythDeintType Type, MythDeintType Override)
Definition: mythframe.cpp:841
static MythCodecID GetSupportedCodec(AVCodecContext **Context, AVCodec **Codec, const QString &Decoder, uint StreamType)
Confirm whether VAAPI support is available given Decoder and Context.
static AVBufferRef * CreateDevice(AVHWDeviceType Type, MythOpenGLInterop *Interop, const QString &Device=QString())
static QString TypeToString(Type InteropType)
#define VA_FOURCC_I420