ff_encode/trim/
trimmer.rs1use std::path::PathBuf;
4use std::time::Duration;
5
6use crate::error::EncodeError;
7
8use super::trim_inner;
9
10pub struct StreamCopyTrimmer {
27 input: PathBuf,
28 output: PathBuf,
29 start_sec: f64,
30 end_sec: f64,
31}
32
33impl StreamCopyTrimmer {
34 pub fn new(
40 input: impl Into<PathBuf>,
41 start_sec: f64,
42 end_sec: f64,
43 output: impl Into<PathBuf>,
44 ) -> Self {
45 Self {
46 input: input.into(),
47 output: output.into(),
48 start_sec,
49 end_sec,
50 }
51 }
52
53 pub fn run(self) -> Result<(), EncodeError> {
60 if self.start_sec >= self.end_sec {
61 return Err(EncodeError::InvalidConfig {
62 reason: format!(
63 "start_sec ({}) must be less than end_sec ({})",
64 self.start_sec, self.end_sec
65 ),
66 });
67 }
68 log::debug!(
69 "stream copy trim start input={} output={} start_sec={} end_sec={}",
70 self.input.display(),
71 self.output.display(),
72 self.start_sec,
73 self.end_sec,
74 );
75 trim_inner::run_trim(&self.input, &self.output, self.start_sec, self.end_sec)
76 }
77}
78
79pub struct StreamCopyTrim {
102 input: PathBuf,
103 start: Duration,
104 end: Duration,
105 output: PathBuf,
106}
107
108impl StreamCopyTrim {
109 pub fn new(
115 input: impl Into<PathBuf>,
116 start: Duration,
117 end: Duration,
118 output: impl Into<PathBuf>,
119 ) -> Self {
120 Self {
121 input: input.into(),
122 start,
123 end,
124 output: output.into(),
125 }
126 }
127
128 pub fn run(self) -> Result<(), EncodeError> {
135 if self.start >= self.end {
136 return Err(EncodeError::MediaOperationFailed {
137 reason: format!(
138 "start ({:?}) must be less than end ({:?})",
139 self.start, self.end
140 ),
141 });
142 }
143 let start_sec = self.start.as_secs_f64();
144 let end_sec = self.end.as_secs_f64();
145 log::debug!(
146 "stream copy trim start input={} output={} start_sec={start_sec} end_sec={end_sec}",
147 self.input.display(),
148 self.output.display(),
149 );
150 trim_inner::run_trim(&self.input, &self.output, start_sec, end_sec)
151 }
152}
153
154#[cfg(test)]
155mod tests {
156 use super::*;
157
158 #[test]
159 fn stream_copy_trimmer_should_reject_start_greater_than_end() {
160 let result = StreamCopyTrimmer::new("input.mp4", 7.0, 2.0, "output.mp4").run();
161 assert!(
162 matches!(result, Err(EncodeError::InvalidConfig { .. })),
163 "expected InvalidConfig for start > end, got {result:?}"
164 );
165 }
166
167 #[test]
168 fn stream_copy_trimmer_should_reject_equal_start_and_end() {
169 let result = StreamCopyTrimmer::new("input.mp4", 5.0, 5.0, "output.mp4").run();
170 assert!(
171 matches!(result, Err(EncodeError::InvalidConfig { .. })),
172 "expected InvalidConfig for start == end, got {result:?}"
173 );
174 }
175
176 #[test]
177 fn stream_copy_trim_should_reject_start_greater_than_end() {
178 let result = StreamCopyTrim::new(
179 "input.mp4",
180 Duration::from_secs(7),
181 Duration::from_secs(2),
182 "output.mp4",
183 )
184 .run();
185 assert!(
186 matches!(result, Err(EncodeError::MediaOperationFailed { .. })),
187 "expected MediaOperationFailed for start > end, got {result:?}"
188 );
189 }
190
191 #[test]
192 fn stream_copy_trim_should_reject_equal_start_and_end() {
193 let result = StreamCopyTrim::new(
194 "input.mp4",
195 Duration::from_secs(5),
196 Duration::from_secs(5),
197 "output.mp4",
198 )
199 .run();
200 assert!(
201 matches!(result, Err(EncodeError::MediaOperationFailed { .. })),
202 "expected MediaOperationFailed for start == end, got {result:?}"
203 );
204 }
205}