mirror of
https://github.com/arcodange-org/mediabunny.git
synced 2026-10-03 05:43:50 +02:00
Replace block sorting algorithm
This commit is contained in:
+2
-29
@@ -41,37 +41,10 @@ const input = new Metamuxer.Input({
|
|||||||
source
|
source
|
||||||
});
|
});
|
||||||
|
|
||||||
//console.log(await input.getMimeType())
|
console.log(await input.getMimeType())
|
||||||
|
|
||||||
let videoTrack = await input.getPrimaryVideoTrack();
|
let videoTrack = await input.getPrimaryVideoTrack();
|
||||||
let audioTrack = null && await input.getPrimaryAudioTrack();
|
let audioTrack = await input.getPrimaryAudioTrack();
|
||||||
|
|
||||||
|
|
||||||
const sink = new Metamuxer.EncodedVideoSampleSink(videoTrack);
|
|
||||||
console.log(await sink.getSample(4.93))
|
|
||||||
await new Promise(() => {});
|
|
||||||
|
|
||||||
for await (const sample of sink.samples()) {
|
|
||||||
console.log(sample);
|
|
||||||
await new Promise(resolve => setTimeout(resolve, 100));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//console.log(await videoTrack.computeDuration());
|
|
||||||
//await new Promise(() => {});
|
|
||||||
|
|
||||||
/*
|
|
||||||
const sink = new Metamuxer.EncodedVideoSampleSink(videoTrack);
|
|
||||||
|
|
||||||
for await (const sample of sink.samples()) {
|
|
||||||
console.log(sample);
|
|
||||||
await new Promise(resolve => setTimeout(resolve, 100));
|
|
||||||
}
|
|
||||||
|
|
||||||
await new Promise(() => {});
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (!(await videoTrack?.canDecode())) {
|
if (!(await videoTrack?.canDecode())) {
|
||||||
videoTrack = null;
|
videoTrack = null;
|
||||||
|
|||||||
@@ -429,7 +429,7 @@ export class MatroskaDemuxer extends Demuxer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (blockReferencesExist) {
|
if (blockReferencesExist) {
|
||||||
trackData.blocks = sortBlocksTopologically(trackData.blocks);
|
trackData.blocks = sortBlocksByReferences(trackData.blocks);
|
||||||
}
|
}
|
||||||
|
|
||||||
trackData.presentationTimestamps = trackData.blocks
|
trackData.presentationTimestamps = trackData.blocks
|
||||||
@@ -1496,119 +1496,42 @@ class MatroskaAudioTrackBacking extends MatroskaTrackBacking<EncodedAudioSample>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Sorts blocks such that referenced blocks come before the blocks that reference them. */
|
||||||
* This function sorts blocks to satisfy block references: If block A is referenced by block B, then block A should
|
const sortBlocksByReferences = (blocks: ClusterBlock[]) => {
|
||||||
* come before block B. The resulting array is one that is in decode order.
|
const timestampToBlock = new Map<number, ClusterBlock>();
|
||||||
*/
|
|
||||||
const sortBlocksTopologically = (blocks: ClusterBlock[]) => {
|
|
||||||
return blocks; // temp
|
|
||||||
// Based on "A fast and effective heuristic for the feedback arc set problem" by Peter Eades et al.
|
|
||||||
|
|
||||||
const n = blocks.length;
|
for (let i = 0; i < blocks.length; i++) {
|
||||||
|
const block = blocks[i]!;
|
||||||
// Build timestamp -> index mapping
|
timestampToBlock.set(block.timestamp, block);
|
||||||
const timestampToIndex = new Map<number, number>();
|
|
||||||
for (let i = 0; i < n; i++) {
|
|
||||||
timestampToIndex.set(blocks[i]!.timestamp, i);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const outgoing = new Array<Set<number>>(n);
|
const processedBlocks = new Set<ClusterBlock>();
|
||||||
const incoming = new Array<Set<number>>(n);
|
const result: ClusterBlock[] = [];
|
||||||
const remaining = new Set<number>();
|
|
||||||
|
|
||||||
for (let i = 0; i < n; i++) {
|
const processBlock = (block: ClusterBlock) => {
|
||||||
outgoing[i] = new Set();
|
if (processedBlocks.has(block)) {
|
||||||
incoming[i] = new Set();
|
return;
|
||||||
remaining.add(i);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build the graph
|
// Marking the block as processed here already; prevents this algorithm from dying on cycles
|
||||||
for (let i = 0; i < n; i++) {
|
processedBlocks.add(block);
|
||||||
const refs = blocks[i]!.referencedTimestamps;
|
|
||||||
for (let j = 0; j < refs.length; j++) {
|
for (let j = 0; j < block.referencedTimestamps.length; j++) {
|
||||||
const referencedIndex = timestampToIndex.get(refs[j]!);
|
const timestamp = block.referencedTimestamps[j]!;
|
||||||
if (referencedIndex !== undefined) {
|
const otherBlock = timestampToBlock.get(timestamp);
|
||||||
outgoing[referencedIndex]!.add(i);
|
if (!otherBlock) {
|
||||||
incoming[i]!.add(referencedIndex);
|
continue;
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pre-allocate arrays with known size
|
processBlock(otherBlock);
|
||||||
const prefix = new Array<number>(n).fill(-1);
|
|
||||||
const suffix = new Array<number>(n).fill(-1);
|
|
||||||
let prefixSize = 0;
|
|
||||||
let suffixSize = 0;
|
|
||||||
|
|
||||||
while (remaining.size > 0) {
|
|
||||||
let progress = false;
|
|
||||||
|
|
||||||
const currentVertices = Array.from(remaining);
|
|
||||||
|
|
||||||
// Remove sinks
|
|
||||||
for (let i = 0; i < currentVertices.length; i++) {
|
|
||||||
const index = currentVertices[i]!;
|
|
||||||
if (outgoing[index]!.size === 0) {
|
|
||||||
suffix[suffixSize++] = index;
|
|
||||||
// Remove this vertex
|
|
||||||
for (const fromIndex of incoming[index]!) {
|
|
||||||
outgoing[fromIndex]!.delete(index);
|
|
||||||
}
|
|
||||||
remaining.delete(index);
|
|
||||||
progress = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove sources
|
result.push(block);
|
||||||
for (let i = 0; i < currentVertices.length; i++) {
|
};
|
||||||
const index = currentVertices[i]!;
|
|
||||||
if (remaining.has(index) && incoming[index]!.size === 0) {
|
for (let i = 0; i < blocks.length; i++) {
|
||||||
prefix[prefixSize++] = index;
|
processBlock(blocks[i]!);
|
||||||
// Remove this vertex
|
|
||||||
for (const toIndex of outgoing[index]!) {
|
|
||||||
incoming[toIndex]!.delete(index);
|
|
||||||
}
|
|
||||||
remaining.delete(index);
|
|
||||||
progress = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If no sinks or sources, remove vertex with maximum Δ
|
return result;
|
||||||
if (!progress && remaining.size > 0) {
|
|
||||||
let maxDelta = -Infinity;
|
|
||||||
let maxDeltaIndex = -1;
|
|
||||||
|
|
||||||
for (const index of remaining) {
|
|
||||||
const delta = outgoing[index]!.size - incoming[index]!.size;
|
|
||||||
if (delta > maxDelta) {
|
|
||||||
maxDelta = delta;
|
|
||||||
maxDeltaIndex = index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
prefix[prefixSize++] = maxDeltaIndex;
|
|
||||||
// Remove this vertex
|
|
||||||
for (const toIndex of outgoing[maxDeltaIndex]!) {
|
|
||||||
incoming[toIndex]!.delete(maxDeltaIndex);
|
|
||||||
}
|
|
||||||
for (const fromIndex of incoming[maxDeltaIndex]!) {
|
|
||||||
outgoing[fromIndex]!.delete(maxDeltaIndex);
|
|
||||||
}
|
|
||||||
remaining.delete(maxDeltaIndex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = new Array<ClusterBlock | null>(n).fill(null);
|
|
||||||
|
|
||||||
// Copy prefix
|
|
||||||
for (let i = 0; i < prefixSize; i++) {
|
|
||||||
result[i] = blocks[prefix[i]!]!;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy suffix in reverse
|
|
||||||
for (let i = 0; i < suffixSize; i++) {
|
|
||||||
result[prefixSize + i] = blocks[suffix[suffixSize - 1 - i]!]!;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result as ClusterBlock[];
|
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user