Skip to content

Commit 00dffce

Browse files
committed
treat as 'max resolution' rather than fixed
1 parent 8889448 commit 00dffce

File tree

8 files changed

+81
-131
lines changed

8 files changed

+81
-131
lines changed

apps/desktop/src-tauri/src/general_settings.rs

Lines changed: 7 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -31,27 +31,6 @@ pub enum PostDeletionBehaviour {
3131
ReopenRecordingWindow,
3232
}
3333

34-
#[derive(Default, Serialize, Deserialize, Type, Debug, Clone, Copy, PartialEq, Eq)]
35-
#[serde(rename_all = "camelCase")]
36-
pub enum InstantModeResolution {
37-
#[default]
38-
Fhd1080,
39-
Hd720,
40-
Qhd1440,
41-
Uhd2160,
42-
}
43-
44-
impl InstantModeResolution {
45-
pub fn target_height(self) -> u32 {
46-
match self {
47-
Self::Hd720 => 720,
48-
Self::Fhd1080 => 1080,
49-
Self::Qhd1440 => 1440,
50-
Self::Uhd2160 => 2160,
51-
}
52-
}
53-
}
54-
5534
impl MainWindowRecordingStartBehaviour {
5635
pub fn perform(&self, window: &tauri::WebviewWindow) -> tauri::Result<()> {
5736
match self {
@@ -141,8 +120,8 @@ pub struct GeneralSettingsStore {
141120
pub excluded_windows: Vec<WindowExclusion>,
142121
#[serde(default)]
143122
pub delete_instant_recordings_after_upload: bool,
144-
#[serde(default)]
145-
pub instant_mode_resolution: InstantModeResolution,
123+
#[serde(default = "default_instant_mode_max_resolution")]
124+
pub instant_mode_max_resolution: u32,
146125
}
147126

148127
fn default_enable_native_camera_preview() -> bool {
@@ -162,6 +141,10 @@ fn default_true() -> bool {
162141
true
163142
}
164143

144+
fn default_instant_mode_max_resolution() -> u32 {
145+
1080
146+
}
147+
165148
fn default_server_url() -> String {
166149
std::option_env!("VITE_SERVER_URL")
167150
.unwrap_or("https://cap.so")
@@ -203,7 +186,7 @@ impl Default for GeneralSettingsStore {
203186
post_deletion_behaviour: PostDeletionBehaviour::DoNothing,
204187
excluded_windows: default_excluded_windows(),
205188
delete_instant_recordings_after_upload: false,
206-
instant_mode_resolution: InstantModeResolution::default(),
189+
instant_mode_max_resolution: 1920,
207190
}
208191
}
209192
}

apps/desktop/src-tauri/src/recording.rs

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,7 @@ use crate::{
4646
auth::AuthStore,
4747
create_screenshot,
4848
general_settings::{
49-
self, GeneralSettingsStore, InstantModeResolution, PostDeletionBehaviour,
50-
PostStudioRecordingBehaviour,
49+
self, GeneralSettingsStore, PostDeletionBehaviour, PostStudioRecordingBehaviour,
5150
},
5251
open_external_link,
5352
presets::PresetsStore,
@@ -467,6 +466,7 @@ pub async fn start_recording(
467466
Err(SendError::HandlerError(camera::LockFeedError::NoInput)) => None,
468467
Err(e) => return Err(e.to_string()),
469468
};
469+
470470
#[cfg(target_os = "macos")]
471471
let shareable_content = crate::platform::get_shareable_content()
472472
.await
@@ -539,13 +539,11 @@ pub async fn start_recording(
539539
inputs.capture_target.clone(),
540540
)
541541
.with_system_audio(inputs.capture_system_audio)
542-
.with_output_height(
542+
.with_max_output_size(
543543
general_settings
544544
.as_ref()
545-
.map(|settings| settings.instant_mode_resolution.target_height())
546-
.unwrap_or_else(|| {
547-
InstantModeResolution::default().target_height()
548-
}),
545+
.map(|settings| settings.instant_mode_max_resolution)
546+
.unwrap_or_else(|| 1920),
549547
);
550548

551549
#[cfg(target_os = "macos")]

apps/desktop/src/routes/(window-chrome)/settings/general.tsx

Lines changed: 15 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ import {
2929
commands,
3030
events,
3131
type GeneralSettingsStore,
32-
type InstantModeResolution,
3332
type MainWindowRecordingStartBehaviour,
3433
type PostDeletionBehaviour,
3534
type PostStudioRecordingBehaviour,
@@ -62,9 +61,7 @@ const getWindowOptionLabel = (window: CaptureWindow) => {
6261
return parts.join(" • ");
6362
};
6463

65-
type ExtendedGeneralSettingsStore = GeneralSettingsStore & {
66-
instantModeResolution?: InstantModeResolution;
67-
};
64+
type ExtendedGeneralSettingsStore = GeneralSettingsStore;
6865

6966
const createDefaultGeneralSettings = (): ExtendedGeneralSettingsStore => ({
7067
uploadIndividualFiles: false,
@@ -76,7 +73,7 @@ const createDefaultGeneralSettings = (): ExtendedGeneralSettingsStore => ({
7673
autoZoomOnClicks: false,
7774
custom_cursor_capture2: true,
7875
excludedWindows: [],
79-
instantModeResolution: "fhd1080",
76+
instantModeMaxResolution: 1920,
8077
});
8178

8279
const deriveInitialSettings = (
@@ -92,12 +89,12 @@ const deriveInitialSettings = (
9289
};
9390

9491
const INSTANT_MODE_RESOLUTION_OPTIONS = [
95-
{ value: "hd720", label: "720p", height: 720 },
96-
{ value: "fhd1080", label: "1080p", height: 1080 },
97-
{ value: "qhd1440", label: "1440p", height: 1440 },
98-
{ value: "uhd2160", label: "4K", height: 2160 },
92+
{ value: 1280, label: "720p", height: 720 },
93+
{ value: 1920, label: "1080p", height: 1080 },
94+
{ value: 2560, label: "1440p", height: 1440 },
95+
{ value: 3840, label: "4K", height: 2160 },
9996
] satisfies {
100-
value: InstantModeResolution;
97+
value: number;
10198
label: string;
10299
height: number;
103100
}[];
@@ -267,9 +264,6 @@ function Inner(props: { initialStore: GeneralSettingsStore | null }) {
267264
return data.filter(isWindowAvailable);
268265
});
269266

270-
const instantResolutionDescription =
271-
"Choose the resolution for Instant Mode recordings.";
272-
273267
const refreshAvailableWindows = async (): Promise<CaptureWindow[]> => {
274268
try {
275269
const refreshed = (await refetchWindows()) ?? windows() ?? [];
@@ -324,7 +318,6 @@ function Inner(props: { initialStore: GeneralSettingsStore | null }) {
324318
| MainWindowRecordingStartBehaviour
325319
| PostStudioRecordingBehaviour
326320
| PostDeletionBehaviour
327-
| InstantModeResolution
328321
| number,
329322
>(props: {
330323
label: string;
@@ -439,17 +432,11 @@ function Inner(props: { initialStore: GeneralSettingsStore | null }) {
439432

440433
<SettingGroup title="Recording">
441434
<SelectSettingItem
442-
label="Instant mode resolution"
443-
description={instantResolutionDescription}
444-
value={
445-
settings.instantModeResolution ??
446-
("fhd1080" as InstantModeResolution)
447-
}
435+
label="Instant mode max resolution"
436+
description="Choose the maximum resolution for Instant Mode recordings."
437+
value={settings.instantModeMaxResolution ?? 1920}
448438
onChange={(value) =>
449-
handleChange(
450-
"instantModeResolution",
451-
value as InstantModeResolution,
452-
)
439+
handleChange("instantModeMaxResolution", value)
453440
}
454441
options={INSTANT_MODE_RESOLUTION_OPTIONS.map((option) => ({
455442
text: option.label,
@@ -460,9 +447,7 @@ function Inner(props: { initialStore: GeneralSettingsStore | null }) {
460447
label="Recording countdown"
461448
description="Countdown before recording starts"
462449
value={settings.recordingCountdown ?? 0}
463-
onChange={(value) =>
464-
handleChange("recordingCountdown", value as number)
465-
}
450+
onChange={(value) => handleChange("recordingCountdown", value)}
466451
options={[
467452
{ text: "Off", value: 0 },
468453
{ text: "3 seconds", value: 3 },
@@ -475,10 +460,7 @@ function Inner(props: { initialStore: GeneralSettingsStore | null }) {
475460
description="The main window recording start behaviour"
476461
value={settings.mainWindowRecordingStartBehaviour ?? "close"}
477462
onChange={(value) =>
478-
handleChange(
479-
"mainWindowRecordingStartBehaviour",
480-
value as MainWindowRecordingStartBehaviour,
481-
)
463+
handleChange("mainWindowRecordingStartBehaviour", value)
482464
}
483465
options={[
484466
{ text: "Close", value: "close" },
@@ -490,10 +472,7 @@ function Inner(props: { initialStore: GeneralSettingsStore | null }) {
490472
description="The studio recording finish behaviour"
491473
value={settings.postStudioRecordingBehaviour ?? "openEditor"}
492474
onChange={(value) =>
493-
handleChange(
494-
"postStudioRecordingBehaviour",
495-
value as PostStudioRecordingBehaviour,
496-
)
475+
handleChange("postStudioRecordingBehaviour", value)
497476
}
498477
options={[
499478
{ text: "Open editor", value: "openEditor" },
@@ -507,12 +486,7 @@ function Inner(props: { initialStore: GeneralSettingsStore | null }) {
507486
label="After deleting recording behaviour"
508487
description="Should Cap reopen after deleting an in progress recording?"
509488
value={settings.postDeletionBehaviour ?? "doNothing"}
510-
onChange={(value) =>
511-
handleChange(
512-
"postDeletionBehaviour",
513-
value as PostDeletionBehaviour,
514-
)
515-
}
489+
onChange={(value) => handleChange("postDeletionBehaviour", value)}
516490
options={[
517491
{ text: "Do Nothing", value: "doNothing" },
518492
{

apps/desktop/src/utils/tauri.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,7 @@ export type ExportSettings = ({ format: "Mp4" } & Mp4ExportSettings) | ({ format
393393
export type FileType = "recording" | "screenshot"
394394
export type Flags = { captions: boolean }
395395
export type FramesRendered = { renderedCount: number; totalFrames: number; type: "FramesRendered" }
396-
export type GeneralSettingsStore = { instanceId?: string; uploadIndividualFiles?: boolean; hideDockIcon?: boolean; hapticsEnabled?: boolean; autoCreateShareableLink?: boolean; enableNotifications?: boolean; disableAutoOpenLinks?: boolean; hasCompletedStartup?: boolean; theme?: AppTheme; commercialLicense?: CommercialLicense | null; lastVersion?: string | null; windowTransparency?: boolean; postStudioRecordingBehaviour?: PostStudioRecordingBehaviour; mainWindowRecordingStartBehaviour?: MainWindowRecordingStartBehaviour; custom_cursor_capture2?: boolean; serverUrl?: string; recordingCountdown?: number | null; enableNativeCameraPreview: boolean; autoZoomOnClicks?: boolean; enableNewRecordingFlow: boolean; postDeletionBehaviour?: PostDeletionBehaviour; excludedWindows?: WindowExclusion[]; deleteInstantRecordingsAfterUpload?: boolean; instantModeResolution?: InstantModeResolution }
396+
export type GeneralSettingsStore = { instanceId?: string; uploadIndividualFiles?: boolean; hideDockIcon?: boolean; hapticsEnabled?: boolean; autoCreateShareableLink?: boolean; enableNotifications?: boolean; disableAutoOpenLinks?: boolean; hasCompletedStartup?: boolean; theme?: AppTheme; commercialLicense?: CommercialLicense | null; lastVersion?: string | null; windowTransparency?: boolean; postStudioRecordingBehaviour?: PostStudioRecordingBehaviour; mainWindowRecordingStartBehaviour?: MainWindowRecordingStartBehaviour; custom_cursor_capture2?: boolean; serverUrl?: string; recordingCountdown?: number | null; enableNativeCameraPreview: boolean; autoZoomOnClicks?: boolean; enableNewRecordingFlow: boolean; postDeletionBehaviour?: PostDeletionBehaviour; excludedWindows?: WindowExclusion[]; deleteInstantRecordingsAfterUpload?: boolean; instantModeMaxResolution?: number }
397397
export type GifExportSettings = { fps: number; resolution_base: XY<number>; quality: GifQuality | null }
398398
export type GifQuality = {
399399
/**
@@ -410,7 +410,6 @@ export type Hotkey = { code: string; meta: boolean; ctrl: boolean; alt: boolean;
410410
export type HotkeyAction = "startStudioRecording" | "startInstantRecording" | "stopRecording" | "restartRecording" | "openRecordingPicker" | "openRecordingPickerDisplay" | "openRecordingPickerWindow" | "openRecordingPickerArea" | "other"
411411
export type HotkeysConfiguration = { show: boolean }
412412
export type HotkeysStore = { hotkeys: { [key in HotkeyAction]: Hotkey } }
413-
export type InstantModeResolution = "fhd1080" | "hd720" | "qhd1440" | "uhd2160"
414413
export type InstantRecordingMeta = { recording: boolean } | { error: string } | { fps: number; sample_rate: number | null }
415414
export type JsonValue<T> = [T]
416415
export type LogicalBounds = { position: LogicalPosition; size: LogicalSize }

crates/recording/src/capture_pipeline.rs

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,7 @@ use crate::{
66
};
77
use anyhow::anyhow;
88
use cap_timestamp::Timestamps;
9-
use scap_targets::bounds::LogicalBounds;
109
use std::{path::PathBuf, sync::Arc};
11-
#[cfg(windows)]
12-
use windows::Graphics::SizeInt32;
1310

1411
pub trait MakeCapturePipeline: ScreenCaptureFormat + std::fmt::Debug + 'static {
1512
async fn make_studio_mode_pipeline(
@@ -25,7 +22,7 @@ pub trait MakeCapturePipeline: ScreenCaptureFormat + std::fmt::Debug + 'static {
2522
system_audio: Option<screen_capture::SystemAudioSourceConfig>,
2623
mic_feed: Option<Arc<MicrophoneFeedLock>>,
2724
output_path: PathBuf,
28-
scaled_output: Option<(u32, u32)>,
25+
output_resolution: (u32, u32),
2926
) -> anyhow::Result<OutputPipeline>
3027
where
3128
Self: Sized;
@@ -52,7 +49,7 @@ impl MakeCapturePipeline for screen_capture::CMSampleBufferCapture {
5249
system_audio: Option<screen_capture::SystemAudioSourceConfig>,
5350
mic_feed: Option<Arc<MicrophoneFeedLock>>,
5451
output_path: PathBuf,
55-
scaled_output: Option<(u32, u32)>,
52+
output_resolution: (u32, u32),
5653
) -> anyhow::Result<OutputPipeline> {
5754
let mut output = OutputPipeline::builder(output_path.clone())
5855
.with_video::<screen_capture::VideoSource>(screen_capture);
@@ -67,7 +64,7 @@ impl MakeCapturePipeline for screen_capture::CMSampleBufferCapture {
6764

6865
output
6966
.build::<AVFoundationMp4Muxer>(AVFoundationMp4MuxerConfig {
70-
output_height: scaled_output.map(|(_, height)| height),
67+
output_height: Some(output_resolution.1),
7168
})
7269
.await
7370
}
@@ -100,7 +97,7 @@ impl MakeCapturePipeline for screen_capture::Direct3DCapture {
10097
system_audio: Option<screen_capture::SystemAudioSourceConfig>,
10198
mic_feed: Option<Arc<MicrophoneFeedLock>>,
10299
output_path: PathBuf,
103-
scaled_output: Option<(u32, u32)>,
100+
output_resolution: (u32, u32),
104101
) -> anyhow::Result<OutputPipeline> {
105102
let d3d_device = screen_capture.d3d_device.clone();
106103
let mut output_builder = OutputPipeline::builder(output_path.clone())
@@ -121,9 +118,9 @@ impl MakeCapturePipeline for screen_capture::Direct3DCapture {
121118
bitrate_multiplier: 0.08f32,
122119
frame_rate: 30u32,
123120
d3d_device,
124-
output_size: scaled_output.map(|(w, h)| SizeInt32 {
125-
Width: w as i32,
126-
Height: h as i32,
121+
output_size: Some(windows::Graphics::SizeInt32 {
122+
Width: output_resolution.0 as i32,
123+
Height: output_resolution.1 as i32,
127124
}),
128125
})
129126
.await

0 commit comments

Comments
 (0)