Skip to content

Commit ea5bc56

Browse files
committed
Add Studio realtime software H264 flag
1 parent abf9f86 commit ea5bc56

4 files changed

Lines changed: 29 additions & 12 deletions

File tree

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,8 @@ session, prints a unique `https://simdeck.djdev.me/simulator/...` URL, and keeps
8080
the outbound bridge alive until you press Ctrl-C. It uses hardware H.264 by
8181
default with realtime stream settings for remote viewing; pass `--low-latency`
8282
to switch to software H.264's low-latency profile for slower Macs or shared
83-
runners.
83+
runners. Pass `--software-h264` to keep the same realtime Studio stream profile
84+
but use the software H.264 encoder.
8485

8586
CLI commands automatically use the same warm daemon:
8687

cli/XCWH264Encoder.m

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -229,13 +229,13 @@ static CGSize XCWScaledDimensionsForSourceSize(int32_t width, int32_t height, XC
229229
return CGSizeZero;
230230
}
231231

232-
int32_t maximumDimension = XCWMaximumEncodedDimension;
233-
if (mode == XCWVideoEncoderModeH264Hardware && realtimeStreamMode) {
234-
maximumDimension = XCWMaximumRealtimeHardwareEncodedDimension;
235-
} else if (mode == XCWVideoEncoderModeH264Software) {
236-
maximumDimension = lowLatencyMode
237-
? XCWMaximumLowLatencySoftwareEncodedDimension
238-
: XCWMaximumSoftwareEncodedDimension;
232+
int32_t maximumDimension = realtimeStreamMode
233+
? XCWMaximumRealtimeHardwareEncodedDimension
234+
: XCWMaximumEncodedDimension;
235+
if (mode == XCWVideoEncoderModeH264Software && lowLatencyMode) {
236+
maximumDimension = XCWMaximumLowLatencySoftwareEncodedDimension;
237+
} else if (mode == XCWVideoEncoderModeH264Software && !realtimeStreamMode) {
238+
maximumDimension = XCWMaximumSoftwareEncodedDimension;
239239
}
240240
int32_t longestEdge = MAX(width, height);
241241
if (longestEdge <= maximumDimension) {
@@ -250,7 +250,7 @@ static CGSize XCWScaledDimensionsForSourceSize(int32_t width, int32_t height, XC
250250
static int32_t XCWAverageBitRateForDimensions(int32_t width, int32_t height, XCWVideoEncoderMode mode, BOOL lowLatencyMode, BOOL realtimeStreamMode) {
251251
int64_t bitsPerPixelBudget = XCWBitsPerPixelBudget;
252252
int64_t minimumAverageBitRate = XCWMinimumAverageBitRate;
253-
if (mode == XCWVideoEncoderModeH264Hardware && realtimeStreamMode) {
253+
if (realtimeStreamMode && !lowLatencyMode) {
254254
bitsPerPixelBudget = XCWRealtimeBitsPerPixelBudget;
255255
minimumAverageBitRate = XCWMinimumRealtimeAverageBitRate;
256256
} else if (mode == XCWVideoEncoderModeH264Software) {
@@ -521,14 +521,23 @@ - (NSUInteger)maximumInFlightFrameCountLocked {
521521
}
522522

523523
- (uint64_t)minimumSoftwareFrameIntervalUsLocked {
524+
if (_realtimeStreamMode && !_lowLatencyMode) {
525+
return XCWRealtimeHardwareMinimumFrameIntervalUs;
526+
}
524527
return _lowLatencyMode ? XCWLowLatencySoftwareMinimumFrameIntervalUs : XCWSoftwareMinimumFrameIntervalUs;
525528
}
526529

527530
- (uint64_t)initialSoftwareFrameIntervalUsLocked {
531+
if (_realtimeStreamMode && !_lowLatencyMode) {
532+
return XCWRealtimeHardwareInitialFrameIntervalUs;
533+
}
528534
return _lowLatencyMode ? XCWLowLatencySoftwareInitialFrameIntervalUs : XCWSoftwareInitialFrameIntervalUs;
529535
}
530536

531537
- (uint64_t)maximumSoftwareFrameIntervalUsLocked {
538+
if (_realtimeStreamMode && !_lowLatencyMode) {
539+
return XCWRealtimeHardwareMaximumFrameIntervalUs;
540+
}
532541
return _lowLatencyMode ? XCWLowLatencySoftwareMaximumFrameIntervalUs : XCWSoftwareMaximumFrameIntervalUs;
533542
}
534543

@@ -542,7 +551,10 @@ - (NSUInteger)softwareHealthyFrameWindowLocked {
542551

543552
- (int32_t)expectedFrameRateLocked {
544553
if (_encoderMode == XCWVideoEncoderModeH264Software) {
545-
return _lowLatencyMode ? XCWTargetLowLatencySoftwareFrameRate : XCWTargetSoftwareFrameRate;
554+
if (_lowLatencyMode) {
555+
return XCWTargetLowLatencySoftwareFrameRate;
556+
}
557+
return _realtimeStreamMode ? XCWTargetRealtimeHardwareFrameRate : XCWTargetSoftwareFrameRate;
546558
}
547559
if (_realtimeStreamMode) {
548560
return XCWTargetRealtimeHardwareFrameRate;

server/src/main.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,8 @@ enum StudioCommand {
435435
bind: IpAddr,
436436
#[arg(long)]
437437
low_latency: bool,
438+
#[arg(long, conflicts_with = "low_latency")]
439+
software_h264: bool,
438440
},
439441
}
440442

@@ -1403,12 +1405,13 @@ fn main() -> anyhow::Result<()> {
14031405
port,
14041406
bind,
14051407
low_latency,
1408+
software_h264,
14061409
} => expose_to_studio(StudioExposeOptions {
14071410
simulator,
14081411
studio_url,
14091412
port,
14101413
bind,
1411-
video_codec: if low_latency {
1414+
video_codec: if low_latency || software_h264 {
14121415
VideoCodecMode::H264Software
14131416
} else {
14141417
VideoCodecMode::H264

skills/simdeck/SKILL.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ run `simdeck studio expose "iPhone 17 Pro"` and keep that process running. It
4848
prints the unique Studio simulator URL. This defaults to hardware H.264; add
4949
`--low-latency` to use software H.264's low-latency profile. Studio expose uses
5050
realtime stream settings so remote viewers drop stale frames instead of building
51-
latency.
51+
latency. Add `--software-h264` to keep the same realtime Studio stream profile
52+
but encode with software H.264.
5253

5354
The local viewer gets the API token automatically. LAN browsers pair with the printed code before receiving the API cookie. Direct HTTP calls need `X-SimDeck-Token` or `Authorization: Bearer <token>`.
5455

0 commit comments

Comments
 (0)