From 044c7e1c75145f1ec9d002b4f6fc4433ff7f9540 Mon Sep 17 00:00:00 2001 From: metamuffin Date: Sat, 13 Sep 2025 16:08:42 +0200 Subject: start remuxer crate rewrite; added matroska demuxer and format detection --- remuxer/src/magic.rs | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 remuxer/src/magic.rs (limited to 'remuxer/src/magic.rs') diff --git a/remuxer/src/magic.rs b/remuxer/src/magic.rs new file mode 100644 index 0000000..65ab4de --- /dev/null +++ b/remuxer/src/magic.rs @@ -0,0 +1,67 @@ +/* + 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 +*/ + +use crate::ContainerFormat; +use anyhow::Result; +use std::io::Read; +use winter_ebml::{Ebml, EbmlHeader, read_vint_slice}; +use winter_matroska::MatroskaFile; + +pub fn detect_container_format(reader: &mut dyn Read) -> Result> { + let mut data = Vec::new(); + reader.take(128).read_to_end(&mut data)?; + Ok(test_matroska(&data)) +} + +fn test_matroska(mut data: &[u8]) -> Option { + let tag = read_vint_slice(&mut data)?; + if tag != MatroskaFile::TAG_EBML_HEADER { + return None; + }; + let size = read_vint_slice(&mut data)? as usize; + if size > data.len() { + return None; + } + let header = EbmlHeader::read(&data[..size]).ok()?; + match header.doc_type.as_str() { + "matroska" => Some(ContainerFormat::Matroska), + "webm" => Some(ContainerFormat::Webm), + _ => None, + } +} + +#[test] +fn verify_matroska() { + // WebM + let sample = "\ +1a45dfa39f4286810142f7810142f2810442f381084282847765626d4287\ +8104428581021853806701000000088a9c1a114d9b74bc4dbb8b53ab8415\ +49a96653ac81a14dbb8b53ab841654ae6b53ac81d64dbb8c53ab841254c3\ +6753ac8201a04dbb8e53ab841c53bb6b53ac84088a9accec010000000000\ +0057000000000000"; + let sample = hex::decode(sample).unwrap(); + assert_eq!(test_matroska(&sample), Some(ContainerFormat::Webm)); + + // Matroska + let sample = "\ +1a45dfa3a34286810142f7810142f2810442f381084282886d6174726f73\ +6b61428781044285810218538067010000005d66b4a2114d9b74c2bf8492\ +1ae3e14dbb8b53ab841549a96653ac81a14dbb8b53ab841654ae6b53ac81\ +ef4dbb8c53ab841254c36753ac82019b4dbb8e53ab841c53bb6b53ac845d\ +66a14aec01000000"; + let sample = hex::decode(sample).unwrap(); + assert_eq!(test_matroska(&sample), Some(ContainerFormat::Matroska)); + + // GIF + let sample = "\ +47494638396100010001f71f000000002400004800006c0000900000b400\ +00d80000fc00000024002424004824006c2400902400b42400d82400fc24\ +000048002448004848006c4800904800b44800d84800fc4800006c00246c\ +00486c006c6c00906c00b46c00d86c00fc6c000090002490004890006c90\ +00909000b49000d8"; + let sample = hex::decode(sample).unwrap(); + assert_eq!(test_matroska(&sample), None) +} -- cgit v1.2.3-70-g09d2