8#define pointer Xpointer
9#if defined(_X11_XLIB_H_) && !defined(Bool)
12#include "vdpau/vdpau_x11.h"
27#define LOC QString("VDPAUHelp: ")
35ok &= (status == VDP_STATUS_OK); \
38 LOG(VB_PLAYBACK, LOG_ERR, LOC + QString("Error at %1:%2 (#%3, %4)") \
39 .arg(__FILE__).arg( __LINE__).arg(status) \
40 .arg(m_vdpGetErrorString(status))); \
43#define GET_PROC(FUNC_ID, PROC) \
44status = m_vdpGetProcAddress(m_device, FUNC_ID, reinterpret_cast<void **>(&(PROC))); CHECK_ST
49 m_maxMacroBlocks(Macroblocks),
60 uint32_t macros =
static_cast<uint32_t
>(((Width + 15) & ~15) * ((Height + 15) & ~15)) / 256;
65 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC + QString(
"Not supported: Size %1x%2 > %3x%4, MBs %5 > %6, Level %7 > %8")
74 static QMutex s_mutex;
75 static bool s_checked =
false;
76 static bool s_available =
false;
78 QMutexLocker locker(&s_mutex);
79 if (s_checked && !Reinit)
90 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Supported/available VDPAU decoders:");
92 for (
const auto&
profile : std::as_const(profiles))
93 LOG(VB_GENERAL, LOG_INFO,
LOC +
98 LOG(VB_GENERAL, LOG_INFO,
LOC +
"VDPAU is NOT available");
104 uint32_t &Macros, uint32_t &Width, uint32_t &Height)
110 VdpBool supported = VDP_FALSE;
112 &Level, &Macros, &Width, &Height);
115 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC + QString(
"ProfileCheck: Prof %1 Supp %2 Level %3 Macros %4 Width %5 Height %6 Status %7")
116 .arg(Profile).arg(supported).arg(Level).arg(Macros).arg(Width).arg(Height).arg(status));
118 if (((supported != VDP_TRUE) || (status != VDP_STATUS_OK)) &&
119 (Profile == VDP_DECODER_PROFILE_H264_CONSTRAINED_BASELINE ||
120 Profile == VDP_DECODER_PROFILE_H264_BASELINE))
122 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Driver does not report support for H264 %1Baseline")
123 .arg(Profile == VDP_DECODER_PROFILE_H264_CONSTRAINED_BASELINE ?
"Constrained " :
""));
130 &Level, &Macros, &Width, &Height);
132 if (supported == VDP_TRUE)
133 LOG(VB_GENERAL, LOG_INFO,
LOC +
"... but assuming available as H264 Main is supported");
136 return supported == VDP_TRUE;
141 static const std::array<const VdpDecoderProfile,15> MainProfiles
143 VDP_DECODER_PROFILE_MPEG1, VDP_DECODER_PROFILE_MPEG2_SIMPLE, VDP_DECODER_PROFILE_MPEG2_MAIN,
144 VDP_DECODER_PROFILE_MPEG4_PART2_SP, VDP_DECODER_PROFILE_MPEG4_PART2_ASP,
145 VDP_DECODER_PROFILE_VC1_SIMPLE, VDP_DECODER_PROFILE_VC1_MAIN, VDP_DECODER_PROFILE_VC1_ADVANCED,
146 VDP_DECODER_PROFILE_H264_BASELINE, VDP_DECODER_PROFILE_H264_MAIN, VDP_DECODER_PROFILE_H264_HIGH,
147 VDP_DECODER_PROFILE_H264_EXTENDED, VDP_DECODER_PROFILE_H264_CONSTRAINED_BASELINE,
148 VDP_DECODER_PROFILE_H264_CONSTRAINED_HIGH, VDP_DECODER_PROFILE_H264_HIGH_444_PREDICTIVE
151 static const std::array<const VdpDecoderProfile,4> HEVCProfiles
153 VDP_DECODER_PROFILE_HEVC_MAIN, VDP_DECODER_PROFILE_HEVC_MAIN_10,
154 VDP_DECODER_PROFILE_HEVC_MAIN_STILL, VDP_DECODER_PROFILE_HEVC_MAIN_444
157 auto VDPAUToMythProfile = [](VdpDecoderProfile Profile)
188 static QRecursiveMutex lock;
189 static bool s_initialised =
false;
192 QMutexLocker locker(&lock);
195 s_initialised =
true;
205 for (VdpDecoderProfile
profile : MainProfiles)
210 s_profiles.emplace_back(prof,
211 VDPAUCodec(prof, QSize(
static_cast<int>(width),
static_cast<int>(height)), macros, level));
217 for (VdpDecoderProfile
profile : HEVCProfiles)
222 s_profiles.emplace_back(prof,
223 VDPAUCodec(prof, QSize(
static_cast<int>(width),
static_cast<int>(height)), macros, level));
234 if (profiles.empty())
237 Decoders.append(
"VDPAU:");
238 for (
const auto&
profile : std::as_const(profiles))
254 : m_device(Context->device),
255 m_vdpGetProcAddress(Context->get_proc_address),
264 LOG(VB_PLAYBACK, LOG_ERR,
LOC +
"Failed to register preemption callback");
275 m_createdDevice(
true)
290 LOG(VB_PLAYBACK, LOG_ERR,
LOC +
"Failed to create VDPAU device.");
350 const char* infostring =
nullptr;
354 if (!ok || !infostring)
357 if (!QString(infostring).contains(
"NVIDIA", Qt::CaseInsensitive))
361 sscanf(infostring,
"NVIDIA VDPAU Driver Shared Library %d", &driver);
362 return !(driver < 410);
370 int mbs =
static_cast<int>(ceil(
static_cast<double>(Context->width) / 16.0));
371 if (mbs != 49 && mbs != 54 && mbs != 59 && mbs != 64 &&
372 mbs != 113 && mbs != 118 &&mbs != 123 && mbs != 128)
378 switch (Context->profile & ~FF_PROFILE_H264_INTRA)
380 case FF_PROFILE_H264_BASELINE:
profile = VDP_DECODER_PROFILE_H264_BASELINE;
break;
381 case FF_PROFILE_H264_CONSTRAINED_BASELINE:
profile = VDP_DECODER_PROFILE_H264_CONSTRAINED_BASELINE;
break;
382 case FF_PROFILE_H264_MAIN:
profile = VDP_DECODER_PROFILE_H264_MAIN;
break;
383 case FF_PROFILE_H264_HIGH:
profile = VDP_DECODER_PROFILE_H264_HIGH;
break;
384#ifdef VDP_DECODER_PROFILE_H264_EXTENDED
385 case FF_PROFILE_H264_EXTENDED:
profile = VDP_DECODER_PROFILE_H264_EXTENDED;
break;
387 case FF_PROFILE_H264_HIGH_10:
profile = VDP_DECODER_PROFILE_H264_HIGH;
break;
388#ifdef VDP_DECODER_PROFILE_H264_HIGH_444_PREDICTIVE
389 case FF_PROFILE_H264_HIGH_422:
390 case FF_PROFILE_H264_HIGH_444_PREDICTIVE:
391 case FF_PROFILE_H264_CAVLC_444:
profile = VDP_DECODER_PROFILE_H264_HIGH_444_PREDICTIVE;
break;
393 default:
return false;
411 static_cast<uint>(Context->height), 2, &
tmp);
417 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"No H264 decoder support for %1x%2")
418 .arg(Context->width).arg(Context->height));
428 VdpOutputSurface result = 0;
431 static_cast<uint>(Size.width()),
432 static_cast<uint>(Size.height()), &result);
450 if (!
m_valid || Size.isEmpty())
453 VdpVideoMixer result = 0;
455 static const std::array<const VdpVideoMixerParameter,3> parameters {
456 VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH,
457 VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT,
458 VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE
462 uint width =
static_cast<uint>(Size.width());
463 uint height =
static_cast<uint>(Size.height());
464 std::array<void const *,3> parametervalues { &width, &height, &ChromaType};
466 uint32_t featurecount = 0;
467 std::array<VdpVideoMixerFeature,2> features {};
468 VdpBool enable = VDP_TRUE;
469 const std::array<VdpBool,2> enables = { enable, enable };
473 features[featurecount] = VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL;
479 features[featurecount] = VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL;
485 3, parameters.data(), parametervalues.data(), &result);
490 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to create video mixer");
503 VdpOutputSurface Dest,
FrameScanType Scan,
int TopFieldFirst,
504 QVector<AVBufferRef*>& Frames)
509 VdpVideoMixerPictureStructure field = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME;
512 field = TopFieldFirst ? VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD :
513 VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD;
517 field = TopFieldFirst ? VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD :
518 VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD;
521 int count = Frames.size();
522 if ((count < 1) || (field == VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME))
526 0,
nullptr,
Source, 0,
nullptr,
nullptr, Dest,
nullptr,
nullptr, 0,
nullptr);
531 std::array<VdpVideoSurface,2> past = { VDP_INVALID_HANDLE, VDP_INVALID_HANDLE };
532 std::array<VdpVideoSurface,1> future = { VDP_INVALID_HANDLE };
534 auto next =
static_cast<VdpVideoSurface
>(
reinterpret_cast<uintptr_t
>(Frames[0]->data));
535 auto current =
static_cast<VdpVideoSurface
>(
reinterpret_cast<uintptr_t
>(Frames[count > 1 ? 1 : 0]->data));
536 auto last =
static_cast<VdpVideoSurface
>(
reinterpret_cast<uintptr_t
>(Frames[count > 2 ? 2 : 0]->data));
538 if (field == VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD)
541 past[0] = past[1] = last;
552 2, past.data(),
current, 1, future.data(),
553 nullptr, Dest,
nullptr,
nullptr, 0,
nullptr);
570 if (!Mixer || !ColourSpace)
573 VdpVideoMixerAttribute attr = { VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX };
574 void const* val = { ColourSpace->data() };
587 auto supported =
static_cast<VdpBool
>(
false);
590 return ok &&
static_cast<bool>(supported);
599 auto supported =
static_cast<VdpBool
>(
false);
602 return ok &&
static_cast<bool>(supported);
616 return {
static_cast<int>(width),
static_cast<int>(height)};
@ H264ConstrainedBaseline
static QString GetProfileDescription(CodecProfile Profile, QSize Size, VideoFrameType Format=FMT_NONE, uint ColorDepth=0)
A simple wrapper around VDPAU functionality.
void DeleteOutputSurface(VdpOutputSurface Surface)
VdpOutputSurface CreateOutputSurface(QSize Size)
VdpVideoMixerDestroy * m_vdpVideoMixerDestroy
VdpVideoMixerSetFeatureEnables * m_vdpVideoMixerSetFeatureEnables
void MixerRender(VdpVideoMixer Mixer, VdpVideoSurface Source, VdpOutputSurface Dest, FrameScanType Scan, int TopFieldFirst, QVector< AVBufferRef * > &Frames)
VdpOutputSurfaceDestroy * m_vdpOutputSurfaceDestroy
static bool CheckH264Decode(AVCodecContext *Context)
VdpVideoMixerCreate * m_vdpVideoMixerCreate
QSize GetSurfaceParameters(VdpVideoSurface Surface, VdpChromaType &Chroma)
VdpDecoderQueryCapabilities * m_vdpDecoderQueryCapabilities
void DeleteMixer(VdpVideoMixer Mixer)
~MythVDPAUHelper(void) override
static bool HaveVDPAU(bool Reinit=false)
VdpDecoderDestroy * m_vdpDecoderDestroy
bool IsFeatureAvailable(uint Feature)
VdpVideoMixerQueryAttributeSupport * m_vdpVideoMixerQueryAttributeSupport
void SetCSCMatrix(VdpVideoMixer Mixer, MythVideoColourSpace *ColourSpace)
static void GetDecoderList(QStringList &Decoders)
VdpGetErrorString * m_vdpGetErrorString
VdpVideoMixerSetAttributeValues * m_vdpVideoMixerSetAttributeValues
VdpVideoMixer CreateMixer(QSize Size, VdpChromaType ChromaType=VDP_CHROMA_TYPE_420, MythDeintType Deinterlacer=DEINT_BASIC)
VdpDeviceDestroy * m_vdpDeviceDestroy
void DisplayPreempted(void)
VdpVideoMixerRender * m_vdpVideoMixerRender
VdpDecoderCreate * m_vdpDecoderCreate
static const VDPAUProfiles & GetProfiles(void)
VdpVideoSurfaceGetParameters * m_vdpVideoSurfaceGetParameters
bool H264DecodeCheck(VdpDecoderProfile Profile, AVCodecContext *Context)
VdpVideoMixerQueryFeatureSupport * m_vdpVideoMixerQueryFeatureSupport
bool ProfileCheck(VdpDecoderProfile Profile, uint32_t &Level, uint32_t &Macros, uint32_t &Width, uint32_t &Height)
bool IsAttributeAvailable(uint Attribute)
VdpOutputSurfaceCreate * m_vdpOutputSurfaceCreate
VdpGetProcAddress * m_vdpGetProcAddress
VdpGetInformationString * m_vdpGetInformationString
VdpPreemptionCallbackRegister * m_vdpPreemptionCallbackRegister
MythVideoColourSpace contains a QMatrix4x4 that can convert YCbCr data to RGB.
uint32_t m_maxMacroBlocks
bool Supported(int Width, int Height, int Level) const
VDPAUCodec(MythCodecContext::CodecProfile Profile, QSize Size, uint32_t Macroblocks, uint32_t Level)
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
#define GET_PROC(FUNC_ID, PROC)
static const char * DummyGetError(VdpStatus)
static void vdpau_preemption_callback(VdpDevice, void *Opaque)
std::vector< VDPAUProfile > VDPAUProfiles
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
VERBOSE_PREAMBLE Most true