Skip to content

Commit db2b82a

Browse files
committed
[*] update normally
1 parent 1a7c86e commit db2b82a

File tree

3 files changed

+221
-35
lines changed

3 files changed

+221
-35
lines changed

lib/recorder/src/recorder.rs

Lines changed: 40 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ pub type ResizedImageBuffer = ImageBuffer<Rgb<u8>, Vec<u8>>;
2727
const RAW_VIDEO_EXTENSION: &str = "h264";
2828
const INPUT_AUDIO_EXTENSION: &str = "input.wav";
2929
const SPEAKER_AUDIO_EXTENSION: &str = "speaker.wav";
30+
const TMP_OUTPUT_VIDEO_EXTENSION: &str = "tmp.mp4";
3031

3132
static CAPTURE_MEAN_TIME: Lazy<Mutex<Option<Duration>>> = Lazy::new(|| Mutex::new(None));
3233

@@ -762,34 +763,43 @@ impl RecordingSession {
762763
writer.finish()?;
763764
}
764765

765-
let combine_config = CombineTracksConfig {
766-
h264_path: self.config.output_path.with_extension(RAW_VIDEO_EXTENSION),
767-
input_wav_path: if self.config.audio_device_name.is_some() {
768-
Some(
769-
self.config
770-
.output_path
771-
.with_extension(INPUT_AUDIO_EXTENSION),
772-
)
773-
} else {
774-
None
775-
},
776-
speaker_wav_path: if self.config.enable_recording_speaker {
777-
Some(
778-
self.config
779-
.output_path
780-
.with_extension(SPEAKER_AUDIO_EXTENSION),
781-
)
782-
} else {
783-
None
784-
},
785-
output_path: self.config.output_path.clone(),
786-
fps: self.config.fps,
787-
stop_sig: self.stop_sig_combine,
788-
};
789-
790766
if !self.config.enable_preview_mode {
767+
let tmp_output_file = self
768+
.config
769+
.output_path
770+
.with_extension(TMP_OUTPUT_VIDEO_EXTENSION);
771+
772+
let combine_config = CombineTracksConfig {
773+
h264_path: self.config.output_path.with_extension(RAW_VIDEO_EXTENSION),
774+
input_wav_path: if self.config.audio_device_name.is_some() {
775+
Some(
776+
self.config
777+
.output_path
778+
.with_extension(INPUT_AUDIO_EXTENSION),
779+
)
780+
} else {
781+
None
782+
},
783+
speaker_wav_path: if self.config.enable_recording_speaker {
784+
Some(
785+
self.config
786+
.output_path
787+
.with_extension(SPEAKER_AUDIO_EXTENSION),
788+
)
789+
} else {
790+
None
791+
},
792+
output_path: tmp_output_file.clone(),
793+
fps: self.config.fps,
794+
stop_sig: self.stop_sig_combine,
795+
};
796+
791797
combine_tracks(combine_config, combine_progress_cb)?;
792798

799+
if tmp_output_file.exists() {
800+
_ = fs::rename(&tmp_output_file, &self.config.output_path);
801+
}
802+
793803
if self.config.output_path.exists() {
794804
log::info!(
795805
"Successfully save recorded file: {} ",
@@ -802,7 +812,7 @@ impl RecordingSession {
802812
)));
803813
}
804814

805-
if self.config.remove_cache_files {
815+
if self.config.remove_cache_files && self.config.output_path.exists() {
806816
if self.config.enable_recording_speaker {
807817
_ = fs::remove_file(
808818
self.config
@@ -1024,6 +1034,10 @@ impl RecordingSession {
10241034
self.stop_sig_combine.store(true, Ordering::Relaxed);
10251035
}
10261036

1037+
pub fn get_stop_combine_tracks(&self) -> Arc<AtomicBool> {
1038+
self.stop_sig_combine.clone()
1039+
}
1040+
10271041
/// Get the user frame receiver if frame channel is enabled.
10281042
///
10291043
/// This method returns the receiver for the user frame channel, which allows

wayshot/src/logic/recorder.rs

Lines changed: 181 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,18 @@ use crate::{
55
tr::tr,
66
},
77
logic_cb,
8-
slint_generatedAppWindow::{AppWindow, Source as UISource, SourceType},
8+
slint_generatedAppWindow::{
9+
AppWindow, Fps as UIFps, RecordStatus as UIRecordStatus, Resolution as UIResolution,
10+
Source as UISource, SourceType,
11+
},
912
toast_warn,
1013
};
1114
use anyhow::{Result, bail};
1215
use once_cell::sync::Lazy;
13-
use recorder::{AudioRecorder, SpeakerRecorder, StreamingAudioRecorder, bounded};
16+
use recorder::{
17+
AudioRecorder, FPS, RecorderConfig, RecordingSession, Resolution, SpeakerRecorder,
18+
StreamingAudioRecorder, bounded,
19+
};
1420
use slint::{ComponentHandle, Model, SharedString, ToSharedString, VecModel, Weak};
1521
use std::{
1622
path::PathBuf,
@@ -26,6 +32,9 @@ struct Cache {
2632
desktop_speaker_amplification: Option<Arc<AtomicI32>>,
2733
input_audio_amplification: Option<Arc<AtomicI32>>,
2834
input_streaming_audio_recorder: Option<StreamingAudioRecorder>,
35+
36+
recorder_stop_sig: Option<Arc<AtomicBool>>,
37+
merge_stop_sig: Option<Arc<AtomicBool>>,
2938
}
3039

3140
static CACHE: Lazy<Mutex<Cache>> = Lazy::new(|| Mutex::new(Cache::default()));
@@ -326,11 +335,156 @@ fn inner_input_audio_changed(ui: &AppWindow, name: SharedString) -> Result<()> {
326335
Ok(())
327336
}
328337

329-
fn start_recording(ui: &AppWindow) {}
338+
fn start_recording(ui: &AppWindow) {
339+
let all_config = config::all();
340+
341+
if all_config.recorder.save_dir.is_empty()
342+
|| !PathBuf::from(all_config.recorder.save_dir.clone()).exists()
343+
|| !PathBuf::from(all_config.recorder.save_dir.clone()).is_dir()
344+
{
345+
let ui_weak = ui.as_weak();
346+
tokio::spawn(async move {
347+
let Some(dir) = picker_directory(ui_weak.clone(), &tr("Choose save directory"), "")
348+
else {
349+
return;
350+
};
351+
352+
let mut all = config::all();
353+
all.recorder.save_dir = dir.to_string_lossy().to_string();
354+
_ = config::save(all);
355+
});
356+
return;
357+
}
358+
359+
let ui_weak = ui.as_weak();
360+
thread::spawn(move || {
361+
if let Err(e) = inner_start_recording(ui_weak.clone()) {
362+
toast::async_toast_warn(ui_weak, e.to_string());
363+
}
364+
});
365+
}
366+
367+
fn inner_start_recording(ui_weak: Weak<AppWindow>) -> Result<()> {
368+
log::info!("start recording...");
369+
let all_config = config::all();
330370

331-
fn stop_recording(ui: &AppWindow) {}
371+
if all_config.control.screen.is_empty() {
372+
bail!("available screen no found");
373+
}
374+
375+
let screen_info = capture::available_screens()?
376+
.into_iter()
377+
.find(|item| item.name == all_config.control.screen);
378+
379+
if screen_info.is_none() {
380+
bail!("no found screen: {}", all_config.control.screen);
381+
}
382+
383+
let screen_info = screen_info.unwrap();
384+
log::debug!("screen_info: {screen_info:?}");
385+
386+
let resolution = if matches!(all_config.recorder.resolution, UIResolution::Original) {
387+
Resolution::Original((
388+
screen_info.logical_size.width as u32,
389+
screen_info.logical_size.height as u32,
390+
))
391+
} else {
392+
all_config.recorder.resolution.into()
393+
};
332394

333-
fn stop_merge_tracks(ui: &AppWindow) {}
395+
let input_audio_name = if all_config.control.input_audio.is_empty() {
396+
None
397+
} else {
398+
Some(all_config.control.input_audio)
399+
};
400+
401+
RecordingSession::init()?;
402+
403+
let config = RecorderConfig::new(
404+
all_config.control.screen.clone(),
405+
screen_info.logical_size.clone(),
406+
RecorderConfig::make_filename(&all_config.recorder.save_dir),
407+
)
408+
.with_enable_frame_channel_user(true)
409+
.with_enable_recording_speaker(true)
410+
.with_include_cursor(all_config.recorder.show_cursor)
411+
.with_remove_cache_files(all_config.recorder.remove_temporary_files)
412+
.with_audio_device_name(input_audio_name)
413+
.with_fps(all_config.recorder.fps.clone().into())
414+
.with_resolution(resolution);
415+
416+
config.validate()?;
417+
log::info!("Recording configuration: {:#?}", config);
418+
419+
let mut session = RecordingSession::new(config);
420+
session.start()?;
421+
422+
ui_weak.upgrade_in_event_loop(move |ui| {
423+
global_store!(ui).set_record_status(UIRecordStatus::Recording);
424+
});
425+
426+
let stop_sig = session.stop_sig().clone();
427+
let stop_sig_merge = session.get_stop_combine_tracks();
428+
{
429+
let mut cache = CACHE.lock().unwrap();
430+
cache.recorder_stop_sig = Some(stop_sig);
431+
cache.merge_stop_sig = Some(stop_sig_merge);
432+
}
433+
434+
let frame_receiver_user = session.get_frame_receiver_user();
435+
thread::spawn(move || {
436+
if let Some(rx) = frame_receiver_user {
437+
while let Ok(frame) = rx.recv() {
438+
log::debug!(
439+
"frame_receiver_user frame len: {} bytes",
440+
frame.cb_data.data.pixel_data.len()
441+
);
442+
}
443+
log::info!("exit frame_receiver_user");
444+
} else {
445+
log::info!("frame_receiver_user is none");
446+
}
447+
});
448+
449+
let ui_weak_clone = ui_weak.clone();
450+
session.wait(move |v| {
451+
log::debug!("combine tracks progress: {}%", (v * 100.0) as u32);
452+
_ = ui_weak_clone.upgrade_in_event_loop(move |ui| {
453+
global_store!(ui).set_record_status(UIRecordStatus::Mergeing);
454+
global_store!(ui).set_merge_tracks_progress(v);
455+
});
456+
})?;
457+
458+
ui_weak.upgrade_in_event_loop(move |ui| {
459+
global_store!(ui).set_record_status(UIRecordStatus::Stopped);
460+
});
461+
462+
log::info!("Recording completed successfully!");
463+
464+
Ok(())
465+
}
466+
467+
fn stop_recording(ui: &AppWindow) {
468+
let stop_sig = CACHE.lock().unwrap().recorder_stop_sig.take();
469+
if let Some(sig) = stop_sig {
470+
sig.store(true, Ordering::Relaxed);
471+
} else {
472+
log::warn!("recorder_stop_sig is None");
473+
}
474+
475+
global_store!(ui).set_record_status(UIRecordStatus::Mergeing);
476+
}
477+
478+
fn stop_merge_tracks(ui: &AppWindow) {
479+
let stop_sig = CACHE.lock().unwrap().merge_stop_sig.take();
480+
if let Some(sig) = stop_sig {
481+
sig.store(true, Ordering::Relaxed);
482+
} else {
483+
log::warn!("merge_stop_sig is None");
484+
}
485+
486+
global_store!(ui).set_record_status(UIRecordStatus::Stopped);
487+
}
334488

335489
pub fn picker_directory(ui: Weak<AppWindow>, title: &str, filename: &str) -> Option<PathBuf> {
336490
let result = native_dialog::DialogBuilder::file()
@@ -351,3 +505,25 @@ pub fn picker_directory(ui: Weak<AppWindow>, title: &str, filename: &str) -> Opt
351505
_ => None,
352506
}
353507
}
508+
509+
impl From<UIResolution> for Resolution {
510+
fn from(entry: UIResolution) -> Self {
511+
match entry {
512+
UIResolution::P720 => Resolution::P720,
513+
UIResolution::P1080 => Resolution::P1080,
514+
UIResolution::P2K => Resolution::P2K,
515+
UIResolution::P4K => Resolution::P4K,
516+
_ => unreachable!(),
517+
}
518+
}
519+
}
520+
521+
impl From<UIFps> for FPS {
522+
fn from(entry: UIFps) -> Self {
523+
match entry {
524+
UIFps::Fps24 => FPS::Fps24,
525+
UIFps::Fps25 => FPS::Fps25,
526+
UIFps::Fps30 => FPS::Fps30,
527+
}
528+
}
529+
}

wayshot/ui/panel/desktop/home.slint

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -337,9 +337,7 @@ component ControlPanel inherits HorizontalLayout {
337337
colorize: Theme.light-text-color;
338338

339339
clicked => {
340-
Store.record-status = RecordStatus.Stopped;
341340
Logic.stop-recording();
342-
Store.record-status = RecordStatus.Mergeing;
343341
}
344342
}
345343
}
@@ -350,7 +348,6 @@ component ControlPanel inherits HorizontalLayout {
350348
colorize: Theme.light-text-color;
351349

352350
clicked => {
353-
Store.record-status = RecordStatus.Recording;
354351
Logic.start-recording();
355352
}
356353
}
@@ -387,7 +384,6 @@ component ControlPanel inherits HorizontalLayout {
387384

388385
clicked => {
389386
Logic.stop-merge-tracks();
390-
Store.record-status = RecordStatus.Stopped;
391387
}
392388
}
393389
}

0 commit comments

Comments
 (0)