Compare commits
4 Commits
b2fff4357b
...
62e66f4505
| Author | SHA1 | Date | |
|---|---|---|---|
| 62e66f4505 | |||
| b7dd6e752b | |||
| 574478db84 | |||
| 5bb14ef3f7 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,2 +1,3 @@
|
||||
public/assets/scripts/ffmpeg/
|
||||
public/assets/scripts/core/
|
||||
|
||||
|
||||
@ -1,32 +1,69 @@
|
||||
const ffmpeg = new FFmpegWASM.FFmpeg();
|
||||
|
||||
const notifier = new Notifier();
|
||||
|
||||
async function compress() {
|
||||
document.getElementById("uploaded-video").pause();
|
||||
showSection("loading");
|
||||
|
||||
const filesize = document.getElementById("filesize").value;
|
||||
const filesizeUnit = document.getElementById("filesize-unit").value;
|
||||
const file = document.getElementById("file-input").files[0];
|
||||
|
||||
updateProgress(0);
|
||||
const videoLength = document.getElementById("uploaded-video").duration;
|
||||
let targetFilesize; // Stored in kBit
|
||||
switch (filesizeUnit) {
|
||||
case "K": targetFilesize = filesize * 8; break;
|
||||
case "M": targetFilesize = filesize * 8000; break;
|
||||
}
|
||||
|
||||
const ffmpeg = new FFmpegWASM.FFmpeg();
|
||||
ffmpeg.on("progress", data => {
|
||||
console.log(data);
|
||||
updateProgress(data.progress);
|
||||
ffmpeg.on("log", event => {
|
||||
console.log("[ffmpeg]", event.type, event.message);
|
||||
});
|
||||
|
||||
let pass = 1;
|
||||
|
||||
updateProgress(0, pass);
|
||||
ffmpeg.on("progress", event => {
|
||||
updateProgress(event.progress, pass);
|
||||
});
|
||||
|
||||
await ffmpeg.load({ coreURL: "/assets/scripts/core/package/dist/umd/ffmpeg-core.js" });
|
||||
|
||||
await ffmpeg.writeFile(file.name, await readFromBlob(file));
|
||||
|
||||
await ffmpeg.exec(["-i", file.name, "-preset", "veryfast", "-fs", filesize + filesizeUnit, "compressed.mp4"]);
|
||||
// Use Two-Pass to create a video file with desired file size
|
||||
// https://trac.ffmpeg.org/wiki/Encode/H.264#twopass
|
||||
|
||||
const bitrate = Math.floor(targetFilesize / videoLength) - 128; // Subtract audio bitrate
|
||||
|
||||
console.debug("Target bitrate:", bitrate, "Video length:", videoLength);
|
||||
|
||||
const options = ["-i", file.name, "-preset", "ultrafast", "-c:v", "libx264", "-b:v", bitrate + "k"];
|
||||
|
||||
await ffmpeg.exec([...options, "-pass", "1", "-vsync", "cfr", "-f", "null", "/dev/null"]);
|
||||
|
||||
pass = 2;
|
||||
|
||||
await ffmpeg.exec([...options, "-pass", "2", "-c:a", "copy", "-b:a", "128k", "compressed.mp4"]);
|
||||
|
||||
const video = await ffmpeg.readFile("compressed.mp4");
|
||||
|
||||
notifier.notifyFinished();
|
||||
|
||||
location.href = URL.createObjectURL(new Blob([video.buffer], { type: "video/mp4" }));
|
||||
}
|
||||
|
||||
function updateProgress(progress) {
|
||||
function cancel() {
|
||||
ffmpeg.terminate();
|
||||
|
||||
showSection("file-picker");
|
||||
}
|
||||
|
||||
function updateProgress(progress, pass) {
|
||||
const percent = (progress * 100).toFixed(1) + "%";
|
||||
|
||||
document.getElementById("progress-step-value").innerText = pass;
|
||||
document.getElementById("progress-percentage").innerText = percent;
|
||||
document.getElementById("progress-indicator").style.clipPath = `rect(0 ${percent} 100% 0)`;
|
||||
}
|
||||
|
||||
@ -40,4 +40,3 @@ function showElements() {
|
||||
}
|
||||
}, TRANSITION_TIME);
|
||||
}
|
||||
|
||||
|
||||
@ -102,9 +102,10 @@ button.primary:focus {
|
||||
}
|
||||
|
||||
button.simple {
|
||||
border: none;
|
||||
border: 1px solid #9E9E9E;
|
||||
border-radius: 0.25rem;
|
||||
background-color: transparent;
|
||||
transition: color 100ms;
|
||||
transition: all 100ms;
|
||||
cursor: pointer;
|
||||
color: #9E9E9E;
|
||||
margin: 1rem auto;
|
||||
@ -112,6 +113,12 @@ button.simple {
|
||||
|
||||
button.simple:hover {
|
||||
color: black;
|
||||
border-color: black;
|
||||
}
|
||||
|
||||
button.simple:focus {
|
||||
border-color: black;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
input, select {
|
||||
@ -129,6 +136,14 @@ input:focus, select:focus {
|
||||
box-shadow: 0 4px 4px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
input[type=checkbox] {
|
||||
accent-color: #4CAF50;
|
||||
}
|
||||
|
||||
label {
|
||||
color: #757575;
|
||||
}
|
||||
|
||||
#filesize {
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
@ -150,7 +165,7 @@ input:focus, select:focus {
|
||||
|
||||
#loading-title {
|
||||
color: #757575;
|
||||
font-size: 3rem;
|
||||
font-size: 2.5rem;
|
||||
font-weight: bold;
|
||||
margin-top: 4rem;
|
||||
margin-bottom: 0;
|
||||
@ -168,7 +183,6 @@ input:focus, select:focus {
|
||||
margin: auto;
|
||||
background-color: #E0E0E0;
|
||||
position: relative;
|
||||
margin-top: 3rem;
|
||||
}
|
||||
|
||||
#progress-indicator {
|
||||
@ -185,3 +199,8 @@ input:focus, select:focus {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
#progress-step {
|
||||
font-weight: bold;
|
||||
margin-top: 3rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Video Compressor</title>
|
||||
<script defer src="/assets/scripts/ffmpeg/package/dist/umd/ffmpeg.js"></script>
|
||||
<script defer src="/assets/scripts/Notifier.js"></script>
|
||||
<script defer src="/assets/scripts/ui.js"></script>
|
||||
<script defer src="/assets/scripts/main.js"></script>
|
||||
<link rel="stylesheet" href="/assets/style/main.css">
|
||||
@ -24,12 +25,11 @@
|
||||
<video id="uploaded-video" controls autoplay></video>
|
||||
<button id="change-file" onclick="openFileSelector()" class="simple">Change video</button>
|
||||
|
||||
<input id="filesize" type="number" value="10" size="3" placeholder="#"><!--
|
||||
<input id="filesize" type="number" value="10" size="3" placeholder="#" style="margin-top: 1rem"><!--
|
||||
|
||||
--><select id="filesize-unit">
|
||||
<option value="K">KB</option>
|
||||
<option value="M" selected>MB</option>
|
||||
<option value="G">GB</option>
|
||||
</select>
|
||||
|
||||
<button id="compress" onclick="compress()" class="primary">Go!</button>
|
||||
@ -39,11 +39,16 @@
|
||||
<h3 id="loading-title">Please wait...</h3>
|
||||
<p id="loading-description">This may take a while</p>
|
||||
|
||||
<p id="progress-step">Step <span id="progress-step-value">1</span>/2</p>
|
||||
<div id="progress-container">
|
||||
<div id="progress-indicator"></div>
|
||||
</div>
|
||||
|
||||
<p id="progress-percentage">0%</p>
|
||||
|
||||
<p><label><input id="notify-checkbox" type="checkbox"> Notify on finish</label></p>
|
||||
|
||||
<button id="cancel" onclick="cancel()" class="simple">Cancel</button>
|
||||
</section>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user