From 06d964adaba25de000dc571065167310364efe3a Mon Sep 17 00:00:00 2001 From: ochibani <11yzyv86j@relay.firefox.com> Date: Wed, 19 Jun 2024 00:11:26 +0200 Subject: [PATCH] update gif record --- interfaces/main.ui | 18 ++++---- locales/ar.ftl | 7 +-- locales/ar_YE.ftl | 7 +-- locales/en.ftl | 6 +-- locales/en_US.ftl | 6 +-- src/config_management.rs | 20 ++++----- src/ffmpeg_interface.rs | 94 +++++++++++++++++++++++++++++++++++++--- src/main.rs | 28 ++++++------ 8 files changed, 134 insertions(+), 52 deletions(-) diff --git a/interfaces/main.ui b/interfaces/main.ui index 67705f2..c65e941 100644 --- a/interfaces/main.ui +++ b/interfaces/main.ui @@ -7,18 +7,18 @@ blue-recorder True - + 10 1 2 - + 0 240 1 10 - + 0 50000 1 @@ -434,7 +434,7 @@ 2 2 number - adjustment-frames + adjustment_frames True @@ -457,7 +457,7 @@ 2 2 number - adjustment-delay + adjustment_delay 1 True @@ -467,7 +467,7 @@ - + True 0.0 @@ -477,7 +477,7 @@ - + True True label @@ -488,13 +488,13 @@ - + True True 2 2 number - adjustment-bitrate + adjustment_bitrate 1 True diff --git a/locales/ar.ftl b/locales/ar.ftl index 692e9a5..ae37a34 100644 --- a/locales/ar.ftl +++ b/locales/ar.ftl @@ -102,8 +102,9 @@ license = لمزيد تفاصيل راجع رخصة جنو العمومية. إن لم تكن حصلت على نسخة من رخصة جنو العمومية مع المسجل الأزرق فانظر { license-website }. -# Bitrate label -bitrate = Bitrate: +# Video bitrate label +video-bitrate = B/Video: + # Recording button record = سجل @@ -146,7 +147,7 @@ format-tooltip = لاختيار صيغة الخَرج frames-tooltip = عدد الإطارات في الثانية hide-tooltip = لإخفاء نافذة المسجل الأزرق عند بدء التسجيل mouse-tooltip = يظهر مؤشر الفأرة عند التسجيل -bitrate-tooltip = Set video bitrate in KB/s +video-bitrate-tooltip = Set video bitrate in KB/s record-tooltip = يبدأ تسجيل الشاشة screen-tooltip = يحدد الشاشة ليسجلها speaker-tooltip = Speakr sound recording diff --git a/locales/ar_YE.ftl b/locales/ar_YE.ftl index 692e9a5..ae37a34 100644 --- a/locales/ar_YE.ftl +++ b/locales/ar_YE.ftl @@ -102,8 +102,9 @@ license = لمزيد تفاصيل راجع رخصة جنو العمومية. إن لم تكن حصلت على نسخة من رخصة جنو العمومية مع المسجل الأزرق فانظر { license-website }. -# Bitrate label -bitrate = Bitrate: +# Video bitrate label +video-bitrate = B/Video: + # Recording button record = سجل @@ -146,7 +147,7 @@ format-tooltip = لاختيار صيغة الخَرج frames-tooltip = عدد الإطارات في الثانية hide-tooltip = لإخفاء نافذة المسجل الأزرق عند بدء التسجيل mouse-tooltip = يظهر مؤشر الفأرة عند التسجيل -bitrate-tooltip = Set video bitrate in KB/s +video-bitrate-tooltip = Set video bitrate in KB/s record-tooltip = يبدأ تسجيل الشاشة screen-tooltip = يحدد الشاشة ليسجلها speaker-tooltip = Speakr sound recording diff --git a/locales/en.ftl b/locales/en.ftl index 7c45d83..d107de0 100644 --- a/locales/en.ftl +++ b/locales/en.ftl @@ -99,8 +99,8 @@ license = Blue Recorder is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Blue Recorder. If not, see { license-website }. -# Bitrate label -bitrate = Bitrate: +# Video bitrate label +video-bitrate = B/Video: # Recording button record = Record @@ -143,7 +143,7 @@ format-tooltip = Select file format frames-tooltip = Frames rate hide-tooltip = Hide window when start recording mouse-tooltip = Mouse appears in video recording -bitrate-tooltip = Set video bitrate in KB/s +video-bitrate-tooltip = Set video bitrate in KB/s record-tooltip = Start screen record screen-tooltip = Select screen to record speaker-tooltip = Speakr sound recording diff --git a/locales/en_US.ftl b/locales/en_US.ftl index 7c45d83..d107de0 100644 --- a/locales/en_US.ftl +++ b/locales/en_US.ftl @@ -99,8 +99,8 @@ license = Blue Recorder is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Blue Recorder. If not, see { license-website }. -# Bitrate label -bitrate = Bitrate: +# Video bitrate label +video-bitrate = B/Video: # Recording button record = Record @@ -143,7 +143,7 @@ format-tooltip = Select file format frames-tooltip = Frames rate hide-tooltip = Hide window when start recording mouse-tooltip = Mouse appears in video recording -bitrate-tooltip = Set video bitrate in KB/s +video-bitrate-tooltip = Set video bitrate in KB/s record-tooltip = Start screen record screen-tooltip = Select screen to record speaker-tooltip = Speakr sound recording diff --git a/src/config_management.rs b/src/config_management.rs index b3f3a8d..c7c77fe 100755 --- a/src/config_management.rs +++ b/src/config_management.rs @@ -28,7 +28,7 @@ pub fn initialize() -> PathBuf { fn default() { for format in 0..7 { - set_default_bitrate(&format.to_string()); + set_default_video_bitrate(&format.to_string()); set_default_frame(&format.to_string()); } set("default", "delay", "0"); @@ -132,16 +132,16 @@ pub fn folder_icon(folder_chooser_name: Option<&str>) -> &str { } } -pub fn set_default_bitrate(format: &str) -> bool { +pub fn set_default_video_bitrate(format: &str) -> bool { let rate = match format { - "0" => self::set("default", "bitrate-0", "0"), - "1" => self::set("default", "bitrate-1", "0"), - "2" => self::set("default", "bitrate-2", "0"), - "3" => self::set("default", "bitrate-3", "0"), - "4" => self::set("default", "bitrate-4", "0"), - "5" => self::set("default", "bitrate-5", "0"), - "6" => self::set("default", "bitrate-6", "0"), - _ => self::set("default", "bitrate-0", "0"), // Default value + "0" => self::set("default", "videobitrate-0", "0"), + "1" => self::set("default", "videobitrate-1", "0"), + "2" => self::set("default", "videobitrate-2", "0"), + "3" => self::set("default", "videobitrate-3", "0"), + "4" => self::set("default", "videobitrate-4", "0"), + "5" => self::set("default", "videobitrate-5", "0"), + "6" => self::set("default", "videobitrate-6", "0"), + _ => self::set("default", "videobitrate-0", "0"), // Default value }; rate } diff --git a/src/ffmpeg_interface.rs b/src/ffmpeg_interface.rs index 517b5e6..598678a 100644 --- a/src/ffmpeg_interface.rs +++ b/src/ffmpeg_interface.rs @@ -39,7 +39,7 @@ pub struct Ffmpeg { pub main_context: gtk::glib::MainContext, pub temp_video_filename: String, pub bundle: String, - pub record_bitrate: SpinButton, + pub video_record_bitrate: SpinButton, } impl Ffmpeg { @@ -85,7 +85,7 @@ impl Ffmpeg { } } - if self.record_video.is_active() && !is_wayland() { + if self.record_video.is_active() && !is_wayland() && self.filename.2.active_id().unwrap().as_str() != "gif" { let mode = config_management::get("default", "mode"); let format = "x11grab"; let display = format!("{}+{},{}", @@ -127,10 +127,10 @@ impl Ffmpeg { .input(display); // Disable bitrate if value is zero - if self.record_bitrate.value() > 0.0 { + if self.video_record_bitrate.value() > 0.0 { ffmpeg_command.args([ "-b:v", - &format!("{}K", self.record_bitrate.value()), + &format!("{}K", self.video_record_bitrate.value()), ]); } @@ -155,6 +155,70 @@ impl Ffmpeg { // sleep for delay sleep(Duration::from_secs(self.record_delay.value() as u64)); + // start recording and return the process id + self.video_process = Some(Rc::new(RefCell::new(ffmpeg_command.spawn().unwrap()))); + } else if self.record_video.is_active() && !is_wayland() && self.filename.2.active_id().unwrap().as_str() == "gif" { + let mode = config_management::get("default", "mode"); + let format = "x11grab"; + let display = format!("{}+{},{}", + std::env::var("DISPLAY").unwrap_or_else(|_| ":0".to_string()) + .as_str(), + x, + y + ); + let mut ffmpeg_command = FfmpegCommand::new(); + + // record video with specified width and hight + if self.follow_mouse.is_active() && mode.as_str() == "screen" { + let width = width as f32 * 0.95; + let height = height as f32 * 0.95; + ffmpeg_command.size(width as u32, height as u32); + } else { + ffmpeg_command.size(width.into(), height.into()); + } + + // if show mouse switch is enabled, draw the mouse to video + if self.record_mouse.is_active() { + ffmpeg_command.args(["-draw_mouse", "1"]); + } else { + ffmpeg_command.args(["-draw_mouse", "0"]); + }; + + // if follow mouse switch is enabled, follow the mouse + if self.follow_mouse.is_active() { + ffmpeg_command.args(["-follow_mouse", "centered"]); + } + + // Disable frame rate if value is zero + if self.record_frames.value() > 0.0 { + ffmpeg_command.args(["-framerate", &self.record_frames.value().to_string()]); + } + + // Video format && input + ffmpeg_command.format(format) + .input(display); + + // Disable bitrate if value is zero + if self.video_record_bitrate.value() > 0.0 { + ffmpeg_command.args([ + "-b:v", + &format!("{}K", self.video_record_bitrate.value()), + ]); + } + + let video_filename = format!( + "{}.temp.without.audio.{}", + self.saved_filename.as_ref().unwrap(), + self.filename.2.active_id().unwrap() + ).replace("gif", "mp4"); + + // Output + ffmpeg_command.arg(video_filename.as_str()) + .overwrite(); + + // sleep for delay + sleep(Duration::from_secs(self.record_delay.value() as u64)); + // start recording and return the process id self.video_process = Some(Rc::new(RefCell::new(ffmpeg_command.spawn().unwrap()))); } else if self.record_video.is_active() && is_wayland() { @@ -231,6 +295,12 @@ impl Ffmpeg { let video_filename = { if is_wayland() { self.temp_video_filename.clone() + } else if !is_wayland() && self.filename.2.active_id().unwrap().as_str() == "gif" { + format!( + "{}.temp.without.audio.{}", + self.saved_filename.as_ref().unwrap(), + self.filename.2.active_id().unwrap() + ).replace("gif", "mp4") } else { format!( "{}.temp.without.audio.{}", @@ -252,10 +322,10 @@ impl Ffmpeg { // convert webm to specified format let mut ffmpeg_command = FfmpegCommand::new(); ffmpeg_command.input(self.temp_video_filename.as_str()); - if self.record_bitrate.value() > 0.0 { + if self.video_record_bitrate.value() > 0.0 { ffmpeg_command.args([ "-b:v", - &format!("{}K", self.record_bitrate.value()), + &format!("{}K", self.video_record_bitrate.value()), ]); } ffmpeg_command.args([ @@ -265,6 +335,16 @@ impl Ffmpeg { ]).overwrite() .spawn() .unwrap().wait().unwrap(); + } else if !is_wayland() && self.filename.2.active_id().unwrap().as_str() == "gif" { + let mut ffmpeg_command = FfmpegCommand::new(); + ffmpeg_command.input(video_filename.as_str()) + .args(["-loop", "0"]) + .filter_complex("fps=10,[0]split[s0][s1]; [s0]palettegen[p]; [s1][p]paletteuse") + .output(self.saved_filename.as_ref().unwrap()) + .overwrite().spawn().unwrap().wait().expect("failed to convert video to gif"); + if is_audio_record { + std::fs::remove_file(audio_filename.clone()).unwrap(); + } } else { let mut move_command = Command::new("mv"); move_command.args([ @@ -279,7 +359,7 @@ impl Ffmpeg { } // if audio record, then merge video and audio - if is_audio_record { + if is_audio_record && self.filename.2.active_id().unwrap().as_str() != "gif" { FfmpegCommand::new().input(video_filename.as_str()) .format("ogg") .input(audio_filename.as_str()) diff --git a/src/main.rs b/src/main.rs index 456366a..9f6358d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -112,8 +112,6 @@ pub fn build_ui(application: &Application) { let main_window: Window = builder.object("main_window").unwrap(); let mouse_switch: CheckButton = builder.object("mouseswitch").unwrap(); let play_button: Button = builder.object("playbutton").unwrap(); - let bitrate_label: Label = builder.object("bitrate_label").unwrap(); - let bitrate_spin: SpinButton = builder.object("bitrate").unwrap(); let record_button: Button = builder.object("recordbutton").unwrap(); let record_label: Label = builder.object("record_label").unwrap(); let record_time_label: Label = builder.object("record_time_label").unwrap(); @@ -123,6 +121,8 @@ pub fn build_ui(application: &Application) { let speaker_switch: CheckButton = builder.object("speakerswitch").unwrap(); let stop_button: Button = builder.object("stopbutton").unwrap(); let stop_label: Label = builder.object("stop_label").unwrap(); + let video_bitrate_label: Label = builder.object("video_bitrate_label").unwrap(); + let video_bitrate_spin: SpinButton = builder.object("video_bitrate").unwrap(); let video_switch: CheckButton = builder.object("videoswitch").unwrap(); let window_grab_button: ToggleButton = builder.object("window_grab_button").unwrap(); let window_grab_icon: Image = builder.object("window_grab_icon").unwrap(); @@ -395,7 +395,7 @@ pub fn build_ui(application: &Application) { .value().unwrap(), None, &mut vec![]).to_string())); delay_spin.set_tooltip_text(Some(&bundle.format_pattern(bundle.get_message("delay-tooltip").unwrap() .value().unwrap(), None, &mut vec![]).to_string())); - bitrate_spin.set_tooltip_text(Some(&bundle.format_pattern(bundle.get_message("bitrate-tooltip").unwrap() + video_bitrate_spin.set_tooltip_text(Some(&bundle.format_pattern(bundle.get_message("video-bitrate-tooltip").unwrap() .value().unwrap(), None, &mut vec![]).to_string())); frames_spin.set_value( config_management::get("default", @@ -410,10 +410,10 @@ pub fn build_ui(application: &Application) { .parse::() .unwrap(), ); - bitrate_spin.set_value( + video_bitrate_spin.set_value( config_management::get("default", &format! - ("bitrate-{}", + ("videobitrate-{}", &format_chooser_combobox.active().unwrap().to_string())) .parse::() .unwrap(), @@ -421,7 +421,7 @@ pub fn build_ui(application: &Application) { let _format_chooser_combobox = format_chooser_combobox.clone(); let _frames_spin = frames_spin.clone(); - let _bitrate_spin = bitrate_spin.clone(); + let _video_bitrate_spin = video_bitrate_spin.clone(); format_chooser_combobox.connect_changed(move |_| { let format_chooser_combobox = _format_chooser_combobox.clone(); if _format_chooser_combobox.active_text().is_some() { @@ -438,10 +438,10 @@ pub fn build_ui(application: &Application) { .parse::() .unwrap(), ); - _bitrate_spin.set_value( + _video_bitrate_spin.set_value( config_management::get("default", &format! - ("bitrate-{}", + ("videobitrate-{}", &format_chooser_combobox.active().unwrap().to_string())) .parse::() .unwrap(), @@ -464,14 +464,14 @@ pub fn build_ui(application: &Application) { "delay", _delay_spin.value().to_string().as_str()); }); - let _bitrate_spin = bitrate_spin.to_owned(); + let _video_bitrate_spin = video_bitrate_spin.to_owned(); let _format_chooser_combobox = format_chooser_combobox.clone(); - bitrate_spin.connect_value_changed(move |_| { + video_bitrate_spin.connect_value_changed(move |_| { config_management::set("default", &format! - ("bitrate-{}", + ("videobitrate-{}", &_format_chooser_combobox.active().unwrap().to_string()), - _bitrate_spin.value().to_string().as_str()); + _video_bitrate_spin.value().to_string().as_str()); }); // Labels @@ -481,7 +481,7 @@ pub fn build_ui(application: &Application) { .value().unwrap(), None, &mut vec![]).to_string()); delay_label.set_label(&bundle.format_pattern(bundle.get_message("delay").unwrap() .value().unwrap(), None, &mut vec![]).to_string()); - bitrate_label.set_label(&bundle.format_pattern(bundle.get_message("bitrate").unwrap() + video_bitrate_label.set_label(&bundle.format_pattern(bundle.get_message("video-bitrate").unwrap() .value().unwrap(), None, &mut vec![]).to_string()); audio_source_label.set_label(&bundle.format_pattern(bundle.get_message("audio-source").unwrap() .value().unwrap(), None, &mut vec![]).to_string()); @@ -626,7 +626,7 @@ pub fn build_ui(application: &Application) { main_context, temp_video_filename: String::new(), bundle: bundle_msg, - record_bitrate: bitrate_spin, + video_record_bitrate: video_bitrate_spin, })); // Record Button