aboutsummaryrefslogtreecommitdiff
path: root/matroska/src/write.rs
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2025-09-13 16:08:42 +0200
committermetamuffin <metamuffin@disroot.org>2025-09-13 16:08:42 +0200
commit044c7e1c75145f1ec9d002b4f6fc4433ff7f9540 (patch)
treedb326c8f2327396ed443a1822936927e7c847494 /matroska/src/write.rs
parente99bde7a00a161ff5dd91eaf1ce546a9d98cef05 (diff)
downloadjellything-044c7e1c75145f1ec9d002b4f6fc4433ff7f9540.tar
jellything-044c7e1c75145f1ec9d002b4f6fc4433ff7f9540.tar.bz2
jellything-044c7e1c75145f1ec9d002b4f6fc4433ff7f9540.tar.zst
start remuxer crate rewrite; added matroska demuxer and format detection
Diffstat (limited to 'matroska/src/write.rs')
-rw-r--r--matroska/src/write.rs382
1 files changed, 0 insertions, 382 deletions
diff --git a/matroska/src/write.rs b/matroska/src/write.rs
deleted file mode 100644
index 58923c6..0000000
--- a/matroska/src/write.rs
+++ /dev/null
@@ -1,382 +0,0 @@
-/*
- This file is part of jellything (https://codeberg.org/metamuffin/jellything)
- which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
- Copyright (C) 2025 metamuffin <metamuffin.org>
-*/
-use crate::{error::Error, matroska::MatroskaTag, size::EbmlSize, Master, Result};
-use log::debug;
-use std::io::{Seek, Write};
-
-pub struct EbmlWriter<W> {
- inner: W,
- position: usize,
-}
-
-impl<W: Write> EbmlWriter<W> {
- pub fn new(inner: W, position: usize) -> Self {
- Self { inner, position }
- }
-
- pub fn position(&self) -> usize {
- self.position
- }
-
- pub fn write_padding(&mut self, position: usize) -> Result<()> {
- debug!("padding up to {position}");
- let mut size = position - self.position;
- match size {
- 0 => return Ok(()),
- 1 => Err(Error::InvalidPadding)?,
- _ => (),
- }
- size -= 1; // subtract tag size
- size -= 4; // subtract vint size
-
- // match size {
- // _ if size < (1 << 7) => size -= 1,
- // _ if size < (1 << 14) => size -= 2,
- // _ if size < (1 << 21) => size -= 3,
- // _ if size < (1 << 28) => size -= 4,
- // _ if size < (1 << 35) => size -= 5,
- // _ => bail!("padding too large"),
- // }
-
- self.write_all(&[0xec])?;
- self.write_vint_len(size.try_into().unwrap(), 4)?;
- self.write_all(&vec![0; size])?;
- Ok(())
- }
-
- #[inline]
- pub fn write_tag(&mut self, tag: &MatroskaTag) -> Result<()> {
- tag.write_full(self)?;
- Ok(())
- }
-
- pub fn write_vint_len(&mut self, i: u64, len: usize) -> Result<()> {
- let mut bytes = i.to_be_bytes();
- let trunc = &mut bytes[(8 - len)..];
- trunc[0] |= 1 << (8 - len);
- self.write_all(trunc)?;
- Ok(())
- }
-}
-
-impl<W: Seek> Seek for EbmlWriter<W> {
- fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
- self.inner.seek(pos)?;
- match pos {
- std::io::SeekFrom::Start(s) => self.position = s as usize,
- std::io::SeekFrom::End(_) => unimplemented!(),
- std::io::SeekFrom::Current(s) => self.position += s as usize,
- }
- Ok(self.position as u64)
- }
-}
-
-impl<W: Write> Write for EbmlWriter<W> {
- fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
- let size = self.inner.write(buf)?;
- self.position += size;
- Ok(size)
- }
-
- fn flush(&mut self) -> std::io::Result<()> {
- todo!()
- }
-}
-
-impl MatroskaTag {
- pub fn write_full(&self, w: &mut impl Write) -> Result<()> {
- for b in self.id().to_be_bytes().iter().skip_while(|&v| *v == 0u8) {
- w.write_all(&[*b])?;
- }
- 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 impl Write, 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.write_all(trunc)?;
- Ok(())
-}
-
-/// this routine works only, if the varint is as small as it can possibly be.
-/// thats not always what we do though - see below
-pub fn vint_length(v: u64) -> usize {
- let mut len = 1;
- while len <= 8 {
- if v < (1 << ((7 * len) - 1)) {
- break;
- }
- len += 1;
- }
- len
-}
-pub fn bad_vint_length(v: u64) -> usize {
- match 64 - v.leading_zeros() {
- x if x <= 8 => 1,
- x if x <= 16 => 2,
- x if x <= 32 => 4,
- _ => 8,
- }
-}
-
-pub trait WriteValue {
- /// writes the contents of a tag, including the size but excluding the id.
- fn write_to(&self, w: &mut impl Write) -> Result<()>;
- fn size(&self) -> usize;
-}
-
-impl WriteValue for i64 {
- fn write_to(&self, w: &mut impl Write) -> Result<()> {
- match 64 - self.leading_zeros() {
- x if x <= 8 => {
- w.write_all(&[0x81])?;
- w.write_all(&(*self as i8).to_be_bytes())?;
- }
- x if x <= 16 => {
- w.write_all(&[0x82])?;
- w.write_all(&(*self as i16).to_be_bytes())?;
- }
- x if x <= 32 => {
- w.write_all(&[0x84])?;
- w.write_all(&(*self as i32).to_be_bytes())?;
- }
- _ => {
- w.write_all(&[0x88])?;
- w.write_all(&self.to_be_bytes())?;
- }
- };
- 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 impl Write) -> Result<()> {
- match 64 - self.leading_zeros() {
- x if x <= 8 => {
- w.write_all(&[0x81])?;
- w.write_all(&(*self as u8).to_be_bytes())?;
- }
- x if x <= 16 => {
- w.write_all(&[0x82])?;
- w.write_all(&(*self as u16).to_be_bytes())?;
- }
- x if x <= 32 => {
- w.write_all(&[0x84])?;
- w.write_all(&(*self as u32).to_be_bytes())?;
- }
- _ => {
- w.write_all(&[0x88])?;
- w.write_all(&self.to_be_bytes())?;
- }
- };
- 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 impl Write) -> Result<()> {
- w.write_all(&[0x88])?;
- w.write_all(&self.to_be_bytes())?;
- Ok(())
- }
- fn size(&self) -> usize {
- 1 + 8
- }
-}
-impl WriteValue for Vec<u8> {
- fn write_to(&self, w: &mut impl Write) -> Result<()> {
- write_vint(w, self.len() as u64)?;
- w.write_all(self)?;
- Ok(())
- }
-
- fn size(&self) -> usize {
- vint_length(self.len() as u64) + self.len()
- }
-}
-impl WriteValue for String {
- fn write_to(&self, w: &mut impl Write) -> Result<()> {
- let sl = self.as_bytes();
- write_vint(w, sl.len() as u64)?;
- w.write_all(sl)?;
- Ok(())
- }
-
- fn size(&self) -> usize {
- vint_length(self.len() as u64) + self.len()
- }
-}
-impl WriteValue for EbmlSize {
- fn write_to(&self, w: &mut impl Write) -> Result<()> {
- match self {
- EbmlSize::Exact(s) => write_vint(w, *s as u64)?,
- EbmlSize::Unknown => w.write_all(&[0xff])?,
- }
- Ok(())
- }
- fn size(&self) -> usize {
- match self {
- EbmlSize::Exact(s) => vint_length(*s as u64),
- EbmlSize::Unknown => 1,
- }
- }
-}
-
-impl WriteValue for Master {
- fn write_to(&self, w: &mut impl Write) -> Result<()> {
- match self {
- Master::Start => EbmlSize::Unknown.write_to(w),
- Master::End => {
- unreachable!()
- }
- Master::Collected(c) => {
- let mut size = 0;
- for c in c {
- size += c.size_full();
- }
- EbmlSize::Exact(size).write_to(w)?;
- for c in c {
- c.write_full(w)?;
- }
- 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
- }
- }
- }
-}
-
-#[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),
- ]));
- }
-}