aboutsummaryrefslogtreecommitdiff
path: root/stream/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'stream/src/lib.rs')
-rw-r--r--stream/src/lib.rs91
1 files changed, 4 insertions, 87 deletions
diff --git a/stream/src/lib.rs b/stream/src/lib.rs
index eb56529..18ad2a7 100644
--- a/stream/src/lib.rs
+++ b/stream/src/lib.rs
@@ -7,6 +7,7 @@
pub mod fragment;
pub mod fragment_index;
pub mod hls;
+pub mod stream_info;
pub mod webvtt;
use anyhow::{anyhow, Context, Result};
@@ -14,18 +15,14 @@ use fragment::fragment_stream;
use fragment_index::fragment_index_stream;
use hls::{hls_master_stream, hls_variant_stream};
use jellybase::common::{
- stream::{
- StreamContainer, StreamFormatInfo, StreamInfo, StreamSegmentInfo, StreamSpec,
- StreamTrackInfo, TrackKind,
- },
+ stream::{StreamContainer, StreamSpec},
Node,
};
-use jellyremuxer::metadata::{matroska_metadata, MatroskaMetadata};
use std::{collections::BTreeSet, io::SeekFrom, ops::Range, path::PathBuf, sync::Arc};
+use stream_info::{stream_info, write_stream_info};
use tokio::{
fs::File,
io::{duplex, AsyncReadExt, AsyncSeekExt, AsyncWriteExt, DuplexStream},
- task::spawn_blocking,
};
use tokio_util::io::SyncIoBridge;
@@ -50,6 +47,7 @@ pub fn stream_head(spec: &StreamSpec) -> StreamHead {
StreamContainer::Matroska => "video/x-matroska",
StreamContainer::WebVTT => "text/vtt",
StreamContainer::JVTT => "application/jellything-vtt+json",
+ StreamContainer::MPEG4 => "video/mp4",
};
match spec {
StreamSpec::Whep { .. } => cons("application/x-todo", false),
@@ -103,87 +101,6 @@ pub async fn stream(
Ok(a)
}
-async fn async_matroska_metadata(path: PathBuf) -> Result<Arc<MatroskaMetadata>> {
- Ok(spawn_blocking(move || matroska_metadata(&path)).await??)
-}
-
-pub(crate) struct InternalStreamInfo {
- pub paths: Vec<PathBuf>,
- pub metadata: Vec<Arc<MatroskaMetadata>>,
- pub track_to_file: Vec<(usize, u64)>,
-}
-
-async fn stream_info(info: Arc<SMediaInfo>) -> Result<(InternalStreamInfo, StreamInfo)> {
- let mut metadata = Vec::new();
- let mut paths = Vec::new();
- for path in &info.files {
- metadata.push(async_matroska_metadata(path.clone()).await?);
- paths.push(path.clone());
- }
-
- let mut tracks = Vec::new();
- let mut track_to_file = Vec::new();
-
- for (i, m) in metadata.iter().enumerate() {
- if let Some(t) = &m.tracks {
- for t in &t.entries {
- let mut formats = Vec::new();
- formats.push(StreamFormatInfo {
- codec: t.codec_id.to_string(),
- remux: true,
- byterate: 10., // TODO
- containers: [StreamContainer::Matroska].to_vec(),
- bit_depth: t.audio.as_ref().and_then(|a| a.bit_depth.map(|e| e as u8)),
- samplerate: t.audio.as_ref().map(|a| a.sampling_frequency),
- channels: t.audio.as_ref().map(|a| a.channels as usize),
- width: t.video.as_ref().map(|v| v.pixel_width),
- height: t.video.as_ref().map(|v| v.pixel_height),
- ..Default::default()
- });
- tracks.push(StreamTrackInfo {
- name: None,
- kind: match t.track_type {
- 1 => TrackKind::Video,
- 2 => TrackKind::Audio,
- 17 => TrackKind::Subtitle,
- _ => todo!(),
- },
- formats,
- });
- track_to_file.push((i, t.track_number));
- }
- }
- }
-
- let segment = StreamSegmentInfo {
- name: None,
- duration: metadata[0]
- .info
- .as_ref()
- .unwrap()
- .duration
- .unwrap_or_default(),
- tracks,
- };
- Ok((
- InternalStreamInfo {
- metadata,
- paths,
- track_to_file,
- },
- StreamInfo {
- name: info.info.title.clone(),
- segments: vec![segment],
- },
- ))
-}
-
-async fn write_stream_info(info: Arc<SMediaInfo>, mut b: DuplexStream) -> Result<()> {
- let (_, info) = stream_info(info).await?;
- b.write_all(&serde_json::to_vec(&info)?).await?;
- Ok(())
-}
-
async fn remux_stream(
node: Arc<Node>,
spec: StreamSpec,