frame_source/
fmf_source.rs1use crate::{FrameData, FrameDataSource, ImageData, Result, Timestamp};
5use fmf::reader::FMFReader;
6use std::path::Path;
7
8struct FmfSourceIter {
9 rdr: FMFReader,
10 frame0_time_utc: chrono::DateTime<chrono::Utc>,
11 idx: usize,
12}
13impl FmfSourceIter {
14 fn new(parent: &FmfSource) -> Result<Self> {
15 let mut rdr = FMFReader::new(&parent.filename)?;
16 let frame0_time_utc = parent.frame0_time_utc;
17 for _ in 0..parent.skip_frames {
18 rdr.next();
19 }
20 Ok(Self {
21 rdr,
22 frame0_time_utc,
23 idx: 0,
24 })
25 }
26}
27impl Iterator for FmfSourceIter {
28 type Item = Result<FrameData>;
29 fn next(&mut self) -> Option<Self::Item> {
30 let pos_start = self.rdr.file_pos();
31 self.rdr.next().map(|fmf_result| match fmf_result {
32 Ok((frame, frame_time_utc)) => {
33 let pos_end = self.rdr.file_pos();
34 let buf_len = pos_end - pos_start;
35 let timestamp = frame_time_utc - self.frame0_time_utc;
36 let timestamp = Timestamp::Duration(timestamp.to_std()?);
37 let idx = self.idx;
38 self.idx += 1;
39 Ok(FrameData {
40 image: ImageData::Decoded(frame),
41 timestamp,
42 buf_len,
43 idx,
44 poc: None,
45 })
46 }
47 Err(e) => Err(e.into()),
48 })
49 }
50}
51
52pub struct FmfSource {
59 filename: std::path::PathBuf,
60 width: u32,
61 height: u32,
62 frame0_time_utc: chrono::DateTime<chrono::Utc>,
63 frame0_time: chrono::DateTime<chrono::FixedOffset>,
64 skip_frames: usize,
65}
66
67impl FrameDataSource for FmfSource {
68 fn width(&self) -> u32 {
69 self.width
70 }
71 fn height(&self) -> u32 {
72 self.height
73 }
74 fn frame0_time(&self) -> Option<chrono::DateTime<chrono::FixedOffset>> {
75 Some(self.frame0_time)
76 }
77 fn skip_n_frames(&mut self, n_frames: usize) -> Result<()> {
78 if n_frames == 0 {
79 return Ok(());
80 }
81 let mut rdr = FMFReader::new(&self.filename)?;
82
83 let mut frame_timestamp = None;
84 for _ in 0..n_frames {
85 frame_timestamp = rdr.next()
86 }
87
88 let frame_timestamp = frame_timestamp
89 .map(|f| f.map_err(Into::into))
90 .unwrap_or_else(|| Err(crate::Error::FmfWithNotEnoughData))?;
91
92 let (_frame, frame_time_utc) = frame_timestamp;
93 let duration = frame_time_utc - self.frame0_time_utc;
94 let frame_time = self.frame0_time + duration;
95
96 self.skip_frames = n_frames;
97 self.frame0_time = frame_time;
98 self.frame0_time_utc = frame_time_utc;
99 Ok(())
100 }
101 fn average_framerate(&self) -> Option<f64> {
102 None
103 }
104 fn estimate_luminance_range(&mut self) -> Result<(u16, u16)> {
105 Err(crate::Error::UnsupportedForEsimatingLuminangeRange)
107 }
108 fn decode_order_iter(&mut self) -> Box<dyn Iterator<Item = Result<FrameData>>> {
109 Box::new(FmfSourceIter::new(self).unwrap())
110 }
111 fn timestamp_source(&self) -> &str {
112 "FMF frame metadata"
113 }
114 fn has_timestamps(&self) -> bool {
115 true
116 }
117}
118
119impl FmfSource {
120 fn new<P: AsRef<std::path::Path>>(filename: P) -> Result<Self> {
121 let filename = filename.as_ref().to_path_buf();
122 let mut rdr = FMFReader::new(&filename)?;
123 let width = rdr.width();
124 let height = rdr.height();
125 let frame_timestamp0 = rdr
126 .next()
127 .map(|f| f.map_err(crate::Error::from))
128 .unwrap_or_else(|| Err(crate::Error::FmfWithNotEnoughData))?;
129
130 let (_frame0, frame0_time_utc) = frame_timestamp0;
131 let frame0_time = mkv_strand_reader::infer_timezone(&frame0_time_utc, filename.to_str())?;
132
133 Ok(Self {
134 filename,
135 width,
136 height,
137 frame0_time_utc,
138 frame0_time,
139 skip_frames: 0,
140 })
141 }
142}
143
144pub fn from_path<P: AsRef<Path>>(path: P) -> Result<FmfSource> {
145 let filename = path.as_ref();
146 FmfSource::new(filename)
147}