aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--matroska/src/bin/mkvdump.rs6
-rw-r--r--matroska/src/write.rs11
-rw-r--r--remuxer/src/lib.rs83
-rw-r--r--server/Cargo.toml3
-rw-r--r--server/src/main.rs4
-rw-r--r--server/src/routes/stream.rs3
-rw-r--r--server/src/routes/ui/account/session.rs5
7 files changed, 84 insertions, 31 deletions
diff --git a/matroska/src/bin/mkvdump.rs b/matroska/src/bin/mkvdump.rs
index 10c697a..ba05c19 100644
--- a/matroska/src/bin/mkvdump.rs
+++ b/matroska/src/bin/mkvdump.rs
@@ -14,9 +14,9 @@ fn main() -> anyhow::Result<()> {
while let Some(tag) = r.next() {
let tag = tag?;
match tag {
- MatroskaTag::SimpleBlock(_) => (),
- MatroskaTag::Block(_) => (),
- _ => eprintln!("{} {tag:?}", r.position),
+ MatroskaTag::SimpleBlock(_) => (), // println!("{} SimpleBlock", r.position),
+ MatroskaTag::Block(_) => (), // println!("{} Block", r.position),
+ _ => println!("{} {tag:?}", r.position),
}
}
Ok(())
diff --git a/matroska/src/write.rs b/matroska/src/write.rs
index ee1c44c..8c1e7bb 100644
--- a/matroska/src/write.rs
+++ b/matroska/src/write.rs
@@ -26,6 +26,10 @@ impl EbmlWriter {
Ok(())
}
+ pub fn position(&self) -> usize {
+ self.position
+ }
+
pub fn write_padding(&mut self, position: usize) -> Result<()> {
let mut size = position - self.position;
match size {
@@ -62,14 +66,17 @@ impl EbmlWriter {
if i > (1 << 56) - 1 {
bail!("vint does not fit");
}
+ self.write_vint_len(i, Self::vint_length(i))
+ }
+ pub fn vint_length(v: u64) -> usize {
let mut len = 1;
while len <= 8 {
- if i < (1 << ((7 * len) - 1)) {
+ if v < (1 << ((7 * len) - 1)) {
break;
}
len += 1;
}
- self.write_vint_len(i, len)
+ len
}
pub fn write_vint_len(&mut self, i: u64, len: usize) -> Result<()> {
let mut bytes = i.to_be_bytes();
diff --git a/remuxer/src/lib.rs b/remuxer/src/lib.rs
index 91c913a..1dfbacd 100644
--- a/remuxer/src/lib.rs
+++ b/remuxer/src/lib.rs
@@ -114,11 +114,18 @@ impl RemuxerContext {
.collect();
output.write_tag(&MatroskaTag::Tracks(Master::Collected(tracks_header)))?;
+ struct ClusterLayout {
+ position: usize,
+ timestamp: u64,
+ blocks: Vec<(usize, BlockIndex)>,
+ }
+
let segment_layout = {
- let mut pts = 0;
- let mut cluster_pts = pts + 2_000;
+ let mut cluster_pts = 0;
let mut clusters = vec![];
let mut cluster = vec![];
+ let mut gp = 0usize; // cluster position (in the segment)
+ let mut p = 0usize; // block position (in the cluster)
loop {
let mut best_block = BlockIndex {
pts: u64::MAX,
@@ -135,14 +142,32 @@ impl RemuxerContext {
};
}
inputs[best_index].temp_index += 1;
- pts = best_block.pts;
- if pts > cluster_pts + 2_000 {
- clusters.push(std::mem::replace(&mut cluster, vec![]));
- cluster_pts = pts;
+ if best_block.pts > cluster_pts + 2_000 {
+ let cluster_content_size = 1 // timestamp tag
+ + 1 // timestamp tag size
+ + EbmlWriter::vint_length(cluster_pts as u64) // timestamp tag value
+ + p;
+ let cluster_header_size = 4 // tag length
+ + EbmlWriter::vint_length(cluster_content_size as u64)// size varint
+ + cluster_content_size;
+ clusters.push(ClusterLayout {
+ position: gp,
+ timestamp: cluster_pts,
+ blocks: std::mem::replace(&mut cluster, vec![]),
+ });
+
+ cluster_pts = best_block.pts;
+ gp += p + cluster_header_size;
+ p = 0;
}
- if pts == u64::MAX {
+ if best_block.pts == u64::MAX {
break;
}
+ p += 1; // simpleblock tag
+ p += EbmlWriter::vint_length(1 + 2 + 1 + best_block.size as u64); // simpleblock size vint
+ p += 1 + 2 + 1; // block {tracknum, pts_off, flags}
+ // TODO does not work, if more than 127 tracks are present
+ p += best_block.size; // block payload
cluster.push((best_index, best_block))
}
info!("segment layout computed ({} clusters)", clusters.len());
@@ -183,28 +208,32 @@ impl RemuxerContext {
for (cluster_index, cluster) in segment_layout.into_iter().enumerate() {
info!(
- "writing cluster {cluster_index} with {} blocks",
- cluster.len()
+ "writing cluster {cluster_index} (pts_base={}) with {} blocks",
+ cluster.timestamp,
+ cluster.blocks.len()
+ );
+ debug!(
+ "calculation was {} bytes off",
+ cluster.position as i64 - output.position() as i64
);
- for (block_index, iblock) in cluster {
+ let mut cluster_blocks = vec![MatroskaTag::Timestamp(cluster.timestamp as u64)];
+ for (block_index, iblock) in cluster.blocks {
let kn = &mut ks[block_index];
let mut block = kn
.peek
.replace(kn.stream.next()?)
.expect("source file too short");
- assert_eq!(iblock.size, block.block.data.len(), "seek index is wrong");
+ assert_eq!(iblock.size, block.inner.data.len(), "seek index is wrong");
assert_eq!(iblock.pts, block.pts(), "seek index is wrong");
- let pts = block.pts();
- block.block.track = kn.mapped;
- block.block.timestamp_off = 0;
- let buf = block.block.dump();
- output.write_tag(&MatroskaTag::Cluster(Master::Collected(vec![
- MatroskaTag::Timestamp(pts),
- MatroskaTag::SimpleBlock(buf),
- ])))?;
+ block.inner.track = kn.mapped;
+ block.inner.timestamp_off = (iblock.pts - cluster.timestamp).try_into().unwrap();
+ debug!("n={} tso={}", block.inner.track, block.inner.timestamp_off);
+ let buf = block.inner.dump();
+ cluster_blocks.push(MatroskaTag::SimpleBlock(buf))
}
+ output.write_tag(&MatroskaTag::Cluster(Master::Collected(cluster_blocks)))?;
}
output.write_tag(&MatroskaTag::Segment(Master::End))?;
Ok(())
@@ -213,7 +242,7 @@ impl RemuxerContext {
struct AbsoluteBlock {
pts_base: u64,
- block: Block,
+ inner: Block,
}
struct SegmentExtractIter<'a> {
@@ -224,7 +253,7 @@ struct SegmentExtractIter<'a> {
impl AbsoluteBlock {
pub fn pts(&self) -> u64 {
- self.block.timestamp_off as u64 + self.pts_base
+ self.inner.timestamp_off as u64 + self.pts_base
}
}
@@ -272,16 +301,20 @@ impl SegmentExtractIter<'_> {
let block = Block::parse(&block.unwrap())?;
if block.track == self.extract {
trace!("block: track={} tso={}", block.track, block.timestamp_off);
- self.emission_queue
- .push_back(AbsoluteBlock { pts_base, block });
+ self.emission_queue.push_back(AbsoluteBlock {
+ pts_base,
+ inner: block,
+ });
}
}
MatroskaTag::SimpleBlock(buf) => {
let block = Block::parse(&buf)?;
if block.track == self.extract {
trace!("block: track={} tso={}", block.track, block.timestamp_off);
- self.emission_queue
- .push_back(AbsoluteBlock { pts_base, block });
+ self.emission_queue.push_back(AbsoluteBlock {
+ pts_base,
+ inner: block,
+ });
}
}
_ => warn!("(rsc) tag ignored: {item:?}"),
diff --git a/server/Cargo.toml b/server/Cargo.toml
index 458f48d..a3214fa 100644
--- a/server/Cargo.toml
+++ b/server/Cargo.toml
@@ -26,3 +26,6 @@ markup = "0.13.1"
sled = "0.34.7"
typed-sled = "0.2.3"
+
+[features]
+bypass-auth = [] \ No newline at end of file
diff --git a/server/src/main.rs b/server/src/main.rs
index 3d08d24..00543ce 100644
--- a/server/src/main.rs
+++ b/server/src/main.rs
@@ -26,6 +26,10 @@ fn rocket() -> _ {
.filter_level(log::LevelFilter::Info)
.parse_env("LOG")
.init();
+
+ #[cfg(feature = "bypass-auth")]
+ warn!("authentification bypass enabled");
+
let remuxer = RemuxerContext::new();
let library = Library::open(&CONF.library_path).unwrap();
let database = Database::open(&CONF.database_path).unwrap();
diff --git a/server/src/routes/stream.rs b/server/src/routes/stream.rs
index eb7bc13..469ad07 100644
--- a/server/src/routes/stream.rs
+++ b/server/src/routes/stream.rs
@@ -3,7 +3,7 @@
which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
Copyright (C) 2023 metamuffin <metamuffin.org>
*/
-use super::ui::error::MyError;
+use super::ui::{account::session::Session, error::MyError};
use crate::library::Library;
use anyhow::{anyhow, Context, Result};
use jellyremuxer::RemuxerContext;
@@ -37,6 +37,7 @@ pub fn stream_uri(path: &PathBuf, tracks: &Vec<u64>, webm: bool) -> String {
#[get("/stream/<path..>?<tracks>&<webm>")]
pub fn r_stream(
+ _sess: Session,
path: PathBuf,
webm: Option<bool>,
tracks: String,
diff --git a/server/src/routes/ui/account/session.rs b/server/src/routes/ui/account/session.rs
index ed40d83..3457d41 100644
--- a/server/src/routes/ui/account/session.rs
+++ b/server/src/routes/ui/account/session.rs
@@ -6,6 +6,7 @@
use crate::{
database::{Database, User},
routes::ui::error::MyError,
+ CONF,
};
use anyhow::anyhow;
use rocket::{
@@ -20,11 +21,15 @@ pub struct Session {
impl Session {
pub async fn from_request_ut(req: &Request<'_>) -> Result<Self, MyError> {
+ #[cfg(not(feature = "bypass-auth"))]
let cookie = req
.cookies()
.get_private("user")
.ok_or(anyhow!("login required"))?;
+ #[cfg(not(feature = "bypass-auth"))]
let username = cookie.value();
+ #[cfg(feature = "bypass-auth")]
+ let username = CONF.admin_username.to_string();
let db = req.guard::<&State<Database>>().await.unwrap();
let user = db