aboutsummaryrefslogtreecommitdiff
path: root/web/script
diff options
context:
space:
mode:
Diffstat (limited to 'web/script')
-rw-r--r--web/script/player/download.ts10
-rw-r--r--web/script/player/mod.ts13
-rw-r--r--web/script/player/track/mod.ts1
-rw-r--r--web/script/player/track/mse.ts20
-rw-r--r--web/script/player/track/vtt.ts24
5 files changed, 48 insertions, 20 deletions
diff --git a/web/script/player/download.ts b/web/script/player/download.ts
index e394ba3..fa3bf1b 100644
--- a/web/script/player/download.ts
+++ b/web/script/player/download.ts
@@ -10,7 +10,9 @@ interface Measurement { time: number, duration: number, size: number }
export class SegmentDownloader {
private measurements: Measurement[] = []
- public bandwidth = new OVar(Infinity)
+ public bandwidth_avail = new OVar(Infinity)
+ public bandwidth_used = new OVar(Infinity)
+ public total_downloaded = new OVar(0)
constructor() { }
@@ -22,6 +24,7 @@ export class SegmentDownloader {
const buf = await res.arrayBuffer()
const dl_body = performance.now();
+ this.total_downloaded.value += buf.byteLength
if (buf.byteLength > 100 * 1000) {
const m = {
time: dl_start,
@@ -37,9 +40,10 @@ export class SegmentDownloader {
update_bandwidth() {
while (this.measurements.length > 32)
this.measurements.splice(0, 1)
+ const total_elapsed = (performance.now() - this.measurements.reduce((a, v) => Math.min(a, v.time), 0)) / 1000;
const total_size = this.measurements.reduce((a, v) => v.size + a, 0)
const total_duration = this.measurements.reduce((a, v) => v.duration + a, 0)
- const average = total_size / total_duration
- this.bandwidth.value = average
+ this.bandwidth_avail.value = total_size / total_duration
+ this.bandwidth_used.value = total_size / total_elapsed
}
}
diff --git a/web/script/player/mod.ts b/web/script/player/mod.ts
index f290db4..1c4b87c 100644
--- a/web/script/player/mod.ts
+++ b/web/script/player/mod.ts
@@ -12,7 +12,6 @@ import { TrackKind, get_track_kind } from "./mediacaps.ts";
import { Player } from "./player.ts";
import { Popup } from "./popup.ts";
import { Playersync, playersync_controls } from "./sync.ts"
-import { MSEPlayerTrack } from "./track/mse.ts";
globalThis.addEventListener("DOMContentLoaded", () => {
if (document.body.classList.contains("player")) {
@@ -218,10 +217,10 @@ function initialize_player(el: HTMLElement, node_id: string) {
player.video,
show_stats.map(do_show => e("div", player.active_tracks.map(tracks =>
!do_show ? e("div") : e("div", { class: "jsp-stats" },
- player.downloader.bandwidth.map(b => e("pre", `estimated bandwidth: ${show.metric(b, "B/s")} | ${show.metric(b * 8, "b/s")}`)),
- ...tracks.map((t, i) => t instanceof MSEPlayerTrack ? t.profile.map(p =>
- e("pre", `mse track ${i}: ` + (p ? `profile ${p.id} (${show_profile(p)})` : `remux`))
- ) : e("pre", `vtt track ${i}: native jvtt`))
+ player.downloader.bandwidth_avail.map(b => e("pre", `estimated available bandwidth: ${show.metric(b, "B/s")} | ${show.metric(b * 8, "b/s")}`)),
+ player.downloader.bandwidth_used.map(b => e("pre", `estimated used bandwidth: ${show.metric(b, "B/s")} | ${show.metric(b * 8, "b/s")}`)),
+ player.downloader.total_downloaded.map(b => e("pre", `downloaded bytes total: ${show.metric(b, "B")}`)),
+ ...tracks.map(t => t.debug())
)
))),
logger.element,
@@ -329,13 +328,13 @@ function mouse_idle(e: HTMLElement, timeout: number): OVar<boolean> {
return idle
}
-function show_profile(profile: EncodingProfile): string {
+export function show_profile(profile: EncodingProfile): string {
if (profile.audio) return `codec=${profile.audio.codec} br=${show.metric(profile.audio.bitrate, "b/s")}${profile.audio.sample_rate ? ` sr=${show.metric(profile.audio.sample_rate, "Hz")}` : ""}`
if (profile.video) return `codec=${profile.video.codec} br=${show.metric(profile.video.bitrate, "b/s")} w=${profile.video.width} preset=${profile.video.preset}`
if (profile.subtitles) return `codec=${profile.subtitles.codec}`
return `???`
}
-function show_volume(v: number): string {
+export function show_volume(v: number): string {
return `${(v * 100).toFixed(2)}% | ${v == 0 ? "-∞" : (Math.log2(v) * 10).toFixed(2)}dB`
}
diff --git a/web/script/player/track/mod.ts b/web/script/player/track/mod.ts
index cdb07cc..e165df6 100644
--- a/web/script/player/track/mod.ts
+++ b/web/script/player/track/mod.ts
@@ -20,5 +20,6 @@ export abstract class PlayerTrack {
public buffered = new OVar<BufferRange[]>([]);
public abort = new AbortController()
async update(_target: number) { }
+ public abstract debug(): HTMLElement | OVar<HTMLElement>
}
diff --git a/web/script/player/track/mse.ts b/web/script/player/track/mse.ts
index 01836b7..8e83c78 100644
--- a/web/script/player/track/mse.ts
+++ b/web/script/player/track/mse.ts
@@ -4,6 +4,8 @@ import { profile_to_partial_track, track_to_content_type } from "../mediacaps.ts
import { BufferRange, Player } from "../player.ts";
import { EncodingProfileExt, ProfileSelector } from "../profiles.ts";
import { PlayerTrack, AppendRange, TARGET_BUFFER_DURATION, MIN_BUFFER_DURATION } from "./mod.ts";
+import { show_profile } from "../mod.ts";
+import { e } from "../../jshelper/src/element.ts";
export class MSEPlayerTrack extends PlayerTrack {
public source_buffer!: SourceBuffer;
@@ -21,7 +23,7 @@ export class MSEPlayerTrack extends PlayerTrack {
private metadata: SourceTrack,
) {
super(track_index);
- this.profile_selector = new ProfileSelector(player, this, player.downloader.bandwidth);
+ this.profile_selector = new ProfileSelector(player, this, player.downloader.bandwidth_avail);
this.init()
}
@@ -143,4 +145,20 @@ export class MSEPlayerTrack extends PlayerTrack {
this.source_buffer.appendBuffer(seg.buf);
}
}
+
+ public debug(): OVar<HTMLElement> {
+ const rtype = (t: string, b: BufferRange[]) => {
+ const c = b.filter(r => r.status == t);
+ return `${c.length} range${c.length != 1 ? "s" : ""}, ${c.reduce((a, v) => a + v.end - v.start, 0).toFixed(2)}s`
+ }
+ return this.profile.liftA2(this.buffered, (p, b) =>
+ e("pre",
+ `mse track ${this.track_index}: ${(p ? `profile ${p.id} (${show_profile(p)})` : `remux`)}`
+ + `\n\ttype: ${track_to_content_type(this.track_from_profile())}`
+ + `\n\tbuffered: ${rtype("buffered", b)}`
+ + `\n\tqueued: ${rtype("queued", b)}`
+ + `\n\tloading: ${rtype("loading", b)}`
+ ) as HTMLElement
+ )
+ }
}
diff --git a/web/script/player/track/vtt.ts b/web/script/player/track/vtt.ts
index 02a7792..8301457 100644
--- a/web/script/player/track/vtt.ts
+++ b/web/script/player/track/vtt.ts
@@ -1,3 +1,4 @@
+import { e } from "../../jshelper/src/element.ts";
import { SourceTrack, JvttCue } from "../jhls.d.ts";
import { Player } from "../player.ts";
import { PlayerTrack } from "./mod.ts";
@@ -48,6 +49,10 @@ export class VttPlayerTrack extends PlayerTrack {
}
this.on_ready()
}
+
+ public debug(): HTMLElement {
+ return e("pre", `vtt track ${this.track_index}\n\t${this.cues?.length} cues loaded`)
+ }
}
function create_cue(cue: JvttCue): VTTCue {
@@ -55,15 +60,16 @@ function create_cue(cue: JvttCue): VTTCue {
const props = parse_layout_properties(cue.content.split("\n")[0])
if (props) {
c.text = cue.content.split("\n").slice(1).join("\n")
- // TODO this does not work at all...
- const region = new VTTRegion()
- if ("position" in props && props.position.endsWith("%"))
- region.regionAnchorX = parseFloat(props.position.replace("%", ""))
- if ("line" in props && props.line.endsWith("%"))
- region.regionAnchorY = parseFloat(props.line.replace("%", ""))
- if ("align" in props)
- c.align = props.align as AlignSetting
- c.region = region
+ // TODO re-enable when it works
+ // // TODO this does not work at all...
+ // const region = new VTTRegion()
+ // if ("position" in props && props.position.endsWith("%"))
+ // region.regionAnchorX = parseFloat(props.position.replace("%", ""))
+ // if ("line" in props && props.line.endsWith("%"))
+ // region.regionAnchorY = parseFloat(props.line.replace("%", ""))
+ // if ("align" in props)
+ // c.align = props.align as AlignSetting
+ // c.region = region
} else {
c.line = -2;
}