aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common/src/lib.rs28
-rw-r--r--common/src/seek_index.rs32
-rw-r--r--remuxer/src/lib.rs82
-rw-r--r--remuxer/src/remux.rs76
-rw-r--r--remuxer/src/seek_index.rs2
-rw-r--r--server/src/database.rs4
6 files changed, 125 insertions, 99 deletions
diff --git a/common/src/lib.rs b/common/src/lib.rs
index d57d2c0..ec6e0df 100644
--- a/common/src/lib.rs
+++ b/common/src/lib.rs
@@ -7,8 +7,8 @@ pub mod config;
pub mod helpers;
pub mod r#impl;
pub mod stream;
+pub mod seek_index;
-use bincode::{Decode, Encode};
#[cfg(feature = "rocket")]
use rocket::{FromFormField, UriDisplayQuery};
use serde::{Deserialize, Serialize};
@@ -139,29 +139,3 @@ pub enum SourceTrackKind {
},
Subtitles,
}
-
-pub const SEEK_INDEX_VERSION: u32 = 0x5eef1de4;
-
-#[derive(Debug, Clone, Decode, Encode)]
-pub struct SeekIndex {
- pub version: u32,
- pub blocks: Vec<BlockIndex>,
- pub keyframes: Vec<usize>,
-}
-
-#[derive(Debug, Clone, Decode, Encode)]
-pub struct BlockIndex {
- pub pts: u64,
- pub source_off: usize,
- pub size: usize,
-}
-
-impl Default for SeekIndex {
- fn default() -> Self {
- Self {
- version: SEEK_INDEX_VERSION,
- blocks: Vec::new(),
- keyframes: Vec::new(),
- }
- }
-}
diff --git a/common/src/seek_index.rs b/common/src/seek_index.rs
new file mode 100644
index 0000000..98afcca
--- /dev/null
+++ b/common/src/seek_index.rs
@@ -0,0 +1,32 @@
+/*
+ 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) 2023 metamuffin <metamuffin.org>
+*/
+use bincode::{Decode, Encode};
+
+pub const SEEK_INDEX_VERSION: u32 = 0x5eef1de4;
+
+#[derive(Debug, Clone, Decode, Encode)]
+pub struct SeekIndex {
+ pub version: u32,
+ pub blocks: Vec<BlockIndex>,
+ pub keyframes: Vec<usize>,
+}
+
+#[derive(Debug, Clone, Decode, Encode)]
+pub struct BlockIndex {
+ pub pts: u64,
+ pub source_off: usize,
+ pub size: usize,
+}
+
+impl Default for SeekIndex {
+ fn default() -> Self {
+ Self {
+ version: SEEK_INDEX_VERSION,
+ blocks: Vec::new(),
+ keyframes: Vec::new(),
+ }
+ }
+}
diff --git a/remuxer/src/lib.rs b/remuxer/src/lib.rs
index 9a5e6c6..e1f8c80 100644
--- a/remuxer/src/lib.rs
+++ b/remuxer/src/lib.rs
@@ -5,9 +5,87 @@
*/
pub mod import;
pub mod remux;
+pub mod seek_index;
pub mod segment_extractor;
-pub mod trim_writer;
pub mod snippet;
-pub mod seek_index;
+pub mod trim_writer;
pub use remux::remux_stream_into;
+pub use snippet::write_snippet_into;
+
+use jellycommon::{SourceTrack, SourceTrackKind};
+use jellymatroska::{Master, MatroskaTag};
+
+pub fn ebml_header(webm: bool) -> MatroskaTag {
+ MatroskaTag::Ebml(Master::Collected(vec![
+ MatroskaTag::EbmlVersion(1),
+ MatroskaTag::EbmlReadVersion(1),
+ MatroskaTag::EbmlMaxIdLength(4),
+ MatroskaTag::EbmlMaxSizeLength(8),
+ MatroskaTag::DocType(if webm {
+ "webm".to_string()
+ } else {
+ "matroska".to_string()
+ }),
+ MatroskaTag::DocTypeVersion(4),
+ MatroskaTag::DocTypeReadVersion(2),
+ ]))
+}
+pub fn ebml_segment_info(title: String, duration: f64) -> MatroskaTag {
+ MatroskaTag::Info(Master::Collected(vec![
+ MatroskaTag::TimestampScale(1_000_000),
+ MatroskaTag::Duration(duration * 1000.0),
+ MatroskaTag::Title(title),
+ MatroskaTag::MuxingApp("jellyremux".to_string()),
+ MatroskaTag::WritingApp("jellything".to_string()),
+ ]))
+}
+
+pub fn ebml_track_entry(
+ number: u64,
+ track: &SourceTrack,
+ codec_private: Option<Vec<u8>>,
+) -> MatroskaTag {
+ let mut els = vec![
+ MatroskaTag::TrackNumber(number),
+ MatroskaTag::TrackUID(number),
+ MatroskaTag::FlagLacing(0),
+ MatroskaTag::Language(track.language.clone()),
+ MatroskaTag::CodecID(track.codec.clone()),
+ ];
+ if let Some(d) = &track.default_duration {
+ els.push(MatroskaTag::DefaultDuration(*d));
+ }
+ match track.kind {
+ SourceTrackKind::Video {
+ width,
+ height,
+ fps: _,
+ } => {
+ els.push(MatroskaTag::TrackType(1));
+ els.push(MatroskaTag::Video(Master::Collected(vec![
+ MatroskaTag::PixelWidth(width),
+ MatroskaTag::PixelHeight(height),
+ ])))
+ }
+ SourceTrackKind::Audio {
+ channels,
+ sample_rate,
+ bit_depth,
+ } => {
+ els.push(MatroskaTag::TrackType(2));
+ els.push(MatroskaTag::Audio(Master::Collected(vec![
+ MatroskaTag::SamplingFrequency(sample_rate),
+ MatroskaTag::Channels(channels.try_into().unwrap()),
+ ])));
+ els.push(MatroskaTag::BitDepth(bit_depth.try_into().unwrap()));
+ }
+ SourceTrackKind::Subtitles => {
+ els.push(MatroskaTag::TrackType(19));
+ }
+ }
+ if let Some(d) = &codec_private {
+ els.push(MatroskaTag::CodecPrivate(d.clone()));
+ }
+ MatroskaTag::TrackEntry(Master::Collected(els))
+}
diff --git a/remuxer/src/remux.rs b/remuxer/src/remux.rs
index 8807a38..d7a30e5 100644
--- a/remuxer/src/remux.rs
+++ b/remuxer/src/remux.rs
@@ -3,9 +3,14 @@
which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
Copyright (C) 2023 metamuffin <metamuffin.org>
*/
-use crate::{segment_extractor::SegmentExtractIter, trim_writer::TrimWriter};
+use crate::{
+ ebml_header, ebml_track_entry, segment_extractor::SegmentExtractIter, trim_writer::TrimWriter,
+};
use anyhow::{anyhow, Context};
-use jellycommon::{BlockIndex, LocalTrack, NodePublic, SeekIndex, SourceTrack, SourceTrackKind};
+use jellycommon::{
+ seek_index::{BlockIndex, SeekIndex},
+ LocalTrack, NodePublic, SourceTrack,
+};
use jellymatroska::{
block::Block,
read::EbmlReader,
@@ -87,19 +92,7 @@ pub fn remux_stream_into(
info!("(perf) prepare inputs: {:?}", Instant::now() - timing_cp);
let timing_cp = Instant::now();
- output.write_tag(&MatroskaTag::Ebml(Master::Collected(vec![
- MatroskaTag::EbmlVersion(1),
- MatroskaTag::EbmlReadVersion(1),
- MatroskaTag::EbmlMaxIdLength(4),
- MatroskaTag::EbmlMaxSizeLength(8),
- MatroskaTag::DocType(if webm {
- "webm".to_string()
- } else {
- "matroska".to_string()
- }),
- MatroskaTag::DocTypeVersion(4),
- MatroskaTag::DocTypeReadVersion(2),
- ])))?;
+ output.write_tag(&ebml_header(webm))?;
output.write_tag(&MatroskaTag::Segment(Master::Start))?;
let segment_offset = output.position();
@@ -115,7 +108,7 @@ pub fn remux_stream_into(
let tracks_header = inputs
.iter_mut()
- .map(|rc| track_to_ebml(rc.mapped, &rc.info, rc.codec_private.take()))
+ .map(|rc| ebml_track_entry(rc.mapped, &rc.info, rc.codec_private.take()))
.collect();
output.write_tag(&MatroskaTag::Tracks(Master::Collected(tracks_header)))?;
@@ -210,7 +203,7 @@ pub fn remux_stream_into(
1 // ctrack id
+ 1 // ctrack size
+ 1 // ctrack content int
- // TODO break if inputs.len() >= 127
+ // TODO this breaks if inputs.len() >= 127
+ 1 // ccp id
+ 1 // ccp len
+ 8 // ccp content offset
@@ -330,52 +323,3 @@ pub fn remux_stream_into(
output.write_tag(&MatroskaTag::Segment(Master::End))?;
Ok(())
}
-
-pub fn track_to_ebml(
- number: u64,
- track: &SourceTrack,
- codec_private: Option<Vec<u8>>,
-) -> MatroskaTag {
- let mut els = vec![
- MatroskaTag::TrackNumber(number),
- MatroskaTag::TrackUID(number),
- MatroskaTag::FlagLacing(0),
- MatroskaTag::Language(track.language.clone()),
- MatroskaTag::CodecID(track.codec.clone()),
- ];
- if let Some(d) = &track.default_duration {
- els.push(MatroskaTag::DefaultDuration(*d));
- }
- match track.kind {
- SourceTrackKind::Video {
- width,
- height,
- fps: _,
- } => {
- els.push(MatroskaTag::TrackType(1));
- els.push(MatroskaTag::Video(Master::Collected(vec![
- MatroskaTag::PixelWidth(width),
- MatroskaTag::PixelHeight(height),
- ])))
- }
- SourceTrackKind::Audio {
- channels,
- sample_rate,
- bit_depth,
- } => {
- els.push(MatroskaTag::TrackType(2));
- els.push(MatroskaTag::Audio(Master::Collected(vec![
- MatroskaTag::SamplingFrequency(sample_rate),
- MatroskaTag::Channels(channels.try_into().unwrap()),
- ])));
- els.push(MatroskaTag::BitDepth(bit_depth.try_into().unwrap()));
- }
- SourceTrackKind::Subtitles => {
- els.push(MatroskaTag::TrackType(19));
- }
- }
- if let Some(d) = &codec_private {
- els.push(MatroskaTag::CodecPrivate(d.clone()));
- }
- MatroskaTag::TrackEntry(Master::Collected(els))
-}
diff --git a/remuxer/src/seek_index.rs b/remuxer/src/seek_index.rs
index 7dbb9f7..f269a23 100644
--- a/remuxer/src/seek_index.rs
+++ b/remuxer/src/seek_index.rs
@@ -4,7 +4,7 @@
Copyright (C) 2023 metamuffin <metamuffin.org>
*/
use anyhow::Result;
-use jellycommon::{BlockIndex, SeekIndex};
+use jellycommon::seek_index::{BlockIndex, SeekIndex};
use jellymatroska::{
block::Block,
read::EbmlReader,
diff --git a/server/src/database.rs b/server/src/database.rs
index be71c98..d5a435f 100644
--- a/server/src/database.rs
+++ b/server/src/database.rs
@@ -6,7 +6,7 @@
use crate::routes::ui::account::hash_password;
use anyhow::Context;
use jellybase::CONF;
-use jellycommon::{Node, SeekIndex};
+use jellycommon::Node;
use log::info;
use serde::{Deserialize, Serialize};
use std::path::Path;
@@ -18,7 +18,6 @@ pub struct Database {
pub user: Tree<String, User>,
pub invite: Tree<String, ()>,
pub node: Tree<String, Node>,
- pub seek_index: Tree<(String, usize), SeekIndex>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
@@ -38,7 +37,6 @@ impl Database {
user: Tree::open(&db, "user"),
invite: Tree::open(&db, "invite"),
node: Tree::open(&db, "node"),
- seek_index: Tree::open(&db, "seek_index"),
db,
});
info!("ready");