7#include "libavcodec/defs.h"
12#define pointer Xpointer
13#if defined(_X11_XLIB_H_) && !defined(Bool)
16#include "vdpau/vdpau_x11.h"
31#define LOC QString("VDPAUHelp: ")
39ok &= (status == VDP_STATUS_OK); \
42 LOG(VB_PLAYBACK, LOG_ERR, LOC + QString("Error at %1:%2 (#%3, %4)") \
43 .arg(__FILE__).arg( __LINE__).arg(status) \
44 .arg(m_vdpGetErrorString(status))); \
47#define GET_PROC(FUNC_ID, PROC) \
48status = m_vdpGetProcAddress(m_device, FUNC_ID, reinterpret_cast<void **>(&(PROC))); CHECK_ST
53 m_maxMacroBlocks(Macroblocks),
64 uint32_t macros =
static_cast<uint32_t
>(((Width + 15) & ~15) * ((Height + 15) & ~15)) / 256;
69 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC + QString(
"Not supported: Size %1x%2 > %3x%4, MBs %5 > %6, Level %7 > %8")
78 static QMutex s_mutex;
79 static bool s_checked =
false;
80 static bool s_available =
false;
82 QMutexLocker locker(&s_mutex);
83 if (s_checked && !Reinit)
94 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Supported/available VDPAU decoders:");
96 for (
const auto&
profile : std::as_const(profiles))
97 LOG(VB_GENERAL, LOG_INFO,
LOC +
102 LOG(VB_GENERAL, LOG_INFO,
LOC +
"VDPAU is NOT available");
108 uint32_t &Macros, uint32_t &Width, uint32_t &Height)
114 VdpBool supported = VDP_FALSE;
116 &Level, &Macros, &Width, &Height);
119 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC + QString(
"ProfileCheck: Prof %1 Supp %2 Level %3 Macros %4 Width %5 Height %6 Status %7")
120 .arg(Profile).arg(supported).arg(Level).arg(Macros).arg(Width).arg(Height).arg(status));
122 if (((supported != VDP_TRUE) || (status != VDP_STATUS_OK)) &&
123 (Profile == VDP_DECODER_PROFILE_H264_CONSTRAINED_BASELINE ||
124 Profile == VDP_DECODER_PROFILE_H264_BASELINE))
126 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Driver does not report support for H264 %1Baseline")
127 .arg(Profile == VDP_DECODER_PROFILE_H264_CONSTRAINED_BASELINE ?
"Constrained " :
""));
134 &Level, &Macros, &Width, &Height);
136 if (supported == VDP_TRUE)
137 LOG(VB_GENERAL, LOG_INFO,
LOC +
"... but assuming available as H264 Main is supported");
140 return supported == VDP_TRUE;
145 static const std::array<const VdpDecoderProfile,15> MainProfiles
147 VDP_DECODER_PROFILE_MPEG1, VDP_DECODER_PROFILE_MPEG2_SIMPLE, VDP_DECODER_PROFILE_MPEG2_MAIN,
148 VDP_DECODER_PROFILE_MPEG4_PART2_SP, VDP_DECODER_PROFILE_MPEG4_PART2_ASP,
149 VDP_DECODER_PROFILE_VC1_SIMPLE, VDP_DECODER_PROFILE_VC1_MAIN, VDP_DECODER_PROFILE_VC1_ADVANCED,
150 VDP_DECODER_PROFILE_H264_BASELINE, VDP_DECODER_PROFILE_H264_MAIN, VDP_DECODER_PROFILE_H264_HIGH,
151 VDP_DECODER_PROFILE_H264_EXTENDED, VDP_DECODER_PROFILE_H264_CONSTRAINED_BASELINE,
152 VDP_DECODER_PROFILE_H264_CONSTRAINED_HIGH, VDP_DECODER_PROFILE_H264_HIGH_444_PREDICTIVE
155 static const std::array<const VdpDecoderProfile,4> HEVCProfiles
157 VDP_DECODER_PROFILE_HEVC_MAIN, VDP_DECODER_PROFILE_HEVC_MAIN_10,
158 VDP_DECODER_PROFILE_HEVC_MAIN_STILL, VDP_DECODER_PROFILE_HEVC_MAIN_444
161 auto VDPAUToMythProfile = [](VdpDecoderProfile Profile)
192 static QRecursiveMutex lock;
193 static bool s_initialised =
false;
196 QMutexLocker locker(&lock);
199 s_initialised =
true;
209 for (VdpDecoderProfile
profile : MainProfiles)
214 s_profiles.emplace_back(prof,
215 VDPAUCodec(prof, QSize(
static_cast<int>(width),
static_cast<int>(height)), macros, level));
221 for (VdpDecoderProfile
profile : HEVCProfiles)
226 s_profiles.emplace_back(prof,
227 VDPAUCodec(prof, QSize(
static_cast<int>(width),
static_cast<int>(height)), macros, level));
238 if (profiles.empty())
241 Decoders.append(
"VDPAU:");
242 for (
const auto&
profile : std::as_const(profiles))
258 : m_device(Context->device),
259 m_vdpGetProcAddress(Context->get_proc_address),
268 LOG(VB_PLAYBACK, LOG_ERR,
LOC +
"Failed to register preemption callback");
279 m_createdDevice(
true)
294 LOG(VB_PLAYBACK, LOG_ERR,
LOC +
"Failed to create VDPAU device.");
354 const char* infostring =
nullptr;
358 if (!ok || !infostring)
361 if (!QString(infostring).contains(
"NVIDIA", Qt::CaseInsensitive))
365 sscanf(infostring,
"NVIDIA VDPAU Driver Shared Library %d", &driver);
366 return !(driver < 410);
374 int mbs =
static_cast<int>(ceil(
static_cast<double>(Context->width) / 16.0));
375 if (mbs != 49 && mbs != 54 && mbs != 59 && mbs != 64 &&
376 mbs != 113 && mbs != 118 &&mbs != 123 && mbs != 128)
382 switch (Context->profile & ~AV_PROFILE_H264_INTRA)
384 case AV_PROFILE_H264_BASELINE:
profile = VDP_DECODER_PROFILE_H264_BASELINE;
break;
385 case AV_PROFILE_H264_CONSTRAINED_BASELINE:
profile = VDP_DECODER_PROFILE_H264_CONSTRAINED_BASELINE;
break;
386 case AV_PROFILE_H264_MAIN:
profile = VDP_DECODER_PROFILE_H264_MAIN;
break;
387 case AV_PROFILE_H264_HIGH:
profile = VDP_DECODER_PROFILE_H264_HIGH;
break;
388#ifdef VDP_DECODER_PROFILE_H264_EXTENDED
389 case AV_PROFILE_H264_EXTENDED:
profile = VDP_DECODER_PROFILE_H264_EXTENDED;
break;
391 case AV_PROFILE_H264_HIGH_10:
profile = VDP_DECODER_PROFILE_H264_HIGH;
break;
392#ifdef VDP_DECODER_PROFILE_H264_HIGH_444_PREDICTIVE
393 case AV_PROFILE_H264_HIGH_422:
394 case AV_PROFILE_H264_HIGH_444_PREDICTIVE:
395 case AV_PROFILE_H264_CAVLC_444:
profile = VDP_DECODER_PROFILE_H264_HIGH_444_PREDICTIVE;
break;
397 default:
return false;
415 static_cast<uint>(Context->height), 2, &tmp);
421 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"No H264 decoder support for %1x%2")
422 .arg(Context->width).arg(Context->height));
432 VdpOutputSurface result = 0;
435 static_cast<uint>(Size.width()),
436 static_cast<uint>(Size.height()), &result);
454 if (!
m_valid || Size.isEmpty())
457 VdpVideoMixer result = 0;
459 static const std::array<const VdpVideoMixerParameter,3> parameters {
460 VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH,
461 VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT,
462 VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE
466 uint width =
static_cast<uint>(Size.width());
467 uint height =
static_cast<uint>(Size.height());
468 std::array<void const *,3> parametervalues { &width, &height, &ChromaType};
470 uint32_t featurecount = 0;
471 std::array<VdpVideoMixerFeature,2> features {};
472 VdpBool enable = VDP_TRUE;
473 const std::array<VdpBool,2> enables = { enable, enable };
477 features[featurecount] = VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL;
483 features[featurecount] = VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL;
489 3, parameters.data(), parametervalues.data(), &result);
494 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Failed to create video mixer");
507 VdpOutputSurface Dest,
FrameScanType Scan,
int TopFieldFirst,
508 QVector<AVBufferRef*>& Frames)
513 VdpVideoMixerPictureStructure field = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME;
516 field = TopFieldFirst ? VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD :
517 VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD;
521 field = TopFieldFirst ? VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD :
522 VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD;
525 int count = Frames.size();
526 if ((count < 1) || (field == VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME))
530 0,
nullptr,
Source, 0,
nullptr,
nullptr, Dest,
nullptr,
nullptr, 0,
nullptr);
535 std::array<VdpVideoSurface,2> past = { VDP_INVALID_HANDLE, VDP_INVALID_HANDLE };
536 std::array<VdpVideoSurface,1> future = { VDP_INVALID_HANDLE };
538 auto next =
static_cast<VdpVideoSurface
>(
reinterpret_cast<uintptr_t
>(Frames[0]->data));
539 auto current =
static_cast<VdpVideoSurface
>(
reinterpret_cast<uintptr_t
>(Frames[count > 1 ? 1 : 0]->data));
540 auto last =
static_cast<VdpVideoSurface
>(
reinterpret_cast<uintptr_t
>(Frames[count > 2 ? 2 : 0]->data));
542 if (field == VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD)
545 past[0] = past[1] = last;
556 2, past.data(),
current, 1, future.data(),
557 nullptr, Dest,
nullptr,
nullptr, 0,
nullptr);
574 if (!Mixer || !ColourSpace)
577 VdpVideoMixerAttribute attr = { VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX };
578 void const* val = { ColourSpace->data() };
591 auto supported =
static_cast<VdpBool
>(
false);
594 return ok &&
static_cast<bool>(supported);
603 auto supported =
static_cast<VdpBool
>(
false);
606 return ok &&
static_cast<bool>(supported);
620 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