192 lines
6.3 KiB
HTML
192 lines
6.3 KiB
HTML
<!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>
|