Skip to content

Commit

Permalink
MythOpenGLInterop: Refactor interop support check
Browse files Browse the repository at this point in the history
- use VideoFrameType rather than MythCodecID for the check - which is a
more sensible indicator.
- ensure subclass interop checks are protected as they do not enforce
thread safety checks.
- ensure all MythCodecContext subclasses call the 'master'
MythOpenGLInterop::GetInteropType which does enforce thread safety
- cache known supported formats in MythOpenGLInterop::GetInteropType to
speed things up a little.
- ensure all subclass constructors/destructors are protected (they are
reference counted so should not be created/deleted directly)
- don't pass the MythRenderOpenGL object to the GetInteropType
implementations.
  • Loading branch information
mark-kendall committed Nov 20, 2019
1 parent 6ff9454 commit 9f7ceac
Show file tree
Hide file tree
Showing 22 changed files with 178 additions and 133 deletions.
4 changes: 4 additions & 0 deletions mythtv/libs/libmythtv/decoders/mythdrmprimecontext.cpp
Expand Up @@ -78,6 +78,10 @@ MythCodecID MythDRMPRIMEContext::GetSupportedCodec(AVCodecContext **Context,
if (Decoder != "drmprime")
return failure;

// check interop support
if (MythOpenGLInterop::GetInteropType(FMT_DRMPRIME) == MythOpenGLInterop::Unsupported)
return failure;

// check support
if (!HavePrimeDecoders((*Codec)->id))
return failure;
Expand Down
2 changes: 1 addition & 1 deletion mythtv/libs/libmythtv/decoders/mythmmalcontext.cpp
Expand Up @@ -90,7 +90,7 @@ MythCodecID MythMMALContext::GetSupportedCodec(AVCodecContext **Context,
return failure;

// check interop
if (!decodeonly && (MythOpenGLInterop::GetInteropType(success) == MythOpenGLInterop::Unsupported))
if (!decodeonly && (MythOpenGLInterop::GetInteropType(FMT_MMAL) == MythOpenGLInterop::Unsupported))
return failure;

// look for a decoder
Expand Down
4 changes: 1 addition & 3 deletions mythtv/libs/libmythtv/decoders/mythnvdeccontext.cpp
Expand Up @@ -161,9 +161,7 @@ int MythNVDECContext::InitialiseDecoder(AVCodecContext *Context)
// Lock
OpenGLLocker locker(render);

MythCodecID codecid = static_cast<MythCodecID>(kCodec_MPEG1_NVDEC + (mpeg_version(Context->codec_id) - 1));
MythOpenGLInterop::Type type = MythNVDECInterop::GetInteropType(codecid, render);
if (type == MythOpenGLInterop::Unsupported)
if (MythOpenGLInterop::GetInteropType(FMT_NVDEC) == MythOpenGLInterop::Unsupported)
return -1;

// Create interop (and CUDA context)
Expand Down
6 changes: 3 additions & 3 deletions mythtv/libs/libmythtv/decoders/mythvaapicontext.cpp
Expand Up @@ -153,7 +153,7 @@ MythCodecID MythVAAPIContext::GetSupportedCodec(AVCodecContext **Context,
}

// direct rendering needs interop support
if (!decodeonly && (MythOpenGLInterop::GetInteropType(success) == MythOpenGLInterop::Unsupported))
if (!decodeonly && (MythOpenGLInterop::GetInteropType(FMT_VAAPI) == MythOpenGLInterop::Unsupported))
return failure;

// check for actual decoder support
Expand Down Expand Up @@ -312,8 +312,7 @@ int MythVAAPIContext::InitialiseContext(AVCodecContext *Context)
if (!Context || !gCoreContext->IsUIThread())
return -1;

MythCodecID vaapiid = static_cast<MythCodecID>(kCodec_MPEG1_VAAPI + (mpeg_version(Context->codec_id) - 1));
MythOpenGLInterop::Type type = MythOpenGLInterop::GetInteropType(vaapiid);
MythOpenGLInterop::Type type = MythOpenGLInterop::GetInteropType(FMT_VAAPI);
if (type == MythOpenGLInterop::Unsupported)
return -1;

Expand Down Expand Up @@ -386,6 +385,7 @@ int MythVAAPIContext::InitialiseContext(AVCodecContext *Context)

if (format != VA_FOURCC_NV12)
{
MythCodecID vaapiid = static_cast<MythCodecID>(kCodec_MPEG1_VAAPI + (mpeg_version(Context->codec_id) - 1));
LOG(VB_GENERAL, LOG_INFO, LOC + QString("Forcing surface format for %1 and %2 with driver '%3'")
.arg(toString(vaapiid)).arg(MythOpenGLInterop::TypeToString(type)).arg(vendor));
}
Expand Down
5 changes: 2 additions & 3 deletions mythtv/libs/libmythtv/decoders/mythvdpaucontext.cpp
Expand Up @@ -39,12 +39,11 @@ int MythVDPAUContext::InitialiseContext(AVCodecContext* Context)
// Lock
OpenGLLocker locker(render);

MythCodecID vdpauid = static_cast<MythCodecID>(kCodec_MPEG1_VDPAU + (mpeg_version(Context->codec_id) - 1));
MythOpenGLInterop::Type type = MythVDPAUInterop::GetInteropType(vdpauid, render);
if (type == MythOpenGLInterop::Unsupported)
if (MythOpenGLInterop::GetInteropType(FMT_VDPAU) == MythOpenGLInterop::Unsupported)
return -1;

// Create interop
MythCodecID vdpauid = static_cast<MythCodecID>(kCodec_MPEG1_VDPAU + (mpeg_version(Context->codec_id) - 1));
MythVDPAUInterop *interop = MythVDPAUInterop::Create(render, vdpauid);
if (!interop)
return -1;
Expand Down
3 changes: 1 addition & 2 deletions mythtv/libs/libmythtv/decoders/mythvtbcontext.cpp
Expand Up @@ -145,8 +145,7 @@ int MythVTBContext::InitialiseDecoder(AVCodecContext *Context)
// Lock
OpenGLLocker locker(render);

MythCodecID vtbid = static_cast<MythCodecID>(kCodec_MPEG1_VTB + (mpeg_version(Context->codec_id) - 1));
MythVTBInterop::Type type = MythVTBInterop::GetInteropType(vtbid, render);
MythVTBInterop::Type type = MythOpenGLInterop::GetInteropType(FMT_VTB, render);
if (type == MythOpenGLInterop::Unsupported)
return -1;

Expand Down
11 changes: 6 additions & 5 deletions mythtv/libs/libmythtv/opengl/mythdrmprimeinterop.cpp
Expand Up @@ -57,13 +57,14 @@ MythDRMPRIMEInterop* MythDRMPRIMEInterop::Create(MythRenderOpenGL *Context, Type
return nullptr;
}

MythOpenGLInterop::Type MythDRMPRIMEInterop::GetInteropType(MythCodecID CodecId, MythRenderOpenGL *Context)
MythOpenGLInterop::Type MythDRMPRIMEInterop::GetInteropType(VideoFrameType Format)
{
// TODO - this should be tied to pix_fmt (i.e. AV_PIX_FMT_DRM_PRIME) not codec.
// Probably applies to all interops
if (!(codec_is_v4l2(CodecId) || codec_is_drmprime(CodecId)))
if (FMT_DRMPRIME != Format)
return Unsupported;
return HaveDMABuf(Context) ? DRMPRIME : Unsupported;
MythRenderOpenGL* context = MythRenderOpenGL::GetOpenGLRender();
if (!context)
return Unsupported;
return HaveDMABuf(context) ? DRMPRIME : Unsupported;
}

AVDRMFrameDescriptor* MythDRMPRIMEInterop::VerifyBuffer(MythRenderOpenGL *Context, VideoFrame *Frame)
Expand Down
12 changes: 7 additions & 5 deletions mythtv/libs/libmythtv/opengl/mythdrmprimeinterop.h
Expand Up @@ -9,18 +9,20 @@ struct AVDRMFrameDescriptor;

class MythDRMPRIMEInterop : public MythOpenGLInterop, public MythEGLDMABUF
{
friend class MythOpenGLInterop;

public:
static MythDRMPRIMEInterop* Create(MythRenderOpenGL *Context, Type InteropType);
static Type GetInteropType(MythCodecID CodecId, MythRenderOpenGL *Context = nullptr);

MythDRMPRIMEInterop(MythRenderOpenGL *Context);
virtual ~MythDRMPRIMEInterop() override;

void DeleteTextures(void) override;
vector<MythVideoTexture*> Acquire(MythRenderOpenGL *Context,
VideoColourSpace *ColourSpace,
VideoFrame *Frame, FrameScanType Scan) override;

protected:
MythDRMPRIMEInterop(MythRenderOpenGL *Context);
virtual ~MythDRMPRIMEInterop() override;
static Type GetInteropType(VideoFrameType Format);

private:
AVDRMFrameDescriptor* VerifyBuffer(MythRenderOpenGL *Context, VideoFrame *Frame);
};
Expand Down
3 changes: 2 additions & 1 deletion mythtv/libs/libmythtv/opengl/mythmediacodecinterop.h
Expand Up @@ -15,14 +15,15 @@ class MythMediaCodecInterop : public MythOpenGLInterop
{
public:
static MythMediaCodecInterop* Create(MythRenderOpenGL *Context, QSize Size);
~MythMediaCodecInterop() override;

virtual vector<MythVideoTexture*> Acquire (MythRenderOpenGL *Context,
VideoColourSpace *ColourSpace,
VideoFrame *Frame, FrameScanType Scan) override;
void* GetSurface(void);

protected:
MythMediaCodecInterop(MythRenderOpenGL *Context);
~MythMediaCodecInterop() override;
bool Initialise(QSize Size);

private:
Expand Down
15 changes: 7 additions & 8 deletions mythtv/libs/libmythtv/opengl/mythmmalinterop.cpp
Expand Up @@ -22,18 +22,17 @@ MythMMALInterop::~MythMMALInterop()
LOG(VB_GENERAL, LOG_INFO, LOC + "Destructor");
}

MythOpenGLInterop::Type MythMMALInterop::GetInteropType(MythCodecID CodecId, MythRenderOpenGL *Context)
MythOpenGLInterop::Type MythMMALInterop::GetInteropType(VideoFrameType Format)
{
if (!codec_is_mmal(CodecId))
if (FMT_MMAL != Format)
return Unsupported;

if (!Context)
Context = MythRenderOpenGL::GetOpenGLRender();
if (!Context)
MythRenderOpenGL* context = MythRenderOpenGL::GetOpenGLRender();
if (!context)
return Unsupported;

OpenGLLocker locker(Context);
if (!Context->IsEGL())
OpenGLLocker locker(context);
if (!context->IsEGL())
return Unsupported;

// MMAL interop only works with the closed source driver
Expand All @@ -46,7 +45,7 @@ MythOpenGLInterop::Type MythMMALInterop::GetInteropType(MythCodecID CodecId, Myt
return Unsupported;
}

return Context->hasExtension("GL_OES_EGL_image") ? MMAL : Unsupported;
return context->hasExtension("GL_OES_EGL_image") ? MMAL : Unsupported;
}

MythMMALInterop* MythMMALInterop::Create(MythRenderOpenGL *Context, Type InteropType)
Expand Down
13 changes: 8 additions & 5 deletions mythtv/libs/libmythtv/opengl/mythmmalinterop.h
Expand Up @@ -12,17 +12,20 @@ extern "C" {

class MythMMALInterop : public MythOpenGLInterop
{
friend class MythOpenGLInterop;

public:
static MythMMALInterop* Create(MythRenderOpenGL *Context, Type InteropType);
static Type GetInteropType(MythCodecID CodecId, MythRenderOpenGL *Context = nullptr);

MythMMALInterop(MythRenderOpenGL *Context);
virtual ~MythMMALInterop() override;

virtual vector<MythVideoTexture*> Acquire(MythRenderOpenGL *Context,
VideoColourSpace *ColourSpace,
VideoFrame *Frame, FrameScanType Scan) override;

protected:
static Type GetInteropType(VideoFrameType Format);

MythMMALInterop(MythRenderOpenGL *Context);
virtual ~MythMMALInterop() override;

private:
MMAL_BUFFER_HEADER_T* VerifyBuffer(MythRenderOpenGL *Context, VideoFrame *Frame);
};
Expand Down
9 changes: 4 additions & 5 deletions mythtv/libs/libmythtv/opengl/mythnvdecinterop.cpp
Expand Up @@ -82,13 +82,12 @@ MythNVDECInterop* MythNVDECInterop::Create(MythRenderOpenGL *Context)
return nullptr;
}

MythOpenGLInterop::Type MythNVDECInterop::GetInteropType(MythCodecID CodecId, MythRenderOpenGL *Context)
MythOpenGLInterop::Type MythNVDECInterop::GetInteropType(VideoFrameType Format)
{
if (!codec_is_nvdec(CodecId) || !gCoreContext->IsUIThread())
if ((FMT_NVDEC != Format) || !gCoreContext->IsUIThread())
return Unsupported;
if (!Context)
Context = MythRenderOpenGL::GetOpenGLRender();
if (!Context)

if (!MythRenderOpenGL::GetOpenGLRender())
return Unsupported;
return NVDEC;
}
Expand Down
7 changes: 4 additions & 3 deletions mythtv/libs/libmythtv/opengl/mythnvdecinterop.h
Expand Up @@ -12,23 +12,24 @@ extern "C" {

class MythNVDECInterop : public MythOpenGLInterop
{
friend class MythOpenGLInterop;

public:
static MythNVDECInterop* Create(MythRenderOpenGL *Context);
static Type GetInteropType(MythCodecID CodecId, MythRenderOpenGL *Context = nullptr);
static bool CreateCUDAContext(MythRenderOpenGL *GLContext, CudaFunctions *&CudaFuncs,
CUcontext &CudaContext);
static void CleanupContext(MythRenderOpenGL *GLContext, CudaFunctions *&CudaFuncs,
CUcontext &CudaContext);

~MythNVDECInterop() override;

bool IsValid(void);
CUcontext GetCUDAContext(void);
vector<MythVideoTexture*> Acquire(MythRenderOpenGL *Context, VideoColourSpace *ColourSpace,
VideoFrame *Frame, FrameScanType Scan) override;

protected:
static Type GetInteropType(VideoFrameType Format);
MythNVDECInterop(MythRenderOpenGL *Context);
~MythNVDECInterop() override;

private:
bool InitialiseCuda(void);
Expand Down
90 changes: 60 additions & 30 deletions mythtv/libs/libmythtv/opengl/mythopenglinterop.cpp
Expand Up @@ -48,73 +48,103 @@ QString MythOpenGLInterop::TypeToString(Type InteropType)
return "Unsupported";
}

QStringList MythOpenGLInterop::GetAllowedRenderers(MythCodecID CodecId)
QStringList MythOpenGLInterop::GetAllowedRenderers(VideoFrameType Format)
{
QStringList result;
if (codec_sw_copy(CodecId))
return result;
if (GetInteropType(CodecId) != Unsupported)
if (GetInteropType(Format) != Unsupported)
result << "opengl-hw";
return result;
}

void MythOpenGLInterop::GetInteropTypeCallback(void *Wait, void *CodecId, void *Result)
void MythOpenGLInterop::GetInteropTypeCallback(void *Wait, void *Format, void *Result)
{
LOG(VB_PLAYBACK, LOG_INFO, LOC + "Check interop callback");
QWaitCondition *wait = reinterpret_cast<QWaitCondition*>(Wait);
MythCodecID *codecid = reinterpret_cast<MythCodecID*>(CodecId);
VideoFrameType *format = reinterpret_cast<VideoFrameType*>(Format);
MythOpenGLInterop::Type *result = reinterpret_cast<MythOpenGLInterop::Type*>(Result);

if (codecid && result)
*result = MythOpenGLInterop::GetInteropType(*codecid);
if (format && result)
*result = MythOpenGLInterop::GetInteropType(*format);
if (wait)
wait->wakeAll();
}

MythOpenGLInterop::Type MythOpenGLInterop::GetInteropType(MythCodecID CodecId)
/*! \brief Check whether we support direct rendering for the given VideoFrameType.
*
* \note GetInteropType is protected in all subclasses to ensure thread safety.
* The subclasses will fail this check if not called from the UI thread.
*/
MythOpenGLInterop::Type MythOpenGLInterop::GetInteropType(VideoFrameType Format)
{
// cache supported formats to avoid potentially expensive callbacks
static QMutex s_lock(QMutex::Recursive);
static QHash<VideoFrameType,Type> s_supported;

Type supported = Unsupported;
if (!gCoreContext->IsUIThread())
bool alreadychecked = false;

// have we checked this format already
s_lock.lock();
if (s_supported.contains(Format))
{
MythMainWindow::HandleCallback("interop check", MythOpenGLInterop::GetInteropTypeCallback,
&CodecId, &supported);
return supported;
supported = s_supported.value(Format);
alreadychecked = true;
}
s_lock.unlock();

// need to check
if (!alreadychecked)
{
if (!gCoreContext->IsUIThread())
{
MythMainWindow::HandleCallback("interop check", MythOpenGLInterop::GetInteropTypeCallback,
&Format, &supported);
return supported;
}

LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Checking interop support for %1")
.arg(format_description(Format)));

#ifdef USING_VTB
if (codec_is_vtb(CodecId))
supported = MythVTBInterop::GetInteropType(CodecId);
if (FMT_VTB == Format)
supported = MythVTBInterop::GetInteropType(Format);
#endif
#ifdef USING_VAAPI
if (codec_is_vaapi(CodecId))
supported = MythVAAPIInterop::GetInteropType(CodecId);
if (FMT_VAAPI == Format)
supported = MythVAAPIInterop::GetInteropType(Format);
#endif
#ifdef USING_MEDIACODEC
if (codec_is_mediacodec(CodecId))
supported = MEDIACODEC;
if (FMT_MEDIACODEC == Format)
supported = MEDIACODEC;
#endif
#ifdef USING_VDPAU
if (codec_is_vdpau_hw(CodecId))
supported = MythVDPAUInterop::GetInteropType(CodecId);
if (FMT_VDPAU == Format)
supported = MythVDPAUInterop::GetInteropType(Format);
#endif
#ifdef USING_NVDEC
if (codec_is_nvdec(CodecId))
supported = MythNVDECInterop::GetInteropType(CodecId);
if (FMT_NVDEC == Format)
supported = MythNVDECInterop::GetInteropType(Format);
#endif
#ifdef USING_MMAL
if (codec_is_mmal(CodecId))
supported = MythMMALInterop::GetInteropType(CodecId);
if (FMT_MMAL == Format)
supported = MythMMALInterop::GetInteropType(Format);
#endif
#ifdef USING_EGL
if (codec_is_v4l2(CodecId) || codec_is_drmprime(CodecId))
supported = MythDRMPRIMEInterop::GetInteropType(CodecId);
if (FMT_DRMPRIME == Format)
supported = MythDRMPRIMEInterop::GetInteropType(Format);
#endif
// update supported formats
s_lock.lock();
s_supported.insert(Format, supported);
s_lock.unlock();
}

if (Unsupported == supported)
LOG(VB_GENERAL, LOG_WARNING, LOC + QString("No render support for codec '%1'").arg(toString(CodecId)));
LOG(VB_GENERAL, LOG_WARNING, LOC + QString("No render support for frame type '%1'")
.arg(format_description(Format)));
else
LOG(VB_GENERAL, LOG_INFO, LOC + QString("Rendering supported for codec '%1' with %2")
.arg(toString(CodecId)).arg(TypeToString(supported)));
LOG(VB_GENERAL, LOG_INFO, LOC + QString("Rendering supported for frame type '%1' with %2")
.arg(format_description(Format)).arg(TypeToString(supported)));
return supported;
}

Expand Down

0 comments on commit 9f7ceac

Please sign in to comment.