Allow negative timestamps in media sources, add negative timestamp support to ISOBMFF muxer

This commit is contained in:
Vanilagy
2026-09-04 11:48:50 +02:00
parent 6c88763a5c
commit 3c94d062d2
10 changed files with 207 additions and 63 deletions
+71
View File
@@ -220,6 +220,77 @@ test('Non-zero start timestamp, fragmented MP4', async () => {
expect(durations).toEqual([0.1, 0.1, 0.1, 0.1]);
});
test('Negative start timestamps, regular MP4', async () => {
await testNegativeTimestampRoundTrip([-1, 0, 1, 2, 3], 1, false);
});
test('Negative start timestamps, fragmented MP4', async () => {
await testNegativeTimestampRoundTrip([-1, 0, 1, 2, 3], 1, true);
});
test('Wholly negative timestamps, regular MP4', async () => {
await testNegativeTimestampRoundTrip([-1, -0.9, -0.8, -0.7, -0.6], 0.1, false);
});
test('Wholly negative timestamps, fragmented MP4', async () => {
await testNegativeTimestampRoundTrip([-1, -0.9, -0.8, -0.7, -0.6], 0.1, true);
});
const testNegativeTimestampRoundTrip = async (
timestamps: number[],
duration: number,
fragmented: boolean,
) => {
const output = new Output({
format: new Mp4OutputFormat({ fastStart: fragmented ? 'fragmented' : false }),
target: new BufferTarget(),
});
const source = new EncodedVideoPacketSource('vp8');
output.addVideoTrack(source);
await output.start();
const meta = { decoderConfig: { codec: 'vp8', codedWidth: 1280, codedHeight: 720 } };
const inputPackets = timestamps.map((timestamp, index) => new EncodedPacket(
new Uint8Array(1024).fill(index),
'key',
timestamp,
duration,
));
for (let i = 0; i < inputPackets.length; i++) {
await source.add(inputPackets[i]!, i === 0 ? meta : undefined);
}
await output.finalize();
using input = new Input({
source: new BufferSource(output.target.buffer!),
formats: ALL_FORMATS,
});
const track = await input.getPrimaryVideoTrack();
assert(track);
const outputPackets: EncodedPacket[] = [];
for await (const packet of new EncodedPacketSink(track).packets()) {
outputPackets.push(packet);
}
expect(outputPackets.map(packet => ({
data: packet.data,
type: packet.type,
timestamp: packet.timestamp,
duration: packet.duration,
}))).toEqual(inputPackets.map(packet => ({
data: packet.data,
type: packet.type,
timestamp: packet.timestamp,
duration: packet.duration,
})));
};
test('PCM audio', async () => {
const output = new Output({
format: new Mp4OutputFormat(),