Add WebVTT subtitle support to MP4 & a bunch of misc changes

This commit is contained in:
Vanilagy
2024-11-24 14:57:31 +01:00
parent 39aea03565
commit 29ecccb26a
15 changed files with 2355 additions and 1557 deletions
+55 -2
View File
@@ -1,5 +1,5 @@
import { Output, OutputAudioTrack, OutputSubtitleTrack, OutputTrack, OutputVideoTrack } from "./output";
import { EncodedSubtitleChunk, EncodedSubtitleChunkMetadata } from "./subtitles";
import { SubtitleCue, SubtitleMetadata } from "./subtitles";
export abstract class Muxer {
output: Output;
@@ -11,9 +11,62 @@ export abstract class Muxer {
abstract start(): void;
abstract addEncodedVideoChunk(track: OutputVideoTrack, chunk: EncodedVideoChunk, meta?: EncodedVideoChunkMetadata): void;
abstract addEncodedAudioChunk(track: OutputAudioTrack, chunk: EncodedAudioChunk, meta?: EncodedAudioChunkMetadata): void;
abstract addEncodedSubtitleChunk(track: OutputSubtitleTrack, chunk: EncodedSubtitleChunk, meta?: EncodedSubtitleChunkMetadata): void;
abstract addSubtitleCue(track: OutputSubtitleTrack, cue: SubtitleCue, meta?: SubtitleMetadata): void;
abstract finalize(): void;
beforeTrackAdd(track: OutputTrack) {}
onTrackClose(track: OutputTrack) {}
private trackTimestampInfo = new WeakMap<OutputTrack, {
timestampOffset: number,
maxTimestamp: number,
lastKeyFrameTimestamp: number
}>();
abstract timestampsMustStartAtZero: boolean;
protected validateAndNormalizeTimestamp(track: OutputTrack, rawTimestampInUs: number, isKeyFrame: boolean) {
let timestampInSeconds = rawTimestampInUs / 1e6;
let timestampInfo = this.trackTimestampInfo.get(track);
if (!timestampInfo) {
if (!isKeyFrame) {
throw new Error('First frame must be a key frame.');
}
if (this.timestampsMustStartAtZero && timestampInSeconds > 0) {
throw new Error(`Timestamps must start at zero (got ${timestampInSeconds}s).`);
}
timestampInfo = {
timestampOffset: timestampInSeconds,
maxTimestamp: track.source.offsetTimestamps ? 0 : timestampInSeconds,
lastKeyFrameTimestamp: track.source.offsetTimestamps ? 0 : timestampInSeconds
};
this.trackTimestampInfo.set(track, timestampInfo);
}
if (track.source.offsetTimestamps) {
timestampInSeconds -= timestampInfo.timestampOffset;
}
if (timestampInSeconds < 0) {
throw new Error(`Timestamps must be non-negative (got ${timestampInSeconds}s).`);
}
if (timestampInSeconds < timestampInfo.lastKeyFrameTimestamp) {
throw new Error(`Timestamp cannot be smaller than last key frame's timestamp (got ${timestampInSeconds}s, last key frame at ${timestampInfo.lastKeyFrameTimestamp}s).`);
}
if (isKeyFrame) {
if (timestampInSeconds < timestampInfo.maxTimestamp) {
throw new Error(`Key frame timestamps cannot be smaller than any timestamp that came before (got ${timestampInSeconds}s, max timestamp was ${timestampInfo.maxTimestamp}s).`);
}
timestampInfo.lastKeyFrameTimestamp = timestampInSeconds;
}
timestampInfo.maxTimestamp = Math.max(timestampInfo.maxTimestamp, timestampInSeconds);
return timestampInSeconds;
}
}