diff --git a/app/streaming/session.cpp b/app/streaming/session.cpp index f1a33119..9d202cbb 100644 --- a/app/streaming/session.cpp +++ b/app/streaming/session.cpp @@ -819,6 +819,11 @@ private: emit m_Session->sessionFinished(m_Session->m_PortTestResults); } + // The video decoder must already be destroyed, since it could + // try to interact with APIs that can only be called between + // LiStartConnection() and LiStopConnection(). + SDL_assert(m_Session->m_VideoDecoder == nullptr); + // Finish cleanup of the connection state LiStopConnection(); @@ -1717,6 +1722,8 @@ DispatchDeferredCleanup: SDL_AtomicUnlock(&m_InputHandlerLock); // Destroy the decoder, since this must be done on the main thread + // NB: This must happen before LiStopConnection() for pull-based + // decoders. SDL_AtomicLock(&m_DecoderLock); delete m_VideoDecoder; m_VideoDecoder = nullptr; diff --git a/app/streaming/video/ffmpeg.cpp b/app/streaming/video/ffmpeg.cpp index 465bbe86..27d8529b 100644 --- a/app/streaming/video/ffmpeg.cpp +++ b/app/streaming/video/ffmpeg.cpp @@ -424,13 +424,15 @@ bool FFmpegVideoDecoder::completeInitialization(const AVCodec* decoder, PDECODER // Tell overlay manager to use this frontend renderer Session::get()->getOverlayManager().setOverlayRenderer(m_FrontendRenderer); - } - m_DecoderThread = SDL_CreateThread(FFmpegVideoDecoder::decoderThreadProcThunk, "FFDecoder", (void*)this); - if (m_DecoderThread == nullptr) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, - "Failed to create decoder thread: %s", SDL_GetError()); - return false; + // Only create the decoder thread when instantiating the decoder for real. It will use APIs from + // moonlight-common-c that can only be legally called with an established connection. + m_DecoderThread = SDL_CreateThread(FFmpegVideoDecoder::decoderThreadProcThunk, "FFDecoder", (void*)this); + if (m_DecoderThread == nullptr) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, + "Failed to create decoder thread: %s", SDL_GetError()); + return false; + } } return true;