Remove reordering Matroska blocks by references (fixes #178)

This commit is contained in:
Vanilagy
2025-11-12 10:49:47 +01:00
parent 198b3d2eae
commit 12216ae29e
2 changed files with 12 additions and 63 deletions
+3 -63
View File
@@ -61,7 +61,6 @@ import {
readElementHeader,
readElementId,
readFloat,
readSignedInt,
readUnsignedInt,
readVarInt,
resync,
@@ -137,7 +136,6 @@ type ClusterBlock = {
timestamp: number;
duration: number;
isKeyFrame: boolean;
referencedTimestamps: number[];
data: Uint8Array;
lacing: BlockLacing;
decoded: boolean;
@@ -649,21 +647,15 @@ export class MatroskaDemuxer extends Demuxer {
// This must hold, as track datas only get created if a block for that track is encountered
assert(trackData.blocks.length > 0);
let blockReferencesExist = false;
let hasLacedBlocks = false;
for (let i = 0; i < trackData.blocks.length; i++) {
const block = trackData.blocks[i]!;
block.timestamp += cluster.timestamp;
blockReferencesExist ||= block.referencedTimestamps.length > 0;
hasLacedBlocks ||= block.lacing !== BlockLacing.None;
}
if (blockReferencesExist) {
trackData.blocks = sortBlocksByReferences(trackData.blocks);
}
trackData.presentationTimestamps = trackData.blocks
.map((block, i) => ({ timestamp: block.timestamp, blockIndex: i }))
.sort((a, b) => a.timestamp - b.timestamp);
@@ -859,7 +851,6 @@ export class MatroskaDemuxer extends Demuxer {
timestamp: frameTimestamp,
duration: frameDuration,
isKeyFrame: originalBlock.isKeyFrame,
referencedTimestamps: originalBlock.referencedTimestamps,
data: frameData,
lacing: BlockLacing.None,
decoded: true,
@@ -1393,7 +1384,6 @@ export class MatroskaDemuxer extends Demuxer {
timestamp: relativeTimestamp, // We'll add the cluster's timestamp to this later
duration: 0, // Will set later
isKeyFrame,
referencedTimestamps: [],
data: blockData,
lacing,
decoded: !hasDecodingInstructions,
@@ -1406,13 +1396,7 @@ export class MatroskaDemuxer extends Demuxer {
this.readContiguousElements(slice.slice(dataStartPos, size));
if (this.currentBlock) {
for (let i = 0; i < this.currentBlock.referencedTimestamps.length; i++) {
this.currentBlock.referencedTimestamps[i]! += this.currentBlock.timestamp;
}
this.currentBlock = null;
}
this.currentBlock = null;
}; break;
case EBMLId.Block: {
@@ -1436,7 +1420,6 @@ export class MatroskaDemuxer extends Demuxer {
timestamp: relativeTimestamp, // We'll add the cluster's timestamp to this later
duration: 0, // Will set later
isKeyFrame: true,
referencedTimestamps: [],
data: blockData,
lacing,
decoded: !hasDecodingInstructions,
@@ -1487,11 +1470,8 @@ export class MatroskaDemuxer extends Demuxer {
if (!this.currentBlock) break;
this.currentBlock.isKeyFrame = false;
const relativeTimestamp = readSignedInt(slice, size);
// We'll offset this by the block's timestamp later
this.currentBlock.referencedTimestamps.push(relativeTimestamp);
// We ignore the actual value here, we just use the reference as an indicator for "not a key frame".
// This is in line with FFmpeg's behavior.
}; break;
case EBMLId.Tag: {
@@ -2380,43 +2360,3 @@ class MatroskaAudioTrackBacking extends MatroskaTrackBacking implements InputAud
};
}
}
/** Sorts blocks such that referenced blocks come before the blocks that reference them. */
const sortBlocksByReferences = (blocks: ClusterBlock[]) => {
const timestampToBlock = new Map<number, ClusterBlock>();
for (let i = 0; i < blocks.length; i++) {
const block = blocks[i]!;
timestampToBlock.set(block.timestamp, block);
}
const processedBlocks = new Set<ClusterBlock>();
const result: ClusterBlock[] = [];
const processBlock = (block: ClusterBlock) => {
if (processedBlocks.has(block)) {
return;
}
// Marking the block as processed here already; prevents this algorithm from dying on cycles
processedBlocks.add(block);
for (let j = 0; j < block.referencedTimestamps.length; j++) {
const timestamp = block.referencedTimestamps[j]!;
const otherBlock = timestampToBlock.get(timestamp);
if (!otherBlock) {
continue;
}
processBlock(otherBlock);
}
result.push(block);
};
for (let i = 0; i < blocks.length; i++) {
processBlock(blocks[i]!);
}
return result;
};