mirror of
https://github.com/arcodange-org/mediabunny.git
synced 2026-09-27 02:43:48 +02:00
Add file compression example
This commit is contained in:
@@ -0,0 +1,137 @@
|
||||
import {
|
||||
Input,
|
||||
ALL_FORMATS,
|
||||
BlobSource,
|
||||
Output,
|
||||
BufferTarget,
|
||||
Mp4OutputFormat,
|
||||
Conversion,
|
||||
QUALITY_VERY_LOW,
|
||||
} from 'mediakit';
|
||||
|
||||
const selectMediaButton = document.querySelector('button') as HTMLButtonElement;
|
||||
const fileNameElement = document.querySelector('#file-name') as HTMLParagraphElement;
|
||||
const horizontalRule = document.querySelector('hr') as HTMLHRElement;
|
||||
const progressBarContainer = document.querySelector('#progress-bar-container') as HTMLDivElement;
|
||||
const progressBar = document.querySelector('#progress-bar') as HTMLDivElement;
|
||||
const speedometer = document.querySelector('#speedometer') as HTMLParagraphElement;
|
||||
const videoElement = document.querySelector('video') as HTMLVideoElement;
|
||||
const compressionFacts = document.querySelector('#compression-facts') as HTMLParagraphElement;
|
||||
const errorElement = document.querySelector('#error-element') as HTMLParagraphElement;
|
||||
|
||||
let currentConversion: Conversion | null = null;
|
||||
let currentIntervalId = -1;
|
||||
|
||||
const compressFile = async (file: File) => {
|
||||
clearInterval(currentIntervalId);
|
||||
await currentConversion?.cancel();
|
||||
|
||||
fileNameElement.textContent = file.name;
|
||||
horizontalRule.style.display = '';
|
||||
progressBarContainer.style.display = '';
|
||||
speedometer.style.display = '';
|
||||
speedometer.textContent = 'Speed: -';
|
||||
videoElement.style.display = 'none';
|
||||
videoElement.src = '';
|
||||
errorElement.textContent = '';
|
||||
|
||||
try {
|
||||
// Create a new input from the file
|
||||
const input = new Input({
|
||||
source: new BlobSource(file),
|
||||
formats: ALL_FORMATS, // Accept all formats
|
||||
});
|
||||
|
||||
// Define the output file
|
||||
const output = new Output({
|
||||
target: new BufferTarget(),
|
||||
format: new Mp4OutputFormat(),
|
||||
});
|
||||
|
||||
// Initialize the conversion process
|
||||
currentConversion = await Conversion.init({
|
||||
input,
|
||||
output,
|
||||
video: {
|
||||
width: 320, // Height will be deduced automatically to retain aspect ratio
|
||||
bitrate: QUALITY_VERY_LOW,
|
||||
},
|
||||
audio: {
|
||||
bitrate: 32e3,
|
||||
},
|
||||
});
|
||||
|
||||
// Keep track of progress
|
||||
let progress = 0;
|
||||
currentConversion.onProgress = newProgress => progress = newProgress;
|
||||
|
||||
const fileDuration = await input.computeDuration();
|
||||
const startTime = performance.now();
|
||||
|
||||
const updateProgress = () => {
|
||||
progressBar.style.width = `${progress * 100}%`;
|
||||
|
||||
const now = performance.now();
|
||||
const elapsedSeconds = (now - startTime) / 1000;
|
||||
const factor = fileDuration / (elapsedSeconds / progress);
|
||||
speedometer.textContent = `Speed: ~${factor.toPrecision(3)}x real time`;
|
||||
};
|
||||
|
||||
// Update the progress indicator regularly
|
||||
currentIntervalId = window.setInterval(updateProgress, 1000 / 60);
|
||||
|
||||
// Start the conversion process
|
||||
await currentConversion.execute();
|
||||
|
||||
clearInterval(currentIntervalId);
|
||||
updateProgress();
|
||||
|
||||
// Display the final media file
|
||||
videoElement.style.display = '';
|
||||
videoElement.src = URL.createObjectURL(new Blob([output.target.buffer!]));
|
||||
void videoElement.play();
|
||||
|
||||
compressionFacts.style.display = '';
|
||||
compressionFacts.textContent
|
||||
= `${(output.target.buffer!.byteLength / file.size * 100).toPrecision(3)}% of original size`;
|
||||
} catch (error) {
|
||||
errorElement.textContent = String(error);
|
||||
clearInterval(currentIntervalId);
|
||||
|
||||
progressBarContainer.style.display = 'none';
|
||||
speedometer.style.display = 'none';
|
||||
compressionFacts.style.display = 'none';
|
||||
videoElement.style.display = 'none';
|
||||
}
|
||||
};
|
||||
|
||||
/** === FILE SELECTION LOGIC === */
|
||||
|
||||
selectMediaButton.addEventListener('click', () => {
|
||||
const fileInput = document.createElement('input');
|
||||
fileInput.type = 'file';
|
||||
fileInput.addEventListener('change', () => {
|
||||
const file = fileInput.files?.[0];
|
||||
if (!file) {
|
||||
return;
|
||||
}
|
||||
|
||||
void compressFile(file);
|
||||
});
|
||||
|
||||
fileInput.click();
|
||||
});
|
||||
|
||||
document.addEventListener('dragover', (event) => {
|
||||
event.preventDefault();
|
||||
event.dataTransfer!.dropEffect = 'copy';
|
||||
});
|
||||
|
||||
document.addEventListener('drop', (event) => {
|
||||
event.preventDefault();
|
||||
const files = event.dataTransfer?.files;
|
||||
const file = files && files.length > 0 ? files[0] : undefined;
|
||||
if (file) {
|
||||
void compressFile(file);
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,54 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" translate="no">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>File compression example | Mediakit</title>
|
||||
<script type="module" src="../base.ts"></script>
|
||||
<script type="module" src="./file-compression.ts"></script>
|
||||
<link rel="stylesheet" href="../base.css">
|
||||
</head>
|
||||
|
||||
<body class="flex flex-col items-center py-10 bg-zinc-50 text-zinc-800 dark:bg-zinc-900 dark:text-zinc-200 px-2">
|
||||
<h1 class="text-3xl font-bold text-teal-800 dark:text-teal-200">File compression example</h1>
|
||||
<p>Select or drop a media file, and Mediakit will convert it to a heavily-compressed MP4 file.</p>
|
||||
|
||||
<div class="flex gap-2 mt-4">
|
||||
<button class="rounded-lg bg-zinc-200 dark:bg-zinc-750 hover:bg-zinc-300 dark:hover:bg-zinc-700 px-5 py-1">
|
||||
Select media file
|
||||
</button>
|
||||
|
||||
<a href="../../assets/big-buck-bunny-trimmed.mp4" download class="rounded-lg bg-zinc-200 dark:bg-zinc-750 hover:bg-zinc-300 dark:hover:bg-zinc-700 px-5 group grid place-items-center" title="Download sample file">
|
||||
<img src="../../assets/download-icon.svg" class="opacity-30 group-hover:opacity-80 dark:invert">
|
||||
</a>
|
||||
</div>
|
||||
<p class="text-xs opacity-60 mt-2" id="file-name"></p>
|
||||
|
||||
<hr class="w-full max-w-96 my-4 border-zinc-300 dark:border-zinc-700" style="display: none;">
|
||||
|
||||
<p id="error-element" class="text-red-500"></p>
|
||||
|
||||
<div class="w-full max-w-80 h-2 rounded-full bg-zinc-200 dark:bg-zinc-750 overflow-hidden" id="progress-bar-container" style="display: none;">
|
||||
<div class="h-full bg-emerald-500 w-0" id="progress-bar"></div>
|
||||
</div>
|
||||
<p class="text-xs font-medium mt-1" id="speedometer" style="display: none;"></p>
|
||||
|
||||
<video controls class="rounded-md mt-4" style="display: none;"></video>
|
||||
<p class="text-xs font-medium mt-1" id="compression-facts" style="display: none;"></p>
|
||||
|
||||
<div class="fixed top-0 left-0 flex gap-2 py-2 px-5 items-center">
|
||||
<img src="../../assets/mediakit-logo.svg" class="size-6 dark:invert">
|
||||
<p class="text-sm font-semibold">Mediakit</p>
|
||||
</div>
|
||||
|
||||
<a
|
||||
href="https://github.com/Vanilagy/metamuxer/tree/main/examples/file-compression"
|
||||
target="_blank"
|
||||
class="flex items-center gap-2 fixed top-0 right-0 py-2 px-5 bg-zinc-200 dark:bg-zinc-750 hover:bg-zinc-300 dark:hover:bg-zinc-700 rounded-bl-xl"
|
||||
>
|
||||
<img src="../../assets/github-mark.svg" class="size-6 dark:invert">
|
||||
<p>View source code</p>
|
||||
</a>
|
||||
</body>
|
||||
</html>
|
||||
@@ -25,7 +25,7 @@
|
||||
</div>
|
||||
<p class="text-xs opacity-60 mt-2" id="file-name"></p>
|
||||
|
||||
<hr class="w-96 my-4 border-zinc-300 dark:border-zinc-700" style="display: none;">
|
||||
<hr class="w-full max-w-96 my-4 border-zinc-300 dark:border-zinc-700" style="display: none;">
|
||||
|
||||
<p id="error-element" class="text-red-500"></p>
|
||||
<div id="player" class="relative bg-black rounded-xl shrink min-h-14 min-w-0 w-full max-w-5xl overflow-hidden select-none" style="display: none;">
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
</div>
|
||||
<p class="text-xs opacity-60 mt-2" id="file-name"></p>
|
||||
|
||||
<hr class="w-96 my-4 border-zinc-300 dark:border-zinc-700" style="display: none;">
|
||||
<hr class="w-full max-w-96 my-4 border-zinc-300 dark:border-zinc-700" style="display: none;">
|
||||
|
||||
<p id="bytes-read" class="text-center text-xs font-medium mb-4"></p>
|
||||
<div id="metadata-container" class="text-sm"></div>
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
</div>
|
||||
<p class="text-xs opacity-60 mt-2" id="file-name"></p>
|
||||
|
||||
<hr class="w-96 my-4 border-gray-300 dark:border-zinc-700" style="display: none;">
|
||||
<hr class="w-full max-w-96 my-4 border-gray-300 dark:border-zinc-700" style="display: none;">
|
||||
|
||||
<p id="error-element" class="text-red-500"></p>
|
||||
<div id="thumbnail-container" class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4"></div>
|
||||
|
||||
Reference in New Issue
Block a user