MythTV  master
vaapicontext.cpp
Go to the documentation of this file.
1 #include "openglvideo.h"
2 #include "mythlogging.h"
3 #include "mythxdisplay.h"
4 #include "mythcodecid.h"
5 #include "mythframe.h"
6 #include "vaapicontext.h"
7 #include "mythmainwindow.h"
8 
9 #define LOC QString("VAAPI: ")
10 #define ERR QString("VAAPI Error: ")
11 #define NUM_VAAPI_BUFFERS 24
12 
13 #define INIT_ST \
14  VAStatus va_status; \
15  bool ok = true
16 
17 #define CHECK_ST \
18  ok &= (va_status == VA_STATUS_SUCCESS); \
19  if (!ok) \
20  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Error at %1:%2 (#%3, %4)") \
21  .arg(__FILE__).arg( __LINE__).arg(va_status) \
22  .arg(vaErrorStr(va_status)))
23 
24 #define CREATE_CHECK(arg1, arg2) \
25  if (ok) \
26  { \
27  ok = arg1; \
28  if (!ok) \
29  LOG(VB_GENERAL, LOG_ERR, LOC + (arg2)); \
30  } while(false)
31 
32 QString profileToString(VAProfile profile);
33 QString entryToString(VAEntrypoint entry);
34 VAProfile preferredProfile(MythCodecID codec);
35 
36 QString profileToString(VAProfile profile)
37 {
38  if (VAProfileMPEG2Simple == profile) return "MPEG2Simple";
39  if (VAProfileMPEG2Main == profile) return "MPEG2Main";
40  if (VAProfileMPEG4Simple == profile) return "MPEG4Simple";
41  if (VAProfileMPEG4AdvancedSimple == profile) return "MPEG4AdvSimple";
42  if (VAProfileMPEG4Main == profile) return "MPEG4Main";
43 #if not VA_CHECK_VERSION(1,0,0) // VAProfileH264Baseline is deprecated
44  if (VAProfileH264Baseline == profile) return "H264Base";
45 #endif
46  if (VAProfileH264ConstrainedBaseline == profile) return "H264ConstrainedBase";
47  if (VAProfileH264Main == profile) return "H264Main";
48  if (VAProfileH264High == profile) return "H264High";
49  if (VAProfileVC1Simple == profile) return "VC1Simple";
50  if (VAProfileVC1Main == profile) return "VC1Main";
51  if (VAProfileVC1Advanced == profile) return "VC1Advanced";
52  if (VAProfileH263Baseline == profile) return "H263Base";
53 
54 #if VA_CHECK_VERSION(0,34,0)
55  if (VAProfileNone == profile) return "None";
56 #endif
57 #if VA_CHECK_VERSION(0,36,0)
58  if (VAProfileH264StereoHigh == profile) return "H264StereoHigh";
59 #endif
60 #if VA_CHECK_VERSION(0,38,0)
61  if (VAProfileHEVCMain == profile) return "HEVCMain";
62  if (VAProfileHEVCMain10 == profile) return "HEVCMain10";
63 #endif
64 
65  return "Unknown";
66 }
67 
68 QString entryToString(VAEntrypoint entry)
69 {
70  if (VAEntrypointVLD == entry) return "VLD ";
71  if (VAEntrypointIZZ == entry) return "IZZ (UNSUPPORTED) ";
72  if (VAEntrypointIDCT == entry) return "IDCT (UNSUPPORTED) ";
73  if (VAEntrypointMoComp == entry) return "MC (UNSUPPORTED) ";
74  if (VAEntrypointDeblocking == entry) return "Deblock (UNSUPPORTED) ";
75  if (VAEntrypointEncSlice == entry) return "EncSlice (UNSUPPORTED) ";
76 #if VA_CHECK_VERSION(0,34,0)
77  if (VAEntrypointVideoProc == entry) return "VideoProc (UNSUPPORTED) ";
78 #endif
79  return "Unknown";
80 }
81 
82 VAProfile preferredProfile(MythCodecID codec)
83 {
84  if (kCodec_H263_VAAPI == codec) return VAProfileMPEG4AdvancedSimple;
85  if (kCodec_MPEG4_VAAPI == codec) return VAProfileMPEG4AdvancedSimple;
86  if (kCodec_H264_VAAPI == codec) return VAProfileH264High;
87  if (kCodec_VC1_VAAPI == codec) return VAProfileVC1Advanced;
88  if (kCodec_WMV3_VAAPI == codec) return VAProfileVC1Main;
89  if (kCodec_MPEG2_VAAPI == codec) return VAProfileMPEG2Main;
90 #if VA_CHECK_VERSION(0,38,0)
91  if (kCodec_HEVC_VAAPI == codec) return VAProfileHEVCMain;
92 #endif
93  // NB Ffmpeg 1.2.2 doesn't support MPEG1 with VAAPI pix_fmts
94  return VAProfileMPEG2Simple; // error
95 }
96 
98 {
99  protected:
100  explicit VAAPIDisplay(VAAPIDisplayType display_type) :
101  ReferenceCounter("VAAPIDisplay"),
102  m_va_disp_type(display_type),
103  m_va_disp(nullptr), m_x_disp(nullptr),
104  m_driver() { }
105  public:
106  ~VAAPIDisplay() override
107  {
108  if (m_va_disp)
109  {
110  INIT_ST;
111  XLOCK(m_x_disp, va_status = vaTerminate(m_va_disp));
112  CHECK_ST;
113  }
114  if (m_x_disp)
115  {
116  m_x_disp->Sync(true);
117  delete m_x_disp;
118  }
119  }
120 
121  bool Create(void)
122  {
124  if (!m_x_disp)
125  return false;
126 
127  MythXLocker locker(m_x_disp);
128 
130  {
132  if (!mw)
133  return false;
134  MythRenderOpenGL *gl =
135  static_cast<MythRenderOpenGL*>(mw->GetRenderDevice());
136  if (!gl)
137  {
138  LOG(VB_PLAYBACK, LOG_ERR, LOC +
139  QString("Failed to get OpenGL context - you must use the "
140  "OpenGL UI painter for VAAPI GLX support."));
141  return false;
142  }
143 
144  gl->makeCurrent();
145  Display *display = glXGetCurrentDisplay();
146  gl->doneCurrent();
147 
148  m_va_disp = vaGetDisplayGLX(display);
149  }
150  else
151  {
152  m_va_disp = vaGetDisplay(m_x_disp->GetDisplay());
153  }
154 
155  if (!m_va_disp)
156  {
157  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create VADisplay");
158  return false;
159  }
160 
161  int major_ver, minor_ver;
162  INIT_ST;
163  va_status = vaInitialize(m_va_disp, &major_ver, &minor_ver);
164  CHECK_ST;
165 
166  if (ok)
167  m_driver = vaQueryVendorString(m_va_disp);
168 
169  static bool debugged = false;
170  if (ok && !debugged)
171  {
172  debugged = true;
173  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Version: %1.%2")
174  .arg(major_ver).arg(minor_ver));
175  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Driver : %1").arg(m_driver));
176  }
177  if (ok)
178  {
179  LOG(VB_PLAYBACK, LOG_INFO, LOC +
180  QString("Created VAAPI %1 display")
181  .arg(m_va_disp_type == kVADisplayGLX ? "GLX" : "X11"));
182  }
183  return ok;
184  }
185 
186  int DecrRef(void) override // ReferenceCounter
187  {
188  QMutexLocker locker(&s_VAAPIDisplayLock);
189 
190  VAAPIDisplay *tmp = this;
191  int cnt = ReferenceCounter::DecrRef();
192  if (cnt == 0)
193  {
194  if (s_VAAPIDisplay == tmp)
195  s_VAAPIDisplay = nullptr;
196  LOG(VB_PLAYBACK, LOG_INFO, LOC + "Deleting VAAPI display.");
197  }
198  return cnt;
199  }
200 
201  QString GetDriver(void)
202  {
203  return m_driver;
204  }
205 
206  static VAAPIDisplay *GetDisplay(VAAPIDisplayType display_type, bool noreuse)
207  {
208  if (noreuse)
209  {
210  VAAPIDisplay *tmp = new VAAPIDisplay(display_type);
211  if (tmp->Create())
212  {
213  return tmp;
214  }
215  tmp->DecrRef();
216  return nullptr;
217  }
218 
219  QMutexLocker locker(&s_VAAPIDisplayLock);
220 
221  if (s_VAAPIDisplay)
222  {
223  if (s_VAAPIDisplay->m_va_disp_type != display_type)
224  {
225  LOG(VB_GENERAL, LOG_ERR, "Already have a VAAPI display "
226  "of a different type - aborting");
227  return nullptr;
228  }
230  return s_VAAPIDisplay;
231  }
232 
233  s_VAAPIDisplay = new VAAPIDisplay(display_type);
234  if (s_VAAPIDisplay->Create())
235  return s_VAAPIDisplay;
236 
238  return nullptr;
239  }
240 
241  static QMutex s_VAAPIDisplayLock;
244  void *m_va_disp;
246  QString m_driver;
247 };
248 
249 QMutex VAAPIDisplay::s_VAAPIDisplayLock(QMutex::Recursive);
251 
253  AVPixelFormat &pix_fmt)
254 {
255  bool result = false;
256  VAAPIContext *ctx = new VAAPIContext(kVADisplayX11, codec);
257  if (ctx->CreateDisplay(size, true))
258  {
259  pix_fmt = ctx->GetPixelFormat();
260  result = pix_fmt == AV_PIX_FMT_VAAPI_VLD;
261  }
262  delete ctx;
263  return result;
264 }
265 
267  MythCodecID codec)
268  : m_dispType(display_type),
269  m_codec(codec),
270  m_display(nullptr),
271  m_vaProfile(VAProfileMPEG2Main)/* ?? */,
272  m_vaEntrypoint(VAEntrypointEncSlice),
273  m_pix_fmt(AV_PIX_FMT_YUV420P), m_numSurfaces(NUM_VAAPI_BUFFERS),
274  m_surfaces(nullptr), m_surfaceData(nullptr), m_pictureAttributes(nullptr),
275  m_pictureAttributeCount(0), m_hueBase(0), m_deriveSupport(false),
276  m_copy(nullptr)
277 {
278  memset(&m_ctx, 0, sizeof(vaapi_context));
279  memset(&m_image, 0, sizeof(m_image));
280  m_image.image_id = VA_INVALID_ID;
281 }
282 
284 {
285  delete [] m_pictureAttributes;
286 
288 
289  if (m_display)
290  {
291  m_display->m_x_disp->Lock();
292 
293  INIT_ST;
294 
295  if (m_image.image_id != VA_INVALID_ID)
296  {
297  va_status = vaDestroyImage(m_ctx.display, m_image.image_id);
298  CHECK_ST;
299  }
300  if (m_ctx.context_id)
301  {
302  va_status = vaDestroyContext(m_ctx.display, m_ctx.context_id);
303  CHECK_ST;
304  }
305  if (m_ctx.config_id)
306  {
307  va_status = vaDestroyConfig(m_ctx.display, m_ctx.config_id);
308  CHECK_ST;
309  }
310  if (m_surfaces)
311  {
312  va_status = vaDestroySurfaces(m_ctx.display, m_surfaces, m_numSurfaces);
313  CHECK_ST;
314  }
315  }
316 
317  delete [] m_surfaces;
318  delete [] m_surfaceData;
319 
320  if (m_display)
321  {
323  m_display->DecrRef();
324  }
325 
326  delete m_copy;
327 
328  LOG(VB_PLAYBACK, LOG_INFO, LOC + "Deleted context");
329 }
330 
331 bool VAAPIContext::CreateDisplay(QSize size, bool noreuse)
332 {
333  m_size = size;
334  if (!m_copy)
335  {
336  m_copy = new MythUSWCCopy(m_size.width());
337  }
338  else
339  {
340  m_copy->reset(m_size.width());
341  }
342 
343  bool ok = true;
345  CREATE_CHECK(!m_size.isEmpty(), "Invalid size");
346  CREATE_CHECK(m_display != nullptr, "Invalid display");
347  CREATE_CHECK(InitDisplay(), "Invalid VADisplay");
348  CREATE_CHECK(InitProfiles(), "No supported profiles");
349  if (ok)
350  LOG(VB_PLAYBACK, LOG_INFO, LOC +
351  QString("Created context (%1x%2->%3x%4)")
352  .arg(size.width()).arg(size.height())
353  .arg(m_size.width()).arg(m_size.height()));
354  // ATI hue adjustment
355  if (m_display)
357 
358  return ok;
359 }
360 
362 {
363  if (!m_display)
364  return;
365  if (!m_display->m_va_disp)
366  return;
367 
368  delete [] m_pictureAttributes;
370  int supported_controls = kPictureAttributeSupported_None;
371  QList<VADisplayAttribute> supported;
372  int num = vaMaxNumDisplayAttributes(m_display->m_va_disp);
373  VADisplayAttribute* attribs = new VADisplayAttribute[num];
374 
375  int actual = 0;
376  INIT_ST;
377  va_status = vaQueryDisplayAttributes(m_display->m_va_disp, attribs, &actual);
378  CHECK_ST;
379 
380  for (int i = 0; i < actual; i++)
381  {
382  int type = attribs[i].type;
383  if ((attribs[i].flags & VA_DISPLAY_ATTRIB_SETTABLE) &&
384  (type == VADisplayAttribBrightness ||
385  type == VADisplayAttribContrast ||
386  type == VADisplayAttribHue ||
387  type == VADisplayAttribSaturation))
388  {
389  supported.push_back(attribs[i]);
390  if (type == VADisplayAttribBrightness)
391  supported_controls += kPictureAttributeSupported_Brightness;
392  if (type == VADisplayAttribHue)
393  supported_controls += kPictureAttributeSupported_Hue;
394  if (type == VADisplayAttribContrast)
395  supported_controls += kPictureAttributeSupported_Contrast;
396  if (type == VADisplayAttribSaturation)
397  supported_controls += kPictureAttributeSupported_Colour;
398  }
399  }
400 
401  colourspace.SetSupportedAttributes((PictureAttributeSupported)supported_controls);
402  delete [] attribs;
403 
404  if (supported.isEmpty())
405  return;
406 
407  m_pictureAttributeCount = supported.size();
408  m_pictureAttributes = new VADisplayAttribute[m_pictureAttributeCount];
409  for (int i = 0; i < m_pictureAttributeCount; i++)
410  m_pictureAttributes[i] = supported.at(i);
411 
412  if (supported_controls & kPictureAttributeSupported_Brightness)
415  if (supported_controls & kPictureAttributeSupported_Hue)
418  if (supported_controls & kPictureAttributeSupported_Contrast)
421  if (supported_controls & kPictureAttributeSupported_Colour)
424 }
425 
427 {
428  if (!m_display)
429  return newValue;
430  if (!m_display->m_va_disp)
431  return newValue;
432 
433  int adj = 0;
434  VADisplayAttribType attrib = VADisplayAttribBrightness;
435  switch (attribute)
436  {
438  attrib = VADisplayAttribBrightness;
439  break;
441  attrib = VADisplayAttribContrast;
442  break;
444  attrib = VADisplayAttribHue;
445  adj = m_hueBase;
446  break;
448  attrib = VADisplayAttribSaturation;
449  break;
450  default:
451  return -1;
452  }
453 
454  bool found = false;
455  for (int i = 0; i < m_pictureAttributeCount; i++)
456  {
457  if (m_pictureAttributes[i].type == attrib)
458  {
459  int min = m_pictureAttributes[i].min_value;
460  int max = m_pictureAttributes[i].max_value;
461  int val = min + (int)(((float)((newValue + adj) % 100) / 100.0F) * (max - min));
462  m_pictureAttributes[i].value = val;
463  found = true;
464  break;
465  }
466  }
467 
468  if (found)
469  {
470  INIT_ST;
471  va_status = vaSetDisplayAttributes(m_display->m_va_disp,
474  CHECK_ST;
475  return newValue;
476  }
477  return -1;
478 }
479 
481 {
482  bool ok = true;
483  CREATE_CHECK(!m_size.isEmpty(), "Invalid size");
484  CREATE_CHECK(InitBuffers(), "Failed to create buffers.");
485  CREATE_CHECK(InitContext(), "Failed to create context");
486  if (ok)
487  LOG(VB_PLAYBACK, LOG_INFO, LOC +
488  QString("Created %1 buffers").arg(m_numSurfaces));
489  return ok;
490 }
491 
493 {
494  if (!m_display)
495  return false;
496  m_ctx.display = m_display->m_va_disp;
497  return m_ctx.display;
498 }
499 
501 {
502  if (!(codec_is_vaapi_hw(m_codec)) || !m_ctx.display)
503  return false;
504 
505  MythXLocker locker(m_display->m_x_disp);
506  int max_profiles, max_entrypoints;
507  VAProfile profile_wanted = preferredProfile(m_codec);
508  if (profile_wanted == VAProfileMPEG2Simple)
509  {
510  LOG(VB_PLAYBACK, LOG_ERR, LOC + "Codec is not supported.");
511  return false;
512  }
513 
514  VAProfile profile_found = VAProfileMPEG2Simple; // unsupported value
515  VAEntrypoint entry_found = VAEntrypointEncSlice; // unsupported value
516 
517  max_profiles = vaMaxNumProfiles(m_ctx.display);
518  max_entrypoints = vaMaxNumEntrypoints(m_ctx.display);
519  VAProfile *profiles = new VAProfile[max_profiles];
520  VAEntrypoint *entries = new VAEntrypoint[max_entrypoints];
521 
522  if (profiles && entries)
523  {
524  static bool debugged = false;
525 
526  INIT_ST;
527  int act_profiles, act_entries;
528  va_status = vaQueryConfigProfiles(m_ctx.display,
529  profiles,
530  &act_profiles);
531  CHECK_ST;
532  if (ok && act_profiles > 0)
533  {
534  for (int i = 0; i < act_profiles; i++)
535  {
536  va_status = vaQueryConfigEntrypoints(m_ctx.display,
537  profiles[i],
538  entries,
539  &act_entries);
540  if (va_status == VA_STATUS_SUCCESS && act_entries > 0)
541  {
542  if (profiles[i] == profile_wanted)
543  {
544  profile_found = profile_wanted;
545  for (int j = 0; j < act_entries; j++)
546  if (entries[j] < entry_found)
547  entry_found = entries[j];
548  }
549 
550  if (!debugged)
551  {
552  QString entrylist = "Entrypoints: ";
553  for (int j = 0; j < act_entries; j++)
554  entrylist += entryToString(entries[j]);
555  LOG(VB_GENERAL, LOG_INFO, LOC +
556  QString("Profile: %1 %2")
557  .arg(profileToString(profiles[i]))
558  .arg(entrylist));
559  }
560  }
561  }
562  }
563  debugged = true;
564  }
565  delete [] profiles;
566  delete [] entries;
567 
568  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Desired profile for '%1': %2")
569  .arg(toString(m_codec)).arg(profileToString(profile_wanted)));
570  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Found profile %1 with entry %2")
571  .arg(profileToString(profile_found)).arg(entryToString(entry_found)));
572 
573  if (profile_wanted != profile_found)
574  {
575  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to find supported profile.");
576  return false;
577  }
578 
579  if (entry_found > VAEntrypointVLD)
580  {
581  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to find suitable entry point.");
582  return false;
583  }
584 
585  m_vaProfile = profile_wanted;
586  m_vaEntrypoint = entry_found;
587  if (VAEntrypointVLD == m_vaEntrypoint)
588  m_pix_fmt = AV_PIX_FMT_VAAPI_VLD;
589  return true;
590 }
591 
593 {
594  if (!m_ctx.display)
595  return false;
596 
597  MythXLocker locker(m_display->m_x_disp);
598  m_surfaces = new VASurfaceID[m_numSurfaces];
600 
601  if (!m_surfaces || !m_surfaceData)
602  return false;
603 
604  memset(m_surfaces, 0, m_numSurfaces * sizeof(VASurfaceID));
605  memset(m_surfaceData, 0, m_numSurfaces * sizeof(vaapi_surface));
606 
607  INIT_ST;
608  va_status = vaCreateSurfaces(m_ctx.display, m_size.width(), m_size.height(),
609  VA_RT_FORMAT_YUV420, m_numSurfaces,
610  m_surfaces);
611  CHECK_ST;
612 
613  for (int i = 0; i < m_numSurfaces; i++)
614  m_surfaceData[i].m_id = m_surfaces[i];
615  return ok;
616 }
617 
619 {
620  if (!m_ctx.display || m_vaEntrypoint > VAEntrypointVLD)
621  return false;
622 
623  MythXLocker locker(m_display->m_x_disp);
624  VAConfigAttrib attrib;
625  attrib.type = VAConfigAttribRTFormat;
626  INIT_ST;
627  va_status = vaGetConfigAttributes(m_ctx.display, m_vaProfile,
628  m_vaEntrypoint, &attrib, 1);
629  CHECK_ST;
630 
631  if (!ok || !(attrib.value & VA_RT_FORMAT_YUV420))
632  {
633  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to confirm YUV420 chroma");
634  return false;
635  }
636 
637  va_status = vaCreateConfig(m_ctx.display, m_vaProfile, m_vaEntrypoint,
638  &attrib, 1, &m_ctx.config_id);
639  CHECK_ST;
640  if (!ok)
641  {
642  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create decoder config.");
643  return false;
644  }
645 
646  va_status = vaCreateContext(m_ctx.display, m_ctx.config_id,
647  m_size.width(), m_size.height(), VA_PROGRESSIVE,
649  &m_ctx.context_id);
650  CHECK_ST;
651  if (!ok)
652  {
653  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create decoder context.");
654  return false;
655  }
656  return true;
657 }
658 
660 {
661  if (i < 0 || i >= m_numSurfaces)
662  return nullptr;
663  return &m_surfaceData[i];
664 }
665 
667 {
668  if (!buf)
669  return nullptr;
670 
671  const vaapi_surface *surf = (vaapi_surface*)buf;
672  if (!surf->m_id)
673  return nullptr;
674 
675  INIT_ST;
676  va_status = vaSyncSurface(m_ctx.display, surf->m_id);
677  CHECK_ST;
678  return (uint8_t*)(uintptr_t)surf->m_id;
679 }
680 
681 bool VAAPIContext::InitImage(const void *buf)
682 {
683  if (!buf)
684  return false;
685  if (m_dispType != kVADisplayX11)
686  return true;
687 
688  int num_formats = 0;
689  int max_formats = vaMaxNumImageFormats(m_ctx.display);
690  VAImageFormat *formats = new VAImageFormat[max_formats];
691 
692  INIT_ST;
693  va_status = vaQueryImageFormats(m_ctx.display, formats, &num_formats);
694  CHECK_ST;
695 
696  const vaapi_surface *surf = (vaapi_surface*)buf;
697  unsigned int deriveImageFormat = 0;
698 
699  if (vaDeriveImage(m_ctx.display, surf->m_id, &m_image) == VA_STATUS_SUCCESS)
700  {
701  m_deriveSupport = true;
702  deriveImageFormat = m_image.format.fourcc;
703  vaDestroyImage(m_ctx.display, m_image.image_id);
704  }
705 
706  int nv12support = -1;
707 
708  for (int i = 0; i < num_formats; i++)
709  {
710  if (formats[i].fourcc == VA_FOURCC_YV12 ||
711  formats[i].fourcc == VA_FOURCC_IYUV ||
712  formats[i].fourcc == VA_FOURCC_NV12)
713  {
714  if (vaCreateImage(m_ctx.display, &formats[i],
715  m_size.width(), m_size.height(), &m_image))
716  {
717  m_image.image_id = VA_INVALID_ID;
718  continue;
719  }
720 
721  if (vaGetImage(m_ctx.display, surf->m_id, 0, 0,
722  m_size.width(), m_size.height(), m_image.image_id))
723  {
724  vaDestroyImage(m_ctx.display, m_image.image_id);
725  m_image.image_id = VA_INVALID_ID;
726  continue;
727  }
728 
729  if (formats[i].fourcc == VA_FOURCC_NV12)
730  {
731  // mark as NV12 as supported, but favor other formats first
732  nv12support = i;
733  vaDestroyImage(m_ctx.display, m_image.image_id);
734  m_image.image_id = VA_INVALID_ID;
735  continue;
736  }
737  break;
738  }
739  }
740 
741  if (m_image.image_id == VA_INVALID_ID && nv12support >= 0)
742  {
743  // only nv12 is supported, use that format
744  if (vaCreateImage(m_ctx.display, &formats[nv12support],
745  m_size.width(), m_size.height(), &m_image))
746  {
747  m_image.image_id = VA_INVALID_ID;
748  }
749  }
750  else if (m_deriveSupport && deriveImageFormat != m_image.format.fourcc)
751  {
752  // only use vaDerive if it's giving us a format we can handle natively
753  m_deriveSupport = false;
754  }
755 
756  delete [] formats;
757 
758  if (m_image.image_id == VA_INVALID_ID)
759  {
760  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create software image.");
761  return false;
762  }
763 
764  LOG(VB_GENERAL, LOG_DEBUG,
765  LOC + QString("InitImage: id %1, width %2 height %3 "
766  "format %4 vaDeriveSupport:%5")
767  .arg(m_image.image_id).arg(m_image.width).arg(m_image.height)
768  .arg(m_image.format.fourcc).arg(m_deriveSupport));
769 
770  if (m_deriveSupport)
771  {
772  vaDestroyImage(m_ctx.display, m_image.image_id );
773  m_image.image_id = VA_INVALID_ID;
774  }
775 
776  return true;
777 }
778 
779 bool VAAPIContext::CopySurfaceToFrame(VideoFrame *frame, const void *buf)
780 {
781  MythXLocker locker(m_display->m_x_disp);
782 
783  if (!m_deriveSupport && m_image.image_id == VA_INVALID_ID)
784  InitImage(buf);
785 
786  if (!frame || !buf || (m_dispType != kVADisplayX11) ||
787  (!m_deriveSupport && m_image.image_id == VA_INVALID_ID))
788  return false;
789 
790  const vaapi_surface *surf = (vaapi_surface*)buf;
791 
792  INIT_ST;
793  va_status = vaSyncSurface(m_ctx.display, surf->m_id);
794  CHECK_ST;
795 
796  if (m_deriveSupport)
797  {
798  va_status = vaDeriveImage(m_ctx.display, surf->m_id, &m_image);
799  }
800  else
801  {
802  va_status = vaGetImage(m_ctx.display, surf->m_id, 0, 0,
803  m_size.width(), m_size.height(),
804  m_image.image_id);
805  }
806  CHECK_ST;
807 
808  if (ok)
809  {
810  VideoFrame src;
811  void* source = nullptr;
812 
813  if (vaMapBuffer(m_ctx.display, m_image.buf, &source))
814  return false;
815 
816  if (m_image.format.fourcc == VA_FOURCC_NV12)
817  {
818  init(&src, FMT_NV12, (unsigned char*)source, m_image.width,
819  m_image.height, m_image.data_size, nullptr,
820  nullptr, frame->aspect, frame->frame_rate);
821  for (int i = 0; i < 2; i++)
822  {
823  src.pitches[i] = m_image.pitches[i];
824  src.offsets[i] = m_image.offsets[i];
825  }
826  }
827  else
828  {
829  // Our VideoFrame YV12 format, is really YUV420P/IYUV
830  bool swap = m_image.format.fourcc == VA_FOURCC_YV12;
831  init(&src, FMT_YV12, (unsigned char*)source, m_image.width,
832  m_image.height, m_image.data_size, nullptr,
833  nullptr, frame->aspect, frame->frame_rate);
834  src.pitches[0] = m_image.pitches[0];
835  src.pitches[1] = m_image.pitches[swap ? 2 : 1];
836  src.pitches[2] = m_image.pitches[swap ? 1 : 2];
837  src.offsets[0] = m_image.offsets[0];
838  src.offsets[1] = m_image.offsets[swap ? 2 : 1];
839  src.offsets[2] = m_image.offsets[swap ? 1 : 2];
840  }
841  m_copy->copy(frame, &src);
842 
843  if (vaUnmapBuffer(m_ctx.display, m_image.buf))
844  return false;
845 
846  if (m_deriveSupport)
847  {
848  vaDestroyImage(m_ctx.display, m_image.image_id );
849  m_image.image_id = VA_INVALID_ID;
850  }
851  return true;
852  }
853 
854  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to get image");
855  return false;
856 }
857 
858 bool VAAPIContext::CopySurfaceToTexture(const void* buf, uint texture,
859  uint texture_type, FrameScanType scan)
860 {
861  if (!buf || (m_dispType != kVADisplayGLX))
862  return false;
863 
864  const vaapi_surface *surf = (vaapi_surface*)buf;
865  void* glx_surface = GetGLXSurface(texture, texture_type);
866  if (!glx_surface)
867  return false;
868 
869  int field = VA_FRAME_PICTURE;
870  if (scan == kScan_Interlaced)
871  field = VA_BOTTOM_FIELD;
872  else if (scan == kScan_Intr2ndField)
873  field = VA_TOP_FIELD;
874 
875  m_display->m_x_disp->Lock();
876  INIT_ST;
877  va_status = vaCopySurfaceGLX(m_ctx.display, glx_surface, surf->m_id, field);
878  CHECK_ST;
880  return true;
881 }
882 
883 void* VAAPIContext::GetGLXSurface(uint texture, uint texture_type)
884 {
885  if (m_dispType != kVADisplayGLX)
886  return nullptr;
887 
888  if (m_glxSurfaces.contains(texture))
889  return m_glxSurfaces.value(texture);
890 
891  MythXLocker locker(m_display->m_x_disp);
892  void *glx_surface = nullptr;
893  INIT_ST;
894  va_status = vaCreateSurfaceGLX(m_ctx.display, texture_type,
895  texture, &glx_surface);
896  CHECK_ST;
897  if (!glx_surface)
898  {
899  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create GLX surface.");
900  return nullptr;
901  }
902 
903  m_glxSurfaces.insert(texture, glx_surface);
904 
905  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Number of VAAPI GLX surfaces: %1")
906  .arg(m_glxSurfaces.size()));
907  return glx_surface;
908 }
909 
911 {
912  if (!m_display || (m_dispType != kVADisplayGLX))
913  return;
914 
915  MythXLocker locker(m_display->m_x_disp);
916  INIT_ST;
917  foreach (void* surface, m_glxSurfaces)
918  {
919  va_status = vaDestroySurfaceGLX(m_ctx.display, surface);
920  CHECK_ST;
921  }
922  m_glxSurfaces.clear();
923 }
bool CopySurfaceToTexture(const void *buf, uint texture, uint texture_type, FrameScanType scan)
QString m_driver
int pitches[3]
Y, U, & V pitches.
Definition: mythframe.h:63
VAEntrypoint m_vaEntrypoint
Definition: vaapicontext.h:67
#define CHECK_ST
#define LOC
Definition: vaapicontext.cpp:9
MythXDisplay * OpenMythXDisplay(void)
static int swap(VideoFrame *frame, int datasize, int offset, int shift)
Definition: filter_vflip.c:24
Display * GetDisplay(void)
Definition: mythxdisplay.h:21
bool InitDisplay(void)
#define CREATE_CHECK(arg1, arg2)
def scan(profile, smoonURL, gate)
Definition: scan.py:43
QHash< uint, void * > m_glxSurfaces
Definition: vaapicontext.h:72
void Unlock(void)
Definition: mythxdisplay.h:24
static bool IsFormatAccelerated(QSize size, MythCodecID codec, AVPixelFormat &pix_fmt)
void ClearGLXSurfaces(void)
PictureAttributeSupported
QString toString(MarkTypes type)
#define XLOCK(dpy, arg)
Definition: mythxdisplay.h:75
VAAPIDisplayType m_dispType
Definition: vaapicontext.h:61
VAImage m_image
Definition: vaapicontext.h:76
void reset(int width)
Will reset the cache for a frame with "width" and reset USWC detection.
Definition: mythframe.cpp:763
MythCodecID
Definition: mythcodecid.h:10
General purpose reference counter.
QString profileToString(VAProfile profile)
static VAAPIDisplay * s_VAAPIDisplay
VAAPIDisplay(VAAPIDisplayType display_type)
FrameScanType
Definition: videoouttypes.h:80
This file is intended to hold X11 specific utility functions.
Definition: mythxdisplay.h:16
void Lock(void)
Definition: mythxdisplay.h:23
unsigned int uint
Definition: compat.h:140
VAAPIDisplayType
Definition: vaapicontext.h:23
const char * formats[8]
Definition: vbilut.cpp:190
VAProfile m_vaProfile
Definition: vaapicontext.h:66
#define INIT_ST
vaapi_surface * m_surfaceData
Definition: vaapicontext.h:71
static guint32 * tmp
Definition: goom_core.c:35
void Sync(bool flush=false)
QString GetDriver(void)
bool Create(void)
MythXDisplay * m_x_disp
bool CreateDisplay(QSize size, bool noreuse=false)
bool InitProfiles(void)
vaapi_context m_ctx
Definition: vaapicontext.h:62
#define NUM_VAAPI_BUFFERS
bool InitImage(const void *buf)
MythCodecID m_codec
Definition: vaapicontext.h:63
int offsets[3]
Y, U, & V offsets.
Definition: mythframe.h:64
virtual int IncrRef(void)
Increments reference count.
float aspect
Definition: mythframe.h:43
VERBOSE_PREAMBLE false
Definition: verbosedefs.h:85
void doneCurrent() override
void copy(VideoFrame *dst, const VideoFrame *src)
Definition: mythframe.cpp:594
MythUSWCCopy * m_copy
Definition: vaapicontext.h:78
int DecrRef(void) override
Decrements reference count and deletes on 0.
bool CreateBuffers(void)
virtual int DecrRef(void)
Decrements reference count and deletes on 0.
bool InitContext(void)
uint8_t * GetSurfaceIDPointer(void *buf)
VASurfaceID m_id
Definition: vaapicontext.h:17
VAAPIDisplay * m_display
Definition: vaapicontext.h:65
AVPixelFormat m_pix_fmt
Definition: vaapicontext.h:68
VAAPIDisplayType m_va_disp_type
PictureAttribute
Definition: videoouttypes.h:89
bool InitBuffers(void)
QString entryToString(VAEntrypoint entry)
MythRender * GetRenderDevice()
MythMainWindow * GetMythMainWindow(void)
void InitPictureAttributes(VideoColourSpace &colourspace)
bool m_deriveSupport
Definition: vaapicontext.h:77
void makeCurrent() override
static int CalcHueBase(const QString &adaptor_name)
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
~VAAPIDisplay() override
int m_pictureAttributeCount
Definition: vaapicontext.h:74
void SetSupportedAttributes(PictureAttributeSupported supported)
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
VASurfaceID * m_surfaces
Definition: vaapicontext.h:70
#define codec_is_vaapi_hw(id)
Definition: mythcodecid.h:136
static VAAPIDisplay * GetDisplay(VAAPIDisplayType display_type, bool noreuse)
int GetPictureAttribute(PictureAttribute attribute)
int SetPictureAttribute(PictureAttribute attribute, int newValue)
VAAPIContext(VAAPIDisplayType display_type, MythCodecID codec)
static QMutex s_VAAPIDisplayLock
void * GetVideoSurface(int i)
AVPixelFormat GetPixelFormat(void) const
Definition: vaapicontext.h:43
bool CopySurfaceToFrame(VideoFrame *frame, const void *buf)
VAProfile preferredProfile(MythCodecID codec)
double frame_rate
Definition: mythframe.h:44
void * GetGLXSurface(uint texture, uint texture_type)
VADisplayAttribute * m_pictureAttributes
Definition: vaapicontext.h:73