use anyhow::{anyhow, Context, Result};
use log::debug;
use std::path::PathBuf;
use std::sync::{
atomic::{AtomicBool, Ordering},
Arc,
};
use fxp_modes::Modes;
use fxp_output::ModeOutput;
use fxp_output::Output;
use crate::sample::{extract_multiple_frames, extract_single_frame};
#[derive(Debug)]
pub struct Sampler {
pub video_path: PathBuf,
pub output_path: PathBuf,
pub duration: u64,
pub sampling_number: usize,
}
impl Sampler {
pub fn new(
video_path: String,
output_path: Option<String>,
duration: u64,
sampling_number: usize,
) -> Result<Self> {
let video_path = PathBuf::from(&video_path);
let mode: Modes = Modes::Sampler;
let output: Output = mode.into();
let output_path = match output {
Output::Sampler(sampler_output) => {
sampler_output.create_output((video_path.clone(), output_path, sampling_number))?
}
_ => unreachable!("Expected Sampler mode"),
};
Ok(Self {
video_path,
output_path: output_path,
duration,
sampling_number,
})
}
}
impl Sampler {
pub fn sample_images(&self, running: Arc<AtomicBool>) -> Result<()> {
debug!("Starting sample processing with arguments: {:?}", self);
if !running.load(Ordering::SeqCst) {
return Err(anyhow!("Processing interrupted before starting."));
}
if self.duration == 0 {
return Err(anyhow!("Invalid video duration: must be greater than 0."));
}
let output_path = &self.output_path;
match self.sampling_number {
1 => {
extract_single_frame(
&self.video_path,
self.duration,
output_path.clone(), running.clone(),
)
.context("Failed to extract single frame")?;
}
num_frames if num_frames > 1 => {
extract_multiple_frames(
&self.video_path,
self.duration,
num_frames,
&output_path, running.clone(),
)
.context("Failed to extract multiple frames")?;
}
_ => {
return Err(anyhow!(
"Invalid sampling number: {:?}",
self.sampling_number
));
}
}
Ok(())
}
}