aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2023-01-16 21:54:28 +0100
committermetamuffin <metamuffin@disroot.org>2023-01-16 21:54:28 +0100
commite65619de86080d72bf81ba72311dce5325976478 (patch)
tree0296089fb71550169a896dfbc7de88e33e655f86
parent56cf07697695dea747b1c62768999e6237c55448 (diff)
downloadjellything-e65619de86080d72bf81ba72311dce5325976478.tar
jellything-e65619de86080d72bf81ba72311dce5325976478.tar.bz2
jellything-e65619de86080d72bf81ba72311dce5325976478.tar.zst
stuff
-rw-r--r--Cargo.lock29
-rw-r--r--common/src/lib.rs2
-rw-r--r--ebml_derive/src/lib.rs4
-rw-r--r--matroska/src/block.rs43
-rw-r--r--matroska/src/lib.rs6
-rw-r--r--matroska/src/matroska.rs4
-rw-r--r--matroska/src/read.rs57
-rw-r--r--matroska/src/size.rs1
-rw-r--r--remuxer/Cargo.toml4
-rw-r--r--remuxer/src/format.rs20
-rw-r--r--remuxer/src/import/mod.rs79
-rw-r--r--remuxer/src/lib.rs1
-rw-r--r--server/src/frontend/mod.rs2
-rw-r--r--server/src/frontend/pages/layout.rs2
-rw-r--r--server/src/frontend/style/mod.rs12
-rw-r--r--server/src/main.rs10
16 files changed, 225 insertions, 51 deletions
diff --git a/Cargo.lock b/Cargo.lock
index f2daf5c..bb328f2 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -132,6 +132,25 @@ dependencies = [
]
[[package]]
+name = "bincode"
+version = "2.0.0-rc.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7bb50c5a2ef4b9b1e7ae73e3a73b52ea24b20312d629f9c4df28260b7ad2c3c4"
+dependencies = [
+ "bincode_derive",
+ "serde",
+]
+
+[[package]]
+name = "bincode_derive"
+version = "2.0.0-rc.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0a45a23389446d2dd25dc8e73a7a3b3c43522b630cac068927f0649d43d719d2"
+dependencies = [
+ "virtue",
+]
+
+[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -791,9 +810,11 @@ name = "jellyremuxer"
version = "0.1.0"
dependencies = [
"anyhow",
+ "bincode 2.0.0-rc.2",
"jellycommon",
"jellymatroska",
"log",
+ "serde",
"tokio",
]
@@ -1865,7 +1886,7 @@ version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1060f05a4450ec5b758da60951b04f225a93a62079316630e76cf25c4034500d"
dependencies = [
- "bincode",
+ "bincode 1.3.3",
"pin-project",
"serde",
"sled",
@@ -1932,6 +1953,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
+name = "virtue"
+version = "0.0.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7b60dcd6a64dd45abf9bd426970c9843726da7fc08f44cd6fcebf68c21220a63"
+
+[[package]]
name = "want"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/common/src/lib.rs b/common/src/lib.rs
index a75f599..c4eac09 100644
--- a/common/src/lib.rs
+++ b/common/src/lib.rs
@@ -12,7 +12,7 @@ pub struct DirectoryInfo {
pub struct ItemInfo {
pub title: String,
pub duration: f64, // in seconds
- pub tracks: BTreeMap<u64, SourceTrack>,
+ pub tracks: BTreeMap<usize, SourceTrack>,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
diff --git a/ebml_derive/src/lib.rs b/ebml_derive/src/lib.rs
index 056071d..1508792 100644
--- a/ebml_derive/src/lib.rs
+++ b/ebml_derive/src/lib.rs
@@ -74,9 +74,7 @@ pub fn define_ebml(ts: TokenStream) -> TokenStream {
.collect::<Vec<_>>();
let write_match = tags
.iter()
- .filter_map(|Tag { name, .. }| {
- Some(quote! { Self::#name(v) => v.write_to(w) })
- })
+ .filter_map(|Tag { name, .. }| Some(quote! { Self::#name(v) => v.write_to(w) }))
.collect::<Vec<_>>();
let cons_master_match = tags
.iter()
diff --git a/matroska/src/block.rs b/matroska/src/block.rs
index e69de29..b0d6f6b 100644
--- a/matroska/src/block.rs
+++ b/matroska/src/block.rs
@@ -0,0 +1,43 @@
+use crate::read::ReadExt;
+use anyhow::Result;
+use std::io::Cursor;
+
+pub enum LacingType {
+ FixedSize,
+ Ebml,
+ Xiph,
+}
+
+pub struct Block {
+ pub track: u64,
+ pub timestamp_off: i16,
+ pub invisible: bool,
+ pub lacing: Option<LacingType>,
+ pub data: Vec<u8>,
+}
+
+impl Block {
+ pub fn parse(buf: &[u8]) -> Result<Self> {
+ let (track, c) = Cursor::new(buf).read_vint_len()?;
+ let timestamp_off = i16::from_be_bytes(buf[c..c + 2].try_into().unwrap());
+ let flags = buf[c + 2];
+ let data = Vec::from(&buf[c + 3..]);
+
+ let invisible = (flags & 0b10000) == 0b10000;
+ let lacing = match flags & 0b1100 {
+ 0b0000 => None,
+ 0b0100 => Some(LacingType::Xiph),
+ 0b1000 => Some(LacingType::Ebml),
+ 0b1100 => Some(LacingType::FixedSize),
+ _ => unreachable!(),
+ };
+
+ Ok(Self {
+ track,
+ data,
+ invisible,
+ lacing,
+ timestamp_off,
+ })
+ }
+}
diff --git a/matroska/src/lib.rs b/matroska/src/lib.rs
index d1e0fba..0bc9cc3 100644
--- a/matroska/src/lib.rs
+++ b/matroska/src/lib.rs
@@ -1,11 +1,11 @@
+pub mod block;
pub mod matroska;
pub mod read;
pub mod size;
-pub mod write;
pub mod unflatten;
-pub mod block;
+pub mod write;
-use matroska::MatroskaTag;
+pub use matroska::MatroskaTag;
pub use read::ReadValue;
pub use write::WriteValue;
diff --git a/matroska/src/matroska.rs b/matroska/src/matroska.rs
index b4078ab..8d63d90 100644
--- a/matroska/src/matroska.rs
+++ b/matroska/src/matroska.rs
@@ -108,7 +108,7 @@ define_ebml! {
SimpleBlock[0xA3]: Binary,
Timestamp[0xE7]: Uint,
},
-
+
Cues[0x1C53BB6B]: {
CuePoint[0xBB]: {
CueTime[0xB3]: Uint,
@@ -327,4 +327,4 @@ define_ebml! {
},
},
},
-} \ No newline at end of file
+}
diff --git a/matroska/src/read.rs b/matroska/src/read.rs
index 95a98b5..6849f11 100644
--- a/matroska/src/read.rs
+++ b/matroska/src/read.rs
@@ -1,6 +1,6 @@
use crate::{matroska::MatroskaTag, size::EbmlSize, Master};
use anyhow::{anyhow, bail, Result};
-use log::{debug, warn};
+use log::{debug, error, warn};
use std::{
collections::VecDeque,
io::{Read, Seek, SeekFrom},
@@ -22,6 +22,14 @@ pub struct EbmlReader {
pub position: usize,
}
+impl Read for EbmlReader {
+ fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
+ let r = self.inner.read(buf)?;
+ self.position += r;
+ Ok(r)
+ }
+}
+
impl EbmlReader {
pub fn new<T: Seek + Read + 'static>(inner: T) -> Self {
Self {
@@ -159,7 +167,22 @@ impl Iterator for EbmlReader {
} else {
match self.read_stuff() {
Ok(()) => self.next(),
- Err(e) => Some(Err(e)),
+ // in case we reached the end (error: failed to fill whole buffer),
+ // return the rest in the queue and pop all items of the stack
+ Err(e) => {
+ // TODO this is horrible, should use a custom error enum instead
+ if format!("{e}").as_str() == "failed to fill whole buffer" {
+ match self.queue.pop_front() {
+ Some(q) => Some(Ok(q)),
+ None => match self.stack.pop() {
+ Some(q) => Some(MatroskaTag::construct_master(q.id, Master::End)),
+ None => Some(Err(e)),
+ },
+ }
+ } else {
+ Some(Err(e))
+ }
+ }
}
}
}
@@ -225,3 +248,33 @@ impl ReadValue for Master {
panic!("master shall not be read like this")
}
}
+
+pub trait ReadExt: Read {
+ fn read_byte(&mut self) -> Result<u8>;
+ fn read_vint_len(&mut self) -> Result<(u64, usize)>;
+ fn read_vint(&mut self) -> Result<u64>;
+}
+impl<T: Read> ReadExt for T {
+ fn read_byte(&mut self) -> Result<u8> {
+ let mut b = [0u8];
+ self.read_exact(&mut b)?;
+ Ok(b[0])
+ }
+ fn read_vint_len(&mut self) -> Result<(u64, usize)> {
+ let s = self.read_byte()?;
+ let len = s.leading_zeros() + 1;
+ if len > 8 {
+ bail!("varint too long");
+ }
+ let mut value = s as u64;
+ value -= 1 << (8 - len);
+ for _ in 1..len {
+ value <<= 8;
+ value += self.read_byte()? as u64;
+ }
+ Ok((value, len as usize))
+ }
+ fn read_vint(&mut self) -> Result<u64> {
+ Ok(self.read_vint_len()?.0)
+ }
+}
diff --git a/matroska/src/size.rs b/matroska/src/size.rs
index e774f0a..a2ca61d 100644
--- a/matroska/src/size.rs
+++ b/matroska/src/size.rs
@@ -1,4 +1,3 @@
-
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EbmlSize {
Exact(usize),
diff --git a/remuxer/Cargo.toml b/remuxer/Cargo.toml
index 82dffd5..b4ee07e 100644
--- a/remuxer/Cargo.toml
+++ b/remuxer/Cargo.toml
@@ -5,9 +5,11 @@ edition = "2021"
[dependencies]
jellycommon = { path = "../common" }
-jellymatroska = {path = "../matroska"}
+jellymatroska = { path = "../matroska" }
tokio = { version = "1.24.1", features = ["io-util"] }
anyhow = "1.0.68"
log = "0.4.17"
+serde = { version = "1.0.152", features = ["derive"] }
+bincode = "2.0.0-rc.2" \ No newline at end of file
diff --git a/remuxer/src/format.rs b/remuxer/src/format.rs
new file mode 100644
index 0000000..f6cc411
--- /dev/null
+++ b/remuxer/src/format.rs
@@ -0,0 +1,20 @@
+use serde::{Deserialize, Serialize};
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct TrackIndex {
+ pub clusters: Vec<ClusterIndex>,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct ClusterIndex {
+ pub timestamp: usize,
+ pub blocks: BlockIndex,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct BlockIndex {
+ pub timestamp_off: usize,
+ pub offset: usize,
+}
+
+pub struct FBlock {}
diff --git a/remuxer/src/import/mod.rs b/remuxer/src/import/mod.rs
index 8a5cd54..bd22cf5 100644
--- a/remuxer/src/import/mod.rs
+++ b/remuxer/src/import/mod.rs
@@ -1,18 +1,24 @@
+use std::collections::HashMap;
+
use anyhow::{anyhow, bail, Result};
use jellycommon::{ItemInfo, SourceTrack, SourceTrackKind};
use jellymatroska::{
matroska::MatroskaTag,
read::EbmlReader,
unflatten::{Unflat, Unflatten},
- Master,
};
-use log::{debug, error, info, trace};
+use log::{debug, error, info, trace, warn};
pub fn import_read(input: &mut EbmlReader, iteminfo: &mut ItemInfo) -> Result<()> {
// TODO dont traverse the entire file, if the tracks are listed at the end
- let (mut timestamp_scale, mut duration) = (None, None);
while let Some(item) = input.next() {
- let item = item?;
+ let item = match item {
+ Ok(item) => item,
+ Err(e) => {
+ warn!("{e}");
+ break;
+ }
+ };
match item {
MatroskaTag::Ebml(_) => {
let mut iter = Unflatten::new_with_end(input, item);
@@ -27,28 +33,44 @@ pub fn import_read(input: &mut EbmlReader, iteminfo: &mut ItemInfo) -> Result<()
}
}
}
- MatroskaTag::SeekHead(_) => {
- Unflatten::new_with_end(input, item);
+ MatroskaTag::Segment(_) => {
+ info!("segment start");
+ let mut children = Unflatten::new_with_end(input, item);
+ import_read_segment(&mut children, iteminfo)?;
+ info!("segment end");
}
+ _ => debug!("(r) tag ignored: {item:?}"),
+ }
+ }
+
+ Ok(())
+}
+
+fn import_read_segment(children: &mut Unflatten, iteminfo: &mut ItemInfo) -> Result<()> {
+ let mut track_mapping = HashMap::<u64, usize>::new(); // maps matroska track id to item track id
+ let (mut timestamp_scale, mut duration) = (None, None);
+ while let Some(Ok(Unflat { children, item })) = children.next() {
+ match item {
+ MatroskaTag::SeekHead(_) => {}
MatroskaTag::Info(_) => {
- let mut iter = Unflatten::new_with_end(input, item);
- while let Some(Ok(Unflat { children, item })) = iter.next() {
+ let mut children = children.unwrap();
+ while let Some(Ok(Unflat { children, item })) = children.next() {
match item {
MatroskaTag::TimestampScale(v) => timestamp_scale = Some(v),
MatroskaTag::Duration(v) => duration = Some(v),
- _ => debug!("(ri) tag ignored: {item:?}"),
+ _ => debug!("(rsi) tag ignored: {item:?}"),
}
}
}
MatroskaTag::Cluster(_) => {
info!("start of cluster found");
- let mut iter = Unflatten::new_with_end(input, item);
- while let Some(Ok(Unflat { children, item })) = iter.next() {
+ let mut children = children.unwrap();
+ while let Some(Ok(Unflat { children, item })) = children.next() {
match item {
MatroskaTag::BlockGroup(_) => {
debug!("group");
- let mut iter = children.unwrap();
- while let Some(Ok(Unflat { children, item })) = iter.next() {
+ let mut children = children.unwrap();
+ while let Some(Ok(Unflat { children, item })) = children.next() {
match item {
MatroskaTag::Block(_) => (),
_ => trace!("{item:?}"),
@@ -58,16 +80,14 @@ pub fn import_read(input: &mut EbmlReader, iteminfo: &mut ItemInfo) -> Result<()
MatroskaTag::SimpleBlock(_) => {
// debug!("simple");
}
- _ => debug!("(rc) tag ignored: {item:?}"),
+ _ => debug!("(rsc) tag ignored: {item:?}"),
}
}
}
- MatroskaTag::Tags(_) => {
- Unflatten::new_with_end(input, item);
- }
+ MatroskaTag::Tags(_) => {}
MatroskaTag::Cues(_) => {
- let mut iter = Unflatten::new_with_end(input, item);
- while let Some(Ok(Unflat { children, item })) = iter.next() {
+ let mut children = children.unwrap();
+ while let Some(Ok(Unflat { children, item })) = children.next() {
match item {
MatroskaTag::CuePoint(_) => {
let mut children = children.unwrap();
@@ -79,12 +99,10 @@ pub fn import_read(input: &mut EbmlReader, iteminfo: &mut ItemInfo) -> Result<()
}
}
}
- MatroskaTag::Chapters(_) => {
- Unflatten::new_with_end(input, item);
- }
+ MatroskaTag::Chapters(_) => {}
MatroskaTag::Tracks(_) => {
- let mut iter = Unflatten::new_with_end(input, item);
- while let Some(Ok(Unflat { children, item })) = iter.next() {
+ let mut children = children.unwrap();
+ while let Some(Ok(Unflat { children, item })) = children.next() {
match item {
MatroskaTag::TrackEntry(_) => {
let mut children = children.unwrap();
@@ -139,7 +157,8 @@ pub fn import_read(input: &mut EbmlReader, iteminfo: &mut ItemInfo) -> Result<()
_ => (),
}
}
- let index = index.unwrap();
+ let itrack_index = iteminfo.tracks.len();
+ let mtrack_index = index.unwrap();
let kind = match kind.ok_or(anyhow!("track type required"))? {
1 => SourceTrackKind::Video {
fps: fps.unwrap_or(f64::NAN), // TODO
@@ -154,8 +173,9 @@ pub fn import_read(input: &mut EbmlReader, iteminfo: &mut ItemInfo) -> Result<()
17 => SourceTrackKind::Subtitles,
_ => bail!("invalid track type"),
};
+ track_mapping.insert(mtrack_index, itrack_index);
iteminfo.tracks.insert(
- index,
+ itrack_index,
SourceTrack {
name: name.unwrap_or_else(|| "unnamed".to_string()),
codec: codec.unwrap(),
@@ -164,13 +184,14 @@ pub fn import_read(input: &mut EbmlReader, iteminfo: &mut ItemInfo) -> Result<()
},
);
}
- _ => debug!("(rt) tag ignored: {item:?}"),
+ _ => debug!("(rst) tag ignored: {item:?}"),
}
}
}
- MatroskaTag::Segment(Master::End) => break,
- _ => debug!("(r) tag ignored: {item:?}"),
+ _ => debug!("(rs) tag ignored: {item:?}"),
}
}
+ iteminfo.duration =
+ (duration.unwrap() * timestamp_scale.unwrap() as f64) as f64 / 1_000_000_000 as f64;
Ok(())
}
diff --git a/remuxer/src/lib.rs b/remuxer/src/lib.rs
index cc189a3..cc508e8 100644
--- a/remuxer/src/lib.rs
+++ b/remuxer/src/lib.rs
@@ -1,4 +1,5 @@
pub mod import;
+pub mod format;
use jellycommon::ItemInfo;
use std::{io::Write, path::PathBuf, sync::Arc};
diff --git a/server/src/frontend/mod.rs b/server/src/frontend/mod.rs
index 99c22f8..043be24 100644
--- a/server/src/frontend/mod.rs
+++ b/server/src/frontend/mod.rs
@@ -1,2 +1,2 @@
-pub mod style;
pub mod pages;
+pub mod style;
diff --git a/server/src/frontend/pages/layout.rs b/server/src/frontend/pages/layout.rs
index 5654d3b..1085f84 100644
--- a/server/src/frontend/pages/layout.rs
+++ b/server/src/frontend/pages/layout.rs
@@ -11,7 +11,7 @@ markup::define! {
body {
nav {
h1 { "Jellything" }
-
+
}
#main { @main }
}
diff --git a/server/src/frontend/style/mod.rs b/server/src/frontend/style/mod.rs
index 1e51d10..ca54aa7 100644
--- a/server/src/frontend/style/mod.rs
+++ b/server/src/frontend/style/mod.rs
@@ -1,6 +1,7 @@
-use std::{fs::{File, read_to_string}, io::Read};
-
-
+use std::{
+ fs::{read_to_string, File},
+ io::Read,
+};
pub fn css_bundle() -> String {
if cfg!(debug_assertions) {
@@ -13,7 +14,10 @@ pub fn css_bundle() -> String {
pub fn font_bundle() -> Vec<u8> {
if cfg!(debug_assertions) {
let mut woff = Vec::new();
- File::open("server/src/frontend/style/cantarell.woff2").unwrap().read_to_end(&mut woff).unwrap();
+ File::open("server/src/frontend/style/cantarell.woff2")
+ .unwrap()
+ .read_to_end(&mut woff)
+ .unwrap();
woff
} else {
include_bytes!("cantarell.woff2").to_vec()
diff --git a/server/src/main.rs b/server/src/main.rs
index a9db370..9a2ca47 100644
--- a/server/src/main.rs
+++ b/server/src/main.rs
@@ -1,6 +1,6 @@
#![feature(box_syntax)]
-use crate::frontend::{pages::MyError};
+use crate::frontend::pages::MyError;
use anyhow::{anyhow, Context};
use database::Database;
use frontend::{
@@ -84,6 +84,12 @@ fn rocket() -> _ {
rocket::build().manage(state).mount(
"/",
- routes![page_home, page_library_node, assets_style, assets_font, stream],
+ routes![
+ page_home,
+ page_library_node,
+ assets_style,
+ assets_font,
+ stream
+ ],
)
}