This commit is contained in:
marcsello 2025-10-09 22:21:38 +02:00
commit fa47df6d89
22 changed files with 1724 additions and 0 deletions

192
player.html Normal file
View file

@ -0,0 +1,192 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
body > div {
padding-bottom: 1em;
}
</style>
<script src="https://cdn.jsdelivr.net/npm/hls.js@1"></script>
</head>
<body>
<div id="videoHolder">
<video id="video" style="width: 100%; height: auto; max-height: 720px;" controls></video>
</div>
<div id="config">
<label for="videoSelect">Video: </label><select id="videoSelect"></select>
<label for="audioSelect">Audio: </label><select id="audioSelect"></select>
<label for="nvencPresetSelect">NVENC Preset: </label><select id="nvencPresetSelect">
<option value="">default (undefined)</option>
<option value="default">default</option>
<option value="slow">slow - hq 2 passes</option>
<option value="medium">medium - hq 1 pass</option>
<option value="fast">fast - hp 1 pass</option>
<option value="hp">hp</option>
<option value="hq">hq</option>
<option value="bd">bd</option>
<option value="ll">ll - low latency</option>
<option value="llhq">llhq - low latency hq</option>
<option value="llhp">llhp - low latency hp</option>
<option value="lossless">lossless - lossless</option>
<option value="losslesshp">losslesshp - lossless hp</option>
<option value="p1">p1 - fastest (lowest quality)</option>
<option value="p2">p2 - faster (lower quality)</option>
<option value="p3">p3 - fast (low quality)</option>
<option value="p4">p4 - medium (default)</option>
<option value="p5">p5 - slow (good quality)</option>
<option value="p6">p6 - slower (better quality)</option>
<option value="p7">p7 - slowest (best quality)</option>
</select>
</div>
<div id="metadata">
Metadata:
<pre id="metadataPre"></pre>
</div>
<script>
const video = document.getElementById('video');
const mediaPath = `/media/${window.location.hash.substring(1)}/`;
const hlsMasterPlaylistPath = `${mediaPath}master.m3u8`;
let onPresetChange = null;
if (Hls.isSupported()) {
const hls = new Hls({
// debug: true,
});
const levelSelector = document.getElementById("videoSelect")
levelSelector.onchange = (e) => {
hls.currentLevel = e.target.selectedIndex // this drops the current buffer
}
hls.on(Hls.Events.MANIFEST_PARSED, function () {
console.log(hls.levels)
hls.levels.forEach((lvl, idx) => {
const opt = document.createElement('option');
opt.value = idx;
opt.innerHTML = lvl.name;
levelSelector.appendChild(opt);
})
})
const audioSelector = document.getElementById("audioSelect")
audioSelector.onchange = (e) => {
hls.audioTrack = e.target.selectedIndex
}
hls.on(Hls.Events.AUDIO_TRACKS_UPDATED, function () {
console.log(hls.audioTracks)
hls.audioTracks.forEach((audio, idx) => {
const opt = document.createElement('option');
opt.value = idx;
opt.innerText = `[${audio.id}] ${audio.lang} ${audio.name}`;
audioSelector.appendChild(opt);
})
})
hls.on(Hls.Events.ERROR, function (event, data) {
if (data.fatal) {
switch (data.type) {
case Hls.ErrorTypes.NETWORK_ERROR:
console.error("Network error");
break;
case Hls.ErrorTypes.MEDIA_ERROR:
console.error("Media error");
break;
default:
console.error("Fatal error");
break;
}
}
})
hls.on(Hls.Events.LEVEL_SWITCHED, function (event, data) {
console.log("Switched to level " + data.level);
levelSelector.selectedIndex = data.level;
});
hls.on(Hls.Events.AUDIO_TRACK_SWITCHED, function (event, data) {
console.log("Switched to audio " + data.id);
audioSelector.selectedIndex = data.id;
});
hls.loadSource(hlsMasterPlaylistPath);
hls.attachMedia(video);
console.log(hls);
onPresetChange = function () {
hls.bufferController.flushBackBuffer()
hls.bufferController.flushFrontBuffer()
}
}
// HLS.js is not supported on platforms that do not have Media Source
// Extensions (MSE) enabled.
//
// When the browser has built-in HLS support (check using `canPlayType`),
// we can provide an HLS manifest (i.e. .m3u8 URL) directly to the video
// element through the `src` property. This is using the built-in support
// of the plain video element, without using HLS.js.
else if (video.canPlayType('application/vnd.apple.mpegurl')) {
video.src = hlsMasterPlaylistPath;
}
const nvencPresetSelect = document.getElementById("nvencPresetSelect")
fetch(`/config/preset`).then((resp) => {
if (resp.status !== 200) {
console.error("unexpected response", resp)
return
}
resp.json().then((data) => {
nvencPresetSelect.value = data
})
}).catch((e) => {
console.error(e)
})
nvencPresetSelect.onchange = (e) => {
nvencPresetSelect.disabled = true;
fetch(`/config/preset`, {
method: "POST",
body: JSON.stringify(nvencPresetSelect.value)
}).then((resp) => {
if (resp.status === 200) {
nvencPresetSelect.disabled = false;
if (onPresetChange !== null) {
onPresetChange()
}
} else {
console.error("failed to update preset!", resp)
}
})
}
fetch(mediaPath).then((resp) => {
if (resp.status !== 200) {
console.error("unexpected response", resp)
return
}
resp.json().then((data) => {
delete data.video_stream.video_chunks
data.audio_streams.forEach(a => {
delete a.audio_chunks
})
document.getElementById("metadataPre").innerText = JSON.stringify(data, null, 2)
})
}).catch((e) => {
console.error(e)
})
</script>
</body>
</html>