aboutsummaryrefslogtreecommitdiff
path: root/web/script/player/track
diff options
context:
space:
mode:
Diffstat (limited to 'web/script/player/track')
-rw-r--r--web/script/player/track/create.ts10
-rw-r--r--web/script/player/track/mod.ts2
-rw-r--r--web/script/player/track/mse.ts63
-rw-r--r--web/script/player/track/vtt.ts6
4 files changed, 37 insertions, 44 deletions
diff --git a/web/script/player/track/create.ts b/web/script/player/track/create.ts
index 1aaf12c..95bccca 100644
--- a/web/script/player/track/create.ts
+++ b/web/script/player/track/create.ts
@@ -3,15 +3,13 @@
which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
Copyright (C) 2025 metamuffin <metamuffin.org>
*/
-import { get_track_kind } from "../mediacaps.ts";
import { VttPlayerTrack } from "./vtt.ts";
import { MSEPlayerTrack } from "./mse.ts";
import { Player } from "../player.ts";
-import { SourceTrack } from "../jhls.d.ts";
import { PlayerTrack } from "./mod.ts";
+import { TrackInfo } from "../types_stream.ts";
-export function create_track(player: Player, node_id: string, track_index: number, metadata: SourceTrack): PlayerTrack | undefined {
- const kind = get_track_kind(metadata.kind)
- if (kind == "subtitles") return new VttPlayerTrack(player, node_id, track_index, metadata)
- else return new MSEPlayerTrack(player, node_id, track_index, metadata)
+export function create_track(player: Player, base_url: string, segment_index: number, track_index: number, track_info: TrackInfo): PlayerTrack | undefined {
+ if (track_info.kind == "subtitles") return new VttPlayerTrack(player, base_url, track_index, track_info)
+ else return new MSEPlayerTrack(player, base_url, segment_index, track_index, track_info)
}
diff --git a/web/script/player/track/mod.ts b/web/script/player/track/mod.ts
index 0c7c1c0..5a91209 100644
--- a/web/script/player/track/mod.ts
+++ b/web/script/player/track/mod.ts
@@ -4,7 +4,7 @@
Copyright (C) 2025 metamuffin <metamuffin.org>
*/
/// <reference lib="dom" />
-import { TimeRange } from "../jhls.d.ts";
+import { TimeRange } from "../types_stream.ts";
import { OVar } from "../../jshelper/mod.ts";
import { BufferRange } from "../player.ts";
diff --git a/web/script/player/track/mse.ts b/web/script/player/track/mse.ts
index d1a8c12..066bbfd 100644
--- a/web/script/player/track/mse.ts
+++ b/web/script/player/track/mse.ts
@@ -3,41 +3,41 @@
which is licensed under the GNU Affero General Public License (version 3); see /COPYING.
Copyright (C) 2025 metamuffin <metamuffin.org>
*/
-import { JhlsTrackIndex, SourceTrack } from "../jhls.d.ts";
import { OVar } from "../../jshelper/mod.ts";
-import { profile_to_partial_track, track_to_content_type } from "../mediacaps.ts";
+import { 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";
+import { FormatInfo, FragmentIndex, StreamContainer, TrackInfo } from "../types_stream.ts";
+
+interface UsableFormat { format_index: number, usable_index: number, format: FormatInfo, container: StreamContainer }
export class MSEPlayerTrack extends PlayerTrack {
public source_buffer!: SourceBuffer;
private current_load?: AppendRange;
private loading = new Set<number>();
private append_queue: AppendRange[] = [];
- public profile_selector: ProfileSelector;
- public profile = new OVar<EncodingProfileExt | undefined>(undefined);
- public index?: JhlsTrackIndex
+ public index?: FragmentIndex
+ public active_format = new OVar<UsableFormat | undefined>(undefined);
+ public usable_formats: UsableFormat[] = []
constructor(
private player: Player,
- private node_id: string,
+ private base_url: string,
+ private segment_index: number,
track_index: number,
- public metadata: SourceTrack,
+ public trackinfo: TrackInfo,
) {
super(track_index);
- this.profile_selector = new ProfileSelector(player, this, player.downloader.bandwidth_avail);
this.init()
}
async init() {
this.buffered.value = [{ start: 0, end: this.player.duration.value, status: "loading" }]
try {
- const res = await fetch(`/n/${encodeURIComponent(this.node_id)}/stream?format=jhlsi&track=${this.track_index}`, { headers: { "Accept": "application/json" } });
+ const res = await fetch(`${this.base_url}?fragmentindex&segment=${this.segment_index}&track=${this.track_index}`, { headers: { "Accept": "application/json" } });
if (!res.ok) return this.player.error.value = "Cannot download index.", undefined;
- let index!: JhlsTrackIndex & { error: string; };
+ let index!: FragmentIndex & { error: string; };
try { index = await res.json(); }
catch (_) { this.player.set_pers("Error: Failed to fetch node"); }
if (index.error) return this.player.set_pers("server error: " + index.error), undefined;
@@ -49,10 +49,9 @@ export class MSEPlayerTrack extends PlayerTrack {
}
this.buffered.value = []
- const canplay = await this.profile_selector.select_optimal_profile(this.track_index, this.profile);
- if (!canplay) return this.player.set_track_enabled(this.track_index, false)
- const ct = track_to_content_type(this.track_from_profile())!;
- console.log(`track ${this.track_index} source buffer content-type: ${ct}`);
+ this.active_format.value = { usable_index: 0, format_index: 0, container: "webm", format: this.trackinfo.formats[0] }
+
+ const ct = track_to_content_type(this.active_format.value!.format, this.active_format.value!.container);
this.source_buffer = this.player.media_source.addSourceBuffer(ct);
this.abort.signal.addEventListener("abort", () => {
console.log(`destroy source buffer for track ${this.track_index}`);
@@ -81,10 +80,6 @@ export class MSEPlayerTrack extends PlayerTrack {
this.update(this.player.video.currentTime)
}
- track_from_profile(): SourceTrack {
- if (this.profile.value) return profile_to_partial_track(this.profile.value);
- else return this.metadata;
- }
update_buf_ranges() {
if (!this.index) return;
@@ -97,7 +92,7 @@ export class MSEPlayerTrack extends PlayerTrack {
});
}
for (const r of this.loading) {
- ranges.push({ ...this.index.fragments[r], status: "loading" });
+ ranges.push({ ...this.index[r], status: "loading" });
}
this.buffered.value = ranges;
}
@@ -107,8 +102,8 @@ export class MSEPlayerTrack extends PlayerTrack {
this.update_buf_ranges(); // TODO required?
const blocking = [];
- for (let i = 0; i < this.index.fragments.length; i++) {
- const frag = this.index.fragments[i];
+ for (let i = 0; i < this.index.length; i++) {
+ const frag = this.index[i];
if (frag.end < target) continue;
if (frag.start >= target + TARGET_BUFFER_DURATION) break;
if (!this.check_buf_collision(frag.start, frag.end)) continue;
@@ -129,13 +124,13 @@ export class MSEPlayerTrack extends PlayerTrack {
async load(index: number) {
this.loading.add(index);
- await this.profile_selector.select_optimal_profile(this.track_index, this.profile);
- const url = `/n/${encodeURIComponent(this.node_id)}/stream?format=frag&webm=true&track=${this.track_index}&index=${index}${this.profile.value ? `&profile=${this.profile.value.id}` : ""}`;
+ // TODO update format selection
+ const url = `${this.base_url}?fragment&segment=${this.segment_index}&track=${this.track_index}&format=${this.active_format.value!.format_index}&index=${index}&container=${this.active_format.value!.container}`;
const buf = await this.player.downloader.download(url);
await new Promise<void>(cb => {
if (!this.index) return;
if (this.abort.signal.aborted) return;
- this.append_queue.push({ buf, ...this.index.fragments[index], index, cb });
+ this.append_queue.push({ buf, ...this.index[index], index, cb });
this.tick_append();
});
}
@@ -146,8 +141,8 @@ export class MSEPlayerTrack extends PlayerTrack {
this.append_queue.splice(0, 1);
this.current_load = frag;
// TODO why is appending so unreliable?! sometimes it does not add it
- this.source_buffer.changeType(track_to_content_type(this.track_from_profile())!);
- this.source_buffer.timestampOffset = this.profile.value !== undefined ? frag.start : 0
+ this.source_buffer.changeType(track_to_content_type(this.active_format.value!.format, this.active_format.value!.container));
+ this.source_buffer.timestampOffset = this.active_format.value !== undefined ? frag.start : 0
console.log(`append track ${this.track_index}`);
this.source_buffer.appendBuffer(frag.buf);
}
@@ -158,13 +153,13 @@ export class MSEPlayerTrack extends PlayerTrack {
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) =>
+ return this.active_format.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)}`
+ p ?
+ `mse track ${this.track_index}: format ${p.format_index} (${p.format.remux ? "remux" : "transcode"})`
+ + `\n\ttype: ${track_to_content_type(p.format, p.container)} br=${p.format.bitrate}`
+ + `\n\tbuffered: ${rtype("buffered", b)} / queued: ${rtype("queued", b)} / loading: ${rtype("loading", b)}`
+ : ""
) as HTMLElement
)
}
diff --git a/web/script/player/track/vtt.ts b/web/script/player/track/vtt.ts
index ea4951c..3dd7670 100644
--- a/web/script/player/track/vtt.ts
+++ b/web/script/player/track/vtt.ts
@@ -4,8 +4,8 @@
Copyright (C) 2025 metamuffin <metamuffin.org>
*/
import { e } from "../../jshelper/src/element.ts";
-import { SourceTrack, JvttCue } from "../jhls.d.ts";
import { Player } from "../player.ts";
+import { JvttCue, TrackInfo } from "../types_stream.ts";
import { PlayerTrack } from "./mod.ts";
export class VttPlayerTrack extends PlayerTrack {
@@ -16,10 +16,10 @@ export class VttPlayerTrack extends PlayerTrack {
private player: Player,
private node_id: string,
track_index: number,
- private metadata: SourceTrack,
+ private track_info: TrackInfo,
) {
super(track_index);
- this.track = this.player.video.addTextTrack("subtitles", this.metadata.name, this.metadata.language);
+ this.track = this.player.video.addTextTrack("subtitles", this.track_info.name, this.track_info.language);
this.buffered.value = [{ start: 0, end: this.player.duration.value, status: "loading" }]
this.init()
}