mirror of
https://github.com/arcodange-org/mediabunny.git
synced 2026-09-27 19:03:46 +02:00
Fix Matroska files where no audio packets are key packets (fixes #192)
This commit is contained in:
+2
-2
@@ -14,8 +14,8 @@
|
|||||||
source: new Mediabunny.BlobSource(file),
|
source: new Mediabunny.BlobSource(file),
|
||||||
});
|
});
|
||||||
|
|
||||||
const videoTrack = await input.getPrimaryVideoTrack();
|
const audioTrack = await input.getPrimaryAudioTrack();
|
||||||
const sink = new Mediabunny.EncodedPacketSink(videoTrack);
|
const sink = new Mediabunny.EncodedPacketSink(audioTrack);
|
||||||
|
|
||||||
for await (const packet of sink.packets()) {
|
for await (const packet of sink.packets()) {
|
||||||
console.log(packet.timestamp, packet.duration, packet.type)
|
console.log(packet.timestamp, packet.duration, packet.type)
|
||||||
|
|||||||
@@ -1374,9 +1374,17 @@ export class MatroskaDemuxer extends Demuxer {
|
|||||||
const relativeTimestamp = readI16Be(slice);
|
const relativeTimestamp = readI16Be(slice);
|
||||||
|
|
||||||
const flags = readU8(slice);
|
const flags = readU8(slice);
|
||||||
const isKeyFrame = !!(flags & 0x80);
|
|
||||||
const lacing = (flags >> 1) & 0x3 as BlockLacing; // If the block is laced, we'll expand it later
|
const lacing = (flags >> 1) & 0x3 as BlockLacing; // If the block is laced, we'll expand it later
|
||||||
|
|
||||||
|
let isKeyFrame = !!(flags & 0x80);
|
||||||
|
if (trackData.track.info?.type === 'audio' && trackData.track.info.codec) {
|
||||||
|
// Some files don't mark their audio packets as key packets (I'm looking at you, Firefox). But, we
|
||||||
|
// can fix this in most cases: if we recognize the codec of the track, then we know every packet is
|
||||||
|
// necessarily a key packet, no matter what the container says.
|
||||||
|
// https://github.com/Vanilagy/mediabunny/issues/192
|
||||||
|
isKeyFrame = true;
|
||||||
|
}
|
||||||
|
|
||||||
const blockData = readBytes(slice, size - (slice.filePos - dataStartPos));
|
const blockData = readBytes(slice, size - (slice.filePos - dataStartPos));
|
||||||
const hasDecodingInstructions = trackData.track.decodingInstructions.length > 0;
|
const hasDecodingInstructions = trackData.track.decodingInstructions.length > 0;
|
||||||
|
|
||||||
|
|||||||
+11
-11
@@ -46,21 +46,21 @@ export abstract class Muxer {
|
|||||||
|
|
||||||
private trackTimestampInfo = new WeakMap<OutputTrack, {
|
private trackTimestampInfo = new WeakMap<OutputTrack, {
|
||||||
maxTimestamp: number;
|
maxTimestamp: number;
|
||||||
maxTimestampBeforeLastKeyFrame: number;
|
maxTimestampBeforeLastKeyPacket: number;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
protected validateAndNormalizeTimestamp(track: OutputTrack, timestampInSeconds: number, isKeyFrame: boolean) {
|
protected validateAndNormalizeTimestamp(track: OutputTrack, timestampInSeconds: number, isKeyPacket: boolean) {
|
||||||
timestampInSeconds += track.source._timestampOffset;
|
timestampInSeconds += track.source._timestampOffset;
|
||||||
|
|
||||||
let timestampInfo = this.trackTimestampInfo.get(track);
|
let timestampInfo = this.trackTimestampInfo.get(track);
|
||||||
if (!timestampInfo) {
|
if (!timestampInfo) {
|
||||||
if (!isKeyFrame) {
|
if (!isKeyPacket) {
|
||||||
throw new Error('First frame must be a key frame.');
|
throw new Error('First packet must be a key packet.');
|
||||||
}
|
}
|
||||||
|
|
||||||
timestampInfo = {
|
timestampInfo = {
|
||||||
maxTimestamp: timestampInSeconds,
|
maxTimestamp: timestampInSeconds,
|
||||||
maxTimestampBeforeLastKeyFrame: timestampInSeconds,
|
maxTimestampBeforeLastKeyPacket: timestampInSeconds,
|
||||||
};
|
};
|
||||||
this.trackTimestampInfo.set(track, timestampInfo);
|
this.trackTimestampInfo.set(track, timestampInfo);
|
||||||
}
|
}
|
||||||
@@ -69,15 +69,15 @@ export abstract class Muxer {
|
|||||||
throw new Error(`Timestamps must be non-negative (got ${timestampInSeconds}s).`);
|
throw new Error(`Timestamps must be non-negative (got ${timestampInSeconds}s).`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isKeyFrame) {
|
if (isKeyPacket) {
|
||||||
timestampInfo.maxTimestampBeforeLastKeyFrame = timestampInfo.maxTimestamp;
|
timestampInfo.maxTimestampBeforeLastKeyPacket = timestampInfo.maxTimestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (timestampInSeconds < timestampInfo.maxTimestampBeforeLastKeyFrame) {
|
if (timestampInSeconds < timestampInfo.maxTimestampBeforeLastKeyPacket) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Timestamps cannot be smaller than the highest timestamp of the previous GOP (a GOP begins with a key`
|
`Timestamps cannot be smaller than the largest timestamp of the previous GOP (a GOP begins with a key`
|
||||||
+ ` frame and ends right before the next key frame). Got ${timestampInSeconds}s, but highest timestamp`
|
+ ` packet and ends right before the next key packet). Got ${timestampInSeconds}s, but largest`
|
||||||
+ ` is ${timestampInfo.maxTimestampBeforeLastKeyFrame}s.`,
|
+ ` timestamp is ${timestampInfo.maxTimestampBeforeLastKeyPacket}s.`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user