MythTV  master
mythrender_vdpau.cpp
Go to the documentation of this file.
1 
2 #include "mythrender_vdpau.h"
3 
4 #include <chrono> // for milliseconds
5 #include <cmath>
6 #include <thread> // for sleep_for
7 
8 #include <QSize>
9 #include <utility>
10 
11 #include "mthread.h"
12 #include "mythlogging.h"
13 #include "mythmainwindow.h"
14 
15 
16 // NB this may be API dependant
17 #ifndef VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1
18 #define VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1 (VdpVideoMixerFeature)11
19 #endif
20 #define NUM_SCALING_LEVELS 9
21 
22 #define LOC QString("VDPAU: ")
23 
24 #define LOCK_RENDER QMutexLocker locker1(&m_render_lock);
25 #define LOCK_DECODE QMutexLocker locker2(&m_decode_lock);
26 #define LOCK_ALL LOCK_RENDER; LOCK_DECODE;
27 
28 #define INIT_ST \
29  VdpStatus vdp_st; \
30  bool ok = true;
31 
32 #define CHECK_ST \
33  ok &= (vdp_st == VDP_STATUS_OK); \
34  if (!ok) \
35  { \
36  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Error at %1:%2 (#%3, %4)") \
37  .arg(__FILE__).arg( __LINE__).arg(vdp_st) \
38  .arg(vdp_get_error_string(vdp_st))); \
39  }
40 
41 #define CHECK_STATUS(arg1) \
42  if (m_preempted) \
43  { \
44  m_render_lock.lock(); \
45  m_decode_lock.lock(); \
46  Preempted(); \
47  m_decode_lock.unlock(); \
48  m_render_lock.unlock(); \
49  } \
50  if (m_errored) \
51  return arg1;
52 
53 #define GET_PROC(FUNC_ID, PROC) \
54  vdp_st = vdp_get_proc_address( \
55  m_device, FUNC_ID, (void **)&(PROC)); \
56  CHECK_ST
57 
58 #define CREATE_CHECK(arg1, arg2) \
59  if (ok) \
60  { \
61  ok = arg1; \
62  if (!ok) \
63  LOG(VB_GENERAL, LOG_ERR, LOC + (arg2)); \
64  }
65 
66 #define CHECK_VIDEO_SURFACES(arg1) \
67  if (m_reset_video_surfaces) \
68  ResetVideoSurfaces(); \
69  if (m_reset_video_surfaces) \
70  return arg1;
71 
72 #define COLOR_BLACK {0.0, 0.0, 0.0, 0.0}
73 
74 static const VdpOutputSurfaceRenderBlendState VDPBlends[3] = {
75 {
76  VDP_OUTPUT_SURFACE_RENDER_BLEND_STATE_VERSION,
77  VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_SRC_ALPHA,
78  VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
79  VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_SRC_ALPHA,
80  VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
81  VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD,
82  VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD,
84 },
85 {
86  VDP_OUTPUT_SURFACE_RENDER_BLEND_STATE_VERSION,
87  VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ZERO,
88  VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE,
89  VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE,
90  VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ZERO,
91  VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD,
92  VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD,
94 },
95 {
96  VDP_OUTPUT_SURFACE_RENDER_BLEND_STATE_VERSION,
97  VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE,
98  VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ZERO,
99  VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE,
100  VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ZERO,
101  VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD,
102  VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD,
104 }};
105 
107 {
108  public:
109  explicit VDPAUColor(int color = 0x0) : m_color(color)
110  {
111  SetColor(m_color);
112  }
113 
114  void SetColor(uint color)
115  {
116  m_color = color;
117  m_vdp_color.red = (float)((m_color & 0xFF000000) >> 24) / 255.0F;
118  m_vdp_color.green = (float)((m_color & 0xFF0000) >> 16) / 255.0F;
119  m_vdp_color.blue = (float)((m_color & 0xFF00) >> 8)/ 255.0F;
120  m_vdp_color.alpha = (float)( m_color & 0xFF) / 255.0F;
121  }
122 
123  int m_color {0};
124  VdpColor m_vdp_color;
125 };
126 
128 {
129  public:
131  {
132  memset(&m_layer, 0, sizeof(m_layer));
133  memset(&m_src, 0, sizeof(m_src));
134  memset(&m_dst, 0, sizeof(m_dst));
135  }
136  VDPAULayer(uint surface, const QRect *src, const QRect *dst)
137  {
138  if (src)
139  {
140  m_src.x0 = src->left();
141  m_src.y0 = src->top();
142  m_src.x1 = src->left() + src->width();
143  m_src.y1 = src->top() + src->height();
144  }
145  else
146  memset(&m_src, 0, sizeof(m_src));
147  if (dst)
148  {
149  m_dst.x0 = dst->left();
150  m_dst.y0 = dst->top();
151  m_dst.x1 = dst->left() + dst->width();
152  m_dst.y1 = dst->top() + dst->height();
153  }
154  else
155  memset(&m_dst, 0, sizeof(m_dst));
156  m_layer.struct_version = VDP_LAYER_VERSION;
157  m_layer.source_surface = surface;
158  m_layer.source_rect = src ? &m_src : nullptr;
159  m_layer.destination_rect = dst ? &m_dst : nullptr;
160  }
161 
162  VdpLayer m_layer;
163  VdpRect m_src;
164  VdpRect m_dst;
165 };
166 
168 {
169  public:
170  VDPAUResource() = default;
171  VDPAUResource(uint id, QSize size) : m_id(id), m_size(size) { }
172  virtual ~VDPAUResource() = default;
173 
174  uint m_id {0};
175  QSize m_size;
176 };
177 
179 {
180  public:
181  VDPAUOutputSurface() = default;
182  VDPAUOutputSurface(uint id, QSize size, VdpRGBAFormat fmt)
183  : VDPAUResource(id, size), m_fmt(fmt) { }
184 
185  VdpRGBAFormat m_fmt {0};
186 };
187 
189 {
190  public:
192  {
193  memset(&m_render, 0, sizeof(struct vdpau_render_state));
194  }
195  VDPAUVideoSurface(uint id, QSize size, VdpChromaType type)
196  : VDPAUResource(id, size), m_type(type)
197  {
198  m_owner = QThread::currentThread();
199  memset(&m_render, 0, sizeof(struct vdpau_render_state));
201  }
202  void SetID(uint id)
203  {
204  // NB render data needs to be updated as well but we cannot do that here
205  // as, for example, the new id's of reference frames are not known
206  m_id = id;
208  }
209 
210  VdpChromaType m_type {0};
212  bool m_needs_reset {false};
213  QThread* m_owner {nullptr};
214 };
215 
217 {
218  public:
219  VDPAUBitmapSurface() = default;
220  VDPAUBitmapSurface(uint id, QSize size, VdpRGBAFormat fmt)
221  : VDPAUResource(id, size), m_fmt(fmt) { }
222 
223  VdpRGBAFormat m_fmt {0};
224 };
225 
227 {
228  public:
229  VDPAUDecoder() = default;
230  VDPAUDecoder(uint id, QSize size, VdpDecoderProfile profile, uint refs)
231  : VDPAUResource(id, size), m_profile(profile), m_max_refs(refs) { }
232 
233  VdpDecoderProfile m_profile {0};
235 };
236 
238 {
239  public:
240  VDPAUVideoMixer() = default;
241  VDPAUVideoMixer(uint id, QSize size, uint layers, uint features,
242  VdpChromaType type)
243  : VDPAUResource(id, size), m_layers(layers), m_features(features),
244  m_type(type), m_noise_reduction(nullptr), m_sharpness(nullptr),
245  m_skip_chroma(nullptr), m_background(nullptr)
246  {
247  memset(&m_csc, 0, sizeof(VdpCSCMatrix));
248  }
249 
250  ~VDPAUVideoMixer() override
251  {
252  delete m_noise_reduction;
253  delete m_sharpness;
254  delete m_skip_chroma;
255  delete m_background;
256  }
257 
260  VdpChromaType m_type {0};
261  VdpCSCMatrix m_csc;
262  float *m_noise_reduction {nullptr};
263  float *m_sharpness {nullptr};
264  uint8_t *m_skip_chroma {nullptr};
266 };
267 
268 static void vdpau_preemption_callback(VdpDevice device, void *myth_render)
269 {
270  (void)device;
271  LOG(VB_GENERAL, LOG_WARNING, LOC + "Display pre-empted.");
272  MythRenderVDPAU *render = (MythRenderVDPAU*)myth_render;
273  if (render)
274  render->SetPreempted();
275 }
276 
281 bool MythRenderVDPAU::gVDPAUNVIDIA = false;
282 
285 {
286  LOCK_ALL
287  ResetProcs();
288  memset(&m_rect, 0, sizeof(VdpRect));
289 }
290 
292 {
293  LOCK_ALL
294  Destroy();
295 }
296 
298 {
300  return true;
301 
302  LOG(VB_PLAYBACK, LOG_INFO, LOC + "Checking VDPAU support.");
303  MythRenderVDPAU *dummy = new MythRenderVDPAU();
304  bool supported = dummy->CreateDummy();
305  delete dummy;
306 
307  return supported;
308 }
309 
311 {
313  return gVDPAUMPEG4Accel;
314 
316 }
317 
319 {
321  return gVDPAUHEVCAccel;
322 
323  return IsVDPAUAvailable() && gVDPAUHEVCAccel;
324 }
325 
327 {
328  int mbs = ceil((double)width / 16.0);
329  // see Appendix H of the NVIDIA proprietary driver README
330  bool check = (mbs == 49 ) || (mbs == 54 ) || (mbs == 59 ) || (mbs == 64) ||
331  (mbs == 113) || (mbs == 118) || (mbs == 123) || (mbs == 128);
332  if (!check)
333  return true;
334 
335  LOG(VB_PLAYBACK, LOG_INFO, LOC +
336  QString("Checking support for H.264 video with width %1").arg(width));
337  bool supported = true;
338  MythRenderVDPAU *dummy = new MythRenderVDPAU();
339  if (dummy && dummy->CreateDummy())
340  {
341  uint test = dummy->CreateDecoder(QSize(width, height),
342  VDP_DECODER_PROFILE_H264_HIGH, 2);
343  if (!test)
344  supported = false;
345  else
346  dummy->DestroyDecoder(test);
347  }
348  LOG(VB_GENERAL, (supported ? LOG_INFO : LOG_WARNING), LOC +
349  QString("Hardware decoding of this H.264 video is %1supported "
350  "on this video card.").arg(supported ? "" : "NOT "));
351  delete dummy;
352  return supported;
353 }
354 
356 {
357  LOCK_ALL
358 
359  bool ok = true;
361  CREATE_CHECK(m_display != nullptr, "Invalid display")
362  CREATE_CHECK(CreateDevice(), "No VDPAU device")
363  CREATE_CHECK(GetProcs(), "No VDPAU procedures")
365 
366  if (!ok)
367  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create dummy device.");
368 
369  return ok;
370 }
371 
373 {
374  LOCK_ALL
375 
376  bool ok = true;
378  CREATE_CHECK(m_display != nullptr, "Invalid display")
379  CREATE_CHECK(CreateDevice(), "No VDPAU device")
380  CREATE_CHECK(GetProcs(), "No VDPAU procedures")
381  CREATE_CHECK(RegisterCallback(), "No callback")
383 
384  if (!ok)
385  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create dummy device.");
386 
387  return ok;
388 }
389 
390 bool MythRenderVDPAU::Create(const QSize &size, WId window, uint colorkey)
391 {
392  LOCK_ALL
393 
394  m_size = size;
395  m_rect.x0 = 0;
396  m_rect.y0 = 0;
397  m_rect.x1 = size.width();
398  m_rect.y1 = size.height();
400  m_window = window;
401 
402  bool ok = true;
403 
404  CREATE_CHECK(!m_size.isEmpty(), "Invalid size")
405  CREATE_CHECK(m_display != nullptr, "Invalid display")
406  CREATE_CHECK(m_window > 0, "Invalid window")
408  CREATE_CHECK(CreateDevice(), "No VDPAU device")
409  CREATE_CHECK(GetProcs(), "No VDPAU procedures")
410  CREATE_CHECK(CreatePresentationQueue(), "No presentation queue")
411  CREATE_CHECK(CreatePresentationSurfaces(), "No presentation surfaces")
412  CREATE_CHECK(SetColorKey(colorkey), "No colorkey")
413  CREATE_CHECK(RegisterCallback(), "No callback")
415 
416  if (ok)
417  {
418  LOG(VB_GENERAL, LOG_INFO, LOC +
419  QString("Created VDPAU render device %1x%2")
420  .arg(size.width()).arg(size.height()));
421  return ok;
422  }
423 
424  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create VDPAU render device.");
425  return ok;
426 }
427 
429 {
430  // tells the UI Painter to refresh its cache
431  if (m_recreated)
432  {
433  m_recreated = false;
434  return true;
435  }
436  return false;
437 }
438 
440 {
441  CHECK_STATUS(false)
443  INIT_ST
444 
445  if (!m_flipQueue)
446  return false;
447 
448  m_colorKey = colorkey;
449  if (m_display && (m_display->GetDepth() < 24))
450  m_colorKey = 0x0;
451 
452  VDPAUColor color((colorkey << 8) + 0xFF);
454  &(color.m_vdp_color));
455  CHECK_ST
456 
457  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Set colorkey to 0x%1")
458  .arg(m_colorKey, 0, 16));
459  return ok;
460 }
461 
463 {
464  if (!m_flipReady)
465  return;
466 
467  VdpOutputSurface surface = 0;
468  {
469  CHECK_STATUS()
471  if (m_surface >= (uint)m_surfaces.size())
472  return;
473  surface = m_outputSurfaces[m_surfaces[m_surface]].m_id;
474  }
475 
476  INIT_ST
477  VdpTime dummy = 0;
478  std::this_thread::sleep_for(std::chrono::milliseconds(2));
480  m_flipQueue, surface, &dummy);
481  CHECK_ST
482 }
483 
485 {
486  if (!m_flipReady || !m_display)
487  return;
488 
489  VdpOutputSurface surface = 0;
490  {
491  CHECK_STATUS()
493  if (m_surface >= (uint)m_surfaces.size())
494  return;
495  surface = m_outputSurfaces[m_surfaces[m_surface]].m_id;
496  m_surface++;
497  if (m_surface >= (uint)m_surfaces.size())
498  m_surface = 0;
499  }
500 
501  INIT_ST
502  vdp_st = vdp_presentation_queue_display(m_flipQueue, surface, m_rect.x1, m_rect.y1, 0);
503  CHECK_ST
504  SyncDisplay();
505 }
506 
508 {
510  if (m_display)
511  m_display->Sync();
512 }
513 
514 void MythRenderVDPAU::DrawDisplayRect(const QRect &rect, bool use_colorkey)
515 {
517  if (!m_display || !m_window)
518  return;
519 
520  uint color = use_colorkey ? m_colorKey : m_display->GetBlack();
521  m_display->SetForeground(color);
523 }
524 
526 {
528  if (m_display && m_window)
530 }
531 
532 bool MythRenderVDPAU::GetScreenShot(int width, int height, QString filename)
533 {
534  CHECK_STATUS(false)
536  if (m_surface >= (uint)m_surfaces.size())
537  return false;
538 
539  VdpRGBAFormat fmt;
540  uint32_t w, h;
541  VdpOutputSurface surface = m_outputSurfaces[m_surfaces[m_surface]].m_id;
542  INIT_ST
543  vdp_st = vdp_output_surface_get_parameters(surface, &fmt, &w, &h);
544  CHECK_ST
545 
546  if (!ok || fmt != VDP_RGBA_FORMAT_B8G8R8A8 || w <= 0 || h <= 0)
547  return false;
548 
549  int size = w * h * 4;
550  unsigned char* buffer = new unsigned char[size];
551  void* const data[1] = { buffer };
552  const uint32_t pitches[1] = { w * 4 };
553  vdp_st = vdp_output_surface_get_bits_native(surface, nullptr, data, pitches);
554  CHECK_ST
555 
556  if (!ok)
557  {
558  delete [] buffer;
559  return false;
560  }
561 
562  bool success = false;
563  QImage img(buffer, w, h, QImage::Format_RGB32);
564  MythMainWindow *window = GetMythMainWindow();
565  if (window)
566  {
567  if (width <= 0)
568  width = img.width();
569  if (height <= 0)
570  height = img.height();
571 
572  img = img.scaled(width, height, Qt::KeepAspectRatio,
573  Qt::SmoothTransformation);
574  success = window->SaveScreenShot(img, std::move(filename));
575  }
576  delete [] buffer;
577  return success;
578 }
579 
581 {
582  CHECK_STATUS()
584  int need = MAX_OUTPUT_SURFACES;
585  int have = m_surfaces.size();
586  int created = 0;
587 
588  // TODO reduce number of surfaces
589  if (have >= need)
590  return;
591 
592  for (; have < need; have++)
593  {
595  if (id)
596  {
597  m_surfaces.push_back(id);
598  created++;
599  }
600  else
601  break;
602  }
603 
604  LOG(VB_GENERAL, LOG_INFO, LOC +
605  QString("Added %1 output surfaces (total %2, max %3)")
606  .arg(created).arg(m_surfaces.size()).arg(need));
607 }
608 
609 uint MythRenderVDPAU::CreateOutputSurface(const QSize &size, VdpRGBAFormat fmt,
610  uint existing)
611 {
612  CHECK_STATUS(0)
614  INIT_ST
615 
616  if ((existing && !m_outputSurfaces.contains(existing)) || size.isEmpty())
617  return 0;
618 
619  VdpOutputSurface tmp;
620  vdp_st = vdp_output_surface_create(m_device, fmt, size.width(),
621  size.height(), &tmp);
622  CHECK_ST
623 
624  if (!ok || !tmp)
625  {
626  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create output surface.");
627  return 0;
628  }
629 
630  if (existing)
631  {
632  m_outputSurfaces[existing].m_id = tmp;
633  return existing;
634  }
635 
636  static uint32_t next_id = 1;
637  static QMutex id_lock(QMutex::Recursive);
638 
639  id_lock.lock();
640  while (m_outputSurfaces.contains(next_id))
641  if ((++next_id) == 0)
642  next_id = 1;
643 
644  uint id = next_id;
645  m_outputSurfaces.insert(id, VDPAUOutputSurface(tmp, size, fmt));
646  id_lock.unlock();
647 
648  return id;
649 }
650 
651 uint MythRenderVDPAU::CreateVideoSurface(const QSize &size, VdpChromaType type,
652  uint existing)
653 {
654  CHECK_STATUS(0)
656  INIT_ST
657 
658  if ((existing && !m_videoSurfaces.contains(existing)) || size.isEmpty())
659  return 0;
660 
661  VdpOutputSurface tmp;
662  vdp_st = vdp_video_surface_create(m_device, type, size.width(),
663  size.height(), &tmp);
664  CHECK_ST
665 
666  if (!ok || !tmp)
667  {
668  LOG(VB_PLAYBACK, LOG_ERR, LOC + "Failed to create video surface.");
669  return 0;
670  }
671 
672  if (existing)
673  {
674  m_videoSurfaces[existing].SetID(tmp);
675  m_videoSurfaceHash[tmp] = existing;
676  return existing;
677  }
678 
679  static uint32_t next_id = 1;
680  static QMutex id_lock(QMutex::Recursive);
681 
682  id_lock.lock();
683  while (m_videoSurfaces.contains(next_id))
684  if ((++next_id) == 0)
685  next_id = 1;
686 
687  uint id = next_id;
688  m_videoSurfaces.insert(id, VDPAUVideoSurface(tmp, size, type));
689  m_videoSurfaceHash[tmp] = id;
690  id_lock.unlock();
691 
692  return id;
693 }
694 
695 uint MythRenderVDPAU::CreateBitmapSurface(const QSize &size, VdpRGBAFormat fmt,
696  uint existing)
697 {
698  CHECK_STATUS(0)
700  INIT_ST
701 
702  if ((existing && !m_bitmapSurfaces.contains(existing)) || size.isEmpty())
703  return 0;
704 
705  VdpBitmapSurface tmp;
706  vdp_st = vdp_bitmap_surface_create(m_device, fmt, size.width(),
707  size.height(), true, &tmp);
708  CHECK_ST
709 
710  if (!ok || !tmp)
711  {
712  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create bitmap surface.");
713  return 0;
714  }
715 
716  if (existing)
717  {
718  m_bitmapSurfaces[existing].m_id = tmp;
719  return existing;
720  }
721 
722  static uint32_t next_id = 1;
723  static QMutex id_lock(QMutex::Recursive);
724 
725  id_lock.lock();
726  while (m_bitmapSurfaces.contains(next_id))
727  if ((++next_id) == 0)
728  next_id = 1;
729 
730  uint id = next_id;
731  m_bitmapSurfaces.insert(id, VDPAUBitmapSurface(tmp, size, fmt));
732  id_lock.unlock();
733 
734  return id;
735 }
736 
738  VdpDecoderProfile profile,
739  uint references, uint existing)
740 {
741  CHECK_STATUS(0)
743  INIT_ST
744 
745  if ((existing && !m_decoders.contains(existing)) || size.isEmpty() ||
746  references < 1)
747  return 0;
748 
749  VdpDecoder tmp;
750  vdp_st = vdp_decoder_create(m_device, profile, size.width(),
751  size.height(), references, &tmp);
752  CHECK_ST
753 
754  if (!ok || !tmp)
755  {
756  LOG(VB_PLAYBACK, LOG_ERR, LOC + "Failed to create decoder.");
757  return 0;
758  }
759 
760  if (existing)
761  {
762  m_decoders[existing].m_id = tmp;
763  return existing;
764  }
765 
766  static uint32_t next_id = 1;
767  static QMutex id_lock(QMutex::Recursive);
768 
769  id_lock.lock();
770  while (m_decoders.contains(next_id))
771  if ((++next_id) == 0)
772  next_id = 1;
773 
774  uint id = next_id;
775  m_decoders.insert(id, VDPAUDecoder(tmp, size, profile, references));
776  id_lock.unlock();
777 
778  return id;
779 }
780 
781 uint MythRenderVDPAU::CreateVideoMixer(const QSize &size, uint layers,
782  uint features, VdpChromaType type,
783  uint existing)
784 {
785  CHECK_STATUS(0)
787  INIT_ST
788 
789  if ((existing && !m_videoMixers.contains(existing)) || size.isEmpty())
790  return 0;
791 
792  VdpVideoMixer tmp;
793  uint width = size.width();
794  uint height = size.height();
795 
796  VdpVideoMixerParameter parameters[] = {
797  VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH,
798  VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT,
799  VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE,
800  VDP_VIDEO_MIXER_PARAMETER_LAYERS,
801  };
802 
803  void const * parameter_values[] = { &width, &height, &type, &layers};
804 
805  int count = 0;
806  VdpVideoMixerFeature feat[6];
807  VdpBool enable = VDP_TRUE;
808  const VdpBool enables[6] = { enable, enable, enable, enable, enable, enable };
809 
810  bool temporal = ((features & kVDPFeatTemporal) != 0U) ||
811  ((features & kVDPFeatSpatial) != 0U);
812  if (temporal)
813  {
814  feat[count] = VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL;
815  count++;
816  }
817 
818  if (features & kVDPFeatSpatial)
819  {
820  feat[count] = VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL;
821  count++;
822  }
823 
824  if ((features & kVDPFeatIVTC) && temporal)
825  {
826  feat[count] = VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE;
827  count++;
828  }
829 
830  if (features & kVDPFeatDenoise)
831  {
832  feat[count] = VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION;
833  count++;
834  }
835 
836  if (features & kVDPFeatSharpness)
837  {
838  feat[count] = VDP_VIDEO_MIXER_FEATURE_SHARPNESS;
839  count++;
840  }
841 
842  if (features & kVDPFeatHQScaling)
843  {
844  if (gVDPAUBestScaling)
845  {
846  feat[count] = gVDPAUBestScaling;
847  count++;
848  LOG(VB_PLAYBACK, LOG_INFO, LOC + "Enabling high quality scaling.");
849  }
850  else
851  LOG(VB_PLAYBACK, LOG_INFO, LOC +
852  "High quality scaling not available");
853  }
854 
855  vdp_st = vdp_video_mixer_create(m_device, count, count ? feat : nullptr,
856  4, parameters, parameter_values, &tmp);
857  CHECK_ST
858 
859  if (!ok || !tmp)
860  {
861  LOG(VB_PLAYBACK, LOG_ERR, LOC + "Failed to create video mixer.");
862  return 0;
863  }
864 
865  if (count)
866  {
868  tmp, count, feat, enables);
869  CHECK_ST
870 
871  if (!ok)
872  LOG(VB_PLAYBACK, LOG_WARNING, LOC +
873  "WARNING: Failed to enable video mixer features.");
874  }
875 
876  if (existing)
877  {
878  m_videoMixers[existing].m_id = tmp;
879  m_videoMixers[existing].m_features = features;
880  m_videoMixers[existing].m_type = type;
881  m_videoMixers[existing].m_size = size;
882 
883  SetCSCMatrix(existing, &m_videoMixers[existing].m_csc);
884 
885  if (m_videoMixers[existing].m_noise_reduction)
887  *(m_videoMixers[existing].m_noise_reduction));
888  if (m_videoMixers[existing].m_sharpness)
890  *(m_videoMixers[existing].m_sharpness));
891  if (m_videoMixers[existing].m_skip_chroma)
893  *(m_videoMixers[existing].m_skip_chroma));
894  if (m_videoMixers[existing].m_background)
896  m_videoMixers[existing].m_background->m_color);
897  return existing;
898  }
899 
900  static uint32_t next_id = 1;
901  static QMutex id_lock(QMutex::Recursive);
902 
903  id_lock.lock();
904  while (m_videoMixers.contains(next_id))
905  if ((++next_id) == 0)
906  next_id = 1;
907 
908  uint id = next_id;
909  m_videoMixers.insert(id,
910  VDPAUVideoMixer(tmp, size, layers, features, type));
911  id_lock.unlock();
912 
913  return id;
914 }
915 
916 uint MythRenderVDPAU::CreateLayer(uint surface, const QRect *src,
917  const QRect *dst)
918 {
919  CHECK_STATUS(0)
921 
922  if (!m_outputSurfaces.contains(surface))
923  return 0;
924 
925  static uint32_t next_id = 1;
926  static QMutex id_lock(QMutex::Recursive);
927 
928  id_lock.lock();
929  while (m_layers.contains(next_id))
930  if ((++next_id) == 0)
931  next_id = 1;
932 
933  uint id = next_id;
934  m_layers.insert(id, VDPAULayer(m_outputSurfaces[surface].m_id, src, dst));
935  id_lock.unlock();
936 
937  return id;
938 }
939 
941 {
943  return;
944 
945  CHECK_STATUS()
947  INIT_ST
948 
949  if (!m_outputSurfaces.contains(id))
950  return;
951 
952  vdp_st = vdp_output_surface_destroy(m_outputSurfaces[id].m_id);
953  CHECK_ST
954  m_outputSurfaces.remove(id);
955 }
956 
958 {
959  CHECK_STATUS()
961  INIT_ST
962 
963  if (!m_videoSurfaces.contains(id))
964  return;
965 
966  vdp_st = vdp_video_surface_destroy(m_videoSurfaces[id].m_id);
967  CHECK_ST
968  m_videoSurfaceHash.remove(m_videoSurfaces[id].m_id);
969  m_videoSurfaces.remove(id);
970 }
971 
973 {
974  CHECK_STATUS()
976  INIT_ST
977 
978  if (!m_bitmapSurfaces.contains(id))
979  return;
980 
981  vdp_st = vdp_bitmap_surface_destroy(m_bitmapSurfaces[id].m_id);
982  CHECK_ST
983  m_bitmapSurfaces.remove(id);
984 }
985 
987 {
988  CHECK_STATUS()
990  INIT_ST
991 
992  if (!m_decoders.contains(id))
993  return;
994 
995  vdp_st = vdp_decoder_destroy(m_decoders[id].m_id);
996  CHECK_ST
997  m_decoders.remove(id);
998 }
999 
1001 {
1002  CHECK_STATUS()
1003  LOCK_RENDER
1004  INIT_ST
1005 
1006  if (!m_videoMixers.contains(id))
1007  return;
1008 
1009  vdp_st = vdp_video_mixer_destroy(m_videoMixers[id].m_id);
1010  CHECK_ST
1011  m_videoMixers.remove(id);
1012 }
1013 
1015 {
1016  CHECK_STATUS()
1017  LOCK_RENDER
1018 
1019  if (!m_layers.contains(id))
1020  return;
1021 
1022  m_layers.remove(id);
1023 }
1024 
1025 bool MythRenderVDPAU::MixAndRend(uint id, VdpVideoMixerPictureStructure field,
1026  uint vid_surface, uint out_surface,
1027  const QVector<uint>* refs, bool top,
1028  QRect src, const QRect &dst,
1029  QRect dst_vid, uint layer1, uint layer2)
1030 {
1031  CHECK_VIDEO_SURFACES(true)
1032  INIT_ST
1033 
1034  VdpVideoSurface past_surfaces[2] = { VDP_INVALID_HANDLE,
1035  VDP_INVALID_HANDLE };
1036  VdpVideoSurface future_surfaces[1] = { VDP_INVALID_HANDLE };
1037  VdpVideoSurface vid_surf = 0;
1038  bool deint = false;
1039  uint num_layers = 0;
1040  VdpLayer layers[2];
1041  VdpOutputSurface surf = 0;
1042  VdpVideoMixer mixer = 0;
1043 
1044  {
1045  CHECK_STATUS(false)
1046  LOCK_RENDER
1047 
1048  if (!out_surface)
1049  out_surface = m_surfaces[m_surface];
1050 
1051  if (!m_videoMixers.contains(id) ||
1052  !m_videoSurfaces.contains(vid_surface)||
1053  !m_outputSurfaces.contains(out_surface))
1054  return false;
1055 
1056  vid_surf = m_videoSurfaces[vid_surface].m_id;
1057 
1058  if (refs && refs->size() == NUM_REFERENCE_FRAMES)
1059  {
1060  deint = true;
1061  VdpVideoSurface act_refs[NUM_REFERENCE_FRAMES];
1062  for (int i = 0; i < NUM_REFERENCE_FRAMES; i++)
1063  {
1064  if (m_videoSurfaces.contains(refs->value(i)))
1065  act_refs[i] = m_videoSurfaces[refs->value(i)].m_id;
1066  else
1067  act_refs[i] = VDP_INVALID_HANDLE;
1068  }
1069 
1070  vid_surf = act_refs[1];
1071 
1072  if (top)
1073  {
1074  future_surfaces[0] = act_refs[1];
1075  past_surfaces[0] = act_refs[0];
1076  past_surfaces[1] = act_refs[0];
1077  }
1078  else
1079  {
1080  future_surfaces[0] = act_refs[2];
1081  past_surfaces[0] = act_refs[1];
1082  past_surfaces[1] = act_refs[0];
1083  }
1084  }
1085 
1086  if (m_layers.contains(layer1))
1087  {
1088  memcpy(&(layers[num_layers]), &(m_layers[layer1].m_layer),
1089  sizeof(VdpLayer));
1090  num_layers++;
1091  }
1092  if (m_layers.contains(layer2))
1093  {
1094  memcpy(&(layers[num_layers]), &(m_layers[layer2].m_layer),
1095  sizeof(VdpLayer));
1096  num_layers++;
1097  }
1098 
1099  surf = m_outputSurfaces[out_surface].m_id;
1100  mixer = m_videoMixers[id].m_id;
1101  }
1102 
1103  if (dst_vid.top() < 0 && dst_vid.height() > 0)
1104  {
1105  float yscale = (float)src.height() /
1106  (float)dst_vid.height();
1107  int tmp = src.top() -
1108  (int)((float)dst_vid.top() * yscale);
1109  src.setTop(std::max(0, tmp));
1110  dst_vid.setTop(0);
1111  }
1112 
1113  if (dst_vid.left() < 0 && dst_vid.width() > 0)
1114  {
1115  float xscale = (float)src.width() /
1116  (float)dst_vid.width();
1117  int tmp = src.left() -
1118  (int)((float)dst_vid.left() * xscale);
1119  src.setLeft(std::max(0, tmp));
1120  dst_vid.setLeft(0);
1121  }
1122 
1123  VdpRect outRect, srcRect, outRectVid;
1124 
1125  outRect.x0 = dst.left();
1126  outRect.y0 = dst.top();
1127  outRect.x1 = dst.left() + dst.width();
1128  outRect.y1 = dst.top() + dst.height();
1129  if (m_flipFrames)
1130  {
1131  // flip the image
1132  srcRect.x0 = src.left() + src.width();
1133  srcRect.y0 = src.top() + src.height();
1134  srcRect.x1 = src.left();
1135  srcRect.y1 = src.top();
1136  }
1137  else
1138  {
1139  srcRect.x0 = src.left();
1140  srcRect.y0 = src.top();
1141  srcRect.x1 = src.left() + src.width();
1142  srcRect.y1 = src.top() + src.height();
1143  }
1144  outRectVid.x0 = dst_vid.left();
1145  outRectVid.y0 = dst_vid.top();
1146  outRectVid.x1 = dst_vid.left() + dst_vid.width();
1147  outRectVid.y1 = dst_vid.top() + dst_vid.height();
1148 
1149  vdp_st = vdp_video_mixer_render(mixer, VDP_INVALID_HANDLE,
1150  nullptr, field, deint ? 2 : 0,
1151  deint ? past_surfaces : nullptr,
1152  vid_surf, deint ? 1 : 0,
1153  deint ? future_surfaces : nullptr,
1154  &srcRect, surf, &outRect, &outRectVid,
1155  num_layers, num_layers ? layers : nullptr);
1156  CHECK_ST
1157  return ok;
1158 }
1159 
1161 {
1162  CHECK_STATUS(false)
1163  LOCK_RENDER
1164 
1165  if (!m_videoMixers.contains(id))
1166  return false;
1167 
1168  static const uint all_deints = kVDPFeatTemporal | kVDPFeatSpatial;
1169  uint current = m_videoMixers[id].m_features;
1170  uint deints = current & all_deints;
1171 
1172  if (deints == deinterlacers)
1173  return true;
1174 
1175  uint newfeats = (current & ~all_deints) + deinterlacers;
1176  return ChangeVideoMixerFeatures(id, newfeats);
1177 }
1178 
1180 {
1181  CHECK_STATUS(false)
1182  LOCK_RENDER
1183 
1184  if (!m_videoMixers.contains(id))
1185  return false;
1186 
1187  INIT_ST
1188  vdp_st = vdp_video_mixer_destroy(m_videoMixers[id].m_id);
1189  CHECK_ST
1190  return (id == CreateVideoMixer(m_videoMixers[id].m_size,
1191  m_videoMixers[id].m_layers, features,
1192  m_videoMixers[id].m_type, id));
1193 }
1194 
1196 {
1197  CHECK_STATUS();
1198  LOCK_RENDER
1199 
1200  if (!m_videoMixers.contains(id))
1201  return;
1202 
1203  memcpy(&m_videoMixers[id].m_csc, vals, sizeof(VdpCSCMatrix));
1204 
1205  VdpVideoMixerAttribute attr = { VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX };
1206  void const * val = { vals };
1207  SetMixerAttribute(id, &attr, &val);
1208 }
1209 
1211 {
1212  CHECK_STATUS(false);
1213  LOCK_RENDER
1214 
1215  if (!m_videoMixers.contains(id) || attrib > kVDPAttribCSCEnd)
1216  return -1;
1217 
1218  if (attrib == kVDPAttribSkipChroma)
1219  {
1220  if (!m_videoMixers[id].m_skip_chroma)
1221  m_videoMixers[id].m_skip_chroma = new uint8_t();
1222  *(m_videoMixers[id].m_skip_chroma) = value;
1223  VdpVideoMixerAttribute attr =
1224  { VDP_VIDEO_MIXER_ATTRIBUTE_SKIP_CHROMA_DEINTERLACE };
1225  void const * val = { &value };
1226  return SetMixerAttribute(id, &attr, &val);
1227  }
1228 
1229  if (attrib == kVDPAttribBackground)
1230  {
1231  if (!m_videoMixers[id].m_background)
1232  m_videoMixers[id].m_background = new VDPAUColor();
1233  m_videoMixers[id].m_background->SetColor(value);
1234  VdpVideoMixerAttribute attr =
1235  { VDP_VIDEO_MIXER_ATTRIBUTE_BACKGROUND_COLOR };
1236  void const * val = { &(m_videoMixers[id].m_background->m_vdp_color) };
1237  return SetMixerAttribute(id, &attr, &val);
1238  }
1239 
1240  return -1;
1241 }
1242 
1243 bool MythRenderVDPAU::SetMixerAttribute(uint id, uint attrib, float value)
1244 {
1245  CHECK_STATUS(false);
1246  LOCK_RENDER
1247 
1248  if (!m_videoMixers.contains(id) || attrib < kVDPAttribFiltersStart)
1249  return false;
1250 
1251  VdpVideoMixerAttribute attr;
1252  void const * val = { &value };
1253 
1254  if (attrib == kVDPAttribNoiseReduction)
1255  {
1256  if (!m_videoMixers[id].m_noise_reduction)
1257  m_videoMixers[id].m_noise_reduction = new float();
1258  *(m_videoMixers[id].m_noise_reduction) = value;
1259  attr = VDP_VIDEO_MIXER_ATTRIBUTE_NOISE_REDUCTION_LEVEL;
1260  }
1261  else if (attrib == kVDPAttribSharpness)
1262  {
1263  if (!m_videoMixers[id].m_sharpness)
1264  m_videoMixers[id].m_sharpness = new float();
1265  *(m_videoMixers[id].m_sharpness) = value;
1266  attr = VDP_VIDEO_MIXER_ATTRIBUTE_SHARPNESS_LEVEL;
1267  }
1268  else
1269  return false;
1270 
1271  return SetMixerAttribute(id, &attr, &val);
1272 }
1273 
1274 bool MythRenderVDPAU::UploadBitmap(uint id, void* const plane[1], uint32_t pitch[1])
1275 {
1276  VdpBitmapSurface bitmap = 0;
1277  {
1278  CHECK_STATUS(false)
1279  LOCK_RENDER
1280  if (!m_bitmapSurfaces.contains(id))
1281  return false;
1282  bitmap = m_bitmapSurfaces[id].m_id;
1283  }
1284 
1285  INIT_ST
1286  vdp_st = vdp_bitmap_surface_put_bits_native(bitmap, plane, pitch, nullptr);
1287  CHECK_ST
1288 
1289  return ok;
1290 }
1291 
1293 {
1294  if (!image)
1295  return false;
1296 
1297  void *plane[1] = { image->bits() };
1298  uint32_t pitch[1] = { static_cast<uint32_t>(image->bytesPerLine()) };
1299  return UploadBitmap(id, plane, pitch);
1300 }
1301 
1302 bool MythRenderVDPAU::UploadYUVFrame(uint id, void* const planes[3],
1303  uint32_t pitches[3])
1304 {
1305  CHECK_VIDEO_SURFACES(false)
1306 
1307  VdpVideoSurface surface = 0;
1308  {
1309  CHECK_STATUS(false)
1310  LOCK_RENDER
1311  if (!m_videoSurfaces.contains(id))
1312  return false;
1313  surface = m_videoSurfaces[id].m_id;
1314  }
1315 
1316  INIT_ST
1317  vdp_st = vdp_video_surface_put_bits_y_cb_cr(surface,
1318  VDP_YCBCR_FORMAT_YV12,
1319  planes, pitches);
1320  CHECK_ST;
1321  return ok;
1322 }
1323 
1324 bool MythRenderVDPAU::DownloadYUVFrame(uint id, void *const planes[3],
1325  uint32_t pitches[3])
1326 {
1327  CHECK_VIDEO_SURFACES(false)
1328 
1329  VdpVideoSurface surface = 0;
1330  {
1331  CHECK_STATUS(false)
1332  LOCK_RENDER
1333  if (!m_videoSurfaces.contains(id))
1334  return false;
1335  surface = m_videoSurfaces[id].m_id;
1336  }
1337 
1338  INIT_ST
1339  vdp_st = vdp_video_surface_get_bits_y_cb_cr(surface,
1340  VDP_YCBCR_FORMAT_YV12,
1341  planes, pitches);
1342  CHECK_ST
1343  return ok;
1344 }
1345 
1347  const QRect *src, const QRect *dst,
1348  VDPBlendType blend,
1349  int alpha, int red, int green, int blue)
1350 {
1351  uint bitmap = VDP_INVALID_HANDLE;
1352  VdpOutputSurface surface = VDP_INVALID_HANDLE;
1353  {
1354  CHECK_STATUS(false)
1355  LOCK_RENDER
1356 
1357  if (!target)
1358  target = m_surfaces[m_surface];
1359  if (!m_outputSurfaces.contains(target))
1360  return false;
1361  surface = m_outputSurfaces[target].m_id;
1362  if (id && m_bitmapSurfaces.contains(id))
1363  bitmap = m_bitmapSurfaces[id].m_id;
1364  }
1365 
1366  VdpRect vdest, vsrc;
1367  if (dst)
1368  {
1369  int width = dst->width();
1370  int height = dst->height();
1371 
1372  if (src)
1373  {
1374  width = std::min(src->width(), width);
1375  height = std::min(src->height(), height);
1376  }
1377 
1378  vdest.x0 = (dst->x() < 0) ? 0 : dst->x();
1379  vdest.y0 = (dst->y() < 0) ? 0 : dst->y();
1380  vdest.x1 = dst->x() + width;
1381  vdest.y1 = dst->y() + height;
1382  }
1383 
1384  if (src)
1385  {
1386  vsrc.x0 = src->x();
1387  vsrc.y0 = src->y();
1388  vsrc.x1 = src->x() + src->width();
1389  vsrc.y1 = src->y() + src->height();
1390  }
1391 
1392  VdpColor color;
1393  if (!(red == 0 && green == 0 && blue == 0 && alpha == 0))
1394  {
1395  color.red = red / 255.0F;
1396  color.green = green / 255.0F;
1397  color.blue = blue / 255.0F;
1398  color.alpha = alpha / 255.0F;
1399  }
1400 
1401  INIT_ST
1402 
1403  bool createdBitmap = false;
1404 
1405  if (!id && !gVDPAUNVIDIA)
1406  {
1407  // Work around MESA bug #80561
1408  vdp_st = vdp_bitmap_surface_create(m_device, VDP_RGBA_FORMAT_B8G8R8A8,
1409  1, 1, true,
1410  &bitmap);
1411  CHECK_ST
1412 
1413  if (ok)
1414  {
1415  uint8_t bmp[] = { 255, 255, 255, 255 };
1416  void *plane[1] = { bmp };
1417  uint32_t pitch[1] = { 4 };
1418  vdp_st =
1419  vdp_bitmap_surface_put_bits_native(bitmap, plane, pitch, nullptr);
1420  CHECK_ST
1421  if (!ok)
1422  {
1424  bitmap = VDP_INVALID_HANDLE;
1425  }
1426  else
1427  {
1428  createdBitmap = ok;
1429  }
1430  }
1431  }
1432 
1434  surface, dst ? &vdest : nullptr, bitmap, src ? &vsrc : nullptr,
1435  alpha >= 0 ? &color : nullptr, &VDPBlends[blend],
1436  VDP_OUTPUT_SURFACE_RENDER_ROTATE_0);
1437  CHECK_ST
1438 
1439  if (createdBitmap)
1440  {
1442  }
1443 
1444  return ok;
1445 }
1446 
1448 {
1449  {
1450  CHECK_STATUS(false)
1451  LOCK_RENDER
1452 
1453  if (!m_layers.contains(id))
1454  return false;
1455  if (!target)
1456  target = m_surfaces[m_surface];
1457  if (!m_outputSurfaces.contains(target))
1458  return false;
1459  }
1460 
1461  INIT_ST
1463  m_outputSurfaces[target].m_id, (m_layers[id].m_layer.destination_rect),
1464  m_layers[id].m_layer.source_surface, (m_layers[id].m_layer.source_rect),
1465  nullptr, &VDPBlends[kVDPBlendNormal], VDP_OUTPUT_SURFACE_RENDER_ROTATE_0);
1466  CHECK_ST
1467  return ok;
1468 }
1469 
1471 {
1472  if (!m_bitmapSurfaces.contains(id))
1473  return 0;
1474  QSize sz = m_bitmapSurfaces[id].m_size;
1475  return sz.width() * sz.height() * 4;
1476 }
1477 
1479 {
1480  CHECK_STATUS(nullptr)
1481  LOCK_RENDER
1482 
1483  if (!m_videoSurfaces.contains(id))
1484  return nullptr;
1485 
1486  return &(m_videoSurfaces[id].m_render);
1487 }
1488 
1489 uint MythRenderVDPAU::GetSurfaceOwner(VdpVideoSurface surface)
1490 {
1491  CHECK_STATUS(0)
1492  LOCK_RENDER
1493 
1494  if (!m_videoSurfaceHash.contains(surface))
1495  return 0;
1496 
1497  return m_videoSurfaceHash[surface];
1498 }
1499 
1501 {
1502  QSize size = QSize(0,0);
1503  CHECK_STATUS(size)
1504  LOCK_RENDER
1505 
1506  if (!m_videoSurfaces.contains(id))
1507  return size;
1508 
1509  uint width = 0;
1510  uint height = 0;
1511  VdpChromaType dummy;
1512 
1513  INIT_ST
1515  &dummy, &width, &height);
1516  CHECK_ST
1517  if (!ok)
1518  {
1519  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to retrieve surface size.");
1520  return size;
1521  }
1522 
1523  size = QSize(width, height);
1524  return size;
1525 }
1526 
1528 {
1530  CHECK_STATUS()
1531  LOCK_RENDER
1532  INIT_ST
1533 
1534  if (!m_videoSurfaces.contains(id))
1535  return;
1536 
1537  uint width = m_videoSurfaces[id].m_size.width();
1538  uint height = m_videoSurfaces[id].m_size.height();
1539  unsigned char *tmp = new unsigned char[(width * height * 3)>>1];
1540 
1541  if (!tmp)
1542  return;
1543 
1544  memset(tmp, 0, width * height);
1545  memset(tmp + (width * height), 127, (width * height)>>1);
1546  uint32_t pitches[3] = {width, (width+1)>>1, (width+1)>>1};
1547  void* const planes[3] = {tmp, tmp + (width * height), tmp + (width * height)};
1549  VDP_YCBCR_FORMAT_YV12,
1550  planes, pitches);
1551  CHECK_ST
1552  delete [] tmp;
1553 }
1554 
1556 {
1557  LOCK_ALL
1558  if (!m_videoSurfaces.contains(id))
1559  return;
1560 
1561  m_videoSurfaces[id].m_owner = QThread::currentThread();
1562 }
1563 
1565 {
1566  Decode(id, render, (VdpPictureInfo const *)&render->info);
1567 }
1568 
1570  const VdpPictureInfo *info)
1571 {
1573 
1574  {
1575  CHECK_STATUS()
1576  LOCK_DECODE
1577  if (!m_decoders.contains(id))
1578  return;
1579  }
1580 
1581  INIT_ST
1582 
1583  vdp_st = vdp_decoder_render(m_decoders[id].m_id, render->surface, info,
1584  render->bitstream_buffers_used,
1585  render->bitstream_buffers);
1586 
1587  CHECK_ST
1588 }
1589 
1590 static const char* dummy_get_error_string(VdpStatus /*status*/)
1591 {
1592  static const char dummy[] = "Unknown";
1593  return &dummy[0];
1594 }
1595 
1597 {
1598  if (!m_display)
1599  return false;
1600 
1601  INIT_ST
1603  XLOCK(m_display, vdp_st = vdp_device_create_x11(m_display->GetDisplay(),
1604  m_display->GetScreen(),
1606  CHECK_ST
1607 
1608  if (!ok)
1609  {
1610  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create VDPAU device.");
1611  return false;
1612  }
1613 
1614  vdp_st = vdp_get_proc_address(m_device, VDP_FUNC_ID_GET_ERROR_STRING,
1615  (void **)&vdp_get_error_string);
1616  ok &= (vdp_st == VDP_STATUS_OK);
1617  if (!ok)
1618  {
1620  ok = true;
1621  }
1622 
1623  return ok;
1624 }
1625 
1627 {
1628  INIT_ST
1629  GET_PROC(VDP_FUNC_ID_DEVICE_DESTROY, vdp_device_destroy);
1630  GET_PROC(VDP_FUNC_ID_VIDEO_SURFACE_CREATE, vdp_video_surface_create);
1631  GET_PROC(VDP_FUNC_ID_VIDEO_SURFACE_DESTROY, vdp_video_surface_destroy);
1632  GET_PROC(VDP_FUNC_ID_VIDEO_SURFACE_PUT_BITS_Y_CB_CR,
1634  GET_PROC(VDP_FUNC_ID_VIDEO_SURFACE_GET_PARAMETERS,
1636  GET_PROC(VDP_FUNC_ID_VIDEO_SURFACE_GET_BITS_Y_CB_CR,
1638  GET_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_CREATE, vdp_output_surface_create);
1639  GET_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_DESTROY, vdp_output_surface_destroy);
1640  GET_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_RENDER_BITMAP_SURFACE,
1642  GET_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_GET_PARAMETERS,
1644  GET_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_GET_BITS_NATIVE,
1646  GET_PROC(VDP_FUNC_ID_OUTPUT_SURFACE_RENDER_OUTPUT_SURFACE,
1648  GET_PROC(VDP_FUNC_ID_VIDEO_MIXER_CREATE, vdp_video_mixer_create);
1649  GET_PROC(VDP_FUNC_ID_VIDEO_MIXER_SET_FEATURE_ENABLES,
1651  GET_PROC(VDP_FUNC_ID_VIDEO_MIXER_DESTROY, vdp_video_mixer_destroy);
1652  GET_PROC(VDP_FUNC_ID_VIDEO_MIXER_RENDER, vdp_video_mixer_render);
1653  GET_PROC(VDP_FUNC_ID_VIDEO_MIXER_SET_ATTRIBUTE_VALUES,
1655  GET_PROC(VDP_FUNC_ID_GENERATE_CSC_MATRIX, vdp_generate_csc_matrix);
1656  GET_PROC(VDP_FUNC_ID_VIDEO_MIXER_QUERY_FEATURE_SUPPORT,
1658  GET_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_TARGET_DESTROY,
1660  GET_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_CREATE,
1662  GET_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_DESTROY,
1664  GET_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_DISPLAY,
1666  GET_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_BLOCK_UNTIL_SURFACE_IDLE,
1668  GET_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_TARGET_CREATE_X11,
1670  GET_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_GET_TIME,
1672  GET_PROC(VDP_FUNC_ID_PRESENTATION_QUEUE_SET_BACKGROUND_COLOR,
1674  GET_PROC(VDP_FUNC_ID_DECODER_CREATE, vdp_decoder_create);
1675  GET_PROC(VDP_FUNC_ID_DECODER_DESTROY, vdp_decoder_destroy);
1676  GET_PROC(VDP_FUNC_ID_DECODER_RENDER, vdp_decoder_render);
1677  GET_PROC(VDP_FUNC_ID_DECODER_QUERY_CAPABILITIES,
1679  GET_PROC(VDP_FUNC_ID_BITMAP_SURFACE_CREATE, vdp_bitmap_surface_create);
1680  GET_PROC(VDP_FUNC_ID_BITMAP_SURFACE_DESTROY,vdp_bitmap_surface_destroy);
1681  GET_PROC(VDP_FUNC_ID_BITMAP_SURFACE_PUT_BITS_NATIVE,
1683  GET_PROC(VDP_FUNC_ID_PREEMPTION_CALLBACK_REGISTER,
1685  GET_PROC(VDP_FUNC_ID_GET_API_VERSION, vdp_get_api_version);
1686  GET_PROC(VDP_FUNC_ID_GET_INFORMATION_STRING, vdp_get_information_string);
1687 
1688  return ok;
1689 }
1690 
1692 {
1693  MythXLocker locker(m_display);
1694  if (!m_device || !m_window)
1695  return false;
1696 
1697  m_surface = 0;
1698  INIT_ST
1700  &m_flipTarget);
1701  CHECK_ST
1702  if (!ok)
1703  return false;
1704 
1706  &m_flipQueue);
1707  CHECK_ST
1708  return ok;
1709 }
1710 
1712 {
1713  int num = MIN_OUTPUT_SURFACES;
1714  bool ok = true;
1715 
1716  for (int i = 0; i < num; i++)
1717  {
1719  if (id)
1720  {
1721  m_surfaces.push_back(id);
1722  }
1723  else
1724  {
1725  ok = false;
1726  break;
1727  }
1728  }
1729 
1730  if (m_surfaces.size() >= MIN_OUTPUT_SURFACES)
1731  {
1733  LOG(VB_GENERAL, LOG_INFO, LOC +
1734  QString("Created %1 output surfaces.") .arg(m_surfaces.size()));
1735  }
1736  return ok;
1737 }
1738 
1740 {
1741  INIT_ST
1743  {
1745  m_device, enable ? &vdpau_preemption_callback : nullptr,
1746  (void*)this);
1747  CHECK_ST
1748  }
1749  else
1750  return false;
1751 
1752  return ok;
1753 }
1754 
1756 {
1758  return false;
1759 
1760  if (!gVDPAUSupportChecked)
1761  {
1762  gVDPAUSupportChecked = true;
1763 
1764  if (vdp_get_api_version)
1765  {
1766  uint version;
1768  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Version %1").arg(version));
1769  }
1771  {
1772  const char * info;
1774  QString vendor(info);
1775 
1776  gVDPAUNVIDIA = vendor.contains("nvidia", Qt::CaseInsensitive);
1777 
1778  LOG(VB_GENERAL, LOG_INFO, LOC +
1779  QString("Information %2").arg(info));
1780  }
1781 
1782  for (int i = 0; i < NUM_SCALING_LEVELS; i++)
1785 
1786  if (gVDPAUBestScaling)
1787  {
1788  LOG(VB_PLAYBACK, LOG_INFO, LOC +
1789  QString("HQ scaling level %1 of %2 available.")
1791  .arg(NUM_SCALING_LEVELS));
1792  }
1793  else
1794  LOG(VB_PLAYBACK, LOG_INFO, LOC + "HQ Scaling not supported.");
1795 
1796 #ifdef VDP_DECODER_PROFILE_MPEG4_PART2_ASP
1797  {
1798  INIT_ST
1799  VdpBool supported = false;
1800  uint32_t tmp1, tmp2, tmp3, tmp4;
1802  VDP_DECODER_PROFILE_MPEG4_PART2_ASP, &supported,
1803  &tmp1, &tmp2, &tmp3, &tmp4);
1804  CHECK_ST
1805  gVDPAUMPEG4Accel = (bool)supported;
1806  }
1807 #endif
1808 
1809 #ifdef VDP_DECODER_PROFILE_HEVC_MAIN
1810  {
1811  INIT_ST
1812  VdpBool supported = false;
1813  uint32_t tmp1, tmp2, tmp3, tmp4;
1815  VDP_DECODER_PROFILE_HEVC_MAIN, &supported,
1816  &tmp1, &tmp2, &tmp3, &tmp4);
1817  CHECK_ST
1818  gVDPAUHEVCAccel = (bool)supported;
1819  }
1820 #endif
1821 
1822  LOG(VB_PLAYBACK, LOG_INFO, LOC +
1823  QString("MPEG4 hardware acceleration %1supported.")
1824  .arg(gVDPAUMPEG4Accel ? "" : "not "));
1825  LOG(VB_PLAYBACK, LOG_INFO, LOC +
1826  QString("HEVC hardware acceleration %1supported.")
1827  .arg(gVDPAUHEVCAccel ? "" : "not "));
1828  }
1829 
1830  return true;
1831 }
1832 
1834 {
1835  INIT_ST
1836  VdpBool supported = false;
1838  feature, &supported);
1839  CHECK_ST
1840  return ok && supported;
1841 }
1842 
1844 {
1850  DestroyDecoders();
1852  DestroyLayers();
1853  RegisterCallback(false);
1854  DestroyDevice();
1855  ResetProcs();
1856  m_size = QSize();
1857  m_errored = false;
1858  memset(&m_rect, 0, sizeof(VdpRect));
1859  m_window = 0;
1860 
1861  if (m_display)
1862  {
1863  delete m_display;
1864  m_display = nullptr;
1865  }
1866 }
1867 
1869 {
1870  vdp_get_error_string = nullptr;
1871  vdp_get_proc_address = nullptr;
1873  {
1875  m_device = 0;
1876  }
1877 }
1878 
1880 {
1881  vdp_device_destroy = nullptr;
1882  vdp_video_surface_create = nullptr;
1883  vdp_video_surface_destroy = nullptr;
1888  vdp_output_surface_create = nullptr;
1889  vdp_output_surface_destroy = nullptr;
1894  vdp_video_mixer_create = nullptr;
1896  vdp_video_mixer_destroy = nullptr;
1897  vdp_video_mixer_render = nullptr;
1899  vdp_generate_csc_matrix = nullptr;
1909  vdp_decoder_create = nullptr;
1910  vdp_decoder_destroy = nullptr;
1911  vdp_decoder_render = nullptr;
1913  vdp_bitmap_surface_create = nullptr;
1914  vdp_bitmap_surface_destroy = nullptr;
1917  vdp_get_api_version = nullptr;
1918  vdp_get_information_string = nullptr;
1919 }
1920 
1922 {
1923  MythXLocker locker(m_display);
1924  INIT_ST
1926  {
1928  CHECK_ST
1929  m_flipQueue = 0;
1930  }
1931 
1933  {
1935  CHECK_ST
1936  m_flipTarget = 0;
1937  }
1938  m_flipReady = false;
1939 }
1940 
1942 {
1943  for (int i = 0; i < m_surfaces.size(); i++)
1945  m_surfaces.clear();
1946  m_surface = 0;
1947  m_flipReady = false;
1948 }
1949 
1951 {
1953  return;
1954 
1955  if (!m_outputSurfaces.empty())
1956  LOG(VB_GENERAL, LOG_WARNING, LOC + "Orphaned output surfaces.");
1957 
1958  INIT_ST
1959  QHash<uint, VDPAUOutputSurface>::iterator it;
1960  for (it = m_outputSurfaces.begin(); it != m_outputSurfaces.end(); ++it)
1961  {
1962  vdp_st = vdp_output_surface_destroy(it.value().m_id);
1963  CHECK_ST
1964  }
1965  m_outputSurfaces.clear();
1966 }
1967 
1969 {
1971  return;
1972 
1973  if (!m_videoSurfaces.empty())
1974  LOG(VB_GENERAL, LOG_WARNING, LOC + "Orphaned video surfaces.");
1975 
1976  INIT_ST
1977  QHash<uint, VDPAUVideoSurface>::iterator it;;
1978  for(it = m_videoSurfaces.begin(); it != m_videoSurfaces.end(); ++it)
1979  {
1980  vdp_st = vdp_video_surface_destroy(it.value().m_id);
1981  CHECK_ST
1982  }
1983  m_videoSurfaces.clear();
1984  m_videoSurfaceHash.clear();
1985 }
1986 
1988 {
1989  if (!m_layers.empty())
1990  LOG(VB_GENERAL, LOG_WARNING, LOC + "Orphaned layers.");
1991  m_layers.clear();
1992 }
1993 
1995 {
1997  return;
1998 
1999  if (!m_bitmapSurfaces.empty())
2000  LOG(VB_GENERAL, LOG_WARNING, LOC + "Orphaned bitmap surfaces.");
2001 
2002  INIT_ST
2003  QHash<uint, VDPAUBitmapSurface>::iterator it;
2004  for (it = m_bitmapSurfaces.begin(); it != m_bitmapSurfaces.end(); ++it)
2005  {
2006  vdp_st = vdp_bitmap_surface_destroy(it.value().m_id);
2007  CHECK_ST
2008  }
2009  m_bitmapSurfaces.clear();
2010 }
2011 
2013 {
2014  if (!vdp_decoder_destroy)
2015  return;
2016 
2017  if (!m_decoders.empty())
2018  LOG(VB_GENERAL, LOG_WARNING, LOC + "Orphaned decoders.");
2019 
2020  INIT_ST
2021  QHash<uint, VDPAUDecoder>::iterator it;
2022  for (it = m_decoders.begin(); it != m_decoders.end(); ++it)
2023  {
2024  vdp_st = vdp_decoder_destroy(it.value().m_id);
2025  CHECK_ST
2026  }
2027  m_decoders.clear();
2028 }
2029 
2031 {
2033  return;
2034 
2035  if (!m_videoMixers.empty())
2036  LOG(VB_GENERAL, LOG_WARNING, LOC + "Orphaned video mixers.");
2037 
2038  INIT_ST
2039  QHash<uint, VDPAUVideoMixer>::iterator it;
2040  for (it = m_videoMixers.begin(); it != m_videoMixers.end(); ++it)
2041  {
2042  vdp_st = vdp_video_mixer_destroy(it.value().m_id);
2043  CHECK_ST
2044  }
2045  m_videoMixers.clear();
2046 }
2047 
2049  VdpVideoMixerAttribute attribute[1],
2050  void const *value[1])
2051 {
2052  INIT_ST
2053 
2054  if (!m_videoMixers.contains(id))
2055  return false;
2056 
2058  attribute, value);
2059  CHECK_ST
2060  return ok;
2061 }
2062 
2064 {
2065  if (!m_preempted || m_recreating)
2066  return;
2067 
2068  LOG(VB_GENERAL, LOG_NOTICE, LOC +
2069  "Attempting to re-create VDPAU resources.");
2070  m_recreating = true;
2071  m_flipReady = false;
2072  ResetProcs();
2073  bool ok = CreateDevice();
2074  if (ok) ok = GetProcs();
2075  if (ok && m_window) ok = CreatePresentationQueue();
2076  if (ok && m_window) ok = SetColorKey(m_colorKey);
2077  if (ok) ok = RegisterCallback();
2078 
2079  if (ok && !m_outputSurfaces.empty())
2080  {
2081  // also need to update output surfaces referenced in VdpLayer structs
2082  QHash<uint ,uint> old_surfaces;
2083  QHash<uint, VDPAUOutputSurface>::iterator it;
2084  for (it = m_outputSurfaces.begin(); it != m_outputSurfaces.end(); ++it)
2085  {
2086  old_surfaces.insert(it.value().m_id, it.key());
2087  uint check = CreateOutputSurface(it.value().m_size,
2088  it.value().m_fmt,it.key());
2089  if (check != it.key())
2090  ok = false;
2091  }
2092  QHash<uint, uint>::iterator old;
2093  for (old = old_surfaces.begin(); old != old_surfaces.end(); ++old)
2094  old.value() = m_outputSurfaces[old.value()].m_id;
2095  QHash<uint, VDPAULayer>::iterator layers;
2096  for (layers = m_layers.begin(); layers != m_layers.end(); ++layers)
2097  {
2098  uint surface = layers.value().m_layer.source_surface;
2099  if (old_surfaces.contains(surface))
2100  layers.value().m_layer.source_surface = old_surfaces[surface];
2101  }
2102  if (ok)
2103  LOG(VB_GENERAL, LOG_INFO, LOC + "Re-created output surfaces.");
2104  }
2105 
2106  if (ok && !m_bitmapSurfaces.empty())
2107  {
2108  QHash<uint, VDPAUBitmapSurface>::iterator it;
2109  for (it = m_bitmapSurfaces.begin(); it != m_bitmapSurfaces.end(); ++it)
2110  {
2111  uint check = CreateBitmapSurface(it.value().m_size,
2112  it.value().m_fmt, it.key());
2113  if (check != it.key())
2114  ok = false;
2115  }
2116  if (ok)
2117  LOG(VB_GENERAL, LOG_INFO, LOC + "Re-created bitmap surfaces.");
2118 
2119  }
2120 
2121  if (ok && !m_decoders.empty())
2122  {
2123  QHash<uint, VDPAUDecoder>::iterator it;
2124  for (it = m_decoders.begin(); it != m_decoders.end(); ++it)
2125  {
2126  uint check = CreateDecoder(it.value().m_size, it.value().m_profile,
2127  it.value().m_max_refs, it.key());
2128  if (check != it.key())
2129  ok = false;
2130  }
2131  if (ok)
2132  LOG(VB_GENERAL, LOG_INFO, LOC + "Re-created decoders.");
2133  }
2134 
2135  if (ok && !m_videoMixers.empty())
2136  {
2137  QHash<uint, VDPAUVideoMixer>::iterator it;
2138  for (it = m_videoMixers.begin(); it != m_videoMixers.end(); ++it)
2139  {
2140  uint check = CreateVideoMixer(it.value().m_size,
2141  it.value().m_layers,
2142  it.value().m_features,
2143  it.value().m_type, it.key());
2144  if (check != it.key())
2145  ok = false;
2146  }
2147  if (ok)
2148  LOG(VB_GENERAL, LOG_INFO, LOC + "Re-created video mixers.");
2149  }
2150 
2151  // reset of hardware surfaces needs to be done in the correct thread
2152  m_reset_video_surfaces = true;
2153  QHash<uint, VDPAUVideoSurface>::iterator it;
2154  for (it = m_videoSurfaces.begin(); it != m_videoSurfaces.end(); ++it)
2155  it.value().m_needs_reset = true;
2156 
2158 
2159  if (!ok)
2160  {
2161  LOG(VB_GENERAL, LOG_INFO, LOC + "Failed to re-create VDPAU resources.");
2162  m_errored = true;
2163  return;
2164  }
2165 
2166  m_preempted = false;
2167  m_recreating = false;
2169  m_recreated = true;
2170 }
2171 
2173 {
2174  LOCK_ALL
2175 
2176  bool ok = true;
2177  QThread *this_thread = QThread::currentThread();
2178  QHash<uint, VDPAUVideoSurface>::iterator it;
2179  int surfaces_owned = 0;
2180 
2181  // save map of existing surfaces and create new surfaces
2182  QHash<uint, uint> old_surfaces;
2183  for (it = m_videoSurfaces.begin(); it != m_videoSurfaces.end(); ++it)
2184  {
2185  old_surfaces.insert(it.value().m_id, it.key());
2186  if ((it.value().m_owner == this_thread) && it.value().m_needs_reset)
2187  {
2188  uint check = CreateVideoSurface(it.value().m_size,
2189  it.value().m_type, it.key());
2190  if (check != it.key())
2191  ok = false;
2192  surfaces_owned++;
2193  it.value().m_needs_reset = false;
2194  }
2195  }
2196 
2197  if (!surfaces_owned)
2198  return;
2199 
2200  LOG(VB_GENERAL, LOG_INFO, LOC +
2201  QString("Attempting to reset %1 video surfaces owned by this thread %2")
2202  .arg(surfaces_owned).arg((long long)this_thread));
2203 
2204  // update old surfaces to map old vdpvideosurface to new vdpvideosurface
2205  QHash<uint, uint>::iterator old;
2206  for (old = old_surfaces.begin(); old != old_surfaces.end(); ++old)
2207  old.value() = m_videoSurfaces[old.value()].m_id;
2208 
2209  // update any render structure surface entries
2210  for (it = m_videoSurfaces.begin(); it != m_videoSurfaces.end(); ++it)
2211  {
2212  // MPEG2
2213  uint fwd = it.value().m_render.info.mpeg.forward_reference;
2214  uint back = it.value().m_render.info.mpeg.backward_reference;
2215  if (fwd != VDP_INVALID_HANDLE && old_surfaces.contains(fwd))
2216  it.value().m_render.info.mpeg.forward_reference = old_surfaces[fwd];
2217  if (back != VDP_INVALID_HANDLE && old_surfaces.contains(back))
2218  it.value().m_render.info.mpeg.backward_reference = old_surfaces[back];
2219 
2220  // H264
2221  for (uint i = 0; i < 16; i++)
2222  {
2223  uint ref = it.value().m_render.info.h264.referenceFrames[i].surface;
2224  if (ref != VDP_INVALID_HANDLE && old_surfaces.contains(ref))
2225  it.value().m_render.info.h264.referenceFrames[i].surface =
2226  old_surfaces[ref];
2227  }
2228 
2229  // VC1
2230  fwd = it.value().m_render.info.vc1.forward_reference;
2231  back = it.value().m_render.info.vc1.backward_reference;
2232  if (fwd != VDP_INVALID_HANDLE && old_surfaces.contains(fwd))
2233  it.value().m_render.info.vc1.forward_reference = old_surfaces[fwd];
2234  if (back != VDP_INVALID_HANDLE && old_surfaces.contains(back))
2235  it.value().m_render.info.vc1.backward_reference = old_surfaces[back];
2236 
2237  // MPEG4
2238 #ifdef VDP_DECODER_PROFILE_MPEG4_PART2_ASP
2239  fwd = it.value().m_render.info.mpeg4.forward_reference;
2240  back = it.value().m_render.info.mpeg4.backward_reference;
2241  if (fwd != VDP_INVALID_HANDLE && old_surfaces.contains(fwd))
2242  it.value().m_render.info.mpeg4.forward_reference = old_surfaces[fwd];
2243  if (back != VDP_INVALID_HANDLE && old_surfaces.contains(back))
2244  it.value().m_render.info.mpeg4.backward_reference = old_surfaces[back];
2245 #endif
2246  }
2247 
2248  if (ok)
2249  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Re-created %1 video surfaces.")
2250  .arg(surfaces_owned));
2251  else
2252  LOG(VB_GENERAL, LOG_ERR, LOC + "Error re-creating video surfaces.");
2253 
2254  int remaining = 0;
2255  for (it = m_videoSurfaces.begin(); it != m_videoSurfaces.end(); ++it)
2256  if (it.value().m_needs_reset)
2257  remaining++;
2258 
2259  LOG(VB_GENERAL, LOG_INFO, LOC +
2260  QString("%1 of %2 video surfaces still need to be reset")
2261  .arg(remaining).arg(m_videoSurfaces.size()));
2262 
2263  m_reset_video_surfaces = remaining;
2264  m_errored = !ok;
2265 }
2266 
2267 void MythRenderVDPAU::BindContext(AVCodecContext *avctx)
2268 {
2269  av_vdpau_bind_context(avctx, m_device, vdp_get_proc_address, 0);
2270 }
virtual ~MythRenderVDPAU()
void ClearVideoSurface(uint id)
#define LOCK_ALL
uint CreateVideoSurface(const QSize &size, VdpChromaType type=VDP_CHROMA_TYPE_420, uint existing=0)
bool CreateGC(Window win)
vdpau_render_state m_render
MythXDisplay * OpenMythXDisplay(void)
VdpPresentationQueueDisplay * vdp_presentation_queue_display
void CheckOutputSurfaces(void)
Display * GetDisplay(void)
Definition: mythxdisplay.h:21
bool CreatePresentationQueue(void)
void SetCSCMatrix(uint id, void *vals)
VdpVideoMixerDestroy * vdp_video_mixer_destroy
static bool IsHEVCAvailable(void)
QHash< uint, VDPAULayer > m_layers
VdpPreemptionCallbackRegister * vdp_preemption_callback_register
uint CreateVideoMixer(const QSize &size, uint layers, uint features, VdpChromaType type=VDP_CHROMA_TYPE_420, uint existing=0)
VdpOutputSurfacePutBitsNative * vdp_output_surface_put_bits_native
bool SetDeinterlacing(uint id, uint deinterlacers=kVDPFeatNone)
bool Create(const QSize &size, WId window, uint colorkey=VDPAU_COLORKEY)
#define MIN_OUTPUT_SURFACES
VdpPresentationQueue m_flipQueue
#define CREATE_CHECK(arg1, arg2)
static bool IsMPEG4Available(void)
void MoveResizeWin(QRect &rect)
static const VdpOutputSurfaceRenderBlendState VDPBlends[3]
uint GetSurfaceOwner(VdpVideoSurface surface)
#define XLOCK(dpy, arg)
Definition: mythxdisplay.h:75
VdpDecoderDestroy * vdp_decoder_destroy
VdpVideoMixerSetAttributeValues * vdp_video_mixer_set_attribute_values
VdpVideoMixerQueryFeatureSupport * vdp_video_mixer_query_feature_support
void Decode(uint id, struct vdpau_render_state *render)
VdpVideoMixerSetFeatureEnables * vdp_video_mixer_set_feature_enables
bool IsFeatureAvailable(uint feature)
VdpOutputSurfaceGetBitsNative * vdp_output_surface_get_bits_native
VDPAUColor * m_background
void DestroyVideoSurface(uint id)
static bool gVDPAUMPEG4Accel
VdpGetApiVersion * vdp_get_api_version
void DestroyOutputSurfaces(void)
void DestroyDecoder(uint id)
void DestroyVideoMixers(void)
bool
Definition: pxsup2dast.c:30
bool DrawBitmap(uint id, uint target, const QRect *src, const QRect *dst, VDPBlendType blendi=kVDPBlendNormal, int alpha=0, int red=0, int green=0, int blue=0)
#define CHECK_STATUS(arg1)
static void vdpau_preemption_callback(VdpDevice device, void *myth_render)
QHash< uint, VDPAUOutputSurface > m_outputSurfaces
~VDPAUVideoMixer() override
unsigned int uint
Definition: compat.h:140
void DestroyBitmapSurface(uint id)
VDPAULayer(uint surface, const QRect *src, const QRect *dst)
bool SaveScreenShot(const QImage &image, QString filename="")
VdpOutputSurfaceGetParameters * vdp_output_surface_get_parameters
void SetPreempted(void)
unsigned long GetBlack(void) const
Definition: mythxdisplay.h:28
bool RegisterCallback(bool enable=true)
static uint gVDPAUBestScaling
static guint32 * tmp
Definition: goom_core.c:35
static float * vals
Definition: tentacle3d.c:16
void DrawDisplayRect(const QRect &rect, bool use_colorkey=false)
uint CreateBitmapSurface(const QSize &size, VdpRGBAFormat fmt=VDP_RGBA_FORMAT_B8G8R8A8, uint existing=0)
VDPAUVideoMixer(uint id, QSize size, uint layers, uint features, VdpChromaType type)
void Sync(bool flush=false)
void DestroyLayer(uint id)
VDPAUVideoSurface(uint id, QSize size, VdpChromaType type)
VdpPresentationQueueBlockUntilSurfaceIdle * vdp_presentation_queue_block_until_surface_idle
int GetScreen(void) const
Definition: mythxdisplay.h:22
RenderType m_type
QHash< VdpVideoSurface, uint > m_videoSurfaceHash
void SetColor(uint color)
#define CHECK_ST
#define NUM_REFERENCE_FRAMES
void DestroyVideoMixer(uint id)
VdpBitstreamBuffer * bitstream_buffers
The user is responsible for freeing this buffer using av_freep().
virtual ~VDPAUResource()=default
#define LOC
static bool IsVDPAUAvailable(void)
bool MixAndRend(uint id, VdpVideoMixerPictureStructure field, uint vid_surface, uint out_surface, const QVector< uint > *refs, bool top, QRect src, const QRect &dst, QRect dst_vid, uint layer1=0, uint layer2=0)
void ChangeVideoSurfaceOwner(uint id)
bool DrawLayer(uint id, uint target)
void DestroyOutputSurface(uint id)
VdpDecoderCreate * vdp_decoder_create
VdpPresentationQueueGetTime * vdp_presentation_queue_get_time
VdpPresentationQueueDestroy * vdp_presentation_queue_destroy
bool CreatePresentationSurfaces(void)
VdpChromaType m_type
int GetDepth(void) const
Definition: mythxdisplay.h:25
VDPAUVideoMixer()=default
MythXDisplay * m_display
void MoveResizeWin(Window win, const QRect &rect)
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:10
QHash< uint, VDPAUVideoMixer > m_videoMixers
union AVVDPAUPictureInfo info
picture parameter information for all supported codecs
int GetBitmapSize(uint id)
void BindContext(AVCodecContext *avctx)
VdpPresentationQueueCreate * vdp_presentation_queue_create
VdpVideoSurfacePutBitsYCbCr * vdp_video_surface_get_bits_y_cb_cr
static bool gVDPAUNVIDIA
void DestroyDecoders(void)
#define MAX_OUTPUT_SURFACES
void DestroyVideoSurfaces(void)
VDPAUBitmapSurface(uint id, QSize size, VdpRGBAFormat fmt)
void DestroyPresentationQueue(void)
bool GetScreenShot(int width=0, int height=0, QString filename="")
#define GET_PROC(FUNC_ID, PROC)
VdpColor m_vdp_color
VDPAUColor(int color=0x0)
VdpVideoSurfaceCreate * vdp_video_surface_create
#define COLOR_BLACK
VdpPresentationQueueTargetCreateX11 * vdp_presentation_queue_target_create_x11
VdpOutputSurfaceRenderBitmapSurface * vdp_output_surface_render_bitmap_surface
VdpVideoSurfaceGetBitsYCbCr * vdp_video_surface_put_bits_y_cb_cr
VdpOutputSurfaceRenderOutputSurface * vdp_output_surface_render_output_surface
bool SetColorKey(uint color)
VdpBitmapSurfacePutBitsNative * vdp_bitmap_surface_put_bits_native
void SetForeground(unsigned long color)
VdpOutputSurfaceDestroy * vdp_output_surface_destroy
void * GetRender(uint id)
VdpGetErrorString * vdp_get_error_string
static const char * dummy_get_error_string(VdpStatus)
QHash< uint, VDPAUVideoSurface > m_videoSurfaces
#define CHECK_VIDEO_SURFACES(arg1)
bool UploadYUVFrame(uint id, void *const planes[3], uint32_t pitches[3])
bool DownloadYUVFrame(uint id, void *const planes[3], uint32_t pitches[3])
uint CreateDecoder(const QSize &size, VdpDecoderProfile profile, uint references, uint existing=0)
MythMainWindow * GetMythMainWindow(void)
static bool H264DecoderSizeSupported(uint width, uint height)
VDPAUDecoder()=default
bool CreateDecodeOnly(void)
VdpBitmapSurfaceCreate * vdp_bitmap_surface_create
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
VdpPresentationQueueTargetDestroy * vdp_presentation_queue_target_destroy
static int x0
Definition: mythsocket.cpp:59
QHash< uint, VDPAUDecoder > m_decoders
VdpDeviceDestroy * vdp_device_destroy
VdpGetProcAddress * vdp_get_proc_address
VDPAUResource()=default
bool UploadMythImage(uint id, MythImage *image)
VdpVideoSurfaceDestroy * vdp_video_surface_destroy
bool CheckHardwareSupport(void)
QHash< uint, VDPAUBitmapSurface > m_bitmapSurfaces
VdpBitmapSurfaceDestroy * vdp_bitmap_surface_destroy
#define LOCK_DECODE
void ResetVideoSurfaces(void)
VdpDecoderRender * vdp_decoder_render
VDPAUOutputSurface()=default
void DestroyPresentationSurfaces(void)
VdpPresentationQueueTarget m_flipTarget
VdpVideoMixerCreate * vdp_video_mixer_create
#define VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1
bool ChangeVideoMixerFeatures(uint id, uint features)
QVector< uint > m_surfaces
#define NUM_SCALING_LEVELS
VdpDecoderQueryCapabilities * vdp_decoder_query_capabilities
QSize GetSurfaceSize(uint id)
uint CreateLayer(uint surface, const QRect *src=nullptr, const QRect *dst=nullptr)
VdpVideoMixerRender * vdp_video_mixer_render
VDPAUBitmapSurface()=default
VDPBlendType
VdpGenerateCSCMatrix * vdp_generate_csc_matrix
static guint32 * back
Definition: goom_core.c:34
VdpGetInformationString * vdp_get_information_string
#define LOCK_RENDER
VdpPresentationQueueSetBackgroundColor * vdp_presentation_queue_set_background_color
void FillRectangle(Window win, const QRect &rect)
VDPAUResource(uint id, QSize size)
uint CreateOutputSurface(const QSize &size, VdpRGBAFormat fmt=VDP_RGBA_FORMAT_B8G8R8A8, uint existing=0)
void DestroyBitmapSurfaces(void)
bool UploadBitmap(uint id, void *const plane[1], uint32_t pitch[1])
static bool gVDPAUHEVCAccel
#define INIT_ST
VDPAUOutputSurface(uint id, QSize size, VdpRGBAFormat fmt)
VdpOutputSurfaceCreate * vdp_output_surface_create
VdpDecoderProfile m_profile
static bool gVDPAUSupportChecked
VDPAUDecoder(uint id, QSize size, VdpDecoderProfile profile, uint refs)
VdpVideoSurfaceGetParameters * vdp_video_surface_get_parameters
VdpVideoSurface surface
Used as rendered surface, never changed.
int SetMixerAttribute(uint id, uint attrib, int value)