use std::time::Duration;
use ffmpeg_next::{Error as FfmpegError, Packet, Rational};
use crate::error::UnbundleError;
use crate::unbundle::MediaFile;
#[derive(Debug, Clone)]
pub struct PacketInfo {
pub stream_index: usize,
pub pts: Option<i64>,
pub dts: Option<i64>,
pub pts_duration: Option<Duration>,
pub size: usize,
pub is_keyframe: bool,
pub time_base: Rational,
}
pub struct PacketIterator<'a> {
unbundler: &'a mut MediaFile,
time_bases: Vec<Rational>,
done: bool,
}
impl<'a> PacketIterator<'a> {
pub(crate) fn new(unbundler: &'a mut MediaFile) -> Self {
log::debug!("Creating PacketIterator");
let time_bases: Vec<Rational> = unbundler
.input_context
.streams()
.map(|s| s.time_base())
.collect();
Self {
unbundler,
time_bases,
done: false,
}
}
}
impl<'a> Iterator for PacketIterator<'a> {
type Item = Result<PacketInfo, UnbundleError>;
fn next(&mut self) -> Option<Self::Item> {
if self.done {
return None;
}
let mut packet = Packet::empty();
match packet.read(&mut self.unbundler.input_context) {
Ok(()) => {
let stream_index = packet.stream() as usize;
let time_base = self
.time_bases
.get(stream_index)
.copied()
.unwrap_or(Rational::new(1, 90_000));
let pts = packet.pts();
let dts = packet.dts();
let pts_duration = pts.map(|p| {
let seconds = p as f64 * time_base.numerator() as f64
/ time_base.denominator().max(1) as f64;
Duration::from_secs_f64(seconds.max(0.0))
});
let is_keyframe = packet.is_key();
let size = packet.size();
Some(Ok(PacketInfo {
stream_index,
pts,
dts,
pts_duration,
size,
is_keyframe,
time_base,
}))
}
Err(FfmpegError::Eof) => {
self.done = true;
None
}
Err(e) => {
self.done = true;
Some(Err(UnbundleError::from(e)))
}
}
}
}