Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option to enforce a minimum latency to improve frame pacing #1139

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions app/cli/commandlineparser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,7 @@ void StreamCommandLineParser::parse(const QStringList &args, StreamingPreference
parser.addChoiceOption("capture-system-keys", "capture system key combos", m_CaptureSysKeysModeMap.keys());
parser.addChoiceOption("video-codec", "video codec", m_VideoCodecMap.keys());
parser.addChoiceOption("video-decoder", "video decoder", m_VideoDecoderMap.keys());
parser.addValueOption("minimum-latency", "Minimum latency");

if (!parser.parse(args)) {
parser.showError(parser.errorText());
Expand Down Expand Up @@ -500,6 +501,13 @@ void StreamCommandLineParser::parse(const QStringList &args, StreamingPreference
preferences->videoDecoderSelection = mapValue(m_VideoDecoderMap, parser.getChoiceOptionValue("video-decoder"));
}

if (parser.isSet("minimum-latency")) {
preferences->minimumLatency = parser.getIntOption("minimum-latency");
if (!inRange(preferences->minimumLatency, 0, 50)) {
parser.showError("Minimum latency must be in range: 0 - 50");
}
}

// This method will not return and terminates the process if --version or
// --help is specified
parser.handleHelpAndVersionOptions();
Expand Down
39 changes: 39 additions & 0 deletions app/gui/SettingsView.qml
Original file line number Diff line number Diff line change
Expand Up @@ -812,6 +812,45 @@ Flickable {
ToolTip.visible: hovered
ToolTip.text: qsTr("Frame pacing reduces micro-stutter by delaying frames that come in too early")
}

Label {
width: parent.width
id: minimumLatencyTitle
text: qsTr("Minimum latency:")
font.pointSize: 12
wrapMode: Text.Wrap
}

Label {
width: parent.width
id: minimumLatencyDesc
text: qsTr("A lower bound on display latency. Set higher to account for more jitter in your connection, at the cost of increased display latency.")
font.pointSize: 9
wrapMode: Text.Wrap
}

Slider {
id: minimumLatencySlider

value: StreamingPreferences.minimumLatency

stepSize: 1
from : 0
to: 50

snapMode: "SnapOnRelease"
width: Math.min(minimumLatencyDesc.implicitWidth, parent.width)

onValueChanged: {
minimumLatencyTitle.text = qsTr("Minimum latency: %1 msec").arg(value)
StreamingPreferences.minimumLatency = value
}

Component.onCompleted: {
// Refresh the text after translations change
languageChanged.connect(onValueChanged)
}
}
}
}

Expand Down
3 changes: 3 additions & 0 deletions app/settings/streamingpreferences.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
#define SER_CAPTURESYSKEYS "capturesyskeys"
#define SER_KEEPAWAKE "keepawake"
#define SER_LANGUAGE "language"
#define SER_MINIMUMLATENCY "minimumlatency"

#define CURRENT_DEFAULT_VER 2

Expand Down Expand Up @@ -122,6 +123,7 @@ void StreamingPreferences::reload()
: UIDisplayMode::UI_MAXIMIZED)).toInt());
language = static_cast<Language>(settings.value(SER_LANGUAGE,
static_cast<int>(Language::LANG_AUTO)).toInt());
minimumLatency = settings.value(SER_MINIMUMLATENCY, 0).toInt();


// Perform default settings updates as required based on last default version
Expand Down Expand Up @@ -295,6 +297,7 @@ void StreamingPreferences::save()
settings.setValue(SER_SWAPFACEBUTTONS, swapFaceButtons);
settings.setValue(SER_CAPTURESYSKEYS, captureSysKeysMode);
settings.setValue(SER_KEEPAWAKE, keepAwake);
settings.setValue(SER_MINIMUMLATENCY, minimumLatency);
}

int StreamingPreferences::getDefaultBitrate(int width, int height, int fps)
Expand Down
5 changes: 4 additions & 1 deletion app/settings/streamingpreferences.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,8 @@ class StreamingPreferences : public QObject
Q_PROPERTY(bool swapFaceButtons MEMBER swapFaceButtons NOTIFY swapFaceButtonsChanged)
Q_PROPERTY(bool keepAwake MEMBER keepAwake NOTIFY keepAwakeChanged)
Q_PROPERTY(CaptureSysKeysMode captureSysKeysMode MEMBER captureSysKeysMode NOTIFY captureSysKeysModeChanged)
Q_PROPERTY(Language language MEMBER language NOTIFY languageChanged);
Q_PROPERTY(Language language MEMBER language NOTIFY languageChanged)
Q_PROPERTY(int minimumLatency MEMBER minimumLatency NOTIFY minimumLatencyChanged);

Q_INVOKABLE bool retranslate();

Expand Down Expand Up @@ -172,6 +173,7 @@ class StreamingPreferences : public QObject
UIDisplayMode uiDisplayMode;
Language language;
CaptureSysKeysMode captureSysKeysMode;
int minimumLatency;

signals:
void displayModeChanged();
Expand Down Expand Up @@ -204,6 +206,7 @@ class StreamingPreferences : public QObject
void captureSysKeysModeChanged();
void keepAwakeChanged();
void languageChanged();
void minimumLatencyChanged();

private:
QString getSuffixFromLanguage(Language lang);
Expand Down
20 changes: 11 additions & 9 deletions app/streaming/session.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,8 @@ void Session::clSetControllerLED(uint16_t controllerNumber, uint8_t r, uint8_t g

bool Session::chooseDecoder(StreamingPreferences::VideoDecoderSelection vds,
SDL_Window* window, int videoFormat, int width, int height,
int frameRate, bool enableVsync, bool enableFramePacing, bool testOnly, IVideoDecoder*& chosenDecoder)
int frameRate, bool enableVsync, bool enableFramePacing, bool testOnly, IVideoDecoder*& chosenDecoder,
int minimumLatency)
{
DECODER_PARAMETERS params;

Expand All @@ -274,6 +275,7 @@ bool Session::chooseDecoder(StreamingPreferences::VideoDecoderSelection vds,
params.enableFramePacing = enableFramePacing;
params.testOnly = testOnly;
params.vds = vds;
params.minimumLatency = minimumLatency;

SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
"V-sync %s",
Expand Down Expand Up @@ -376,7 +378,7 @@ void Session::getDecoderInfo(SDL_Window* window,
// Try an HEVC Main10 decoder first to see if we have HDR support
if (chooseDecoder(StreamingPreferences::VDS_FORCE_HARDWARE,
window, VIDEO_FORMAT_H265_MAIN10, 1920, 1080, 60,
false, false, true, decoder)) {
false, false, true, decoder, 0)) {
isHardwareAccelerated = decoder->isHardwareAccelerated();
isFullScreenOnly = decoder->isAlwaysFullScreen();
isHdrSupported = decoder->isHdrSupported();
Expand All @@ -389,7 +391,7 @@ void Session::getDecoderInfo(SDL_Window* window,
// Try an AV1 Main10 decoder next to see if we have HDR support
if (chooseDecoder(StreamingPreferences::VDS_FORCE_HARDWARE,
window, VIDEO_FORMAT_AV1_MAIN10, 1920, 1080, 60,
false, false, true, decoder)) {
false, false, true, decoder, 0)) {
// If we've got a working AV1 Main 10-bit decoder, we'll enable the HDR checkbox
// but we will still continue probing to get other attributes for HEVC or H.264
// decoders. See the AV1 comment at the top of the function for more info.
Expand All @@ -405,7 +407,7 @@ void Session::getDecoderInfo(SDL_Window* window,
// Try a regular hardware accelerated HEVC decoder now
if (chooseDecoder(StreamingPreferences::VDS_FORCE_HARDWARE,
window, VIDEO_FORMAT_H265, 1920, 1080, 60,
false, false, true, decoder)) {
false, false, true, decoder, 0)) {
isHardwareAccelerated = decoder->isHardwareAccelerated();
isFullScreenOnly = decoder->isAlwaysFullScreen();
maxResolution = decoder->getDecoderMaxResolution();
Expand All @@ -418,7 +420,7 @@ void Session::getDecoderInfo(SDL_Window* window,
#if 0 // See AV1 comment at the top of this function
if (chooseDecoder(StreamingPreferences::VDS_FORCE_HARDWARE,
window, VIDEO_FORMAT_AV1_MAIN8, 1920, 1080, 60,
false, false, true, decoder)) {
false, false, true, decoder, 0)) {
isHardwareAccelerated = decoder->isHardwareAccelerated();
isFullScreenOnly = decoder->isAlwaysFullScreen();
maxResolution = decoder->getDecoderMaxResolution();
Expand All @@ -432,7 +434,7 @@ void Session::getDecoderInfo(SDL_Window* window,
// This will fall back to software decoding, so it should always work.
if (chooseDecoder(StreamingPreferences::VDS_AUTO,
window, VIDEO_FORMAT_H264, 1920, 1080, 60,
false, false, true, decoder)) {
false, false, true, decoder, 0)) {
isHardwareAccelerated = decoder->isHardwareAccelerated();
isFullScreenOnly = decoder->isAlwaysFullScreen();
maxResolution = decoder->getDecoderMaxResolution();
Expand All @@ -451,7 +453,7 @@ bool Session::isHardwareDecodeAvailable(SDL_Window* window,
{
IVideoDecoder* decoder;

if (!chooseDecoder(vds, window, videoFormat, width, height, frameRate, false, false, true, decoder)) {
if (!chooseDecoder(vds, window, videoFormat, width, height, frameRate, false, false, true, decoder, 0)) {
return false;
}

Expand Down Expand Up @@ -489,7 +491,7 @@ bool Session::populateDecoderProperties(SDL_Window* window)
m_StreamConfig.width,
m_StreamConfig.height,
m_StreamConfig.fps,
false, false, true, decoder)) {
false, false, true, decoder, 0)) {
return false;
}

Expand Down Expand Up @@ -1974,7 +1976,7 @@ void Session::execInternal()
enableVsync,
enableVsync && m_Preferences->framePacing,
false,
s_ActiveSession->m_VideoDecoder)) {
s_ActiveSession->m_VideoDecoder, m_Preferences->minimumLatency)) {
SDL_AtomicUnlock(&m_DecoderLock);
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"Failed to recreate decoder after reset");
Expand Down
2 changes: 1 addition & 1 deletion app/streaming/session.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ class Session : public QObject
SDL_Window* window, int videoFormat, int width, int height,
int frameRate, bool enableVsync, bool enableFramePacing,
bool testOnly,
IVideoDecoder*& chosenDecoder);
IVideoDecoder*& chosenDecoder, int mimimumLatency);

static
void clStageStarting(int stage);
Expand Down
1 change: 1 addition & 0 deletions app/streaming/video/decoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ typedef struct _DECODER_PARAMETERS {
bool enableVsync;
bool enableFramePacing;
bool testOnly;
int minimumLatency;
} DECODER_PARAMETERS, *PDECODER_PARAMETERS;

class IVideoDecoder {
Expand Down
Loading