1use std::io::{Seek, Write};
2use std::path::Path;
3
4use super::reader::Reader;
5use super::track::Track;
6use super::writer::{Options, TrackConfig, Writer};
7use crate::media::{Error, Result};
8use crate::mp4::remux::{Timeline, plan_tracks};
9use crate::mp4::{ByteSource, Cut, Snap, Span, TrackKind};
10
11const WINDOW: u64 = 8 << 20;
12
13impl Timeline for Track {
14 fn len(&self) -> usize {
15 self.samples.len()
16 }
17 fn keyframes(&self) -> &[u32] {
18 Track::keyframes(self)
19 }
20 fn pts(&self, i: usize) -> i64 {
21 self.samples[i].pts
22 }
23 fn duration(&self, i: usize) -> i64 {
24 self.samples[i].duration as i64
25 }
26 fn ticks(&self, seconds: f64) -> i64 {
27 Track::ticks(self, seconds)
28 }
29 fn seconds(&self, ticks: i64) -> f64 {
30 Track::seconds(self, ticks)
31 }
32 fn end(&self) -> i64 {
33 Track::end(self)
34 }
35}
36
37pub fn plan<S: ByteSource>(reader: &Reader<S>, from: f64, to: f64, snap: Snap) -> Result<Cut> {
38 plan_tracks(
39 reader.duration_seconds(),
40 &reader.tracks,
41 reader.video(),
42 reader.audio(),
43 (from, to),
44 snap,
45 )
46}
47
48pub fn copy<S: ByteSource, W: Write + Seek>(
49 reader: &Reader<S>,
50 cut: &Cut,
51 writer: &mut Writer<W>,
52) -> Result<()> {
53 let mut map = Vec::new();
54 let mut origin_ns = i64::MAX;
55 for (src, range) in &cut.tracks {
56 let t = reader
57 .tracks
58 .get(*src)
59 .ok_or_else(|| Error::Invalid(format!("no track {src}")))?;
60 let samples = t
61 .samples
62 .get(range.clone())
63 .ok_or_else(|| Error::Invalid(format!("no samples {range:?} in track {src}")))?;
64 map.push(writer.add_track(TrackConfig::from_track(t))?);
65 if let Some(first) = samples.iter().map(|s| s.pts).min() {
66 origin_ns = origin_ns.min(t.nanos(first).saturating_add(t.codec_delay as i64));
67 }
68 }
69 if origin_ns == i64::MAX {
70 origin_ns = 0;
71 }
72 let mut order: Vec<(u64, usize, usize)> = cut
73 .tracks
74 .iter()
75 .enumerate()
76 .flat_map(|(k, (src, range))| {
77 let t = &reader.tracks[*src];
78 range.clone().map(move |i| (t.samples[i].offset, k, i))
79 })
80 .collect();
81 order.sort_unstable();
82 let src = reader.source();
83 let len = reader.len();
84 let mut window = Vec::new();
85 let mut window_start = 0u64;
86 let mut frame = Vec::new();
87 for (offset, k, i) in order {
88 let t = &reader.tracks[cut.tracks[k].0];
89 let s = t.samples[i];
90 let shift =
91 origin_ns as i128 * t.time_base.den as i128 / (t.time_base.num as i128 * 1_000_000_000);
92 let pts = s.pts.saturating_sub(shift as i64);
93 let prefix = t.stripped_header().unwrap_or(&[]);
94 let end = offset
95 .checked_add(s.size as u64)
96 .filter(|&e| e <= len)
97 .ok_or_else(|| Error::Invalid("truncated Matroska data".into()))?;
98 let data: &[u8] = if prefix.is_empty() && s.size as u64 <= WINDOW {
99 if offset < window_start || end > window_start + window.len() as u64 {
100 let n = (len.saturating_sub(offset)).min(WINDOW.max(s.size as u64));
101 window.resize(n as usize, 0);
102 src.read_at(offset, &mut window)?;
103 window_start = offset;
104 }
105 let at = (offset - window_start) as usize;
106 &window[at..at + s.size as usize]
107 } else {
108 super::reader::read_frame(src, len, t, offset, s.size, &mut frame)?;
109 &frame
110 };
111 writer.push_sample(map[k], data, pts, None, s.keyframe)?;
112 }
113 Ok(())
114}
115
116pub fn remux(
117 src: impl AsRef<Path>,
118 dst: impl AsRef<Path>,
119 from: f64,
120 to: f64,
121 snap: Snap,
122) -> Result<Span> {
123 let reader = Reader::open(src)?;
124 let cut = plan(&reader, from, to, snap)?;
125 let options = Options {
126 webm: reader.is_webm(),
127 ..Options::default()
128 };
129 let mut writer = Writer::create_with(dst, options)?;
130 copy(&reader, &cut, &mut writer)?;
131 writer.finish()?;
132 Ok(cut.span)
133}
134
135pub fn remux_mp4(src: impl AsRef<Path>, dst: impl AsRef<Path>) -> Result<()> {
136 let reader = crate::mp4::Reader::open(src)?;
137 let mut writer = Writer::create(dst)?;
138 let mut tracks = Vec::new();
139 for (i, t) in reader.tracks.iter().enumerate() {
140 if matches!(t.kind, TrackKind::Video | TrackKind::Audio) {
141 tracks.push((i, writer.add_track(TrackConfig::from_mp4(t)?)?));
142 }
143 }
144 let mut order: Vec<(u64, usize, usize)> = tracks
145 .iter()
146 .enumerate()
147 .flat_map(|(k, &(i, _))| {
148 reader.tracks[i]
149 .samples
150 .iter()
151 .enumerate()
152 .map(move |(n, s)| (s.offset, k, n))
153 })
154 .collect();
155 order.sort_unstable();
156 let shift: Vec<i64> = tracks
157 .iter()
158 .map(|&(i, _)| {
159 let t = &reader.tracks[i];
160 (0..t.samples.len())
161 .filter_map(|n| t.presentation(n))
162 .min()
163 .unwrap_or(0)
164 .min(0)
165 })
166 .collect();
167 let mut data = Vec::new();
168 for (_, k, n) in order {
169 let (i, dst) = tracks[k];
170 let t = &reader.tracks[i];
171 reader.read_into(i, n, &mut data)?;
172 let pts = t.presentation(n).unwrap_or(0).saturating_sub(shift[k]);
173 writer.push_sample(dst, &data, pts, None, t.samples[n].keyframe)?;
174 }
175 writer.finish()?;
176 Ok(())
177}