aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2026-03-05 16:35:00 +0100
committermetamuffin <metamuffin@disroot.org>2026-03-05 16:35:00 +0100
commit1184539329ee82f2e82b3261953ebc87e7b855e0 (patch)
tree508673a16178c18b41df19d63d1a7421d00d70f3
parent3fd3df27b1611867d8a2a224a7849bd4505406fa (diff)
downloadjellything-1184539329ee82f2e82b3261953ebc87e7b855e0.tar
jellything-1184539329ee82f2e82b3261953ebc87e7b855e0.tar.bz2
jellything-1184539329ee82f2e82b3261953ebc87e7b855e0.tar.zst
more boxes
-rw-r--r--remuxer/mp4/src/boxes.rs93
-rw-r--r--remuxer/src/muxers/mp4.rs22
2 files changed, 111 insertions, 4 deletions
diff --git a/remuxer/mp4/src/boxes.rs b/remuxer/mp4/src/boxes.rs
index d2c3918..4c14eb1 100644
--- a/remuxer/mp4/src/boxes.rs
+++ b/remuxer/mp4/src/boxes.rs
@@ -44,6 +44,22 @@ impl WriteBox for FileType<'_> {
}
}
+pub struct SegmentType<'a> {
+ pub major_brand: [u8; 4],
+ pub minor_version: u32,
+ pub compatible_brands: &'a [[u8; 4]],
+}
+impl WriteBox for SegmentType<'_> {
+ const BOXTYPE: [u8; 4] = *b"styp";
+ fn write(&self, buf: &mut Vec<u8>) {
+ buf.extend(self.major_brand);
+ buf.extend(self.minor_version.to_be_bytes());
+ for cb in self.compatible_brands {
+ buf.extend(cb);
+ }
+ }
+}
+
pub struct MovieHeader {
pub creation_time: u64,
pub modification_time: u64,
@@ -135,6 +151,7 @@ pub struct EditListEntry {
}
impl WriteBox for EditList<'_> {
const BOXTYPE: [u8; 4] = *b"elst";
+ const VERSION: Option<u8> = Some(1);
fn write(&self, buf: &mut Vec<u8>) {
buf.extend((self.entries.len() as u32).to_be_bytes());
for e in self.entries {
@@ -242,6 +259,7 @@ pub struct TrackFragmentHeader {
}
impl WriteBox for TrackFragmentHeader {
const BOXTYPE: [u8; 4] = *b"tfhd";
+ const VERSION: Option<u8> = Some(0);
fn write(&self, buf: &mut Vec<u8>) {
buf.extend(self.track_id.to_be_bytes());
}
@@ -252,6 +270,7 @@ pub struct TrackFragmentBaseMediaDecodeTime {
}
impl WriteBox for TrackFragmentBaseMediaDecodeTime {
const BOXTYPE: [u8; 4] = *b"tfdt";
+ const VERSION: Option<u8> = Some(1);
fn write(&self, buf: &mut Vec<u8>) {
buf.extend(self.base_media_decode_time.to_be_bytes());
}
@@ -262,7 +281,81 @@ pub struct TrackRun {
}
impl WriteBox for TrackRun {
const BOXTYPE: [u8; 4] = *b"trun";
+ const VERSION: Option<u8> = Some(1);
fn write(&self, buf: &mut Vec<u8>) {
buf.extend(self.data_offset.to_be_bytes());
}
}
+
+pub struct TimeToSample<'a>(pub &'a [TimeToSampleEntry]);
+pub struct TimeToSampleEntry {
+ pub sample_count: u32,
+ pub sample_delta: u32,
+}
+impl WriteBox for TimeToSample<'_> {
+ const BOXTYPE: [u8; 4] = *b"stts";
+ const VERSION: Option<u8> = Some(0);
+ fn write(&self, buf: &mut Vec<u8>) {
+ buf.extend((self.0.len() as u32).to_be_bytes());
+ for e in self.0 {
+ buf.extend(e.sample_count.to_be_bytes());
+ buf.extend(e.sample_delta.to_be_bytes());
+ }
+ }
+}
+
+pub struct TimeToChunk<'a>(pub &'a [TimeToChunkEntry]);
+pub struct TimeToChunkEntry {
+ pub first_chunk: u32,
+ pub samples_per_chunk: u32,
+ pub sample_description_index: u32,
+}
+impl WriteBox for TimeToChunk<'_> {
+ const BOXTYPE: [u8; 4] = *b"stsc";
+ const VERSION: Option<u8> = Some(0);
+ fn write(&self, buf: &mut Vec<u8>) {
+ buf.extend((self.0.len() as u32).to_be_bytes());
+ for e in self.0 {
+ buf.extend(e.first_chunk.to_be_bytes());
+ buf.extend(e.samples_per_chunk.to_be_bytes());
+ buf.extend(e.sample_description_index.to_be_bytes());
+ }
+ }
+}
+
+pub struct SampleSize<'a> {
+ pub sample_size: u32,
+ pub entries: &'a [u32],
+}
+impl WriteBox for SampleSize<'_> {
+ const BOXTYPE: [u8; 4] = *b"stts";
+ const VERSION: Option<u8> = Some(0);
+ fn write(&self, buf: &mut Vec<u8>) {
+ buf.extend(self.sample_size.to_be_bytes());
+ buf.extend((self.entries.len() as u32).to_be_bytes());
+ if self.sample_size == 0 {
+ for e in self.entries {
+ buf.extend(e.to_be_bytes());
+ }
+ }
+ }
+}
+
+pub struct ChunkOffset<'a>(pub &'a [u32]);
+impl WriteBox for ChunkOffset<'_> {
+ const BOXTYPE: [u8; 4] = *b"stco";
+ const VERSION: Option<u8> = Some(0);
+ fn write(&self, buf: &mut Vec<u8>) {
+ buf.extend((self.0.len() as u32).to_be_bytes());
+ for e in self.0 {
+ buf.extend(e.to_be_bytes());
+ }
+ }
+}
+
+pub struct SampleDescription;
+impl WriteBox for SampleDescription {
+ const BOXTYPE: [u8; 4] = *b"stsd";
+ const VERSION: Option<u8> = Some(0);
+ fn write(&self, _buf: &mut Vec<u8>) {}
+}
diff --git a/remuxer/src/muxers/mp4.rs b/remuxer/src/muxers/mp4.rs
index c3191d1..5975921 100644
--- a/remuxer/src/muxers/mp4.rs
+++ b/remuxer/src/muxers/mp4.rs
@@ -14,9 +14,9 @@ impl FragmentMuxer for MP4FragmentMuxer {
fn write_init(out: &mut Vec<u8>, segment: Segment) -> Result<()> {
let mut out = BoxW::new(out);
out.write(FileType {
- major_brand: *b"mp41",
- minor_version: 0,
- compatible_brands: &[*b"iso6"],
+ major_brand: *b"iso5",
+ minor_version: 512,
+ compatible_brands: &[*b"iso5", *b"iso6", *b"mp41"],
});
out.write(Movie(|moov| {
moov.write(MovieHeader {
@@ -41,7 +41,16 @@ impl FragmentMuxer for MP4FragmentMuxer {
minf.write(DataInformation(|dinf| {
dinf.write(DataReference { entries: &[] });
}));
- minf.write(SampleTable(|stbl| {}));
+ minf.write(SampleTable(|stbl| {
+ stbl.write(SampleDescription);
+ stbl.write(TimeToSample(&[]));
+ stbl.write(TimeToChunk(&[]));
+ stbl.write(ChunkOffset(&[]));
+ stbl.write(SampleSize {
+ sample_size: 0,
+ entries: &[],
+ });
+ }));
}));
}));
}));
@@ -52,6 +61,11 @@ impl FragmentMuxer for MP4FragmentMuxer {
fn write_frag(out: &mut Vec<u8>, segment: Segment) -> Result<()> {
let mut out = BoxW::new(out);
+ out.write(SegmentType {
+ major_brand: *b"msdh",
+ minor_version: 0,
+ compatible_brands: &[*b"msdh", *b"msix"],
+ });
out.write(MovieFragment(|moof| {
moof.write(MovieFragmentHeader { sequence_number: 0 });
moof.write(TrackFragment(|traf| {