pub struct AudioAdder { /* private fields */ }Expand description
Mux an audio track into a silent (or existing) video file.
The video bitstream is stream-copied (no decode/encode cycle). When the
audio source is shorter than the video and loop_audio
has been called, the audio is looped by re-seeking and advancing the PTS
offset until the video is exhausted.
Returns RemuxError::OperationFailed when no video stream is found
in video_input or no audio stream is found in audio_input.
§Example
ⓘ
use ff_remux::AudioAdder;
AudioAdder::new("silent.mp4", "soundtrack.mp3", "output.mp4")
.loop_audio()
.run()?;Implementations§
Source§impl AudioAdder
impl AudioAdder
Sourcepub fn new(
video_input: impl Into<PathBuf>,
audio_input: impl Into<PathBuf>,
output: impl Into<PathBuf>,
) -> Self
pub fn new( video_input: impl Into<PathBuf>, audio_input: impl Into<PathBuf>, output: impl Into<PathBuf>, ) -> Self
Create a new AudioAdder.
video_input— source file whose video stream is kept.audio_input— source file whose first audio stream is used.output— path for the combined output file.
Examples found in repository?
examples/audio_addition.rs (line 67)
27fn main() {
28 let mut args = std::env::args().skip(1);
29 let mut video = None::<String>;
30 let mut audio = None::<String>;
31 let mut output = None::<String>;
32 let mut loop_audio = false;
33
34 while let Some(flag) = args.next() {
35 match flag.as_str() {
36 "--video" | "-v" => video = Some(args.next().unwrap_or_default()),
37 "--audio" | "-a" => audio = Some(args.next().unwrap_or_default()),
38 "--output" | "-o" => output = Some(args.next().unwrap_or_default()),
39 "--loop" | "-l" => loop_audio = true,
40 other => {
41 eprintln!("Unknown flag: {other}");
42 process::exit(1);
43 }
44 }
45 }
46
47 let video = video.unwrap_or_else(|| {
48 eprintln!("Usage: audio_addition --video <file> --audio <file> --output <file> [--loop]");
49 process::exit(1);
50 });
51 let audio = audio.unwrap_or_else(|| {
52 eprintln!("--audio is required");
53 process::exit(1);
54 });
55 let output = output.unwrap_or_else(|| {
56 eprintln!("--output is required");
57 process::exit(1);
58 });
59
60 println!("Video source: {video}");
61 println!("Audio source: {audio}");
62 println!("Loop audio: {loop_audio}");
63 println!("Output: {output}");
64 println!();
65 println!("Adding audio track (stream-copy, no re-encode)…");
66
67 let mut adder = AudioAdder::new(&video, &audio, &output);
68 if loop_audio {
69 adder = adder.loop_audio();
70 }
71
72 adder.run().unwrap_or_else(|e| {
73 eprintln!("Error: {e}");
74 process::exit(1);
75 });
76
77 let size = match std::fs::metadata(&output) {
78 Ok(m) => {
79 #[allow(clippy::cast_precision_loss)]
80 let kb = m.len() as f64 / 1024.0;
81 if kb < 1024.0 {
82 format!("{kb:.0} KB")
83 } else {
84 format!("{:.1} MB", kb / 1024.0)
85 }
86 }
87 Err(_) => "(unknown size)".to_string(),
88 };
89
90 println!("Done. {output} {size}");
91}Sourcepub fn loop_audio(self) -> Self
pub fn loop_audio(self) -> Self
Loop the audio when it is shorter than the video.
The audio is re-seeked to the start and the PTS offset is advanced each time the audio stream is exhausted, until the video ends.
Examples found in repository?
examples/audio_addition.rs (line 69)
27fn main() {
28 let mut args = std::env::args().skip(1);
29 let mut video = None::<String>;
30 let mut audio = None::<String>;
31 let mut output = None::<String>;
32 let mut loop_audio = false;
33
34 while let Some(flag) = args.next() {
35 match flag.as_str() {
36 "--video" | "-v" => video = Some(args.next().unwrap_or_default()),
37 "--audio" | "-a" => audio = Some(args.next().unwrap_or_default()),
38 "--output" | "-o" => output = Some(args.next().unwrap_or_default()),
39 "--loop" | "-l" => loop_audio = true,
40 other => {
41 eprintln!("Unknown flag: {other}");
42 process::exit(1);
43 }
44 }
45 }
46
47 let video = video.unwrap_or_else(|| {
48 eprintln!("Usage: audio_addition --video <file> --audio <file> --output <file> [--loop]");
49 process::exit(1);
50 });
51 let audio = audio.unwrap_or_else(|| {
52 eprintln!("--audio is required");
53 process::exit(1);
54 });
55 let output = output.unwrap_or_else(|| {
56 eprintln!("--output is required");
57 process::exit(1);
58 });
59
60 println!("Video source: {video}");
61 println!("Audio source: {audio}");
62 println!("Loop audio: {loop_audio}");
63 println!("Output: {output}");
64 println!();
65 println!("Adding audio track (stream-copy, no re-encode)…");
66
67 let mut adder = AudioAdder::new(&video, &audio, &output);
68 if loop_audio {
69 adder = adder.loop_audio();
70 }
71
72 adder.run().unwrap_or_else(|e| {
73 eprintln!("Error: {e}");
74 process::exit(1);
75 });
76
77 let size = match std::fs::metadata(&output) {
78 Ok(m) => {
79 #[allow(clippy::cast_precision_loss)]
80 let kb = m.len() as f64 / 1024.0;
81 if kb < 1024.0 {
82 format!("{kb:.0} KB")
83 } else {
84 format!("{:.1} MB", kb / 1024.0)
85 }
86 }
87 Err(_) => "(unknown size)".to_string(),
88 };
89
90 println!("Done. {output} {size}");
91}Sourcepub fn run(self) -> Result<(), RemuxError>
pub fn run(self) -> Result<(), RemuxError>
Execute the audio addition operation.
§Errors
RemuxError::OperationFailedifvideo_inputhas no video stream oraudio_inputhas no audio stream.RemuxError::Ffmpegif anyFFmpegAPI call fails.
Examples found in repository?
examples/audio_addition.rs (line 72)
27fn main() {
28 let mut args = std::env::args().skip(1);
29 let mut video = None::<String>;
30 let mut audio = None::<String>;
31 let mut output = None::<String>;
32 let mut loop_audio = false;
33
34 while let Some(flag) = args.next() {
35 match flag.as_str() {
36 "--video" | "-v" => video = Some(args.next().unwrap_or_default()),
37 "--audio" | "-a" => audio = Some(args.next().unwrap_or_default()),
38 "--output" | "-o" => output = Some(args.next().unwrap_or_default()),
39 "--loop" | "-l" => loop_audio = true,
40 other => {
41 eprintln!("Unknown flag: {other}");
42 process::exit(1);
43 }
44 }
45 }
46
47 let video = video.unwrap_or_else(|| {
48 eprintln!("Usage: audio_addition --video <file> --audio <file> --output <file> [--loop]");
49 process::exit(1);
50 });
51 let audio = audio.unwrap_or_else(|| {
52 eprintln!("--audio is required");
53 process::exit(1);
54 });
55 let output = output.unwrap_or_else(|| {
56 eprintln!("--output is required");
57 process::exit(1);
58 });
59
60 println!("Video source: {video}");
61 println!("Audio source: {audio}");
62 println!("Loop audio: {loop_audio}");
63 println!("Output: {output}");
64 println!();
65 println!("Adding audio track (stream-copy, no re-encode)…");
66
67 let mut adder = AudioAdder::new(&video, &audio, &output);
68 if loop_audio {
69 adder = adder.loop_audio();
70 }
71
72 adder.run().unwrap_or_else(|e| {
73 eprintln!("Error: {e}");
74 process::exit(1);
75 });
76
77 let size = match std::fs::metadata(&output) {
78 Ok(m) => {
79 #[allow(clippy::cast_precision_loss)]
80 let kb = m.len() as f64 / 1024.0;
81 if kb < 1024.0 {
82 format!("{kb:.0} KB")
83 } else {
84 format!("{:.1} MB", kb / 1024.0)
85 }
86 }
87 Err(_) => "(unknown size)".to_string(),
88 };
89
90 println!("Done. {output} {size}");
91}Auto Trait Implementations§
impl Freeze for AudioAdder
impl RefUnwindSafe for AudioAdder
impl Send for AudioAdder
impl Sync for AudioAdder
impl Unpin for AudioAdder
impl UnsafeUnpin for AudioAdder
impl UnwindSafe for AudioAdder
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more