Fix file compression example, add processedTime parameter to onProgress for Conversion API

This commit is contained in:
Vanilagy
2026-04-24 14:33:19 +02:00
parent 9de93877bd
commit 66997ddd16
2 changed files with 72 additions and 51 deletions
+24 -14
View File
@@ -62,31 +62,41 @@ const compressFile = async (resource: File | string) => {
currentConversion = await Conversion.init({ currentConversion = await Conversion.init({
input, input,
output, output,
video: track => ({ tracks: 'primary', // Keep only one track per type
video: {
width: 320, // Height will be deduced automatically to retain aspect ratio width: 320, // Height will be deduced automatically to retain aspect ratio
bitrate: QUALITY_VERY_LOW, bitrate: QUALITY_VERY_LOW,
discard: track.number > 1, // Keep only the first video track },
}), audio: {
audio: track => ({ bitrate: QUALITY_VERY_LOW,
bitrate: 32e3, },
discard: track.number > 1, // Keep only the first audio track
}),
}); });
if (!currentConversion.isValid) {
console.info(currentConversion.discardedTracks);
throw new Error('Conversion is invalid and cannot be executed; see the console for more.');
}
// Keep track of progress // Keep track of progress
let progress = 0; let progress = 0;
currentConversion.onProgress = newProgress => progress = newProgress; let processedTime = 0;
let startTime: number | null = null;
const fileDuration = (await input.computeDuration()) - (await input.getFirstTimestamp()); currentConversion.onProgress = (newProgress, newProcessedTime) => {
const startTime = performance.now(); progress = newProgress;
processedTime = newProcessedTime;
startTime ??= performance.now();
};
const updateProgress = () => { const updateProgress = () => {
progressBar.style.width = `${progress * 100}%`; progressBar.style.width = `${progress * 100}%`;
const now = performance.now(); if (startTime !== null) {
const elapsedSeconds = (now - startTime) / 1000; const now = performance.now();
const factor = fileDuration / (elapsedSeconds / progress); const elapsedSeconds = (now - startTime) / 1000;
speedometer.textContent = `Speed: ~${factor.toPrecision(3)}x real time`; const factor = processedTime / elapsedSeconds;
speedometer.textContent = `Speed: ~${factor.toPrecision(3)}x real time`;
}
}; };
// Update the progress indicator regularly // Update the progress indicator regularly
+48 -37
View File
@@ -563,13 +563,15 @@ export class Conversion {
_canceled = false; _canceled = false;
/** /**
* A callback that is fired whenever the conversion progresses. Returns a number between 0 and 1, indicating the * A callback that is fired whenever the conversion progresses. Gets passed as first argument a number between
* completion of the conversion. Note that a progress of 1 doesn't necessarily mean the conversion is complete; * 0 and 1, indicating the completion of the conversion. Note that a progress of 1 doesn't necessarily mean the
* the conversion is complete once `execute()` resolves. * conversion is complete; the conversion is complete once `execute()` resolves.
*
* As second argument, this callback receives the input time in seconds that has been processed.
* *
* In order for progress to be computed, this property must be set before `execute` is called. * In order for progress to be computed, this property must be set before `execute` is called.
*/ */
onProgress?: (progress: number) => unknown = undefined; onProgress?: (progress: number, processedTime: number) => unknown = undefined;
/** @internal */ /** @internal */
_computeProgress = false; _computeProgress = false;
/** @internal */ /** @internal */
@@ -929,7 +931,11 @@ export class Conversion {
} }
if (!this.isValid) { if (!this.isValid) {
warnElements.push('\n\n' + this._getInvalidityExplanation().join('')); if (warnElements.length > 0) {
warnElements.push('\n\n');
}
warnElements.push(this._getInvalidityExplanation().join(''));
} }
if (warnElements.length > 0) { if (warnElements.length > 0) {
@@ -949,7 +955,7 @@ export class Conversion {
} else { } else {
const encodabilityIsTheProblem = this.discardedTracks.every(x => const encodabilityIsTheProblem = this.discardedTracks.every(x =>
x.reason === 'discarded_by_user' || x.reason === 'no_encodable_target_codec', x.reason === 'discarded_by_user' || x.reason === 'no_encodable_target_codec',
); ) && this.discardedTracks.some(x => x.reason === 'no_encodable_target_codec');
elements.push( elements.push(
'Due to discarded tracks, this conversion cannot be executed.', 'Due to discarded tracks, this conversion cannot be executed.',
@@ -1054,7 +1060,7 @@ export class Conversion {
this._maxTimestamps.set(id, 0); this._maxTimestamps.set(id, 0);
} }
this.onProgress?.(0); this.onProgress?.(0, 0);
} }
await this.output.start(); await this.output.start();
@@ -1078,7 +1084,8 @@ export class Conversion {
await this.output.finalize(); await this.output.finalize();
if (this._computeProgress) { if (this._computeProgress) {
this.onProgress?.(1); const minTimestamp = Math.min(...this._maxTimestamps.values());
this.onProgress?.(1, minTimestamp);
} }
} }
@@ -1547,21 +1554,23 @@ export class Conversion {
}); });
} }
for (const finalSample of finalSamples) { try {
if (this._canceled) { for (const finalSample of finalSamples) {
break; if (this._canceled) {
break;
}
await source.add(finalSample);
if (this._synchronizer.shouldWait(outputTrackId, finalSample.timestamp)) {
await this._synchronizer.wait(finalSample.timestamp);
}
} }
} finally {
await source.add(finalSample); for (const finalSample of finalSamples) {
if (finalSample !== sample) {
if (this._synchronizer.shouldWait(outputTrackId, finalSample.timestamp)) { finalSample.close();
await this._synchronizer.wait(finalSample.timestamp); }
}
}
for (const finalSample of finalSamples) {
if (finalSample !== sample) {
finalSample.close();
} }
} }
} }
@@ -1801,21 +1810,23 @@ export class Conversion {
finalSamples = processed; finalSamples = processed;
} }
for (const finalSample of finalSamples) { try {
if (this._canceled) { for (const finalSample of finalSamples) {
break; if (this._canceled) {
break;
}
await source.add(finalSample);
if (this._synchronizer.shouldWait(outputTrackId, finalSample.timestamp)) {
await this._synchronizer.wait(finalSample.timestamp);
}
} }
} finally {
await source.add(finalSample); for (const finalSample of finalSamples) {
if (finalSample !== sample) {
if (this._synchronizer.shouldWait(outputTrackId, finalSample.timestamp)) { finalSample.close();
await this._synchronizer.wait(finalSample.timestamp); }
}
}
for (const finalSample of finalSamples) {
if (finalSample !== sample) {
finalSample.close();
} }
} }
} }
@@ -1890,7 +1901,7 @@ export class Conversion {
if (newProgress !== this._lastProgress) { if (newProgress !== this._lastProgress) {
this._lastProgress = newProgress; this._lastProgress = newProgress;
this.onProgress?.(newProgress); this.onProgress?.(newProgress, minTimestamp);
} }
} }
} }