use super::{Frame, OrderedConsumer, Timestamp};
use crate::Error;
#[derive(Clone)]
pub struct OrderedProducer {
pub track: moq_lite::TrackProducer,
group: Option<moq_lite::GroupProducer>,
group_start: Option<Timestamp>,
group_frames: u64,
max_group_duration: Option<Timestamp>,
}
impl OrderedProducer {
pub fn new(inner: moq_lite::TrackProducer) -> Self {
Self {
track: inner,
group: None,
group_start: None,
group_frames: 0,
max_group_duration: None,
}
}
pub fn with_max_group_duration(mut self, duration: Timestamp) -> Self {
self.max_group_duration = Some(duration);
self
}
pub fn keyframe(&mut self) -> Result<(), Error> {
if let Some(mut group) = self.group.take() {
group.finish()?;
}
Ok(())
}
pub fn write(&mut self, frame: Frame) -> Result<(), Error> {
tracing::trace!(?frame, "write frame");
if let (Some(max_duration), Some(group_start)) = (self.max_group_duration, self.group_start)
&& self.group.is_some()
&& frame.timestamp.checked_sub(group_start).unwrap_or(Timestamp::ZERO) >= max_duration
&& let Some(mut group) = self.group.take()
{
group.finish()?;
}
if self.group.is_none() {
let group = self.track.append_group()?;
self.group = Some(group);
self.group_start = Some(frame.timestamp);
self.group_frames = 0;
}
let mut group = self.group.take().expect("group should exist");
frame.encode(&mut group)?;
self.group.replace(group);
self.group_frames += 1;
if let (Some(max_duration), Some(group_start)) = (self.max_group_duration, self.group_start) {
let elapsed = frame
.timestamp
.checked_sub(group_start)
.unwrap_or(Timestamp::ZERO)
.as_micros();
let max = max_duration.as_micros();
if elapsed * (self.group_frames as u128 + 1) >= max * self.group_frames as u128
&& let Some(mut group) = self.group.take()
{
group.finish()?;
}
}
Ok(())
}
pub fn finish(&mut self) -> Result<(), Error> {
if let Some(mut group) = self.group.take() {
group.finish()?;
}
self.track.finish()?;
Ok(())
}
pub fn consume(&self, max_latency: std::time::Duration) -> OrderedConsumer {
OrderedConsumer::new(self.track.consume(), max_latency)
}
}
impl From<moq_lite::TrackProducer> for OrderedProducer {
fn from(inner: moq_lite::TrackProducer) -> Self {
Self::new(inner)
}
}
impl std::ops::Deref for OrderedProducer {
type Target = moq_lite::TrackProducer;
fn deref(&self) -> &Self::Target {
&self.track
}
}