aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2026-03-04 20:11:48 +0100
committermetamuffin <metamuffin@disroot.org>2026-03-04 20:11:48 +0100
commitec2228f6ee9349c0866483abc21124dae31f2b52 (patch)
tree89ac03ad42437ac00f06769f2c3a7ea5889985eb
parent7ded052e22df1be30b29a2943b2bbe9196152a2d (diff)
downloadjellything-ec2228f6ee9349c0866483abc21124dae31f2b52.tar
jellything-ec2228f6ee9349c0866483abc21124dae31f2b52.tar.bz2
jellything-ec2228f6ee9349c0866483abc21124dae31f2b52.tar.zst
use codec param in js player
-rw-r--r--remuxer/src/codec_param/mod.rs4
-rw-r--r--stream/src/stream_info.rs4
-rw-r--r--ui/client-scripts/src/player/mediacaps.ts38
-rw-r--r--ui/client-scripts/src/player/types_stream.ts1
4 files changed, 19 insertions, 28 deletions
diff --git a/remuxer/src/codec_param/mod.rs b/remuxer/src/codec_param/mod.rs
index 8c0b6b7..147fa0d 100644
--- a/remuxer/src/codec_param/mod.rs
+++ b/remuxer/src/codec_param/mod.rs
@@ -11,7 +11,8 @@ mod av1;
mod hevc;
pub fn codec_param(te: &TrackEntry) -> String {
- let cp = te.codec_private.as_ref().unwrap();
+ let empty_cp = vec![];
+ let cp = te.codec_private.as_ref().unwrap_or(&empty_cp);
match te.codec_id.as_str() {
"A_AAC" => format!("mp4a.40.2"), // TODO
"A_FLAC" => "flac".to_string(),
@@ -21,6 +22,7 @@ pub fn codec_param(te: &TrackEntry) -> String {
"V_AV1" => av1_codec_param(cp),
"V_MPEG4/ISO/AVC" => format!("avc1.{:02x}{:02x}{:02x}", cp[1], cp[2], cp[3]),
"V_MPEGH/ISO/HEVC" => hevc_codec_param(cp),
+ "V_VP9" => "vp09.00.50.08".to_string(), // TODO
x => todo!("{x:?}"),
}
diff --git a/stream/src/stream_info.rs b/stream/src/stream_info.rs
index 1cc1663..adebda8 100644
--- a/stream/src/stream_info.rs
+++ b/stream/src/stream_info.rs
@@ -149,7 +149,7 @@ fn stream_formats(
}
}
TrackType::Audio => {
- for br in [256e3, 128e3, 64e3] {
+ for br in [128e3, 64e3, 32e3] {
formats.push(StreamFormatInfo {
codec: "A_OPUS".to_string(),
codec_param: "opus".to_string(),
@@ -184,7 +184,7 @@ fn containers_by_codec(codec: &str) -> Vec<StreamContainer> {
use StreamContainer::*;
match codec {
"V_VP8" | "V_VP9" | "V_AV1" | "A_OPUS" | "A_VORBIS" => vec![Matroska, WebM],
- "V_MPEG4/ISO/AVC" | "A_AAC" => vec![Matroska, MPEG4],
+ "V_MPEG4/ISO/AVC" | "V_MPEGH/ISO/HEVC" | "A_AAC" => vec![Matroska, MPEG4],
"S_TEXT/UTF8" | "S_TEXT/WEBVTT" => vec![Matroska, WebVTT, WebM, JVTT],
_ => vec![Matroska],
}
diff --git a/ui/client-scripts/src/player/mediacaps.ts b/ui/client-scripts/src/player/mediacaps.ts
index 9b0e934..4393fe9 100644
--- a/ui/client-scripts/src/player/mediacaps.ts
+++ b/ui/client-scripts/src/player/mediacaps.ts
@@ -7,24 +7,22 @@
import { FormatInfo, StreamContainer } from "./types_stream.ts";
-const cache = new Map<string, boolean>()
+const cache = new Map<string, CodecSupport>()
-// TODO this testing method makes the assumption, that if the codec is supported on its own, it can be
-// TODO arbitrarly combined with others that are supported. in reality this is true but the spec does not gurantee it.
+export type CodecSupport = "unsupported" | "supported" | "supported_smooth"
-export async function test_media_capability(format: FormatInfo, container: StreamContainer): Promise<boolean> {
+export async function test_media_capability(format: FormatInfo, container: StreamContainer): Promise<CodecSupport> {
const cache_key = JSON.stringify(format) + container
const cached = cache.get(cache_key);
if (cached !== undefined) return cached
const r = await test_media_capability_inner(format, container)
- console.log(`${r ? "positive" : "negative"} media capability test finished for codec=${format.codec}`);
+ console.log(`media caps: codec=${format.codec} sup=${r}`);
cache.set(cache_key, r)
return r
}
-async function test_media_capability_inner(format: FormatInfo, container: StreamContainer) {
- if (format.codec.startsWith("S_") || format.codec.startsWith("D_")) {
- // TODO do we need to check this?
- return format.codec == "S_TEXT/WEBVTT" || format.codec == "S_TEXT/UTF8" || format.codec == "D_WEBVTT/SUBTITLES"
+async function test_media_capability_inner(format: FormatInfo, container: StreamContainer): Promise<CodecSupport> {
+ if (format.codec == "S_TEXT/WEBVTT" || format.codec == "S_TEXT/UTF8" || format.codec == "D_WEBVTT/SUBTITLES") {
+ return "supported"
}
let res;
if (format.codec.startsWith("A_")) {
@@ -37,39 +35,29 @@ async function test_media_capability_inner(format: FormatInfo, container: Stream
bitrate: format.bitrate,
}
})
- }
- if (format.codec.startsWith("V_")) {
+ } else if (format.codec.startsWith("V_")) {
res = await navigator.mediaCapabilities.decodingInfo({
type: "media-source",
video: {
contentType: track_to_content_type(format, container),
- framerate: 30, // TODO get average framerate from server
+ framerate: format.samplerate ?? 60,
width: format.width ?? 1920,
height: format.height ?? 1080,
bitrate: format.bitrate
}
})
+ } else {
+ res = { supported: false, smooth: false }
}
- return res?.supported ?? false
+ return res.supported ? (res.smooth ? "supported_smooth" : "supported") : "unsupported"
}
export function track_to_content_type(format: FormatInfo, container: StreamContainer): string {
let c = CONTAINER_TO_MIME_TYPE[container];
if (format.codec.startsWith("A_")) c = c.replace("video/", "audio/")
- return `${c}; codecs="${MASTROSKA_CODEC_MAP[format.codec]}"`
+ return `${c}; codecs="${format.codec_param}"`
}
-const MASTROSKA_CODEC_MAP: { [key: string]: string } = {
- "V_VP9": "vp9",
- "V_VP8": "vp8",
- "V_AV1": "av1",
- "V_MPEG4/ISO/AVC": "avc1.42C01F",
- "V_MPEGH/ISO/HEVC": "hev1.1.6.L93.90",
- "A_OPUS": "opus",
- "A_VORBIS": "vorbis",
- "S_TEXT/WEBVTT": "webvtt",
- "D_WEBVTT/SUBTITLES": "webvtt",
-}
const CONTAINER_TO_MIME_TYPE: { [key in StreamContainer]: string } = {
webvtt: "text/webvtt",
webm: "video/webm",
diff --git a/ui/client-scripts/src/player/types_stream.ts b/ui/client-scripts/src/player/types_stream.ts
index 272f98b..4719335 100644
--- a/ui/client-scripts/src/player/types_stream.ts
+++ b/ui/client-scripts/src/player/types_stream.ts
@@ -23,6 +23,7 @@ export interface TrackInfo {
export type StreamContainer = "webm" | "matroska" | "mpeg4" | "jvtt" | "webvtt"
export interface FormatInfo {
codec: string,
+ codec_param: string,
bitrate: number,
remux: boolean,
containers: StreamContainer[]