diff options
author | metamuffin <metamuffin@disroot.org> | 2024-01-26 15:51:04 +0100 |
---|---|---|
committer | metamuffin <metamuffin@disroot.org> | 2024-01-26 15:51:04 +0100 |
commit | e4d4b62178a1f83b4c9632b4fd8b2dcd2eef1bd9 (patch) | |
tree | 7f4d8538a7f6992eda45b255fe68e82f3a9af788 | |
parent | e63d873ac0e47eb49dfb10d6cf607fa9c7bd6e27 (diff) | |
download | jellything-e4d4b62178a1f83b4c9632b4fd8b2dcd2eef1bd9.tar jellything-e4d4b62178a1f83b4c9632b4fd8b2dcd2eef1bd9.tar.bz2 jellything-e4d4b62178a1f83b4c9632b4fd8b2dcd2eef1bd9.tar.zst |
less useless copying in the matroska library
-rw-r--r-- | ebml_derive/src/lib.rs | 7 | ||||
-rw-r--r-- | matroska/src/write.rs | 188 | ||||
-rw-r--r-- | remuxer/src/remux.rs | 2 | ||||
-rw-r--r-- | remuxer/src/snippet.rs | 2 |
4 files changed, 177 insertions, 22 deletions
diff --git a/ebml_derive/src/lib.rs b/ebml_derive/src/lib.rs index cd2d194..34510b9 100644 --- a/ebml_derive/src/lib.rs +++ b/ebml_derive/src/lib.rs @@ -81,6 +81,10 @@ pub fn define_ebml(ts: TokenStream) -> TokenStream { .iter() .map(|Tag { name, .. }| quote! { Self::#name(v) => v.write_to(w) }) .collect::<Vec<_>>(); + let size_match = tags + .iter() + .map(|Tag { name, .. }| quote! { Self::#name(v) => v.size() }) + .collect::<Vec<_>>(); let cons_master_match = tags .iter() .filter_map( @@ -131,6 +135,9 @@ pub fn define_ebml(ts: TokenStream) -> TokenStream { pub fn write(&self, w: &mut Vec<u8>) -> crate::Result<()> { match self { #(#write_match),* } } + pub fn size(&self) -> usize { + match self { #(#size_match),* } + } } } .into() diff --git a/matroska/src/write.rs b/matroska/src/write.rs index fe6033f..3b127f8 100644 --- a/matroska/src/write.rs +++ b/matroska/src/write.rs @@ -91,13 +91,25 @@ impl<W: Seek> Seek for EbmlWriter<W> { impl MatroskaTag { pub fn write_full(&self, w: &mut Vec<u8>) -> Result<()> { - let mut buf = vec![]; - buf.extend(self.id().to_be_bytes().iter().skip_while(|&v| *v == 0u8)); - //* note: it is relevant here, to pass the buffer with the id, such that closing tags, can clear it - self.write(&mut buf)?; - w.extend_from_slice(&buf); + w.extend(self.id().to_be_bytes().iter().skip_while(|&v| *v == 0u8)); + self.write(w)?; Ok(()) } + pub fn size_full(&self) -> usize { + (8 - self.id().leading_zeros() as usize / 8) + self.size() + } +} + +pub fn write_vint(w: &mut Vec<u8>, i: u64) -> Result<()> { + if i > (1 << 56) - 1 { + Err(Error::VarintTooLong)? + } + let len = (64 - i.leading_zeros() as usize) / 7 + 1; + let mut bytes = i.to_be_bytes(); + let trunc = &mut bytes[(8 - len)..]; + trunc[0] |= 1 << (8 - len); + w.extend_from_slice(trunc); + Ok(()) } /// this routine works only, if the varint is as small as it can possibly be. @@ -124,6 +136,7 @@ pub fn bad_vint_length(v: u64) -> usize { pub trait WriteValue { /// writes the contents of a tag, including the size but excluding the id. fn write_to(&self, w: &mut Vec<u8>) -> Result<()>; + fn size(&self) -> usize; } impl WriteValue for i64 { @@ -148,6 +161,15 @@ impl WriteValue for i64 { }; Ok(()) } + + fn size(&self) -> usize { + 1 + match 64 - self.leading_zeros() { + x if x <= 8 => 1, + x if x <= 16 => 2, + x if x <= 32 => 4, + _ => 8, + } + } } impl WriteValue for u64 { fn write_to(&self, w: &mut Vec<u8>) -> Result<()> { @@ -171,6 +193,14 @@ impl WriteValue for u64 { }; Ok(()) } + fn size(&self) -> usize { + 1 + match 64 - self.leading_zeros() { + x if x <= 8 => 1, + x if x <= 16 => 2, + x if x <= 32 => 4, + _ => 8, + } + } } impl WriteValue for f64 { fn write_to(&self, w: &mut Vec<u8>) -> Result<()> { @@ -178,6 +208,9 @@ impl WriteValue for f64 { w.extend_from_slice(&self.to_be_bytes()); Ok(()) } + fn size(&self) -> usize { + 1 + 8 + } } impl WriteValue for Vec<u8> { fn write_to(&self, w: &mut Vec<u8>) -> Result<()> { @@ -185,6 +218,10 @@ impl WriteValue for Vec<u8> { w.extend_from_slice(self); Ok(()) } + + fn size(&self) -> usize { + vint_length(self.len() as u64) + self.len() + } } impl WriteValue for String { fn write_to(&self, w: &mut Vec<u8>) -> Result<()> { @@ -193,6 +230,10 @@ impl WriteValue for String { w.extend_from_slice(sl); Ok(()) } + + fn size(&self) -> usize { + vint_length(self.as_bytes().len() as u64) + self.as_bytes().len() + } } impl WriteValue for EbmlSize { fn write_to(&self, w: &mut Vec<u8>) -> Result<()> { @@ -202,6 +243,13 @@ impl WriteValue for EbmlSize { } Ok(()) } + + fn size(&self) -> usize { + match self { + EbmlSize::Exact(s) => vint_length(*s as u64), + EbmlSize::Unknown => 8, + } + } } impl WriteValue for Master { @@ -209,30 +257,130 @@ impl WriteValue for Master { match self { Master::Start => EbmlSize::Unknown.write_to(w), Master::End => { - w.clear(); - Ok(()) + unreachable!() } Master::Collected(c) => { - let mut ib = vec![]; + let mut size = 0; + for c in c { + size += c.size_full(); + } + EbmlSize::Exact(size).write_to(w)?; + let k = w.len(); for c in c { - c.write_full(&mut ib)?; + c.write_full(w)?; } - EbmlSize::Exact(ib.len()).write_to(w)?; - w.extend_from_slice(&ib); + debug_assert_eq!(w.len() - k, size, "real size of collected differs"); Ok(()) } } } + fn size(&self) -> usize { + match self { + Master::Start => EbmlSize::Unknown.size(), + Master::End => unreachable!(), + Master::Collected(c) => { + let mut size = 0; + for c in c { + size += c.size_full(); + } + EbmlSize::Exact(size).size() + size + } + } + } } -pub fn write_vint(w: &mut Vec<u8>, i: u64) -> Result<()> { - if i > (1 << 56) - 1 { - Err(Error::VarintTooLong)? +#[cfg(test)] +mod test { + use crate::{Master, MatroskaTag, WriteValue}; + + #[test] + fn test_int_size() { + let test = |x: i64| { + eprintln!("{x:?}"); + let mut out = Vec::new(); + x.write_to(&mut out).unwrap(); + assert_eq!(out.len(), x.size()) + }; + test(1); + test(2); + test(20); + test(200); + test(2000); + test(20000); + test(200000); + } + + #[test] + fn test_uint_size() { + let test = |x: u64| { + eprintln!("{x:?}"); + let mut out = Vec::new(); + x.write_to(&mut out).unwrap(); + assert_eq!(out.len(), x.size()) + }; + test(1); + test(2); + test(20); + test(200); + test(2000); + test(20000); + test(200000); + } + + #[test] + fn test_string_size() { + let test = |x: &str| { + eprintln!("{x:?}"); + let x = x.to_owned(); + let mut out = Vec::new(); + x.write_to(&mut out).unwrap(); + assert_eq!(out.len(), x.size()) + }; + test(""); + test("x"); + test("wub"); + test("Hello world"); + test("just making sure that"); + test("this is actually working *exactly* how i want it to"); + test("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); + } + + #[test] + fn test_vec_size() { + let test = |x: &[u8]| { + eprintln!("{x:?}"); + let x = x.to_owned(); + let mut out = Vec::new(); + x.write_to(&mut out).unwrap(); + assert_eq!(out.len(), x.size()) + }; + test(&[]); + test(&[1]); + test(&[1, 2]); + test(&[23, 4, 4, 23, 4, 234, 232, 4, 234, 23, 1]); + test(&[ + 34, 123, 5, 1, 3, 13, 1, 23, 12, 5, 5, 3, 123, 12, 3, 13, 12, 5, 3, 123, 13, 1, 3, + ]); + } + + #[test] + fn test_master_size() { + let test = |x: Master| { + eprintln!("{x:?}"); + let x = x.to_owned(); + let mut out = Vec::new(); + x.write_to(&mut out).unwrap(); + assert_eq!(out.len(), x.size()) + }; + test(Master::Start); + // test(Master::End); + test(Master::Collected(vec![])); + test(Master::Collected(vec![MatroskaTag::EbmlVersion(1)])); + test(Master::Collected(vec![ + MatroskaTag::EbmlVersion(1), + MatroskaTag::EbmlMaxSizeLength(4), + MatroskaTag::EbmlReadVersion(3), + MatroskaTag::EbmlMaxIdLength(4), + ])); } - let len = (64 - i.leading_zeros() as usize) / 7 + 1; - let mut bytes = i.to_be_bytes(); - let trunc = &mut bytes[(8 - len)..]; - trunc[0] |= 1 << (8 - len); - w.extend_from_slice(trunc); - Ok(()) } diff --git a/remuxer/src/remux.rs b/remuxer/src/remux.rs index 1e75b06..8273c9e 100644 --- a/remuxer/src/remux.rs +++ b/remuxer/src/remux.rs @@ -325,7 +325,7 @@ pub fn remux_stream_into( } output.write_tag(&MatroskaTag::Cluster(Master::Collected(cluster_blocks)))?; } - output.write_tag(&MatroskaTag::Segment(Master::End))?; + // output.write_tag(&MatroskaTag::Segment(Master::End))?; Ok(()) } diff --git a/remuxer/src/snippet.rs b/remuxer/src/snippet.rs index 8fcb109..75e0471 100644 --- a/remuxer/src/snippet.rs +++ b/remuxer/src/snippet.rs @@ -198,7 +198,7 @@ pub fn write_snippet_into( output.write_tag(&MatroskaTag::Cluster(Master::Collected(blocks)))?; } - output.write_tag(&MatroskaTag::Segment(Master::End))?; + // output.write_tag(&MatroskaTag::Segment(Master::End))?; debug!("wrote {} bytes", output.position()); Ok(()) |