/* 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::{fragment_index::fragment_index, stream_info, SMediaInfo}; use anyhow::Result; use jellystream_types::{FormatNum, StreamContainer, StreamSpec, TrackKind, TrackNum}; use std::{ fmt::Write, io::{Cursor, Read}, ops::Range, sync::Arc, }; pub fn hls_multivariant_stream( info: Arc, container: StreamContainer, ) -> Result> { let (_iinfo, info) = stream_info(info)?; let mut out = String::new(); writeln!(out, "#EXTM3U")?; writeln!(out, "#EXT-X-VERSION:4")?; // writeln!(out, "#EXT-X-INDEPENDENT-SEGMENTS")?; for (i, t) in info.tracks.iter().enumerate() { let uri = format!( "stream{}", StreamSpec::HlsVariant { track: i, container, format: 0 } .to_query() ); let r#type = match t.kind { TrackKind::Video => "VIDEO", TrackKind::Audio => "AUDIO", TrackKind::Subtitle => "SUBTITLES", }; // TODO bw writeln!(out, "#EXT-X-STREAM-INF:BANDWIDTH=5000000,TYPE={type}")?; writeln!(out, "{uri}")?; } Ok(Box::new(Cursor::new(out))) } pub fn hls_variant_stream( info: Arc, track: TrackNum, format: FormatNum, container: StreamContainer, ) -> Result> { let frags = fragment_index(info.clone(), track)?; let (_, info) = stream_info(info)?; let mut out = String::new(); writeln!(out, "#EXTM3U")?; writeln!(out, "#EXT-X-PLAYLIST-TYPE:VOD")?; writeln!(out, "#EXT-X-TARGETDURATION:{}", info.duration)?; writeln!(out, "#EXT-X-VERSION:4")?; writeln!(out, "#EXT-X-MEDIA-SEQUENCE:0")?; for (index, Range { start, end }) in frags.iter().enumerate() { writeln!(out, "#EXTINF:{:},", end - start)?; writeln!( out, "stream{}", StreamSpec::Fragment { track, index, container, format, } .to_query() )?; } writeln!(out, "#EXT-X-ENDLIST")?; Ok(Box::new(Cursor::new(out))) }