Add onSegmentPopped, add more tests, improve validation, improve M3U8 grammar

This commit is contained in:
Vanilagy
2026-04-16 14:48:57 +02:00
parent f99adf2208
commit 56b25fbdf8
5 changed files with 102 additions and 2 deletions
+8 -1
View File
@@ -54,6 +54,7 @@ type PlaylistSegment = {
timestamp: number;
byteSize: number;
byteOffset: number | null;
info?: HlsOutputSegmentInfo;
};
type Playlist = {
@@ -1034,6 +1035,7 @@ export class HlsMuxer extends Muxer {
byteOffset: playlist.singleFile
? playlist.singleFile.nextOffset
: null,
info: segmentInfo ?? undefined,
});
this.globalTargetDuration = Math.max(this.globalTargetDuration, segmentDuration);
@@ -1047,8 +1049,13 @@ export class HlsMuxer extends Muxer {
if (this.isLive) {
while (playlist.writtenSegments.length > this.maxLiveSegmentCount) {
playlist.writtenSegments.shift();
const popped = playlist.writtenSegments.shift()!;
playlist.mediaSequence++;
if (!this.singleFilePerPlaylist) {
assert(popped.info);
this.format._options.onSegmentPopped?.(popped.path, popped.info);
}
}
await this.writePlaylist(playlist);
+9
View File
@@ -1271,6 +1271,12 @@ export type HlsOutputFormatOptions = {
* function is never called.
*/
onInit?: (target: Target, info: HlsOutputPlaylistInfo) => unknown;
/**
* Called when a media segment is removed from the start of a media playlist due to
* {@link HlsOutputFormatOptions.maxLiveSegmentCount}. Will not be called when
* {@link HlsOutputFormatOptions.singleFilePerPlaylist} is `true`.
*/
onSegmentPopped?: (path: string, info: HlsOutputSegmentInfo) => unknown;
};
/**
@@ -1348,6 +1354,9 @@ export class HlsOutputFormat extends OutputFormat {
if (options.onInit !== undefined && typeof options.onInit !== 'function') {
throw new TypeError('options.onInit, when provided, must be a function.');
}
if (options.onSegmentPopped !== undefined && typeof options.onSegmentPopped !== 'function') {
throw new TypeError('options.onSegmentPopped, when provided, must be a function.');
}
super();
+5
View File
@@ -179,11 +179,16 @@ export class OutputTrackGroup {
/**
* Marks this group as being pairable with another group, symmetrically. Output tracks where each track is assigned
* to one half of a group pairing are then considered pairable.
*
* You cannot pair a group with itself.
*/
pairWith(other: OutputTrackGroup) {
if (!(other instanceof OutputTrackGroup)) {
throw new TypeError('other must be an OutputTrackGroup.');
}
if (this === other) {
throw new TypeError('Cannot pair a group with itself.');
}
this._pairedGroups.add(other);
other._pairedGroups.add(this);