Skip to content

Commit

Permalink
VideoOutputOpenGL: Check interop support when the input changes
Browse files Browse the repository at this point in the history
- VideoOutput::InputChanged is usually called from the decoder thread
and hence we need to initiate a callback into the UI thread to check for
interop support for the new video codec
- this is complicated by the decoder thread holding the osd and video
filters locks which block the UI thread and hence the callback does not
work.
- add a new MythMultiLocker class to pass the held locks to VideoOutput
so it can unlock and relock all held locks in a safe manner.
  • Loading branch information
mark-kendall committed Apr 29, 2019
1 parent f90e4e2 commit 2338457
Show file tree
Hide file tree
Showing 14 changed files with 92 additions and 27 deletions.
20 changes: 19 additions & 1 deletion mythtv/libs/libmythtv/mythopenglinterop.cpp
@@ -1,4 +1,8 @@
// Qt
#include <QWaitCondition>

// MythTV
#include "mythmainwindow.h"
#include "videooutbase.h"
#include "videocolourspace.h"
#include "mythrender_opengl.h"
Expand Down Expand Up @@ -63,12 +67,26 @@ QStringList MythOpenGLInterop::GetAllowedRenderers(MythCodecID CodecId)
return result;
}

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

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

MythOpenGLInterop::Type MythOpenGLInterop::GetInteropType(MythCodecID CodecId)
{
Type supported = Unsupported;
if (!gCoreContext->IsUIThread())
{
LOG(VB_GENERAL, LOG_ERR, LOC + "GetInteropType called from the wrong thread");
MythMainWindow::HandleCallback("interop check", MythOpenGLInterop::GetInteropTypeCallback,
&CodecId, &supported);
return supported;
}

Expand Down
1 change: 1 addition & 0 deletions mythtv/libs/libmythtv/mythopenglinterop.h
Expand Up @@ -41,6 +41,7 @@ class MythOpenGLInterop : public QObject, public ReferenceCounter

static QStringList GetAllowedRenderers (MythCodecID CodecId);
static Type GetInteropType (MythCodecID CodecId);
static void GetInteropTypeCallback(void *Wait, void *CodecId, void* Result);
static vector<MythVideoTexture*> Retrieve(MythRenderOpenGL *Context,
VideoColourSpace *ColourSpace,
VideoFrame *Frame,
Expand Down
38 changes: 29 additions & 9 deletions mythtv/libs/libmythtv/mythplayer.cpp
Expand Up @@ -122,6 +122,31 @@ static int toTrackType(int type)
return kTrackTypeUnknown;
}

MythMultiLocker::MythMultiLocker(std::initializer_list<QMutex*> Locks)
: m_locks(Locks)
{
Relock();
}

MythMultiLocker::~MythMultiLocker()
{
Unlock();
}

void MythMultiLocker::Unlock(void)
{
for (QVector<QMutex*>::const_reverse_iterator it = m_locks.crbegin(); it != m_locks.crend(); ++it)
if (*it)
(*it)->unlock();
}

void MythMultiLocker::Relock(void)
{
for (QVector<QMutex*>::const_iterator it = m_locks.cbegin(); it != m_locks.cend(); ++it)
if (*it)
(*it)->unlock();
}

MythPlayer::MythPlayer(PlayerFlags flags)
: playerFlags(flags),
decoder(nullptr), decoder_change_lock(QMutex::Recursive),
Expand Down Expand Up @@ -285,9 +310,7 @@ MythPlayer::~MythPlayer(void)
interactiveTV = nullptr;
}

QMutexLocker lk1(&osdLock);
QMutexLocker lk2(&vidExitLock);
QMutexLocker lk3(&videofiltersLock);
MythMultiLocker locker({&osdLock, &vidExitLock, &videofiltersLock});

if (osd)
{
Expand Down Expand Up @@ -586,15 +609,13 @@ void MythPlayer::ReinitVideo(void)

bool aspect_only = false;
{
QMutexLocker locker1(&osdLock);
QMutexLocker locker2(&vidExitLock);
QMutexLocker locker3(&videofiltersLock);
MythMultiLocker locker({&osdLock, &vidExitLock, &videofiltersLock});

videoOutput->SetVideoFrameRate(video_frame_rate);
float aspect = (forced_video_aspect > 0) ? forced_video_aspect :
video_aspect;
if (!videoOutput->InputChanged(video_dim, video_disp_dim, aspect,
decoder->GetVideoCodecID(), aspect_only))
decoder->GetVideoCodecID(), aspect_only, &locker))
{
LOG(VB_GENERAL, LOG_ERR, LOC +
"Failed to Reinitialize Video. Exiting..");
Expand Down Expand Up @@ -5753,8 +5774,7 @@ InteractiveTV *MythPlayer::GetInteractiveTV(void)
#ifdef USING_MHEG
if (!interactiveTV && itvEnabled && !FlagIsSet(kNoITV))
{
QMutexLocker locker1(&osdLock);
QMutexLocker locker2(&itvLock);
MythMultiLocker locker({&osdLock, &itvLock});
if (!interactiveTV && osd)
interactiveTV = new InteractiveTV(this);
}
Expand Down
15 changes: 15 additions & 0 deletions mythtv/libs/libmythtv/mythplayer.h
Expand Up @@ -119,6 +119,21 @@ class DecoderThread : public MThread
bool m_start_paused;
};

class MythMultiLocker
{
public:
MythMultiLocker(std::initializer_list<QMutex*> Locks);
MythMultiLocker() = delete;
~MythMultiLocker();

void Unlock(void);
void Relock(void);

private:
Q_DISABLE_COPY(MythMultiLocker)
QVector<QMutex*> m_locks;
};

class MTV_PUBLIC MythPlayer
{
Q_DECLARE_TR_FUNCTIONS(MythPlayer)
Expand Down
3 changes: 2 additions & 1 deletion mythtv/libs/libmythtv/videoout_d3d.cpp
Expand Up @@ -140,7 +140,8 @@ bool VideoOutputD3D::InputChanged(const QSize &video_dim_buf,
const QSize &video_dim_disp,
float aspect,
MythCodecID av_codec_id,
bool &aspect_only)
bool &aspect_only,
MythMultiLocker*)
{
QMutexLocker locker(&m_lock);

Expand Down
3 changes: 2 additions & 1 deletion mythtv/libs/libmythtv/videoout_d3d.h
Expand Up @@ -34,7 +34,8 @@ class VideoOutputD3D : public VideoOutput
const QSize &video_dim_disp,
float aspect,
MythCodecID av_codec_id,
bool &aspect_only) override; // VideoOutput
bool &aspect_only,
MythMultiLocker *Locks) override; // VideoOutput
void MoveResizeWindow(QRect new_rect) override {;} // VideoOutput
void UpdatePauseFrame(int64_t &disp_timecode) override; // VideoOutput
void DrawUnusedRects(bool) override {;} // VideoOutput
Expand Down
5 changes: 3 additions & 2 deletions mythtv/libs/libmythtv/videoout_null.cpp
Expand Up @@ -92,7 +92,8 @@ bool VideoOutputNull::InputChanged(const QSize &video_dim_buf,
const QSize &video_dim_disp,
float aspect,
MythCodecID av_codec_id,
bool &aspect_only)
bool &aspect_only,
MythMultiLocker* Locks)
{
LOG(VB_PLAYBACK, LOG_INFO,
QString("InputChanged(WxH = %1x%2, aspect = %3)")
Expand All @@ -117,7 +118,7 @@ bool VideoOutputNull::InputChanged(const QSize &video_dim_buf,
}

VideoOutput::InputChanged(video_dim_buf, video_dim_disp,
aspect, av_codec_id, aspect_only);
aspect, av_codec_id, aspect_only, Locks);
vbuffers.DeleteBuffers();

MoveResize();
Expand Down
3 changes: 2 additions & 1 deletion mythtv/libs/libmythtv/videoout_null.h
Expand Up @@ -25,7 +25,8 @@ class VideoOutputNull : public VideoOutput
const QSize &video_dim_disp,
float aspect,
MythCodecID av_codec_id,
bool &aspect_only) override; // VideoOutput
bool &aspect_only,
MythMultiLocker* Locks) override; // VideoOutput
void EmbedInWidget(const QRect &rect) override; // VideoOutput
void StopEmbedding(void) override; // VideoOutput
void DrawUnusedRects(bool sync = true) override; // VideoOutput
Expand Down
5 changes: 3 additions & 2 deletions mythtv/libs/libmythtv/videoout_omx.cpp
Expand Up @@ -479,7 +479,8 @@ bool VideoOutputOMX::InputChanged( // Return true if successful
const QSize &video_dim_disp, // video display size
float aspect, // w/h of presented video
MythCodecID av_codec_id, // video codec
bool &aspect_only ) // Out: true if aspect only changed
bool &aspect_only, // Out: true if aspect only changed
MythMultiLocker* Locks)
{
QSize cursize = window.GetVideoDim();

Expand Down Expand Up @@ -513,7 +514,7 @@ bool VideoOutputOMX::InputChanged( // Return true if successful
}

VideoOutput::InputChanged(video_dim_buf, video_dim_disp,
aspect, av_codec_id, aspect_only);
aspect, av_codec_id, aspect_only, Locks);

m_imagefx.Shutdown();
m_render.Shutdown();
Expand Down
2 changes: 1 addition & 1 deletion mythtv/libs/libmythtv/videoout_omx.h
Expand Up @@ -36,7 +36,7 @@ class VideoOutputOMX : public VideoOutput, private OMXComponentCtx

// VideoOutput overrides
bool Init(const QSize&, const QSize&, float, WId, const QRect&, MythCodecID) override;
bool InputChanged(const QSize&, const QSize&, float, MythCodecID, bool&) override;
bool InputChanged(const QSize&, const QSize&, float, MythCodecID, bool&, MythMultiLocker*) override;
void EmbedInWidget(const QRect&) override;
void StopEmbedding(void) override;
bool ApproveDeintFilter(const QString&) const override;
Expand Down
13 changes: 7 additions & 6 deletions mythtv/libs/libmythtv/videoout_opengl.cpp
Expand Up @@ -248,7 +248,8 @@ bool VideoOutputOpenGL::Init(const QSize &VideoDim, const QSize &VideoDispDim, f
}

bool VideoOutputOpenGL::InputChanged(const QSize &VideoDim, const QSize &VideoDispDim,
float Aspect, MythCodecID CodecId, bool &AspectOnly)
float Aspect, MythCodecID CodecId, bool &AspectOnly,
MythMultiLocker* Locks)
{
QSize currentvideodim = window.GetVideoDim();
QSize currentvideodispdim = window.GetVideoDispDim();
Expand All @@ -275,11 +276,11 @@ bool VideoOutputOpenGL::InputChanged(const QSize &VideoDim, const QSize &VideoDi
// fail fast if we don't know how to display the codec
if (!codec_sw_copy(CodecId))
{
if (!gCoreContext->IsUIThread())
{
LOG(VB_GENERAL, LOG_WARNING, LOC + "Cannot check interop support from this thread");
}
else if (MythOpenGLInterop::GetInteropType(CodecId) == MythOpenGLInterop::Unsupported)
// MythOpenGLInterop::GetInteropType will block if we don't release our current locks
Locks->Unlock();
MythOpenGLInterop::Type support = MythOpenGLInterop::GetInteropType(CodecId);
Locks->Relock();
if (support == MythOpenGLInterop::Unsupported)
{
LOG(VB_GENERAL, LOG_ERR, LOC + "New video codec is not supported.");
errorState = kError_Unknown;
Expand Down
3 changes: 2 additions & 1 deletion mythtv/libs/libmythtv/videoout_opengl.h
Expand Up @@ -27,7 +27,8 @@ class VideoOutputOpenGL : public VideoOutput
void Show(FrameScanType ) override;
void ClearAfterSeek(void) override;
bool InputChanged(const QSize &VideoDim, const QSize &VideoDispDim,
float Aspect, MythCodecID CodecId, bool &AspectOnly) override;
float Aspect, MythCodecID CodecId, bool &AspectOnly,
MythMultiLocker* Locks) override;
void UpdatePauseFrame(int64_t &DisplayTimecode) override;
void DrawUnusedRects(bool) override { }
void InitPictureAttributes(void) override;
Expand Down
3 changes: 2 additions & 1 deletion mythtv/libs/libmythtv/videooutbase.cpp
Expand Up @@ -667,7 +667,8 @@ bool VideoOutput::InputChanged(const QSize &video_dim_buf,
const QSize &video_dim_disp,
float aspect,
MythCodecID myth_codec_id,
bool &/*aspect_only*/)
bool &/*aspect_only*/,
MythMultiLocker*)
{
window.InputChanged(video_dim_buf, video_dim_disp, aspect);

Expand Down
5 changes: 4 additions & 1 deletion mythtv/libs/libmythtv/videooutbase.h
Expand Up @@ -43,6 +43,8 @@ struct ImgReSampleContext;
struct SwsContext;
}

class MythMultiLocker;

class VideoOutput
{
public:
Expand Down Expand Up @@ -96,7 +98,8 @@ class VideoOutput
const QSize &video_dim_disp,
float aspect,
MythCodecID myth_codec_id,
bool &aspect_changed);
bool &aspect_changed,
MythMultiLocker* Locks);

virtual void VideoAspectRatioChanged(float aspect);

Expand Down

0 comments on commit 2338457

Please sign in to comment.