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