Skip to content

Commit 7a3d817

Browse files
Merge pull request #1471 from CapSoftware/recording-benchmark
Add synthetic recording test framework and improve frame converter reliability
2 parents 5982627 + 25ebb6c commit 7a3d817

36 files changed

+5328
-131
lines changed

.claude/settings.local.json

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,25 @@
5454
"Bash(./target/release/examples/decode-benchmark:*)",
5555
"Bash(RUST_LOG=warn ./target/release/examples/decode-benchmark:*)",
5656
"Bash(git mv:*)",
57-
"Bash(xargs cat:*)"
57+
"Bash(xargs cat:*)",
58+
"Bash(cargo test:*)",
59+
"Bash(/opt/homebrew/bin/ffmpeg:*)",
60+
"Bash(RUST_LOG=info cargo run:*)",
61+
"Bash(RUST_LOG=warn cargo run:*)",
62+
"Bash(CAP_MUXER_BUFFER_SIZE=240 RUST_LOG=info cargo run:*)",
63+
"Bash(CAP_MUXER_BUFFER_SIZE=480 RUST_LOG=debug cargo run:*)",
64+
"Bash(CAP_MUXER_BUFFER_SIZE=480 RUST_LOG=info cargo run:*)",
65+
"Bash(RUST_LOG=debug cargo run:*)",
66+
"Bash(RUST_LOG=info ./target/release/examples/synthetic-test-runner:*)",
67+
"Bash(CAP_MUXER_BUFFER_SIZE=960 RUST_LOG=info cargo run:*)",
68+
"Bash(CAP_MUXER_BUFFER_SIZE=1200 RUST_LOG=warn ./target/release/examples/synthetic-test-runner:*)",
69+
"Bash(./target/release/examples/synthetic-test-runner:*)",
70+
"Bash(CAP_VIDEO_SOURCE_BUFFER_SIZE=2400 CAP_MUXER_BUFFER_SIZE=2400 RUST_LOG=warn ./target/release/examples/synthetic-test-runner:*)",
71+
"Bash(CAP_VIDEO_SOURCE_BUFFER_SIZE=2400 CAP_MUXER_BUFFER_SIZE=2400 RUST_LOG=info cargo run:*)",
72+
"Bash(sysctl:*)",
73+
"Bash(CAP_VIDEO_SOURCE_BUFFER_SIZE=4800 CAP_MUXER_BUFFER_SIZE=4800 RUST_LOG=warn cargo run:*)",
74+
"Bash(RUST_LOG=cap_enc_ffmpeg::video::h264=debug cargo run:*)",
75+
"Bash(CAP_VIDEO_SOURCE_BUFFER_SIZE=5400 CAP_MUXER_BUFFER_SIZE=5400 RUST_LOG=info cargo run:*)"
5876
],
5977
"deny": [],
6078
"ask": []

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

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

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -347,25 +347,12 @@ pub enum RecordingInputKind {
347347
#[derive(tauri_specta::Event, specta::Type, Clone, Debug, serde::Serialize)]
348348
#[serde(tag = "variant")]
349349
pub enum RecordingEvent {
350-
Countdown {
351-
value: u32,
352-
},
350+
Countdown { value: u32 },
353351
Started,
354352
Stopped,
355-
Failed {
356-
error: String,
357-
},
358-
InputLost {
359-
input: RecordingInputKind,
360-
},
361-
InputRestored {
362-
input: RecordingInputKind,
363-
},
364-
DiskSpaceLow {
365-
available_mb: u32,
366-
threshold_mb: u32,
367-
path: String,
368-
},
353+
Failed { error: String },
354+
InputLost { input: RecordingInputKind },
355+
InputRestored { input: RecordingInputKind },
369356
}
370357

371358
#[derive(Serialize, Type)]

apps/desktop/src/utils/socket.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,11 @@ export function createImageDataWS(
261261
directCanvas.height = height;
262262
}
263263

264-
const imageData = new ImageData(frameData, width, height);
264+
const imageData = new ImageData(
265+
new Uint8ClampedArray(frameData.buffer),
266+
width,
267+
height,
268+
);
265269
directCtx.putImageData(imageData, 0, 0);
266270

267271
if (!hasRenderedFrame()) {

apps/desktop/src/utils/tauri.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -477,7 +477,7 @@ export type ProjectConfiguration = { aspectRatio: AspectRatio | null; background
477477
export type ProjectRecordingsMeta = { segments: SegmentRecordings[] }
478478
export type RecordingAction = "Started" | "InvalidAuthentication" | "UpgradeRequired"
479479
export type RecordingDeleted = { path: string }
480-
export type RecordingEvent = { variant: "Countdown"; value: number } | { variant: "Started" } | { variant: "Stopped" } | { variant: "Failed"; error: string } | { variant: "InputLost"; input: RecordingInputKind } | { variant: "InputRestored"; input: RecordingInputKind } | { variant: "DiskSpaceLow"; available_mb: number; threshold_mb: number; path: string }
480+
export type RecordingEvent = { variant: "Countdown"; value: number } | { variant: "Started" } | { variant: "Stopped" } | { variant: "Failed"; error: string } | { variant: "InputLost"; input: RecordingInputKind } | { variant: "InputRestored"; input: RecordingInputKind }
481481
export type RecordingInputKind = "microphone" | "camera"
482482
export type RecordingMeta = (StudioRecordingMeta | InstantRecordingMeta) & { platform?: Platform | null; pretty_name: string; sharing?: SharingMeta | null; upload?: UploadMeta | null }
483483
export type RecordingMetaWithMetadata = ((StudioRecordingMeta | InstantRecordingMeta) & { platform?: Platform | null; pretty_name: string; sharing?: SharingMeta | null; upload?: UploadMeta | null }) & { mode: RecordingMode; status: StudioRecordingStatus }

apps/desktop/src/utils/webgpu-renderer.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ export function renderFrameWebGPU(
197197

198198
device.queue.writeTexture(
199199
{ texture: renderer.frameTexture },
200-
textureData,
200+
textureData.buffer as unknown as GPUAllowSharedBufferSource,
201201
{ bytesPerRow: width * 4, rowsPerImage: height },
202202
{ width, height },
203203
);

crates/enc-ffmpeg/src/mux/segmented_stream.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ use std::{
1010
};
1111
use sysinfo::Disks;
1212

13-
use crate::video::h264::{H264Encoder, H264EncoderBuilder, H264EncoderError, H264Preset};
13+
use crate::video::h264::{
14+
DEFAULT_KEYFRAME_INTERVAL_SECS, H264Encoder, H264EncoderBuilder, H264EncoderError, H264Preset,
15+
};
1416

1517
const INIT_SEGMENT_NAME: &str = "init.mp4";
1618
const DISK_SPACE_WARNING_THRESHOLD_MB: u64 = 500;
@@ -142,7 +144,7 @@ pub enum QueueFrameError {
142144
FFmpeg(#[from] ffmpeg::Error),
143145
#[error("Init: {0}")]
144146
Init(#[from] InitError),
145-
#[error("Encode: {0}")]
147+
#[error(transparent)]
146148
Encode(#[from] crate::video::h264::QueueFrameError),
147149
#[error("Init segment validation failed: {0}")]
148150
InitSegmentInvalid(String),
@@ -164,7 +166,7 @@ pub struct SegmentedVideoEncoderConfig {
164166
impl Default for SegmentedVideoEncoderConfig {
165167
fn default() -> Self {
166168
Self {
167-
segment_duration: Duration::from_secs(3),
169+
segment_duration: Duration::from_secs(DEFAULT_KEYFRAME_INTERVAL_SECS as u64),
168170
preset: H264Preset::Ultrafast,
169171
bpp: H264EncoderBuilder::QUALITY_BPP,
170172
output_size: None,
@@ -210,6 +212,7 @@ impl SegmentedVideoEncoder {
210212
set_opt("use_timeline", "0");
211213
set_opt("use_template", "1");
212214
set_opt("single_file", "0");
215+
set_opt("hls_playlist", "1");
213216
}
214217

215218
let mut builder = H264EncoderBuilder::new(video_config)

0 commit comments

Comments
 (0)