Skip to content

Commit 134f9ed

Browse files
committed
Better support for fractional framerates
1 parent 5f22801 commit 134f9ed

3 files changed

Lines changed: 51 additions & 1 deletion

File tree

src/Limelight.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ typedef struct _STREAM_CONFIGURATION {
7676

7777
// If specified, the client's display refresh rate x 100. For example,
7878
// 59.94 Hz would be specified as 5994. This is used by recent versions
79-
// of GFE for enhanced frame pacing.
79+
// of GFE for enhanced frame pacing. Ignored by Sunshine.
8080
int clientRefreshRateX100;
8181

8282
// If specified, sets the encoder colorspace to the provided COLORSPACE_*
@@ -100,11 +100,23 @@ typedef struct _STREAM_CONFIGURATION {
100100
// in /launch and /resume requests.
101101
char remoteInputAesKey[16];
102102
char remoteInputAesIv[16];
103+
104+
// Fractional frame rate of the video stream (in the form of numerator
105+
// and denominator). Supported by recent versions of Sunshine.
106+
// The non-fractional frame rate still needs to be specified for backward
107+
// compatibility. LiConvertFloatingPointFrameRateToFraction() can be used for
108+
// converting floating-point frame rates to this representation.
109+
int fpsNum;
110+
int fpsDen;
103111
} STREAM_CONFIGURATION, *PSTREAM_CONFIGURATION;
104112

105113
// Use this function to zero the stream configuration when allocated on the stack or heap
106114
void LiInitializeStreamConfiguration(PSTREAM_CONFIGURATION streamConfig);
107115

116+
// Use this function to convert floating-point frame rates to fractional frame
117+
// rates (in the form of numerator and denominator) while trying to maximize precision.
118+
void LiConvertFloatingPointFrameRateToFraction(double value, int* outNum, int* outDen);
119+
108120
// These identify codec configuration data in the buffer lists
109121
// of frames identified as IDR frames for H.264 and HEVC formats.
110122
// For other codecs, all data is marked as BUFFER_TYPE_PICDATA.

src/Misc.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#include "Limelight-internal.h"
22

3+
#include <math.h>
4+
35
#define ENET_INTERNAL_TIMEOUT_MS 100
46

57
// This function wraps enet_host_service() and hides the fact that it must be called
@@ -128,6 +130,33 @@ void LiInitializeStreamConfiguration(PSTREAM_CONFIGURATION streamConfig) {
128130
memset(streamConfig, 0, sizeof(*streamConfig));
129131
}
130132

133+
void LiConvertFloatingPointFrameRateToFraction(double value, int* outNum, int* outDen) {
134+
if (fabs(value) < 1.0) {
135+
// Unrealistic scenario, we don't care about perfect precision
136+
*outNum = round(INT32_MAX * value);
137+
*outDen = INT32_MAX;
138+
}
139+
else if (fabs(value) > 1000.0) {
140+
// Unrealistic scenario, we don't care about perfect precision
141+
*outNum = INT32_MAX;
142+
*outDen = round(INT32_MAX / value);
143+
}
144+
else {
145+
// Try different numerators for the best precision
146+
double maxError = 1.0;
147+
for (int i = 0; i < value; ++i) {
148+
int num = INT32_MAX - i;
149+
int den = round(num / value);
150+
double error = fabs((double)num / den - value);
151+
if (error < maxError) {
152+
maxError = error;
153+
*outNum = num;
154+
*outDen = den;
155+
}
156+
}
157+
}
158+
}
159+
131160
void LiInitializeVideoCallbacks(PDECODER_RENDERER_CALLBACKS drCallbacks) {
132161
memset(drCallbacks, 0, sizeof(*drCallbacks));
133162
}

src/SdpGenerator.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,15 @@ static PSDP_OPTION getAttributesList(char*urlSafeAddr) {
309309
else {
310310
err |= addAttributeString(&optionHead, "x-ss-video[0].chromaSamplingType", "0");
311311
}
312+
313+
// Specify fractional frame rate if requested
314+
if (StreamConfig.fpsNum > 0 && StreamConfig.fpsDen > 0) {
315+
snprintf(payloadStr, sizeof(payloadStr), "%d", StreamConfig.fpsNum);
316+
err |= addAttributeString(&optionHead, "x-ml-video.targetFrameRateNum", payloadStr);
317+
318+
snprintf(payloadStr, sizeof(payloadStr), "%d", StreamConfig.fpsDen);
319+
err |= addAttributeString(&optionHead, "x-ml-video.targetFrameRateDen", payloadStr);
320+
}
312321
}
313322

314323
snprintf(payloadStr, sizeof(payloadStr), "%d", StreamConfig.width);

0 commit comments

Comments
 (0)