#![allow(clippy::unwrap_used)]
mod fixtures;
use ff_encode::{HardwareEncoder, VideoCodec, VideoEncoder};
use fixtures::{FileGuard, assert_valid_output_file, create_black_frame, test_output_path};
#[test]
fn test_h264_codec_fallback() {
let output_path = test_output_path("test_h264_fallback.mp4");
let _guard = FileGuard::new(output_path.clone());
let result = VideoEncoder::create(&output_path)
.video(1280, 720, 30.0)
.video_codec(VideoCodec::H264)
.build();
match result {
Ok(encoder) => {
let actual_codec = encoder.actual_video_codec();
println!("H.264 selected codec: {}", actual_codec);
assert!(
actual_codec.contains("h264")
|| actual_codec.contains("nvenc")
|| actual_codec.contains("qsv")
|| actual_codec.contains("amf")
|| actual_codec.contains("videotoolbox")
|| actual_codec.contains("vaapi")
|| actual_codec.contains("x264")
|| actual_codec.contains("vp9"),
"Unexpected codec: {}",
actual_codec
);
}
Err(e) => {
println!("H.264 encoder creation failed: {}", e);
}
}
}
#[test]
fn test_h264_hardware_preference() {
let output_path = test_output_path("test_h264_hw.mp4");
let _guard = FileGuard::new(output_path.clone());
let result = VideoEncoder::create(&output_path)
.video(1280, 720, 30.0)
.video_codec(VideoCodec::H264)
.hardware_encoder(HardwareEncoder::Auto)
.build();
match result {
Ok(encoder) => {
let actual_codec = encoder.actual_video_codec();
println!("H.264 with HW auto selected: {}", actual_codec);
if encoder.is_hardware_encoding() {
println!("✓ Hardware encoder is being used");
assert!(
actual_codec.contains("nvenc")
|| actual_codec.contains("qsv")
|| actual_codec.contains("amf")
|| actual_codec.contains("videotoolbox")
|| actual_codec.contains("vaapi"),
"Should use hardware encoder, got: {}",
actual_codec
);
} else {
println!("⚠ Hardware encoder not available, using software fallback");
}
}
Err(e) => {
println!("H.264 hardware encoder creation failed: {}", e);
}
}
}
#[test]
fn test_h264_software_only() {
let output_path = test_output_path("test_h264_sw.mp4");
let _guard = FileGuard::new(output_path.clone());
let result = VideoEncoder::create(&output_path)
.video(1280, 720, 30.0)
.video_codec(VideoCodec::H264)
.hardware_encoder(HardwareEncoder::None)
.build();
match result {
Ok(encoder) => {
let actual_codec = encoder.actual_video_codec();
println!("H.264 software-only selected: {}", actual_codec);
assert!(
!encoder.is_hardware_encoding(),
"Should use software encoder"
);
#[cfg(feature = "gpl")]
{
assert!(
actual_codec.contains("x264") || actual_codec.contains("vp9"),
"Expected libx264 or VP9, got: {}",
actual_codec
);
}
#[cfg(not(feature = "gpl"))]
{
assert!(
actual_codec.contains("vp9"),
"Expected VP9 fallback, got: {}",
actual_codec
);
}
}
Err(e) => {
println!("H.264 software encoder creation failed: {}", e);
}
}
}
#[test]
fn test_h265_codec_fallback() {
let output_path = test_output_path("test_h265_fallback.mp4");
let _guard = FileGuard::new(output_path.clone());
let result = VideoEncoder::create(&output_path)
.video(1280, 720, 30.0)
.video_codec(VideoCodec::H265)
.build();
match result {
Ok(encoder) => {
let actual_codec = encoder.actual_video_codec();
println!("H.265 selected codec: {}", actual_codec);
assert!(
actual_codec.contains("hevc")
|| actual_codec.contains("h265")
|| actual_codec.contains("x265")
|| actual_codec.contains("av1")
|| actual_codec.contains("aom"),
"Unexpected codec: {}",
actual_codec
);
}
Err(e) => {
println!("H.265 encoder creation failed: {}", e);
}
}
}
#[test]
fn test_lgpl_compliance_without_gpl_feature() {
#[cfg(not(feature = "gpl"))]
{
let output_path = test_output_path("test_lgpl_compliance.mp4");
let _guard = FileGuard::new(output_path.clone());
let result = VideoEncoder::create(&output_path)
.video(1280, 720, 30.0)
.video_codec(VideoCodec::H264)
.hardware_encoder(HardwareEncoder::None) .build();
match result {
Ok(encoder) => {
let actual_codec = encoder.actual_video_codec();
println!("LGPL-compliant codec selected: {}", actual_codec);
assert!(
encoder.is_lgpl_compliant(),
"Encoder should be LGPL-compliant, got: {}",
actual_codec
);
assert!(
actual_codec.contains("vp9"),
"Should fallback to VP9 without GPL, got: {}",
actual_codec
);
}
Err(e) => {
println!("LGPL-compliant encoder creation failed: {}", e);
}
}
}
#[cfg(feature = "gpl")]
{
println!("Skipping LGPL test (GPL feature is enabled)");
}
}
#[test]
fn test_lgpl_compliance_with_hardware() {
let output_path = test_output_path("test_lgpl_hw.mp4");
let _guard = FileGuard::new(output_path.clone());
let result = VideoEncoder::create(&output_path)
.video(1280, 720, 30.0)
.video_codec(VideoCodec::H264)
.hardware_encoder(HardwareEncoder::Auto)
.build();
match result {
Ok(encoder) => {
let actual_codec = encoder.actual_video_codec();
println!("Hardware codec selected: {}", actual_codec);
if encoder.is_hardware_encoding() {
assert!(
encoder.is_lgpl_compliant(),
"Hardware encoder should be LGPL-compliant: {}",
actual_codec
);
println!("✓ Hardware encoder is LGPL-compliant");
}
}
Err(e) => {
println!("Hardware encoder creation failed: {}", e);
}
}
}
#[test]
fn test_vp9_codec() {
let output_path = test_output_path("test_vp9_codec.webm");
let _guard = FileGuard::new(output_path.clone());
let result = VideoEncoder::create(&output_path)
.video(640, 480, 30.0)
.video_codec(VideoCodec::Vp9)
.build();
match result {
Ok(mut encoder) => {
let actual_codec = encoder.actual_video_codec();
println!("VP9 codec: {}", actual_codec);
assert!(
actual_codec.contains("vp9"),
"Expected VP9 codec, got: {}",
actual_codec
);
assert!(encoder.is_lgpl_compliant(), "VP9 should be LGPL-compliant");
for _ in 0..10 {
let frame = create_black_frame(640, 480);
encoder.push_video(&frame).expect("Failed to push frame");
}
encoder.finish().expect("Failed to finish encoding");
assert_valid_output_file(&output_path);
}
Err(e) => {
println!("VP9 encoder creation failed: {}", e);
}
}
}
#[test]
fn test_av1_codec() {
let output_path = test_output_path("test_av1_codec.webm");
let _guard = FileGuard::new(output_path.clone());
let result = VideoEncoder::create(&output_path)
.video(640, 480, 30.0)
.video_codec(VideoCodec::Av1)
.build();
match result {
Ok(encoder) => {
let actual_codec = encoder.actual_video_codec();
println!("AV1 codec: {}", actual_codec);
assert!(
actual_codec.contains("av1") || actual_codec.contains("aom"),
"Expected AV1 codec, got: {}",
actual_codec
);
assert!(encoder.is_lgpl_compliant(), "AV1 should be LGPL-compliant");
}
Err(e) => {
println!("AV1 encoder not available: {}", e);
}
}
}
#[test]
fn test_mpeg4_codec() {
let output_path = test_output_path("test_mpeg4_codec.mp4");
let _guard = FileGuard::new(output_path.clone());
let result = VideoEncoder::create(&output_path)
.video(640, 480, 30.0)
.video_codec(VideoCodec::Mpeg4)
.build();
match result {
Ok(mut encoder) => {
let actual_codec = encoder.actual_video_codec();
println!("MPEG-4 codec: {}", actual_codec);
assert!(
actual_codec.contains("mpeg4"),
"Expected MPEG-4 codec, got: {}",
actual_codec
);
assert!(
encoder.is_lgpl_compliant(),
"MPEG-4 should be LGPL-compliant"
);
for _ in 0..10 {
let frame = create_black_frame(640, 480);
encoder.push_video(&frame).expect("Failed to push frame");
}
encoder.finish().expect("Failed to finish encoding");
assert_valid_output_file(&output_path);
}
Err(e) => {
panic!("MPEG-4 encoder should always be available, got: {}", e);
}
}
}