Skip to content

Commit

Permalink
make export and ui duations more consistent
Browse files Browse the repository at this point in the history
  • Loading branch information
Brendonovich committed Jan 14, 2025
1 parent ddf0ca1 commit 1bf8538
Show file tree
Hide file tree
Showing 9 changed files with 126 additions and 122 deletions.
4 changes: 2 additions & 2 deletions apps/cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ use cap_media::sources::{get_target_fps, ScreenCaptureTarget};
use cap_project::{RecordingMeta, XY};
use cap_recording::RecordingOptions;
use cap_rendering::RenderVideoConstants;
use clap::{Args, Parser, Subcommand, ValueEnum};
use tokio::io::{AsyncBufReadExt, BufReader};
use clap::{Args, Parser, Subcommand};
use tokio::io::AsyncBufReadExt;
use uuid::Uuid;

#[derive(Parser)]
Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/src-tauri/src/export.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ pub async fn export_video(
);

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

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

Expand Down
8 changes: 6 additions & 2 deletions apps/desktop/src-tauri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2389,12 +2389,16 @@ impl<T: tauri_specta::Event> EventExt for T {}

#[tauri::command(async)]
#[specta::specta]
async fn get_editor_total_frames(app: AppHandle, video_id: String) -> Result<u32, String> {
async fn get_editor_total_frames(
app: AppHandle,
video_id: String,
fps: u32,
) -> Result<u32, String> {
let editor_instances = app.state::<EditorInstancesState>();
let instances = editor_instances.lock().await;

let instance = instances
.get(&video_id)
.ok_or_else(|| "Editor instance not found".to_string())?;
Ok(instance.get_total_frames())
Ok(instance.get_total_frames(fps))
}
2 changes: 1 addition & 1 deletion apps/desktop/src/routes/editor/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export type CurrentDialog =

export type DialogState = { open: false } | ({ open: boolean } & CurrentDialog);

export const FPS = 30;
export const FPS = 60;

export const [EditorContextProvider, useEditorContext] = createContextProvider(
(props: {
Expand Down
4 changes: 2 additions & 2 deletions apps/desktop/src/utils/tauri.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,8 +161,8 @@ async showWindow(window: ShowCapWindow) : Promise<void> {
async writeClipboardString(text: string) : Promise<null> {
return await TAURI_INVOKE("write_clipboard_string", { text });
},
async getEditorTotalFrames(videoId: string) : Promise<number> {
return await TAURI_INVOKE("get_editor_total_frames", { videoId });
async getEditorTotalFrames(videoId: string, fps: number) : Promise<number> {
return await TAURI_INVOKE("get_editor_total_frames", { videoId, fps });
}
}

Expand Down
25 changes: 14 additions & 11 deletions crates/editor/src/editor_instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use cap_media::frame_ws::create_frame_ws;
use cap_project::RecordingConfig;
use cap_project::{CursorEvents, ProjectConfiguration, RecordingMeta, XY};
use cap_rendering::{
ProjectRecordings, ProjectUniforms, RecordingSegmentDecoders, RenderOptions,
get_duration, ProjectRecordings, ProjectUniforms, RecordingSegmentDecoders, RenderOptions,
RenderVideoConstants, SegmentVideoPaths,
};
use std::ops::Deref;
Expand All @@ -32,7 +32,7 @@ pub struct EditorInstance {
),
ws_shutdown: Arc<StdMutex<Option<mpsc::Sender<()>>>>,
pub segments: Arc<Vec<Segment>>,
pub total_frames: u32,
meta: RecordingMeta,
}

impl EditorInstance {
Expand Down Expand Up @@ -61,13 +61,9 @@ impl EditorInstance {
}

let meta = cap_project::RecordingMeta::load_for_project(&project_path).unwrap();
let project = meta.project_config();
let recordings = ProjectRecordings::new(&meta);

// Calculate total frames based on actual video duration and fps
let duration = recordings.duration();
let fps = recordings.segments[0].display.fps();
let total_frames = (duration * fps as f64).round() as u32;

let render_options = RenderOptions {
screen_size: XY::new(
recordings.segments[0].display.width,
Expand Down Expand Up @@ -113,10 +109,10 @@ impl EditorInstance {
})),
on_state_change: Box::new(on_state_change),
preview_tx,
project_config: watch::channel(meta.project_config()),
project_config: watch::channel(project),
ws_shutdown: Arc::new(StdMutex::new(Some(ws_shutdown))),
segments: Arc::new(segments),
total_frames,
meta,
});

this.state.lock().await.preview_task =
Expand Down Expand Up @@ -268,8 +264,15 @@ impl EditorInstance {
})
}

pub fn get_total_frames(&self) -> u32 {
self.total_frames
pub fn get_total_frames(&self, fps: u32) -> u32 {
// Calculate total frames based on actual video duration and fps
let duration = get_duration(
&self.recordings,
&self.meta,
&self.project_config.1.borrow(),
);

(fps as f64 * duration).ceil() as u32
}
}

Expand Down
35 changes: 18 additions & 17 deletions crates/export/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,15 +201,16 @@ where
.next_frame_data(samples, project.timeline.as_ref().map(|t| t))
{
let mut frame = audio_info.wrap_frame(&frame_data, 0);
let pts = (frame_count as f64 * f64::from(audio_info.sample_rate) / f64::from(fps)) as i64;
let pts = (frame_count as f64 * f64::from(audio_info.sample_rate)
/ f64::from(fps)) as i64;
frame.set_pts(Some(pts));
println!(
"Export: Sending audio frame {} with PTS: {:?}, samples: {}, data size: {}",
frame_count,
frame.pts(),
samples,
frame_data.len()
);
// println!(
// "Export: Sending audio frame {} with PTS: {:?}, samples: {}, data size: {}",
// frame_count,
// frame.pts(),
// samples,
// frame_data.len()
// );
Some(frame)
} else {
None
Expand All @@ -218,10 +219,10 @@ where
None
};

println!(
"Export: Processing frame {} (size: {}x{}, padded_bytes_per_row: {})",
frame_count, frame.width, frame.height, frame.padded_bytes_per_row
);
// println!(
// "Export: Processing frame {} (size: {}x{}, padded_bytes_per_row: {})",
// frame_count, frame.width, frame.height, frame.padded_bytes_per_row
// );

let mut video_frame = VideoInfo::from_raw(
RawVideoFormat::Rgba,
Expand All @@ -236,11 +237,11 @@ where
);
video_frame.set_pts(Some(frame_count as i64));

println!(
"Export: Sending frame {} to encoder (PTS: {:?})",
frame_count,
video_frame.pts()
);
// println!(
// "Export: Sending frame {} to encoder (PTS: {:?})",
// frame_count,
// video_frame.pts()
// );

frame_tx
.send(MP4Input {
Expand Down
68 changes: 34 additions & 34 deletions crates/media/src/encoders/mp4.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,11 +163,11 @@ impl MP4Encoder {
}

pub fn queue_video_frame(&mut self, mut frame: FFVideo) {
println!(
"MP4Encoder: Processing frame {} (input PTS: {:?})",
self.video.frame_count,
frame.pts()
);
// println!(
// "MP4Encoder: Processing frame {} (input PTS: {:?})",
// self.video.frame_count,
// frame.pts()
// );
let mut scaler = ffmpeg::software::converter(
(frame.width(), frame.height()),
frame.format(),
Expand All @@ -181,10 +181,10 @@ impl MP4Encoder {
// Set PTS in microseconds (1/1_000_000 second units)
let pts = frame.pts().unwrap_or_else(|| self.video.frame_count);
output.set_pts(Some(pts));
println!(
"MP4Encoder: Setting frame {} PTS to {}",
self.video.frame_count, pts
);
// println!(
// "MP4Encoder: Setting frame {} PTS to {}",
// self.video.frame_count, pts
// );
self.video.frame_count += 1;

self.video.encoder.send_frame(&output).unwrap();
Expand All @@ -196,11 +196,11 @@ impl MP4Encoder {
return;
};

println!(
"MP4Encoder: Queueing audio frame with PTS: {:?}, samples: {}",
frame.pts(),
frame.samples()
);
// println!(
// "MP4Encoder: Queueing audio frame with PTS: {:?}, samples: {}",
// frame.pts(),
// frame.samples()
// );

audio.buffer.consume(frame);

Expand All @@ -218,23 +218,23 @@ impl MP4Encoder {
output.set_pts(Some(pts));
}

println!(
"MP4Encoder: Sending audio frame with PTS: {:?}, samples: {}",
output.pts(),
output.samples()
);
// println!(
// "MP4Encoder: Sending audio frame with PTS: {:?}, samples: {}",
// output.pts(),
// output.samples()
// );

// Send frame to encoder
audio.encoder.send_frame(&output).unwrap();

// Process any encoded packets
let mut encoded_packet = FFPacket::empty();
while audio.encoder.receive_packet(&mut encoded_packet).is_ok() {
println!(
"MP4Encoder: Writing audio packet with PTS: {:?}, size: {}",
encoded_packet.pts(),
encoded_packet.size()
);
// println!(
// "MP4Encoder: Writing audio packet with PTS: {:?}, size: {}",
// encoded_packet.pts(),
// encoded_packet.size()
// );

encoded_packet.set_stream(1);
encoded_packet.rescale_ts(
Expand All @@ -257,21 +257,21 @@ impl MP4Encoder {
.receive_packet(&mut encoded_packet)
.is_ok()
{
println!(
"MP4Encoder: Got encoded packet with PTS: {:?}, DTS: {:?}",
encoded_packet.pts(),
encoded_packet.dts()
);
// println!(
// "MP4Encoder: Got encoded packet with PTS: {:?}, DTS: {:?}",
// encoded_packet.pts(),
// encoded_packet.dts()
// );
encoded_packet.set_stream(0); // Video is stream 0
encoded_packet.rescale_ts(
self.video.encoder.time_base(),
self.output_ctx.stream(0).unwrap().time_base(),
);
println!(
"MP4Encoder: Writing packet with rescaled PTS: {:?}, DTS: {:?}",
encoded_packet.pts(),
encoded_packet.dts()
);
// println!(
// "MP4Encoder: Writing packet with rescaled PTS: {:?}, DTS: {:?}",
// encoded_packet.pts(),
// encoded_packet.dts()
// );
encoded_packet
.write_interleaved(&mut self.output_ctx)
.unwrap();
Expand Down
Loading

1 comment on commit 1bf8538

@vercel
Copy link

@vercel vercel bot commented on 1bf8538 Jan 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.