Skip to content

Commit 4b7d1e0

Browse files
Merge pull request #1489 from CapSoftware/recording-bits
Ensure even video dimensions and improve recording pipeline robustness
2 parents 91d35a2 + 6ef9230 commit 4b7d1e0

File tree

8 files changed

+648
-191
lines changed

8 files changed

+648
-191
lines changed

apps/desktop/src/utils/queries.ts

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {
77
useQuery,
88
} from "@tanstack/solid-query";
99
import { getCurrentWindow } from "@tauri-apps/api/window";
10-
import { createEffect, createMemo, onCleanup } from "solid-js";
10+
import { batch, createEffect, createMemo, onCleanup } from "solid-js";
1111
import { createStore, reconcile } from "solid-js/store";
1212
import { useRecordingOptions } from "~/routes/(window-chrome)/OptionsContext";
1313
import {
@@ -170,20 +170,29 @@ export function createOptionsQuery() {
170170
if (e.key === PERSIST_KEY) _setState(JSON.parse(e.newValue ?? "{}"));
171171
});
172172

173+
let initialized = false;
174+
175+
recordingSettingsStore.get().then((data) => {
176+
batch(() => {
177+
if (data?.mode && data.mode !== _state.mode) {
178+
_setState("mode", data.mode);
179+
}
180+
initialized = true;
181+
});
182+
});
183+
173184
createEffect(() => {
174-
recordingSettingsStore.set({
185+
const settings = {
175186
target: _state.captureTarget,
176187
micName: _state.micName,
177188
cameraId: _state.cameraID,
178189
mode: _state.mode,
179190
systemAudio: _state.captureSystemAudio,
180191
organizationId: _state.organizationId,
181-
});
182-
});
192+
};
183193

184-
recordingSettingsStore.get().then((data) => {
185-
if (data?.mode && data.mode !== _state.mode) {
186-
_setState("mode", data.mode);
194+
if (initialized) {
195+
recordingSettingsStore.set(settings);
187196
}
188197
});
189198

crates/enc-ffmpeg/src/video/h264.rs

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::{thread, time::Duration};
22

3-
use cap_media_info::{Pixel, VideoInfo};
3+
use cap_media_info::{Pixel, VideoInfo, ensure_even};
44
use ffmpeg::{
55
Dictionary,
66
codec::{codec::Codec, context, encoder},
@@ -90,15 +90,21 @@ impl H264EncoderBuilder {
9090
output: &mut format::context::Output,
9191
) -> Result<H264Encoder, H264EncoderError> {
9292
let input_config = self.input_config;
93-
let (output_width, output_height) = self
93+
let (raw_width, raw_height) = self
9494
.output_size
9595
.unwrap_or((input_config.width, input_config.height));
9696

97-
if output_width == 0 || output_height == 0 {
98-
return Err(H264EncoderError::InvalidOutputDimensions {
99-
width: output_width,
100-
height: output_height,
101-
});
97+
let output_width = ensure_even(raw_width);
98+
let output_height = ensure_even(raw_height);
99+
100+
if raw_width != output_width || raw_height != output_height {
101+
warn!(
102+
raw_width,
103+
raw_height,
104+
output_width,
105+
output_height,
106+
"Auto-adjusted odd dimensions to even for H264 encoding"
107+
);
102108
}
103109

104110
let candidates = get_codec_and_options(&input_config, self.preset);

crates/enc-ffmpeg/src/video/hevc.rs

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::{thread, time::Duration};
22

3-
use cap_media_info::{Pixel, VideoInfo};
3+
use cap_media_info::{Pixel, VideoInfo, ensure_even};
44
use ffmpeg::{
55
Dictionary,
66
codec::{codec::Codec, context, encoder},
@@ -9,7 +9,7 @@ use ffmpeg::{
99
frame,
1010
threading::Config,
1111
};
12-
use tracing::{debug, error, trace};
12+
use tracing::{debug, error, trace, warn};
1313

1414
use crate::base::EncoderBase;
1515

@@ -89,15 +89,21 @@ impl HevcEncoderBuilder {
8989
output: &mut format::context::Output,
9090
) -> Result<HevcEncoder, HevcEncoderError> {
9191
let input_config = self.input_config;
92-
let (output_width, output_height) = self
92+
let (raw_width, raw_height) = self
9393
.output_size
9494
.unwrap_or((input_config.width, input_config.height));
9595

96-
if output_width == 0 || output_height == 0 {
97-
return Err(HevcEncoderError::InvalidOutputDimensions {
98-
width: output_width,
99-
height: output_height,
100-
});
96+
let output_width = ensure_even(raw_width);
97+
let output_height = ensure_even(raw_height);
98+
99+
if raw_width != output_width || raw_height != output_height {
100+
warn!(
101+
raw_width,
102+
raw_height,
103+
output_width,
104+
output_height,
105+
"Auto-adjusted odd dimensions to even for HEVC encoding"
106+
);
101107
}
102108

103109
let candidates = get_codec_and_options(&input_config, self.preset);

crates/media-info/src/lib.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,11 @@ impl VideoInfo {
325325
}
326326
}
327327

328+
pub fn ensure_even(value: u32) -> u32 {
329+
let adjusted = value - (value % 2);
330+
if adjusted == 0 { 2 } else { adjusted }
331+
}
332+
328333
pub fn ffmpeg_sample_format_for(sample_format: SampleFormat) -> Option<Sample> {
329334
match sample_format {
330335
SampleFormat::U8 => Some(Sample::U8(Type::Planar)),

crates/recording/src/instant_recording.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use crate::{
55
},
66
feeds::microphone::MicrophoneFeedLock,
77
output_pipeline::{self, OutputPipeline},
8+
resolution_limits::ensure_even,
89
sources::screen_capture::{ScreenCaptureConfig, ScreenCaptureTarget},
910
};
1011
use anyhow::Context as _;
@@ -227,7 +228,12 @@ async fn create_pipeline(
227228
),
228229
)
229230
})
230-
.unwrap_or((screen_info.width, screen_info.height));
231+
.unwrap_or_else(|| {
232+
(
233+
ensure_even(screen_info.width),
234+
ensure_even(screen_info.height),
235+
)
236+
});
231237

232238
let (screen_capture, system_audio) = screen_source.to_sources().await?;
233239

@@ -413,11 +419,6 @@ fn current_time_f64() -> f64 {
413419
.as_secs_f64()
414420
}
415421

416-
fn ensure_even(value: u32) -> u32 {
417-
let adjusted = value - (value % 2);
418-
if adjusted == 0 { 2 } else { adjusted }
419-
}
420-
421422
fn clamp_size(input: (u32, u32), max: (u32, u32)) -> (u32, u32) {
422423
// 16/9-ish
423424
if input.0 >= input.1 && (input.0 as f64 / input.1 as f64) <= 16.0 / 9.0 {

0 commit comments

Comments
 (0)