From 49e922cbfb1363296c00cedf0c057c08d135e106 Mon Sep 17 00:00:00 2001 From: mrjvs Date: Thu, 19 Oct 2023 16:59:55 +0200 Subject: [PATCH] hls quality discovery --- src/components/player/display/base.ts | 35 +++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/src/components/player/display/base.ts b/src/components/player/display/base.ts index 3eed12ee..c191b593 100644 --- a/src/components/player/display/base.ts +++ b/src/components/player/display/base.ts @@ -1,12 +1,12 @@ import fscreen from "fscreen"; -import Hls from "hls.js"; +import Hls, { Level } from "hls.js"; import { DisplayInterface, DisplayInterfaceEvents, } from "@/components/player/display/displayInterface"; import { handleBuffered } from "@/components/player/utils/handleBuffered"; -import { LoadableSource } from "@/stores/player/utils/qualities"; +import { LoadableSource, SourceQuality } from "@/stores/player/utils/qualities"; import { canChangeVolume, canFullscreen, @@ -15,6 +15,17 @@ import { } from "@/utils/detectFeatures"; import { makeEmitter } from "@/utils/events"; +const levelConversionMap: Record = { + 360: "360", + 1080: "1080", + 720: "720", + 480: "480", +}; + +function hlsLevelToQuality(level: Level): SourceQuality | null { + return levelConversionMap[level.height] ?? null; +} + export function makeVideoElementDisplayInterface(): DisplayInterface { const { emit, on, off } = makeEmitter(); let source: LoadableSource | null = null; @@ -26,6 +37,15 @@ export function makeVideoElementDisplayInterface(): DisplayInterface { let isSeeking = false; let startAt = 0; + function reportLevels() { + if (!hls) return; + const levels = hls.levels; + const convertedLevels = levels + .map((v) => hlsLevelToQuality(v)) + .filter((v): v is SourceQuality => !!v); + emit("qualities", convertedLevels); + } + function setupSource(vid: HTMLVideoElement, src: LoadableSource) { if (src.type === "hls") { if (!Hls.isSupported()) throw new Error("HLS not supported"); @@ -40,6 +60,17 @@ export function makeVideoElementDisplayInterface(): DisplayInterface { ); } }); + hls.on(Hls.Events.MANIFEST_LOADED, () => { + if (!hls) return; + reportLevels(); + const quality = hlsLevelToQuality(hls.levels[hls.currentLevel]); + emit("changedquality", quality); + }); + hls.on(Hls.Events.LEVEL_SWITCHED, () => { + if (!hls) return; + const quality = hlsLevelToQuality(hls.levels[hls.currentLevel]); + emit("changedquality", quality); // hi (hello) + }); } hls.attachMedia(vid);