use super::snapshot::{OutputProgress, Progress};
use super::state::ProgressState;
use super::tracker::ProgressTracker;
use crate::core::scheduler::ffmpeg_scheduler::{STATUS_ABORT, STATUS_END, STATUS_PAUSE};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
#[derive(Clone)]
pub struct ProgressHandle {
status: Arc<AtomicUsize>,
pause_epoch: Arc<AtomicUsize>,
tracker: Arc<ProgressTracker>,
}
impl ProgressHandle {
pub(crate) fn new(
status: Arc<AtomicUsize>,
pause_epoch: Arc<AtomicUsize>,
tracker: Arc<ProgressTracker>,
) -> Self {
Self {
status,
pause_epoch,
tracker,
}
}
pub fn snapshot(&self) -> Progress {
let state = self.state();
let elapsed = self.tracker.elapsed();
let outputs = self
.tracker
.outputs()
.iter()
.enumerate()
.map(|(index, telemetry)| OutputProgress::collect(index, telemetry, elapsed))
.collect();
Progress::new(state, elapsed, outputs)
}
pub fn is_ended(&self) -> bool {
self.tracker.is_completed()
}
fn state(&self) -> ProgressState {
if self.tracker.is_completed() {
return ProgressState::Ended;
}
match self.status.load(Ordering::Acquire) {
STATUS_PAUSE => ProgressState::Paused,
STATUS_END | STATUS_ABORT => ProgressState::Finishing,
_ => {
if self.pause_epoch.load(Ordering::Acquire) % 2 == 1 {
ProgressState::Paused
} else if self.tracker.inputs_drained() {
ProgressState::Finishing
} else {
ProgressState::Running
}
}
}
}
}
impl std::fmt::Debug for ProgressHandle {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ProgressHandle")
.field("state", &self.state())
.field("is_ended", &self.is_ended())
.finish_non_exhaustive()
}
}