use std::{
fs,
path::{Path, PathBuf},
process::Command,
};
use tracing::{debug, error, info, instrument};
use crate::error::VideoEncodeError;
#[instrument(skip(segment_paths))]
pub fn concatenate_videos_and_copy_streams(
segment_paths: Vec<PathBuf>,
original_input: &Path,
output_file: &Path,
temp_dir: &PathBuf,
expected_segments: usize,
) -> Result<(), VideoEncodeError> {
if segment_paths.len() != expected_segments {
return Err(VideoEncodeError::Concatenation(format!(
"Mismatch in segment count. Expected: {}, Found: {}",
expected_segments,
segment_paths.len()
)));
}
for path in segment_paths.iter() {
if !path.exists() {
return Err(VideoEncodeError::Concatenation(format!(
"Segment file not found: {:?}",
path
)));
}
}
let temp_file_list = PathBuf::from("file_list.txt");
let file_list_content: String = segment_paths
.iter()
.map(|path| format!("file '{}'\n", path.to_str().unwrap()))
.collect();
fs::write(&temp_file_list, file_list_content)?;
let temp_st = temp_file_list.to_string_lossy();
let original_input = original_input.to_string_lossy();
let output_file = output_file.to_string_lossy();
let ffmpeg_args = vec![
"-f",
"concat",
"-safe",
"0",
"-i",
&temp_st,
"-i",
&original_input,
"-map",
"0:v", "-map",
"1", "-c",
"copy",
&output_file,
];
debug!("FFmpeg command: ffmpeg {:?}", ffmpeg_args);
let status = Command::new("ffmpeg").arg("-hide_banner").args(&ffmpeg_args).status()?;
if !status.success() {
error!("Failed to concatenate videos and copy streams");
return Err(VideoEncodeError::Concatenation(
"Failed to concatenate videos and copy streams".to_string(),
));
}
info!(
"Successfully concatenated {} video segments and copied all streams to the final video",
segment_paths.len(),
);
fs::remove_file(temp_file_list)?;
Ok(())
}