From 7fe3a99bcd28142d43d193f435d1e37c3472a874 Mon Sep 17 00:00:00 2001 From: ochibani <11yzyv86j@relay.firefox.com> Date: Sun, 16 Jun 2024 01:40:13 +0200 Subject: [PATCH] update ffmpeg --- Cargo.lock | 60 +++++++++------- Cargo.toml | 3 +- interfaces/main.ui | 64 ++++++++++++++--- locales/ar.ftl | 8 +++ locales/ar_YE.ftl | 8 +++ locales/en.ftl | 10 ++- locales/en_US.ftl | 10 ++- src/config_management.rs | 17 +++++ src/ffmpeg_interface.rs | 147 +++++++++++++++------------------------ src/main.rs | 90 ++++++++++++++---------- 10 files changed, 253 insertions(+), 164 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b6c9019..0b909ff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -285,9 +285,9 @@ dependencies = [ [[package]] name = "async-signal" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "329972aa325176e89114919f2a80fdae4f4c040f66a370b1a1159c6c0f94e7aa" +checksum = "794f185324c2f00e771cd9f1ae8b5ac68be2ca7abb129a87afd6e86d228bc54d" dependencies = [ "async-io 2.3.3", "async-lock 3.4.0", @@ -432,6 +432,7 @@ dependencies = [ "cpal", "dark-light", "dirs", + "ffmpeg-sidecar", "filename", "fluent-bundle", "gdk-pixbuf 0.9.0", @@ -484,7 +485,7 @@ dependencies = [ [[package]] name = "cairo-rs" version = "0.20.0" -source = "git+https://github.com/gtk-rs/gtk-rs-core?branch=master#7cd06421c5027e2c1b4cc657529e6acd8bac1ea3" +source = "git+https://github.com/gtk-rs/gtk-rs-core?branch=master#0a0d3166157123035acc396c00ce8816011b1697" dependencies = [ "bitflags 2.5.0", "cairo-sys-rs 0.20.0", @@ -507,7 +508,7 @@ dependencies = [ [[package]] name = "cairo-sys-rs" version = "0.20.0" -source = "git+https://github.com/gtk-rs/gtk-rs-core?branch=master#7cd06421c5027e2c1b4cc657529e6acd8bac1ea3" +source = "git+https://github.com/gtk-rs/gtk-rs-core?branch=master#0a0d3166157123035acc396c00ce8816011b1697" dependencies = [ "glib-sys 0.20.0", "libc", @@ -889,6 +890,15 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" +[[package]] +name = "ffmpeg-sidecar" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bec830aba6cd3da7621c58e8f06727e3b750e8383bcd934d789f2b9c3c4ea595" +dependencies = [ + "anyhow", +] + [[package]] name = "field-offset" version = "0.3.6" @@ -1091,7 +1101,7 @@ dependencies = [ [[package]] name = "gdk-pixbuf" version = "0.20.0" -source = "git+https://github.com/gtk-rs/gtk-rs-core?branch=master#7cd06421c5027e2c1b4cc657529e6acd8bac1ea3" +source = "git+https://github.com/gtk-rs/gtk-rs-core?branch=master#0a0d3166157123035acc396c00ce8816011b1697" dependencies = [ "gdk-pixbuf-sys 0.20.0", "gio 0.20.0", @@ -1128,7 +1138,7 @@ dependencies = [ [[package]] name = "gdk-pixbuf-sys" version = "0.20.0" -source = "git+https://github.com/gtk-rs/gtk-rs-core?branch=master#7cd06421c5027e2c1b4cc657529e6acd8bac1ea3" +source = "git+https://github.com/gtk-rs/gtk-rs-core?branch=master#0a0d3166157123035acc396c00ce8816011b1697" dependencies = [ "gio-sys 0.20.0", "glib-sys 0.20.0", @@ -1173,7 +1183,7 @@ dependencies = [ [[package]] name = "gdk4" version = "0.9.0" -source = "git+https://github.com/gtk-rs/gtk4-rs.git#32e7155cd32bd5c27e1847c7e38aae825642043a" +source = "git+https://github.com/gtk-rs/gtk4-rs.git#d1c8a6fedad4d21dfbdb09abe607bf1875cada7e" dependencies = [ "cairo-rs 0.20.0", "gdk-pixbuf 0.20.0", @@ -1204,7 +1214,7 @@ dependencies = [ [[package]] name = "gdk4-sys" version = "0.9.0" -source = "git+https://github.com/gtk-rs/gtk4-rs.git#32e7155cd32bd5c27e1847c7e38aae825642043a" +source = "git+https://github.com/gtk-rs/gtk4-rs.git#d1c8a6fedad4d21dfbdb09abe607bf1875cada7e" dependencies = [ "cairo-sys-rs 0.20.0", "gdk-pixbuf-sys 0.20.0", @@ -1279,7 +1289,7 @@ dependencies = [ [[package]] name = "gio" version = "0.20.0" -source = "git+https://github.com/gtk-rs/gtk-rs-core?branch=master#7cd06421c5027e2c1b4cc657529e6acd8bac1ea3" +source = "git+https://github.com/gtk-rs/gtk-rs-core?branch=master#0a0d3166157123035acc396c00ce8816011b1697" dependencies = [ "futures-channel", "futures-core", @@ -1335,7 +1345,7 @@ dependencies = [ [[package]] name = "gio-sys" version = "0.20.0" -source = "git+https://github.com/gtk-rs/gtk-rs-core?branch=master#7cd06421c5027e2c1b4cc657529e6acd8bac1ea3" +source = "git+https://github.com/gtk-rs/gtk-rs-core?branch=master#0a0d3166157123035acc396c00ce8816011b1697" dependencies = [ "glib-sys 0.20.0", "gobject-sys 0.20.0", @@ -1409,7 +1419,7 @@ dependencies = [ [[package]] name = "glib" version = "0.20.0" -source = "git+https://github.com/gtk-rs/gtk-rs-core?branch=master#7cd06421c5027e2c1b4cc657529e6acd8bac1ea3" +source = "git+https://github.com/gtk-rs/gtk-rs-core?branch=master#0a0d3166157123035acc396c00ce8816011b1697" dependencies = [ "bitflags 2.5.0", "futures-channel", @@ -1476,7 +1486,7 @@ dependencies = [ [[package]] name = "glib-macros" version = "0.20.0" -source = "git+https://github.com/gtk-rs/gtk-rs-core?branch=master#7cd06421c5027e2c1b4cc657529e6acd8bac1ea3" +source = "git+https://github.com/gtk-rs/gtk-rs-core?branch=master#0a0d3166157123035acc396c00ce8816011b1697" dependencies = [ "heck 0.5.0", "proc-macro-crate 3.1.0", @@ -1518,7 +1528,7 @@ dependencies = [ [[package]] name = "glib-sys" version = "0.20.0" -source = "git+https://github.com/gtk-rs/gtk-rs-core?branch=master#7cd06421c5027e2c1b4cc657529e6acd8bac1ea3" +source = "git+https://github.com/gtk-rs/gtk-rs-core?branch=master#0a0d3166157123035acc396c00ce8816011b1697" dependencies = [ "libc", "system-deps 6.2.2", @@ -1578,7 +1588,7 @@ dependencies = [ [[package]] name = "gobject-sys" version = "0.20.0" -source = "git+https://github.com/gtk-rs/gtk-rs-core?branch=master#7cd06421c5027e2c1b4cc657529e6acd8bac1ea3" +source = "git+https://github.com/gtk-rs/gtk-rs-core?branch=master#0a0d3166157123035acc396c00ce8816011b1697" dependencies = [ "glib-sys 0.20.0", "libc", @@ -2308,7 +2318,7 @@ dependencies = [ [[package]] name = "pango" version = "0.20.0" -source = "git+https://github.com/gtk-rs/gtk-rs-core?branch=master#7cd06421c5027e2c1b4cc657529e6acd8bac1ea3" +source = "git+https://github.com/gtk-rs/gtk-rs-core?branch=master#0a0d3166157123035acc396c00ce8816011b1697" dependencies = [ "gio 0.20.0", "glib 0.20.0", @@ -2331,7 +2341,7 @@ dependencies = [ [[package]] name = "pango-sys" version = "0.20.0" -source = "git+https://github.com/gtk-rs/gtk-rs-core?branch=master#7cd06421c5027e2c1b4cc657529e6acd8bac1ea3" +source = "git+https://github.com/gtk-rs/gtk-rs-core?branch=master#0a0d3166157123035acc396c00ce8816011b1697" dependencies = [ "glib-sys 0.20.0", "gobject-sys 0.20.0", @@ -2551,9 +2561,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.4" +version = "1.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" +checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" dependencies = [ "aho-corasick", "memchr", @@ -2563,9 +2573,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" dependencies = [ "aho-corasick", "memchr", @@ -2574,9 +2584,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "rust-ini" @@ -3475,12 +3485,12 @@ dependencies = [ [[package]] name = "xdg-home" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21e5a325c3cb8398ad6cf859c1135b25dd29e186679cf2da7581d9679f63b38e" +checksum = "ca91dcf8f93db085f3a0a29358cd0b9d670915468f4290e8b85d118a34211ab8" dependencies = [ "libc", - "winapi", + "windows-sys 0.52.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 79ec0f4..13dc5a3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,8 +11,9 @@ chrono = "0.4.19" cpal = "0.15.3" dark-light = "1.0.0" dirs = "4.0.0" -fluent-bundle = "0.15.3" +ffmpeg-sidecar = "1.1.0" filename = "0.1.1" +fluent-bundle = "0.15.3" gdk = { git = "https://github.com/gtk-rs/gtk4-rs.git", package = "gdk4"} gdk-pixbuf = "0.9.0" gio = { version = "0.15.0" } diff --git a/interfaces/main.ui b/interfaces/main.ui index f693eb7..e807bff 100644 --- a/interfaces/main.ui +++ b/interfaces/main.ui @@ -15,17 +15,12 @@ 1 200 - 30 1 10 - 100 - 1 - 10 - - - 100 + 0 + 51 1 10 @@ -403,6 +398,20 @@ + + + checkbutton + True + True + False + False + True + + 1 + 2 + + + True @@ -478,6 +487,43 @@ + + + True + True + label + + 0 + 2 + + + + + + True + True + 2 + 2 + number + adjustment3 + 1 + True + + 1 + 2 + + + + + + True + 0.0 + + 1 + 2 + + + @@ -502,7 +548,7 @@ True 1 - 1 + 2 @@ -515,7 +561,7 @@ label 0 - 1 + 2 diff --git a/locales/ar.ftl b/locales/ar.ftl index 0975019..24b3e5e 100644 --- a/locales/ar.ftl +++ b/locales/ar.ftl @@ -102,12 +102,18 @@ license = لمزيد تفاصيل راجع رخصة جنو العمومية. إن لم تكن حصلت على نسخة من رخصة جنو العمومية مع المسجل الأزرق فانظر { license-website }. +# Quality label +quality = الجودة: + # Recording button record = سجل # Record audio label record-audio = تسجيل الصوت +# Record speaker label +record-speaker = تسجيل المكبر + # Record video label record-video = تسجيل الصورة @@ -140,8 +146,10 @@ format-tooltip = لاختيار صيغة الخَرج frames-tooltip = عدد الإطارات في الثانية hide-tooltip = لإخفاء نافذة المسجل الأزرق عند بدء التسجيل mouse-tooltip = يظهر مؤشر الفأرة عند التسجيل +quality-tooltip = جودة التسجيل (CRF) record-tooltip = يبدأ تسجيل الشاشة screen-tooltip = يحدد الشاشة ليسجلها +speaker-tooltip = تسجيل صوت المكبر stop-tooltip = وقف تسجيل الشاشة video-tooltip = يسجل الشاشة wayland-tooltip = غير مدعوم في وايلاند diff --git a/locales/ar_YE.ftl b/locales/ar_YE.ftl index 0975019..24b3e5e 100644 --- a/locales/ar_YE.ftl +++ b/locales/ar_YE.ftl @@ -102,12 +102,18 @@ license = لمزيد تفاصيل راجع رخصة جنو العمومية. إن لم تكن حصلت على نسخة من رخصة جنو العمومية مع المسجل الأزرق فانظر { license-website }. +# Quality label +quality = الجودة: + # Recording button record = سجل # Record audio label record-audio = تسجيل الصوت +# Record speaker label +record-speaker = تسجيل المكبر + # Record video label record-video = تسجيل الصورة @@ -140,8 +146,10 @@ format-tooltip = لاختيار صيغة الخَرج frames-tooltip = عدد الإطارات في الثانية hide-tooltip = لإخفاء نافذة المسجل الأزرق عند بدء التسجيل mouse-tooltip = يظهر مؤشر الفأرة عند التسجيل +quality-tooltip = جودة التسجيل (CRF) record-tooltip = يبدأ تسجيل الشاشة screen-tooltip = يحدد الشاشة ليسجلها +speaker-tooltip = تسجيل صوت المكبر stop-tooltip = وقف تسجيل الشاشة video-tooltip = يسجل الشاشة wayland-tooltip = غير مدعوم في وايلاند diff --git a/locales/en.ftl b/locales/en.ftl index f758083..c0f51ba 100644 --- a/locales/en.ftl +++ b/locales/en.ftl @@ -99,12 +99,18 @@ 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 }. +# Quality label +quality = Quality: + # Recording button record = Record # Record audio label record-audio = Record Audio +# Record speaker label +record-speaker = Record Speaker + # Record video label record-video = Record Video @@ -132,13 +138,15 @@ audio-source-tooltip = Select audio source audio-tooltip = Audio recording delay-tooltip = Delay time before starting record folder-tooltip = Select storage location -follow-mouse-tooltip = Highlight Mouse +follow-mouse-tooltip = Highlight mouse format-tooltip = Select file format frames-tooltip = Frames rate hide-tooltip = Hide window when start recording mouse-tooltip = Mouse appears in video recording +quality-tooltip = Video quality (CRF) record-tooltip = Start screen record screen-tooltip = Select screen to record +speaker-tooltip = Speakr sound recording stop-tooltip = Stop screen recording video-tooltip = Video recording wayland-tooltip = Not supported in Wayland diff --git a/locales/en_US.ftl b/locales/en_US.ftl index f758083..c0f51ba 100644 --- a/locales/en_US.ftl +++ b/locales/en_US.ftl @@ -99,12 +99,18 @@ 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 }. +# Quality label +quality = Quality: + # Recording button record = Record # Record audio label record-audio = Record Audio +# Record speaker label +record-speaker = Record Speaker + # Record video label record-video = Record Video @@ -132,13 +138,15 @@ audio-source-tooltip = Select audio source audio-tooltip = Audio recording delay-tooltip = Delay time before starting record folder-tooltip = Select storage location -follow-mouse-tooltip = Highlight Mouse +follow-mouse-tooltip = Highlight mouse format-tooltip = Select file format frames-tooltip = Frames rate hide-tooltip = Hide window when start recording mouse-tooltip = Mouse appears in video recording +quality-tooltip = Video quality (CRF) record-tooltip = Start screen record screen-tooltip = Select screen to record +speaker-tooltip = Speakr sound recording stop-tooltip = Stop screen recording video-tooltip = Video recording wayland-tooltip = Not supported in Wayland diff --git a/src/config_management.rs b/src/config_management.rs index bc81d18..49eada4 100755 --- a/src/config_management.rs +++ b/src/config_management.rs @@ -29,6 +29,8 @@ pub fn initialize() -> PathBuf { fn default() { set("default", "frame", "60"); set("default", "delay", "0"); + set("default", "format", "0"); + set("default", "quality", get_quality(&self::get("default", "format"))); set( "default", "folder", @@ -54,6 +56,7 @@ fn default() { set("default", "mousecheck", "1"); set("default", "followmousecheck", "0"); set("default", "hidecheck", "0"); + set("default", "speakercheck", "0"); } fn merge_previous_version() -> Option { @@ -125,3 +128,17 @@ pub fn folder_icon(folder_chooser_name: Option<&str>) -> &str { } } } + +pub fn get_quality(format: &str) -> &str { + let crf = match format { + "0" => "23", + "1" => "23", + "2" => "10.0", + "3" => "23", + "4" => "23", + "5" => "23", + "6" => "23.0", + _=> "23", // Default value + }; + crf +} diff --git a/src/ffmpeg_interface.rs b/src/ffmpeg_interface.rs index 91227b1..8c8e73b 100644 --- a/src/ffmpeg_interface.rs +++ b/src/ffmpeg_interface.rs @@ -2,12 +2,14 @@ extern crate subprocess; use crate::utils::{is_snap, is_wayland}; use crate::wayland_record::{CursorModeTypes, RecordTypes, WaylandRecorder}; use chrono::prelude::*; +use ffmpeg_sidecar::child::FfmpegChild; +use ffmpeg_sidecar::command::FfmpegCommand; use gtk::{prelude::*, ResponseType}; use gtk::{ButtonsType, DialogFlags, MessageDialog, MessageType}; use gtk::{CheckButton, ComboBoxText, Entry, FileChooserNative, SpinButton, Window}; use std::cell::RefCell; use std::path::PathBuf; -use std::process::{Child, Command}; +use std::process::Command; use std::rc::Rc; use std::sync::mpsc::Sender; use std::thread::sleep; @@ -26,8 +28,8 @@ pub struct Ffmpeg { pub record_frames: SpinButton, pub record_delay: SpinButton, pub command: Entry, - pub video_process: Option>>, - pub audio_process: Option>>, + pub video_process: Option>>, + pub audio_process: Option>>, pub saved_filename: Option, pub unbound: Option>, pub window: Window, @@ -36,6 +38,7 @@ pub struct Ffmpeg { pub main_context: gtk::glib::MainContext, pub temp_video_filename: String, pub bundle: String, + pub record_quality: SpinButton, } impl Ffmpeg { @@ -82,27 +85,17 @@ impl Ffmpeg { } if self.record_video.is_active() && !is_wayland() { - let mut ffmpeg_command: Command = Command::new("ffmpeg"); + let mut ffmpeg_command = FfmpegCommand::new(); // record video with specified width and hight - ffmpeg_command.args([ - "-video_size", - format!("{}x{}", width, height).as_str(), - "-framerate", - self.record_frames.value().to_string().as_str(), - "-f", - "x11grab", - "-i", - format!( - "{}+{},{}", - std::env::var("DISPLAY") - .unwrap_or_else(|_| ":0".to_string()) - .as_str(), - x, - y - ) - .as_str(), - ]); + ffmpeg_command.size(width.into(), height.into()) + .rate(self.record_frames.value() as f32) + .format("x11grab") + .input(format!("{}+{},{}", std::env::var("DISPLAY").unwrap_or_else(|_| ":0".to_string()) + .as_str(), + x, + y + )); // if show mouse switch is enabled, draw the mouse to video ffmpeg_command.arg("-draw_mouse"); @@ -123,9 +116,8 @@ impl Ffmpeg { self.filename.2.active_id().unwrap() ); + ffmpeg_command.crf(self.record_quality.value() as u32); ffmpeg_command.args([ - "-crf", - "1", { if self.record_audio.is_active() { video_filename.as_str() @@ -133,8 +125,8 @@ impl Ffmpeg { self.saved_filename.as_ref().unwrap() } }, - "-y", ]); + ffmpeg_command.overwrite(); // sleep for delay sleep(Duration::from_secs(self.record_delay.value() as u64)); @@ -171,18 +163,15 @@ impl Ffmpeg { } if self.record_audio.is_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.active_id().unwrap()); - ffmpeg_command.arg("-f"); - ffmpeg_command.arg("ogg"); + let mut ffmpeg_command = FfmpegCommand::new(); + ffmpeg_command.format("pulse") + .input(&self.audio_id.active_id().unwrap()) + .format("ogg"); ffmpeg_command.arg(format!( "{}.temp.audio", self.saved_filename.as_ref().unwrap() )); - ffmpeg_command.arg("-y"); + ffmpeg_command.overwrite(); self.audio_process = Some(Rc::new(RefCell::new(ffmpeg_command.spawn().unwrap()))); } @@ -192,19 +181,11 @@ impl Ffmpeg { pub fn stop_record(&mut self) { // kill the process to stop recording if self.video_process.is_some() { - Command::new("kill") - .arg(format!( - "{}", - self.video_process.clone().unwrap().borrow_mut().id() - )) - .output() - .unwrap(); - self.video_process .clone() .unwrap() .borrow_mut() - .wait() + .quit() .unwrap(); println!("video killed"); @@ -213,20 +194,13 @@ impl Ffmpeg { } if self.audio_process.is_some() { - Command::new("kill") - .arg(format!( - "{}", - self.audio_process.clone().unwrap().borrow_mut().id() - )) - .output() - .unwrap(); - self.audio_process .clone() .unwrap() .borrow_mut() - .wait() + .quit() .unwrap(); + println!("audio killed"); } @@ -252,20 +226,15 @@ impl Ffmpeg { if is_video_record { if is_wayland() { // convert webm to specified format - Command::new("ffmpeg") - .args([ - "-i", - self.temp_video_filename - .as_str(), - "-crf", - "23", // default quality - "-c:a", - self.filename.2.active_id().unwrap().as_str(), - self.saved_filename.as_ref().unwrap(), - "-y", - ]) - .output() - .unwrap(); + let mut ffmpeg_command = FfmpegCommand::new(); + ffmpeg_command.input(self.temp_video_filename.as_str()) + .crf(self.record_quality.value() as u32) + .args([ + "-c:a", + self.filename.2.active_id().unwrap().as_str(), + self.saved_filename.as_ref().unwrap(), + ]).overwrite().spawn() + .unwrap().wait().unwrap(); } else { let mut move_command = Command::new("mv"); move_command.args([ @@ -281,23 +250,20 @@ impl Ffmpeg { // if audio record, then merge video and audio if is_audio_record { - Command::new("ffmpeg") - .args([ - "-i", - video_filename.as_str(), - "-f", - "ogg", - "-i", - audio_filename.as_str(), - "-crf", - "23", // default quality - "-c:a", - "aac", - self.saved_filename.as_ref().unwrap(), - "-y", - ]) - .output() - .expect("failed to merge video and audio"); + FfmpegCommand::new().input(video_filename.as_str()) + .format("ogg") + .input(audio_filename.as_str()) + .crf(self.record_quality.value() as u32) + .args([ + "-c:a", + "aac", + self.saved_filename.as_ref().unwrap(), + ]) + .overwrite() + .spawn() + .unwrap() + .wait() + .expect("failed to merge video and audio"); std::fs::remove_file(audio_filename).unwrap(); } @@ -306,16 +272,13 @@ impl Ffmpeg { } // if only audio is recording then convert it to chosen format else if is_audio_record { - Command::new("ffmpeg") - .args([ - "-f", - "ogg", - "-i", - audio_filename.as_str(), - self.saved_filename.as_ref().unwrap(), - ]) - .output() - .expect("failed convert audio to video"); + let mut ffmpeg_command = FfmpegCommand::new(); + ffmpeg_command.format("ogg").input(audio_filename.as_str()).arg( + self.saved_filename.as_ref().unwrap(), + ).spawn() + .unwrap() + .wait() + .expect("failed convert audio to video"); std::fs::remove_file(audio_filename).unwrap(); } diff --git a/src/main.rs b/src/main.rs index 66a3c61..4a4b13e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -81,7 +81,6 @@ pub fn build_ui(application: &Application) { config_management::initialize(); // Get Objects from UI - let main_window: Window = builder.object("main_window").unwrap(); let area_apply_label: Label = builder.object("area_apply").unwrap(); let area_chooser_window: Window = builder.object("area_chooser_window").unwrap(); let area_grab_button: ToggleButton = builder.object("area_grab_button").unwrap(); @@ -110,14 +109,18 @@ pub fn build_ui(application: &Application) { let frames_label: Label = builder.object("frames_label").unwrap(); let frames_spin: SpinButton = builder.object("frames").unwrap(); let hide_switch: CheckButton = builder.object("hideswitch").unwrap(); + 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 quality_label: Label = builder.object("quality_label").unwrap(); + let quality_spin: SpinButton = builder.object("quality").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(); let screen_grab_button: ToggleButton = builder.object("screen_grab_button").unwrap(); let screen_grab_icon: Image = builder.object("screen_grab_icon").unwrap(); let screen_grab_label: Label = builder.object("screen_grab_label").unwrap(); + 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_switch: CheckButton = builder.object("videoswitch").unwrap(); @@ -133,10 +136,6 @@ pub fn build_ui(application: &Application) { area_chooser_window.set_title(Some(&bundle.format_pattern(bundle.get_message("area-chooser").unwrap() .value().unwrap(), None, &mut vec![]).to_string())); // Title is hidden - // disable interaction with main window - // main_window.set_can_focus(false); - // main_window.set_can_target(false); - // Hide stop & play buttons stop_button.hide(); play_button.hide(); @@ -169,7 +168,7 @@ pub fn build_ui(application: &Application) { filename_entry.set_text(&config_management::get("default", "filename")); command_entry.set_text(&config_management::get("default", "command")); - // CheckBox + // Format combobox format_chooser_combobox.append(Some("mp4"), &bundle.format_pattern(bundle.get_message("mp4-format").unwrap() .value().unwrap(), None, &mut vec![]).to_string()); format_chooser_combobox.append( @@ -187,39 +186,13 @@ pub fn build_ui(application: &Application) { .value().unwrap(), None, &mut vec![]).to_string()); format_chooser_combobox.append(Some("nut"), &bundle.format_pattern(bundle.get_message("nut-format").unwrap() .value().unwrap(), None, &mut vec![]).to_string()); - format_chooser_combobox.set_active(Some(0)); + //format_chooser_combobox.set_active(Some(config_management::get("default", "format").parse::().unwrap())); // Get audio sources let input_device = host_audio_device.input_devices().unwrap(); let sources_descriptions: Vec = input_device .filter_map(|device| device.name().ok()) .collect(); - /*let sources_descriptions: Vec = { - let list_sources_child = Command::new("pactl") - .args(&["list", "sources"]) - .stdout(Stdio::piped()) - .spawn(); - let sources_descriptions = String::from_utf8(if let Ok(..) = list_sources_child { - Command::new("grep") - .args(&["-e", "device.description"]) - .stdin(list_sources_child.unwrap().stdout.take().unwrap()) - .output() - .unwrap() - .stdout - } else { - Vec::new() - }) - .unwrap(); - sources_descriptions - .split('\n') - .map(|s| { - s.trim() - .replace("device.description = ", "") - .replace('\"', "") - }) - .filter(|s| !s.is_empty()) - .collect() - };*/ audio_source_combobox.append(Some("default"), &bundle.format_pattern(bundle.get_message("audio-input").unwrap() .value().unwrap(), None, &mut vec![]).to_string()); @@ -249,11 +222,16 @@ pub fn build_ui(application: &Application) { .value().unwrap(), None, &mut vec![]).to_string())); hide_switch.set_label(Some(&bundle.format_pattern(bundle.get_message("auto-hide").unwrap() .value().unwrap(), None, &mut vec![]).to_string())); + speaker_switch.set_tooltip_text(Some(&bundle.format_pattern(bundle.get_message("speaker-tooltip").unwrap() + .value().unwrap(), None, &mut vec![]).to_string())); + speaker_switch.set_label(Some(&bundle.format_pattern(bundle.get_message("record-speaker").unwrap() + .value().unwrap(), None, &mut vec![]).to_string())); video_switch.set_active(config_management::get_bool("default", "videocheck")); audio_switch.set_active(config_management::get_bool("default", "audiocheck")); mouse_switch.set_active(config_management::get_bool("default", "mousecheck")); follow_mouse_switch.set_active(config_management::get_bool("default", "followmousecheck")); hide_switch.set_active(config_management::get_bool("default", "hidecheck")); + speaker_switch.set_active(config_management::get_bool("default", "speakercheck")); let _video_switch = video_switch.clone(); let _audio_switch = audio_switch.clone(); @@ -295,6 +273,9 @@ pub fn build_ui(application: &Application) { hide_switch.connect_toggled(|switch: &CheckButton| { config_management::set_bool("default", "hidecheck", switch.is_active()); }); + speaker_switch.connect_toggled(|switch: &CheckButton| { + config_management::set_bool("default", "speakercheck", switch.is_active()); + }); match dark_light::detect() { // Dark mode @@ -414,17 +395,43 @@ 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())); + quality_spin.set_tooltip_text(Some(&bundle.format_pattern(bundle.get_message("quality-tooltip").unwrap() + .value().unwrap(), None, &mut vec![]).to_string())); frames_spin.set_value( config_management::get("default", "frame") .parse::() .unwrap(), ); - delay_spin.set_value( config_management::get("default", "delay") .parse::() .unwrap(), ); + //quality_spin.set_value( + //config_management::get("default", "quality") + //.parse::() + //.unwrap(), + //); + + let _format_chooser_combobox = format_chooser_combobox.clone(); + let _quality_spin = quality_spin.clone(); + format_chooser_combobox.connect_changed(move |_| { + if _format_chooser_combobox.active_text().is_some() { + config_management::set( + "default", + "format", + &_format_chooser_combobox.active().unwrap().to_string(), + ); + let quality_spin = _quality_spin.clone(); + _quality_spin.connect_value_changed(move |_| { + config_management::set( + "default", + "quality", + quality_spin.to_string().as_str(), + ); + }); + } + }); let _frames_spin = frames_spin.to_owned(); frames_spin.connect_value_changed(move |_| { @@ -436,7 +443,17 @@ pub fn build_ui(application: &Application) { }); let _delay_spin = delay_spin.to_owned(); delay_spin.connect_value_changed(move |_| { - config_management::set("default", "delay", _delay_spin.value().to_string().as_str()); + config_management::set("default", + "delay", + _delay_spin.value().to_string().as_str()); + }); + let _quality_spin = delay_spin.to_owned(); + quality_spin.connect_value_changed(move |_| { + config_management::set( + "default", + "quality", + _quality_spin.value().to_string().as_str(), + ); }); // Labels @@ -446,6 +463,8 @@ 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()); + quality_label.set_label(&bundle.format_pattern(bundle.get_message("quality").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()); @@ -583,6 +602,7 @@ pub fn build_ui(application: &Application) { main_context, temp_video_filename: String::new(), bundle: bundle_msg, + record_quality: quality_spin, })); // Record Button