Skip to content

Commit 3d52c09

Browse files
fix: restore 4K integer mode; drop 3.6K preset; clarify bitrate
Keep fractional NTSC out of 4K launch mode to avoid C5 black screen, remove the 3.6K resolution preset now that native 4K is the path, and document that bitrates above 250 Mbps rarely help and can increase loss. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent bac4c22 commit 3d52c09

7 files changed

Lines changed: 26 additions & 16 deletions

File tree

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ Unofficial fork of [Moonlight TV](https://github.com/mariotaku/moonlight-tv) for
77
## Highlights
88

99
- **AMOLED layout** — pure black background, dark surfaces, violet accent.
10-
- **3.6K (3584×2016)** — between 2K and 4K; strong quality with less decoder load than native 4K.
10+
- **Native 4K (3840×2160)** streaming with HDR10 when supported.
1111
- **HDR10 (PQ)** over HEVC Main10 (when supported).
12-
- Up to **300 Mbps** bitrate; **~270 Mbps** is a practical ceiling on stable 5 GHz Wi‑Fi for 3.6K HDR 120 Hz.
12+
- Bitrate slider up to **300 Mbps**; above **250 Mbps** there is usually no visible gain and packet loss becomes more likely as the link becomes less stable.
1313
- **Performance stats overlay**, **full on-screen keyboard**, and **virtual mouse** during streaming.
1414

1515
## Screenshots
@@ -28,10 +28,10 @@ Unofficial fork of [Moonlight TV](https://github.com/mariotaku/moonlight-tv) for
2828

2929
| Setting | Suggestion |
3030
|---------|------------|
31-
| Resolution | **3.6K** (3584×2016) |
31+
| Resolution | **4K** (3840×2160) |
3232
| FPS | 60 or 120 |
3333
| Codec | HEVC (H.265) |
34-
| Bitrate | Start at **120–180 Mbps**; raise toward **~270 Mbps** on a stable link |
34+
| Bitrate | Start at **120–180 Mbps**; stay at or below **250 Mbps** for a stable link. Higher values rarely help and can increase packet loss. |
3535

3636
## Streaming controls
3737

core/libgamestream/src/client.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -488,9 +488,14 @@ static void append_launch_mode_param(char *url, size_t url_len, int width, int h
488488
int client_refresh_x100, bool is_gfe) {
489489
/* Apollo and several Sunshine forks parse the third mode component with atof() and
490490
* store refresh rate in millihertz (119.88 -> 119880). Sending an integer (120) makes
491-
* them run at exactly 120 Hz even when clientRefreshRateX100 carries 11988. */
491+
* them run at exactly 120 Hz even when clientRefreshRateX100 carries 11988.
492+
*
493+
* At native 4K, a fractional mode string (e.g. 3840x2160x119.88) produces a black video
494+
* plane on some LG webOS sets (C5). Keep mode integer at 4K; clientRefreshRateX100 is
495+
* still sent separately for encode pacing when NTSC is enabled. */
492496
const bool fractional = !is_gfe && client_refresh_x100 > 0 && (client_refresh_x100 % 100) != 0;
493-
if (fractional) {
497+
const bool uhd_4k = width >= 3840 && height >= 2160;
498+
if (fractional && !uhd_4k) {
494499
append_param(url, url_len, "mode", "%dx%dx%d.%02d", width, height,
495500
client_refresh_x100 / 100, client_refresh_x100 % 100);
496501
} else {

docs/superpowers/specs/2026-07-19-c5-4k-latency-and-v1.1.4-design.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ Limelight → session_video Feed
6262
5. **SS4S API** `SS4S_PlayerGetVideoRenderQueueLength(player, int *length)` → false if unsupported.
6363
6. **Overlay**: Starfish `RQ` was prototyped then dropped from the compact overlay (symbol unavailable on device → always `-`). Compact stats show a single FPS plus audio layout (Stereo / 5.1) instead.
6464
7. Keep Smooth PTS / host PTS mapping as in v1.1.3.
65-
8. **4K + NTSC:** launch `mode=` may carry fractional NTSC (e.g. `3840x2160x119.88`) when the option is enabled; `clientRefreshRateX100` is also sent for encode pacing.
65+
8. **4K + NTSC:** launch `mode=` stays integer at 4K (avoids black screen on C5); `clientRefreshRateX100` still carries NTSC for encode pacing.
6666

6767
## Phase B — Soft recovery (after C5 RQ validation)
6868

src/app/app_settings.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,6 @@ extern const size_t audio_config_len;
103103
#define RES_720P RES_MERGE(1280, 720)
104104
#define RES_1080P RES_MERGE(1920, 1080)
105105
#define RES_1440P RES_MERGE(2560, 1440)
106-
/** ~90% of 4K (3584×2016); stable on recent LG TVs without full-4K input delay */
107-
#define RES_3_6K RES_MERGE(3584, 2016)
108106
#define RES_1800P RES_MERGE(3200, 1800)
109107
#define RES_4K RES_MERGE(3840, 2160)
110108

src/app/ui/settings/panes/basic.pane.c

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -152,9 +152,11 @@ static lv_obj_t *create_obj(lv_fragment_t *self, lv_obj_t *container) {
152152
&app_configuration->use_ntsc_refresh, false);
153153
lv_obj_add_event_cb(ntsc_checkbox, on_ntsc_refresh_changed, LV_EVENT_VALUE_CHANGED, self);
154154
pref_desc_label(view,
155-
locstr("When enabled, 60/120 FPS presets use fractional NTSC pacing (59.94/119.88), "
156-
"including at 4K. When disabled, presets use integer 60/120 like Moonlight mobile. "
157-
"Custom FPS still allows any fractional rate."),
155+
locstr("When enabled, 60/120 FPS presets use fractional NTSC pacing (59.94/119.88). "
156+
"When disabled, presets use integer 60/120 like Moonlight mobile. "
157+
"At 4K the host virtual-display mode stays integer (120) to avoid a black "
158+
"screen on some webOS TVs; NTSC is still sent as clientRefreshRateX100 for "
159+
"encode pacing. Custom FPS still allows any fractional rate."),
158160
false);
159161

160162
pref_desc_label(view,
@@ -264,8 +266,14 @@ static void update_bitrate_label(basic_pane_t *pane) {
264266

265267
static void update_bitrate_hint(basic_pane_t *pane) {
266268
app_t *app = pane->parent->app;
267-
if (app->ss4s.video_cap.suggestedBitrate > 0 &&
268-
app_configuration->stream.bitrate > app->ss4s.video_cap.suggestedBitrate) {
269+
const int bitrate = app_configuration->stream.bitrate;
270+
if (bitrate > 250000) {
271+
lv_obj_clear_flag(pane->bitrate_warning, LV_OBJ_FLAG_HIDDEN);
272+
lv_label_set_text_static(pane->bitrate_warning,
273+
locstr("Above 250 Mbps usually brings no quality gain and can cause "
274+
"packet loss as the connection becomes less stable."));
275+
} else if (app->ss4s.video_cap.suggestedBitrate > 0 &&
276+
bitrate > app->ss4s.video_cap.suggestedBitrate) {
269277
lv_obj_clear_flag(pane->bitrate_warning, LV_OBJ_FLAG_HIDDEN);
270278
lv_label_set_text_static(pane->bitrate_warning, locstr("Higher bitrate may cause performance issue, "
271279
"try with caution."));

src/app/ui/settings/panes/pref_res.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ static const resolution_pair_t built_in_resolutions[] = {
3939
{1280, 720, true, NULL},
4040
{1920, 1080, false, NULL},
4141
{2560, 1440, false, NULL},
42-
{3584, 2016, false, "3.6K"},
4342
{3840, 2160, false, NULL},
4443
};
4544

src/app/ui/settings/panes/video.pane.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ static lv_obj_t *create_obj(lv_fragment_t *self, lv_obj_t *container) {
166166
pref_desc_label(view,
167167
locstr("Stamp video presentation timestamps on a steady frame grid instead of "
168168
"wall-clock feed time. Reduces hitching when camera pans at high bitrate "
169-
"(e.g. 3.6K HDR HEVC). Disable only for A/B comparison."),
169+
"(e.g. 4K HDR HEVC). Disable only for A/B comparison."),
170170
false);
171171
pref_checkbox(view, locstr("Pause at decode time (Starfish)"), &app_configuration->pause_at_decode_time, false);
172172
pref_desc_label(view,

0 commit comments

Comments
 (0)