split audio from video recording in Xorg then merge it with video

This commit is contained in:
Salem Yaslem 2021-05-15 14:08:54 +03:00
parent b299dd6042
commit f39f2685a1
2 changed files with 183 additions and 148 deletions

View File

@ -1,7 +1,10 @@
extern crate subprocess;
use chrono::prelude::*;
use gtk::prelude::*;
use gtk::{CheckButton, ComboBoxText, Entry, FileChooser, ProgressBar, SpinButton, Window, WindowType, WindowPosition};
use gtk::{
CheckButton, ComboBoxText, Entry, FileChooser, ProgressBar, SpinButton, Window, WindowPosition,
WindowType,
};
use std::collections::HashMap;
use std::path::PathBuf;
use std::process::Command;
@ -96,15 +99,22 @@ pub struct Ffmpeg {
pub record_frames: SpinButton,
pub record_delay: SpinButton,
pub command: Entry,
pub process_id: Option<u32>,
pub video_process_id: Option<u32>,
pub audio_process_id: Option<u32>,
pub saved_filename: Option<String>,
pub unbound: Option<Sender<bool>>,
pub progress_widget: ProgressWidget,
}
impl Ffmpeg {
pub fn start_record(&mut self, x: u16, y: u16, width: u16, height: u16) -> u32 {
if self.process_id.is_some() {
pub fn start_record(
&mut self,
x: u16,
y: u16,
width: u16,
height: u16,
) -> (Option<u32>, Option<u32>) {
if self.video_process_id.is_some() || self.audio_process_id.is_some() {
self.stop_record();
}
@ -127,6 +137,22 @@ impl Ffmpeg {
.to_string(),
);
if self.record_audio.get_active() {
let mut ffmpeg_command = Command::new("ffmpeg");
ffmpeg_command.arg("-f");
ffmpeg_command.arg("pulse");
ffmpeg_command.arg("-i");
ffmpeg_command.arg(self.audio_id.get_active_id().unwrap().to_string());
ffmpeg_command.arg("-f");
ffmpeg_command.arg("ogg");
ffmpeg_command.arg(format!(
"{}.temp.audio",
self.saved_filename.as_ref().unwrap().to_string()
));
ffmpeg_command.arg("-y");
self.audio_process_id = Some(ffmpeg_command.spawn().unwrap().id());
}
if is_wayland() {
if self.record_video.get_active() {
if self.unbound.is_some() {
@ -145,118 +171,106 @@ impl Ffmpeg {
);
}
if self.record_audio.get_active() {
let mut ffmpeg_command = Command::new("ffmpeg");
ffmpeg_command.arg("-f");
ffmpeg_command.arg("pulse");
ffmpeg_command.arg("-i");
ffmpeg_command.arg(self.audio_id.get_active_id().unwrap().to_string());
ffmpeg_command.arg("-f");
ffmpeg_command.arg("ogg");
ffmpeg_command.arg(format!(
"{}.temp.audio",
self.saved_filename.as_ref().unwrap().to_string()
));
ffmpeg_command.arg("-y");
self.process_id = Some(ffmpeg_command.spawn().unwrap().id());
}
return self.process_id.unwrap();
return (None, self.audio_process_id);
}
let mut ffmpeg_command: Command = Command::new("ffmpeg");
// if recorder video switch is enabled, record video with specified width and hight
if self.record_video.get_active() {
let mut ffmpeg_command: Command = Command::new("ffmpeg");
// record video with specified width and hight
ffmpeg_command.arg("-video_size");
ffmpeg_command.arg(format!("{}x{}", width, height));
}
// if show mouse switch is enabled, draw the mouse to video
ffmpeg_command.arg("-draw_mouse");
if self.record_mouse.get_active() {
ffmpeg_command.arg("1");
} else {
ffmpeg_command.arg("0");
}
// if follow mouse switch is enabled, follow the mouse
if self.follow_mouse.get_active() {
ffmpeg_command.arg("-follow_mouse");
ffmpeg_command.arg("centered");
}
ffmpeg_command.arg("-framerate");
ffmpeg_command.arg(format!("{}", self.record_frames.get_value()));
ffmpeg_command.arg("-f");
ffmpeg_command.arg("x11grab");
ffmpeg_command.arg("-i");
ffmpeg_command.arg(format!(
"{}+{},{}",
std::env::var("DISPLAY")
.unwrap_or(":1".to_string())
.as_str(),
x,
y
));
// if follow audio switch is enabled, record the audio
if self.record_audio.get_active() {
// if show mouse switch is enabled, draw the mouse to video
ffmpeg_command.arg("-draw_mouse");
if self.record_mouse.get_active() {
ffmpeg_command.arg("1");
} else {
ffmpeg_command.arg("0");
}
// if follow mouse switch is enabled, follow the mouse
if self.follow_mouse.get_active() {
ffmpeg_command.arg("-follow_mouse");
ffmpeg_command.arg("centered");
}
ffmpeg_command.arg("-framerate");
ffmpeg_command.arg(format!("{}", self.record_frames.get_value()));
ffmpeg_command.arg("-f");
ffmpeg_command.arg("pulse");
ffmpeg_command.arg("x11grab");
ffmpeg_command.arg("-i");
ffmpeg_command.arg(self.audio_id.get_active_id().unwrap().to_string());
ffmpeg_command.arg("-strict");
ffmpeg_command.arg("-2");
ffmpeg_command.arg(format!(
"{}+{},{}",
std::env::var("DISPLAY")
.unwrap_or(":1".to_string())
.as_str(),
x,
y
));
ffmpeg_command.arg("-q");
ffmpeg_command.arg("1");
ffmpeg_command.arg(self.saved_filename.as_ref().unwrap().to_string());
ffmpeg_command.arg("-y");
// sleep for delay
sleep(Duration::from_secs(self.record_delay.get_value() as u64));
// start recording and return the process id
self.video_process_id = Some(ffmpeg_command.spawn().unwrap().id());
return (self.video_process_id, self.audio_process_id);
}
ffmpeg_command.arg("-q");
ffmpeg_command.arg("1");
ffmpeg_command.arg(self.saved_filename.as_ref().unwrap());
ffmpeg_command.arg("-y");
// sleep for delay
sleep(Duration::from_secs(self.record_delay.get_value() as u64));
// start recording and return the process id
self.process_id = Some(ffmpeg_command.spawn().unwrap().id());
self.process_id.unwrap()
(None, None)
}
pub fn stop_record(&self) {
&self.progress_widget.show();
// kill the process to stop recording
if self.process_id.is_some() {
if self.video_process_id.is_some() {
&self
.progress_widget
.set_progress("Stop Recording".to_string(), 1, 5);
.set_progress("Stop Recording Video".to_string(), 1, 6);
Command::new("kill")
.arg(format!("{}", self.process_id.unwrap()))
.arg(format!("{}", self.video_process_id.unwrap()))
.output()
.unwrap();
}
if is_wayland() {
if self.audio_process_id.is_some() {
&self
.progress_widget
.set_progress("Stop Recording Audio".to_string(), 2, 6);
Command::new("kill")
.arg(format!("{}", self.audio_process_id.unwrap()))
.output()
.unwrap();
}
let is_video_record = std::path::Path::new(
format!(
"{}{}",
self.saved_filename.as_ref().unwrap_or(&String::from("")),
if is_wayland() { ".temp" } else { "" }
)
.as_str(),
)
.exists();
let is_audio_record = std::path::Path::new(
format!(
"{}.temp.audio",
self.saved_filename.as_ref().unwrap_or(&String::from(""))
)
.as_str(),
)
.exists();
if is_video_record && is_wayland() {
// create new dbus session
let connection = zbus::Connection::new_session().unwrap();
// bind the connection to gnome screencast proxy
let gnome_screencast_proxy = GnomeScreencastProxy::new(&connection).unwrap();
gnome_screencast_proxy.stop_screencast().unwrap();
let is_audio_record = std::path::Path::new(
format!("{}.temp.audio", self.saved_filename.as_ref().unwrap_or(&String::from(""))).as_str()
)
.exists();
let is_video_record = std::path::Path::new(
format!("{}.temp", self.saved_filename.as_ref().unwrap_or(&String::from(""))).as_str()
)
.exists();
if self.unbound.is_some() {
&self.progress_widget.set_progress(
"Stop Wayland Video Recording".to_string(),
2,
5,
3,
6,
);
self.unbound
.as_ref()
@ -288,86 +302,106 @@ impl Ffmpeg {
ffmpeg_convert_command.output().unwrap();
std::fs::remove_file(format!("{}.temp", self.saved_filename.as_ref().unwrap()))
.unwrap();
if is_audio_record {
&self.progress_widget.set_progress(
"Stop Wayland Audio Recording".to_string(),
3,
5,
);
// merge audio with video
let mut ffmpeg_audio_merge_command = Command::new("ffmpeg");
ffmpeg_audio_merge_command.arg("-i");
ffmpeg_audio_merge_command.arg(format!(
"{}.temp.without.audio.{}",
self.saved_filename.as_ref().unwrap(),
self.filename.2.get_active_id().unwrap().to_string()
));
ffmpeg_audio_merge_command.arg("-i");
ffmpeg_audio_merge_command.arg(format!(
"{}.temp.audio",
self.saved_filename.as_ref().unwrap()
));
ffmpeg_audio_merge_command.arg("-c:v");
ffmpeg_audio_merge_command.arg("copy");
ffmpeg_audio_merge_command.arg("-c:a");
ffmpeg_audio_merge_command.arg("aac");
ffmpeg_audio_merge_command.arg(self.saved_filename.as_ref().unwrap());
ffmpeg_audio_merge_command.arg("-y");
ffmpeg_audio_merge_command.output().unwrap();
std::fs::remove_file(format!(
"{}.temp.audio",
self.saved_filename.as_ref().unwrap()
))
.unwrap();
std::fs::remove_file(format!(
"{}.temp.without.audio.{}",
self.saved_filename.as_ref().unwrap(),
self.filename.2.get_active_id().unwrap().to_string()
))
.unwrap();
}
}
} else if is_audio_record {
&self.progress_widget.set_progress(
"Convert Audio to choosen format".to_string(),
3,
5,
);
println!("convert audio");
Command::new("ffmpeg")
.arg("-f")
.arg("ogg")
.arg("-i")
.arg(format!(
"{}.temp.audio",
self.saved_filename.as_ref().unwrap()
))
.arg(format!("{}", self.saved_filename.as_ref().unwrap()))
.output()
.unwrap();
}
}
if is_video_record {
let mut move_command = Command::new("mv");
move_command.arg(format!(
"{}{}",
self.saved_filename.as_ref().unwrap(),
if is_wayland() { ".temp" } else { "" }
));
move_command.arg(format!(
"{}{}",
self.saved_filename.as_ref().unwrap_or(&String::new()),
if is_audio_record {
format!(
".temp.without.audio.{}",
self.filename.2.get_active_id().unwrap().to_string()
)
} else {
"".to_string()
}
));
move_command.output().unwrap();
// if audio record, then merge video with audio
if is_audio_record {
&self
.progress_widget
.set_progress("Save Audio Recording".to_string(), 4, 6);
let mut ffmpeg_audio_merge_command = Command::new("ffmpeg");
ffmpeg_audio_merge_command.arg("-i");
ffmpeg_audio_merge_command.arg(format!(
"{}.temp.without.audio.{}",
self.saved_filename.as_ref().unwrap(),
self.filename.2.get_active_id().unwrap().to_string()
));
ffmpeg_audio_merge_command.arg("-i");
ffmpeg_audio_merge_command.arg(format!(
"{}.temp.audio",
self.saved_filename.as_ref().unwrap()
));
ffmpeg_audio_merge_command.arg("-c:v");
ffmpeg_audio_merge_command.arg("copy");
ffmpeg_audio_merge_command.arg("-c:a");
ffmpeg_audio_merge_command.arg("aac");
ffmpeg_audio_merge_command.arg(self.saved_filename.as_ref().unwrap());
ffmpeg_audio_merge_command.arg("-y");
sleep(Duration::from_secs(1));
ffmpeg_audio_merge_command.output().unwrap();
std::fs::remove_file(format!(
"{}.temp.audio",
self.saved_filename.as_ref().unwrap()
))
.unwrap();
std::fs::remove_file(format!(
"{}.temp.without.audio.{}",
self.saved_filename.as_ref().unwrap(),
self.filename.2.get_active_id().unwrap().to_string()
))
.unwrap();
}
}
// if only audio is recording then convert it to chosen fromat
else if is_audio_record {
&self
.progress_widget
.set_progress("Convert Audio to choosen format".to_string(), 4, 6);
sleep(Duration::from_secs(1));
Command::new("ffmpeg")
.arg("-f")
.arg("ogg")
.arg("-i")
.arg(format!(
"{}.temp.audio",
self.saved_filename.as_ref().unwrap()
))
.arg(format!("{}", self.saved_filename.as_ref().unwrap()))
.output()
.unwrap();
std::fs::remove_file(format!(
"{}.temp.audio",
self.saved_filename.as_ref().unwrap()
))
.unwrap();
}
// execute command after finish recording
if !(self.command.get_text().trim() == "") {
&self.progress_widget.set_progress(
"execute custom command after finish".to_string(),
4,
5,
6,
);
Exec::shell(self.command.get_text().trim()).popen().unwrap();
}
&self
.progress_widget
.set_progress("Finish".to_string(), 5, 5);
.set_progress("Finish".to_string(), 6, 6);
&self.progress_widget.hide();
}

View File

@ -290,7 +290,8 @@ fn main() {
record_frames: frames_spin,
record_delay: delay_spin,
command: command_entry,
process_id: None,
video_process_id: None,
audio_process_id: None,
saved_filename: None,
unbound: None,
progress_widget: ProgressWidget::new(&main_window),