Skip to content

Commit

Permalink
Merge branch 'main' into pr/231
Browse files Browse the repository at this point in the history
  • Loading branch information
richiemcilroy committed Jan 6, 2025
2 parents 5e6c679 + ac2f956 commit 5fb8727
Show file tree
Hide file tree
Showing 26 changed files with 1,197 additions and 561 deletions.
5 changes: 1 addition & 4 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,4 @@ The video segments are stored in your app data directory, under the folder `so.c

### Notes for development on Windows:

<!-- TODO: Update instructions once setupSidecar handles this -->

Required dlls: `avutil`, `avformat`, `avcodec`, `avdevice`.
Put the full version of ffmpeg for the target arch into `target/binaries`.
Requirements: llvm, clang and VCPKG are required for compiling ffmpeg-sys.
70 changes: 45 additions & 25 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion apps/desktop/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "@cap/desktop",
"type": "module",
"scripts": {
"dev": "RUST_BACKTRACE=1 dotenv -e ../../.env -- pnpm run preparescript && tauri dev",
"dev": "cross-env RUST_BACKTRACE=1 dotenv -e ../../.env -- pnpm run preparescript && tauri dev",
"build:tauri": "dotenv -e ../../.env -- pnpm run preparescript && tauri build",
"preparescript": "node scripts/prepare.js",
"localdev": "dotenv -e ../../.env -- vinxi dev --port 3001",
Expand Down Expand Up @@ -64,6 +64,7 @@
"@tauri-apps/cli": ">=2.1.0",
"@total-typescript/ts-reset": "^0.6.1",
"@types/dom-webcodecs": "^0.1.11",
"cross-env": "^7.0.3",
"typescript": "^5.7.2",
"vite": "^5.4.3",
"vite-tsconfig-paths": "^5.0.1"
Expand Down
19 changes: 10 additions & 9 deletions apps/desktop/src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,19 @@ tauri = { workspace = true, features = [
] }
tauri-specta = { version = "=2.0.0-rc.20", features = ["derive", "typescript"] }
tauri-plugin-dialog = "2.0.0"
tauri-plugin-fs = "2.0.0-rc.0"
tauri-plugin-global-shortcut = "2.0.1"
tauri-plugin-http = "2.0.4"
tauri-plugin-notification = "2.0.1"
tauri-plugin-os = "2.0.0"
tauri-plugin-fs = "2.2.0"
tauri-plugin-global-shortcut = "2.1.0"
tauri-plugin-http = "2.1.0"
tauri-plugin-notification = "2.1.0"
tauri-plugin-os = "2.1.0"
tauri-plugin-process = "2.0.1"
tauri-plugin-shell = "2.0.0"
tauri-plugin-shell = "2.1.0"
tauri-plugin-single-instance = "2.0.1"
tauri-plugin-store = "2.0.0"
tauri-plugin-updater = "2.1.0"
tauri-plugin-store = "2.2.0"
tauri-plugin-updater = "2.2.0"
tauri-plugin-oauth = { git = "https://github.com/FabianLars/tauri-plugin-oauth", branch = "v2" }
tauri-plugin-window-state = "2.0.2"
tauri-plugin-window-state = "2.2.0"
tauri-plugin-positioner = "2.2.0"

serde = { version = "1", features = ["derive"] }
serde_json = "1"
Expand Down
75 changes: 56 additions & 19 deletions apps/desktop/src-tauri/src/export.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,42 @@ pub async fn export_video(
force: bool,
use_custom_muxer: bool,
) -> Result<PathBuf, String> {
let VideoRecordingMetadata { duration, .. } =
get_video_metadata(app.clone(), video_id.clone(), Some(VideoType::Screen))
let screen_metadata =
match get_video_metadata(app.clone(), video_id.clone(), Some(VideoType::Screen)).await {
Ok(meta) => meta,
Err(e) => {
sentry::capture_message(
&format!("Failed to get video metadata: {}", e),
sentry::Level::Error,
);
return Err(
"Failed to read video metadata. The recording may be from an incompatible version."
.to_string(),
);
}
};

// Get camera metadata if it exists
let camera_metadata =
get_video_metadata(app.clone(), video_id.clone(), Some(VideoType::Camera))
.await
.unwrap();
.ok();

// Use the longer duration between screen and camera
let duration = screen_metadata.duration.max(
camera_metadata
.map(|m| m.duration)
.unwrap_or(screen_metadata.duration),
);

// 30 FPS (calculated for output video)
let total_frames = (duration * 30.0).round() as u32;
// Calculate total frames with ceiling to ensure we don't exceed 100%
let total_frames = ((duration * 30.0).ceil() as u32).max(1);

let editor_instance = upsert_editor_instance(&app, video_id.clone()).await;

let output_path = editor_instance.meta().output_path();

// If the file exists, return it immediately
// If the file exists and we're not forcing a re-render, return it
if output_path.exists() && !force {
return Ok(output_path);
}
Expand All @@ -37,14 +60,25 @@ pub async fn export_video(
.send(RenderProgress::EstimatedTotalFrames { total_frames })
.ok();

// Create a modified project configuration that accounts for different video lengths
let mut modified_project = project.clone();
if let Some(timeline) = &mut modified_project.timeline {
// Ensure timeline duration matches the longest video
for segment in timeline.segments.iter_mut() {
if segment.end > duration {
segment.end = duration;
}
}
}

let exporter = cap_export::Exporter::new(
project,
modified_project,
output_path.clone(),
move |frame_index| {
// Ensure progress never exceeds total frames
let current_frame = (frame_index + 1).min(total_frames);
progress
.send(RenderProgress::FrameRendered {
current_frame: frame_index + 1,
})
.send(RenderProgress::FrameRendered { current_frame })
.ok();
},
editor_instance.project_path.clone(),
Expand All @@ -57,17 +91,20 @@ pub async fn export_video(
e.to_string()
})?;

if use_custom_muxer {
let result = if use_custom_muxer {
exporter.export_with_custom_muxer().await
} else {
exporter.export_with_ffmpeg_cli().await
}
.map_err(|e| {
sentry::capture_message(&e.to_string(), sentry::Level::Error);
e.to_string()
})?;
};

ShowCapWindow::PrevRecordings.show(&app).ok();

Ok(output_path)
match result {
Ok(_) => {
ShowCapWindow::PrevRecordings.show(&app).ok();
Ok(output_path)
}
Err(e) => {
sentry::capture_message(&e.to_string(), sentry::Level::Error);
Err(e.to_string())
}
}
}
Loading

0 comments on commit 5fb8727

Please sign in to comment.