mirror of
https://github.com/moonlight-stream/moonlight-qt.git
synced 2026-06-17 22:23:31 +00:00
Reuse the test decoder to improve startup performance
This commit is contained in:
@@ -190,6 +190,9 @@ public:
|
|||||||
// If the renderer doesn't provide an explicit test routine,
|
// If the renderer doesn't provide an explicit test routine,
|
||||||
// we will always assume that any returned AVFrame can be
|
// we will always assume that any returned AVFrame can be
|
||||||
// rendered successfully.
|
// rendered successfully.
|
||||||
|
//
|
||||||
|
// NB: The test frame passed to this callback may differ in
|
||||||
|
// dimensions from the actual video stream.
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -473,7 +473,7 @@ bool FFmpegVideoDecoder::completeInitialization(const AVCodec* decoder, enum AVP
|
|||||||
m_VideoFormat = params->videoFormat;
|
m_VideoFormat = params->videoFormat;
|
||||||
|
|
||||||
// Don't bother initializing Pacer if we're not actually going to render
|
// Don't bother initializing Pacer if we're not actually going to render
|
||||||
if (!testFrame) {
|
if (!m_TestOnly) {
|
||||||
m_Pacer = new Pacer(m_FrontendRenderer, &m_ActiveWndVideoStats);
|
m_Pacer = new Pacer(m_FrontendRenderer, &m_ActiveWndVideoStats);
|
||||||
if (!m_Pacer->initialize(params->window, params->frameRate,
|
if (!m_Pacer->initialize(params->window, params->frameRate,
|
||||||
params->enableFramePacing || (params->enableVsync && (m_FrontendRenderer->getRendererAttributes() & RENDERER_ATTRIBUTE_FORCE_PACING)))) {
|
params->enableFramePacing || (params->enableVsync && (m_FrontendRenderer->getRendererAttributes() & RENDERER_ATTRIBUTE_FORCE_PACING)))) {
|
||||||
@@ -662,8 +662,12 @@ bool FFmpegVideoDecoder::completeInitialization(const AVCodec* decoder, enum AVP
|
|||||||
}
|
}
|
||||||
|
|
||||||
av_frame_free(&frame);
|
av_frame_free(&frame);
|
||||||
|
|
||||||
|
// Flush the codec to prepare for the real stream
|
||||||
|
avcodec_flush_buffers(m_VideoDecoderCtx);
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
|
if (!m_TestOnly) {
|
||||||
if ((params->videoFormat & VIDEO_FORMAT_MASK_H264) &&
|
if ((params->videoFormat & VIDEO_FORMAT_MASK_H264) &&
|
||||||
!(m_BackendRenderer->getDecoderCapabilities() & CAPABILITY_REFERENCE_FRAME_INVALIDATION_AVC)) {
|
!(m_BackendRenderer->getDecoderCapabilities() & CAPABILITY_REFERENCE_FRAME_INVALIDATION_AVC)) {
|
||||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
@@ -1065,6 +1069,26 @@ IFFmpegRenderer* FFmpegVideoDecoder::createHwAccelRenderer(const AVCodecHWConfig
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool FFmpegVideoDecoder::isSeparateTestDecoderRequired(const AVCodec* decoder)
|
||||||
|
{
|
||||||
|
// We can generally reuse the test decoder for real rendering as long as
|
||||||
|
// the decoder can handle a change in surface sizes while streaming.
|
||||||
|
// We know v4l2m2m can't handle this (see comment below), so let's just
|
||||||
|
// opt-out all non-hwaccel decoders just to be safe.
|
||||||
|
if (qEnvironmentVariableIntValue("SEPARATE_TEST_DECODER")) {
|
||||||
|
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"Using separate test decoder due to environment variable");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (getAVCodecCapabilities(decoder) & AV_CODEC_CAP_HARDWARE) {
|
||||||
|
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"Using separate test decoder for non-hwaccel decoder");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool FFmpegVideoDecoder::tryInitializeRenderer(const AVCodec* decoder,
|
bool FFmpegVideoDecoder::tryInitializeRenderer(const AVCodec* decoder,
|
||||||
enum AVPixelFormat requiredFormat,
|
enum AVPixelFormat requiredFormat,
|
||||||
PDECODER_PARAMETERS params,
|
PDECODER_PARAMETERS params,
|
||||||
@@ -1073,17 +1097,20 @@ bool FFmpegVideoDecoder::tryInitializeRenderer(const AVCodec* decoder,
|
|||||||
std::function<IFFmpegRenderer*()> createRendererFunc)
|
std::function<IFFmpegRenderer*()> createRendererFunc)
|
||||||
{
|
{
|
||||||
DECODER_PARAMETERS testFrameDecoderParams = *params;
|
DECODER_PARAMETERS testFrameDecoderParams = *params;
|
||||||
|
bool separateTestDecoder = isSeparateTestDecoderRequired(decoder);
|
||||||
|
|
||||||
// Setup the test decoder parameters using the dimensions for the test frame. These are
|
if (separateTestDecoder) {
|
||||||
// used to populate the AVCodecContext fields of the same names.
|
// Setup the test decoder parameters using the dimensions for the test frame. These are
|
||||||
//
|
// used to populate the AVCodecContext fields of the same names.
|
||||||
// While most decoders don't care what dimensions we specify here, V4L2M2M seems to puke
|
//
|
||||||
// if we pass whatever the native stream resolution is then decode a 720p test frame.
|
// While most decoders don't care what dimensions we specify here, V4L2M2M seems to puke
|
||||||
//
|
// if we pass whatever the native stream resolution is then decode a 720p test frame.
|
||||||
// For qcom-venus, it seems to lead to failures allocating capture buffers (bug #1042).
|
//
|
||||||
// For wave5 (VisionFive), it leads to an invalid pitch error when calling drmModeAddFB2().
|
// For qcom-venus, it seems to lead to failures allocating capture buffers (bug #1042).
|
||||||
testFrameDecoderParams.width = 1280;
|
// For wave5 (VisionFive), it leads to an invalid pitch error when calling drmModeAddFB2().
|
||||||
testFrameDecoderParams.height = 720;
|
testFrameDecoderParams.width = 1280;
|
||||||
|
testFrameDecoderParams.height = 720;
|
||||||
|
}
|
||||||
|
|
||||||
m_HwDecodeCfg = hwConfig;
|
m_HwDecodeCfg = hwConfig;
|
||||||
|
|
||||||
@@ -1116,21 +1143,27 @@ bool FFmpegVideoDecoder::tryInitializeRenderer(const AVCodec* decoder,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The test worked, so now let's initialize it for real
|
if (separateTestDecoder) {
|
||||||
reset();
|
// The test worked, so now let's initialize it for real
|
||||||
|
reset();
|
||||||
|
|
||||||
if ((m_BackendRenderer = createRendererFunc()) == nullptr) {
|
if ((m_BackendRenderer = createRendererFunc()) == nullptr) {
|
||||||
// Out of memory
|
// Out of memory
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (initializeRendererInternal(m_BackendRenderer, params) &&
|
if (initializeRendererInternal(m_BackendRenderer, params) &&
|
||||||
completeInitialization(decoder, requiredFormat, params, false, i == 0 /* EGL/DRM */)) {
|
completeInitialization(decoder, requiredFormat, params, false, i == 0 /* EGL/DRM */)) {
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
SDL_LogCritical(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"Decoder failed to initialize after successful test");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
SDL_LogCritical(SDL_LOG_CATEGORY_APPLICATION,
|
// The test decoder can be used for real decoding
|
||||||
"Decoder failed to initialize after successful test");
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -79,6 +79,8 @@ private:
|
|||||||
|
|
||||||
bool initializeRendererInternal(IFFmpegRenderer* renderer, PDECODER_PARAMETERS params);
|
bool initializeRendererInternal(IFFmpegRenderer* renderer, PDECODER_PARAMETERS params);
|
||||||
|
|
||||||
|
static bool isSeparateTestDecoderRequired(const AVCodec* decoder);
|
||||||
|
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
void writeBuffer(PLENTRY entry, int& offset);
|
void writeBuffer(PLENTRY entry, int& offset);
|
||||||
|
|||||||
Reference in New Issue
Block a user