#![allow(clippy::unwrap_used)]
mod fixtures;
use ff_encode::{AudioAdder, EncodeError};
use fixtures::{FileGuard, assert_valid_output_file, create_black_frame, test_output_path};
#[test]
fn audio_adder_should_fail_when_video_input_missing() {
let result = AudioAdder::new("nonexistent_video.mp4", "nonexistent_audio.mp3", "out.mp4").run();
assert!(
result.is_err(),
"expected error for nonexistent video input, got Ok(())"
);
}
#[test]
fn audio_adder_should_fail_when_audio_input_has_no_audio_stream() {
use ff_encode::{BitrateMode, Preset, VideoCodec, VideoEncoder};
let video_path = test_output_path("adder_video.mp4");
let audio_only_video_path = test_output_path("adder_video_no_audio.mp4");
let output_path = test_output_path("adder_no_audio_stream_out.mp4");
let _guard_v = FileGuard::new(video_path.clone());
let _guard_a = FileGuard::new(audio_only_video_path.clone());
let _guard_o = FileGuard::new(output_path.clone());
let mut enc = match VideoEncoder::create(&video_path)
.video(160, 120, 15.0)
.video_codec(VideoCodec::Mpeg4)
.bitrate_mode(BitrateMode::Cbr(200_000))
.preset(Preset::Ultrafast)
.build()
{
Ok(e) => e,
Err(e) => {
println!("Skipping: video encoder unavailable ({e})");
return;
}
};
for _ in 0..15 {
let frame = create_black_frame(160, 120);
if let Err(e) = enc.push_video(&frame) {
println!("Skipping: push_video failed ({e})");
return;
}
}
if let Err(e) = enc.finish() {
println!("Skipping: encoder.finish failed ({e})");
return;
}
let mut enc2 = match VideoEncoder::create(&audio_only_video_path)
.video(160, 120, 15.0)
.video_codec(VideoCodec::Mpeg4)
.bitrate_mode(BitrateMode::Cbr(200_000))
.preset(Preset::Ultrafast)
.build()
{
Ok(e) => e,
Err(e) => {
println!("Skipping: video encoder unavailable ({e})");
return;
}
};
for _ in 0..15 {
let frame = create_black_frame(160, 120);
if let Err(e) = enc2.push_video(&frame) {
println!("Skipping: push_video failed ({e})");
return;
}
}
if let Err(e) = enc2.finish() {
println!("Skipping: encoder.finish failed ({e})");
return;
}
let result = AudioAdder::new(&video_path, &audio_only_video_path, &output_path).run();
assert!(
matches!(result, Err(EncodeError::MediaOperationFailed { .. })),
"expected MediaOperationFailed when audio_input has no audio stream, got {result:?}"
);
}
#[test]
fn audio_adder_should_produce_output_with_both_streams() {
use ff_encode::{AudioCodec, AudioEncoder, BitrateMode, Preset, VideoCodec, VideoEncoder};
use ff_format::{AudioFrame, SampleFormat};
let video_path = test_output_path("adder_video_source.mp4");
let audio_path = test_output_path("adder_audio_source.mp3");
let output_path = test_output_path("adder_combined_out.mp4");
let _guard_v = FileGuard::new(video_path.clone());
let _guard_a = FileGuard::new(audio_path.clone());
let _guard_o = FileGuard::new(output_path.clone());
let mut venc = match VideoEncoder::create(&video_path)
.video(160, 120, 15.0)
.video_codec(VideoCodec::Mpeg4)
.bitrate_mode(BitrateMode::Cbr(200_000))
.preset(Preset::Ultrafast)
.build()
{
Ok(e) => e,
Err(e) => {
println!("Skipping: video encoder unavailable ({e})");
return;
}
};
for _ in 0..15 {
let frame = create_black_frame(160, 120);
if let Err(e) = venc.push_video(&frame) {
println!("Skipping: push_video failed ({e})");
return;
}
}
if let Err(e) = venc.finish() {
println!("Skipping: video encoder.finish failed ({e})");
return;
}
let mut aenc = match AudioEncoder::create(&audio_path)
.audio(44100, 1)
.audio_codec(AudioCodec::Mp3)
.audio_bitrate(64_000)
.build()
{
Ok(e) => e,
Err(e) => {
println!("Skipping: audio encoder unavailable ({e})");
return;
}
};
let frame_size: usize = 1152;
let silence = match AudioFrame::empty(frame_size, 1, 44100, SampleFormat::F32) {
Ok(f) => f,
Err(e) => {
println!("Skipping: AudioFrame::empty failed ({e})");
return;
}
};
let frames_needed = (44100 / frame_size) + 1;
for _ in 0..frames_needed {
if let Err(e) = aenc.push(&silence) {
println!("Skipping: aenc.push failed ({e})");
return;
}
}
if let Err(e) = aenc.finish() {
println!("Skipping: audio encoder.finish failed ({e})");
return;
}
let result = AudioAdder::new(&video_path, &audio_path, &output_path).run();
match result {
Ok(()) => {}
Err(e) => {
println!("Skipping: AudioAdder::run failed ({e})");
return;
}
}
assert_valid_output_file(&output_path);
}
#[test]
fn audio_adder_loop_audio_should_produce_output_when_audio_is_shorter() {
use ff_encode::{AudioCodec, AudioEncoder, BitrateMode, Preset, VideoCodec, VideoEncoder};
use ff_format::{AudioFrame, SampleFormat};
let video_path = test_output_path("adder_loop_video.mp4");
let audio_path = test_output_path("adder_loop_audio.mp3");
let output_path = test_output_path("adder_loop_out.mp4");
let _guard_v = FileGuard::new(video_path.clone());
let _guard_a = FileGuard::new(audio_path.clone());
let _guard_o = FileGuard::new(output_path.clone());
let mut venc = match VideoEncoder::create(&video_path)
.video(160, 120, 15.0)
.video_codec(VideoCodec::Mpeg4)
.bitrate_mode(BitrateMode::Cbr(200_000))
.preset(Preset::Ultrafast)
.build()
{
Ok(e) => e,
Err(e) => {
println!("Skipping: video encoder unavailable ({e})");
return;
}
};
for _ in 0..30 {
let frame = create_black_frame(160, 120);
if let Err(e) = venc.push_video(&frame) {
println!("Skipping: push_video failed ({e})");
return;
}
}
if let Err(e) = venc.finish() {
println!("Skipping: video encoder.finish failed ({e})");
return;
}
let mut aenc = match AudioEncoder::create(&audio_path)
.audio(44100, 1)
.audio_codec(AudioCodec::Mp3)
.audio_bitrate(64_000)
.build()
{
Ok(e) => e,
Err(e) => {
println!("Skipping: audio encoder unavailable ({e})");
return;
}
};
let frame_size: usize = 1152;
let silence = match AudioFrame::empty(frame_size, 1, 44100, SampleFormat::F32) {
Ok(f) => f,
Err(e) => {
println!("Skipping: AudioFrame::empty failed ({e})");
return;
}
};
let frames_needed = (22050 / frame_size) + 1;
for _ in 0..frames_needed {
if let Err(e) = aenc.push(&silence) {
println!("Skipping: aenc.push failed ({e})");
return;
}
}
if let Err(e) = aenc.finish() {
println!("Skipping: audio encoder.finish failed ({e})");
return;
}
let result = AudioAdder::new(&video_path, &audio_path, &output_path)
.loop_audio()
.run();
match result {
Ok(()) => {}
Err(e) => {
println!("Skipping: AudioAdder::run (loop) failed ({e})");
return;
}
}
assert_valid_output_file(&output_path);
}