Add support for live HLS streams, add playlist refresh logic, add live input tracks

This commit is contained in:
Vanilagy
2026-03-12 15:54:19 +01:00
parent ff523c01c8
commit e8df451bf5
23 changed files with 22399 additions and 417 deletions
+46 -12
View File
@@ -16,17 +16,19 @@
progressElement.max = 1;
document.body.append(progressElement);
fileInput.addEventListener('change', async () => {
const file = fileInput.files[0];
const source = new Mediabunny.BlobSource(file);
window.addEventListener('click', async () => {
const target = new Mediabunny.BufferTarget() ?? new Mediabunny.StreamTarget(new WritableStream({
write: console.log
}), {
chunked: true,
chunkSize: 2**20
});
const outputFormat = new Mediabunny.Mp4OutputFormat({fastStart: 'fragmented'});
const outputFormat = new Mediabunny.Mp4OutputFormat();
const p = document.createElement('p');
p.textContent = 'Capturing...';
document.body.append(p);
const button = document.createElement('button');
button.textContent = 'Cancel';
@@ -50,14 +52,43 @@
target
});
let ctx = null;
const conversion = await Mediabunny.Conversion.init({
input: new Mediabunny.Input({
let input;
const tracks = [];
let start = 0;
if (true) {
input = new Mediabunny.Input({
entryPath: 'https://zdf-hls-15.akamaized.net/hls/live/2016498/de/high/master.m3u8',
source: ({ path }) => new Mediabunny.UrlSource(path),
formats: Mediabunny.ALL_FORMATS,
});
const videoTrack = await input.getPrimaryVideoTrack();
const audioTrack = await input.getPrimaryAudioTrack();
if (videoTrack) tracks.push(videoTrack);
if (audioTrack) tracks.push(audioTrack);
start = Math.min(...await Promise.all([
videoTrack.computeDuration({ skipLiveWait: true }),
audioTrack.computeDuration({ skipLiveWait: true }),
]));
} else {
const file = fileInput.files[0];
const source = new Mediabunny.BlobSource(file);
input = new Mediabunny.Input({
formats: Mediabunny.ALL_FORMATS,
source
}),
});
}
let ctx = null;
const conversion = await Mediabunny.Conversion.init({
input,
output,
audio: (_, n) => ({
audio: (track, n) => ({
discard: !tracks.includes(track),
//codec: 'eac3',
//discard: true,
//discard: n > 1,
@@ -103,7 +134,8 @@
bitrate: 320000
},
*/
video: () => ({
video: (track) => ({
discard: !tracks.includes(track),
//forceTranscode: true,
//forceTranscode: true,
//width: 1280,
@@ -188,6 +220,8 @@
}
},
trim: {
start,
end: start + 5,
//start: 0,
//end: 10
},
@@ -230,5 +264,5 @@
a.click();
URL.revokeObjectURL(url);
}
});
}, { once: true });
</script>
+36 -8
View File
@@ -11,6 +11,7 @@
document.body.append(fileInput);
fileInput.addEventListener('change', async () => {
/*
const file = fileInput.files[0];
const input = new Mediabunny.Input({
formats: Mediabunny.ALL_FORMATS,
@@ -20,13 +21,47 @@
const audTrack = await input.getPrimaryAudioTrack();
console.log((await audTrack.getDecoderConfig()).description.join(','));
return;
*/
const manifest = new Mediabunny.Input({
entryPath: 'https://s3.amazonaws.com/qa.jwplayer.com/hlsjs/muxed-fmp4/hls.m3u8',
entryPath: 'https://zdf-hls-15.akamaized.net/hls/live/2016498/de/high/master.m3u8',
source: ({ path }) => new Mediabunny.UrlSource(path),
formats: Mediabunny.ALL_FORMATS,
});
const videoTrack = await manifest.getPrimaryVideoTrack();
await videoTrack.hydrate();
const sink = new Mediabunny.EncodedPacketSink(videoTrack);
const firstTimestamp = await videoTrack.getFirstTimestamp();
console.log("FIRST", firstTimestamp)
let last = -Infinity;
for await (const packet of sink.packets()) {
const rel = packet.timestamp - firstTimestamp;
console.log(rel, rel - last);
last = rel;
if (rel >= 10) {
break;
}
}
/*
console.log("here")
const lastPacket = await sink.getPacket(Infinity, { skipLiveWait: true });
const other = await sink.getPacket(lastPacket.timestamp - 5);
for await (const packet of sink.packets(other)) {
console.log(packet.timestamp);
}
console.log("Done")
*/
/*
const tracks = await manifest.getTracks();
//await input.hydrateAllTracks();
@@ -34,11 +69,6 @@
return;
*/
const videoTrack = await manifest.getPrimaryVideoTrack();
const audioTrack = await manifest.getPrimaryAudioTrack();
console.log(await videoTrack.getFirstTimestamp(), await audioTrack.getFirstTimestamp());
/*
for await (using sample of sink.samples()) {
console.log(sample.timestamp);
@@ -105,8 +135,6 @@
}
*/
console.log("Done")
/*
//const secondPacket = await sink.getNextPacket(firstPacket);