draggable
This commit is contained in:
parent
64473bd201
commit
99b4143dd6
|
@ -15,6 +15,8 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@sveltejs/vite-plugin-svelte": "^2.4.2",
|
"@sveltejs/vite-plugin-svelte": "^2.4.2",
|
||||||
"svelte": "^4.0.5",
|
"svelte": "^4.0.5",
|
||||||
|
"svelte-dnd-action": "^0.9.25",
|
||||||
|
"uuid": "^9.0.0",
|
||||||
"vite": "^4.4.5"
|
"vite": "^4.4.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -819,6 +821,15 @@
|
||||||
"node": ">=16"
|
"node": ">=16"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/svelte-dnd-action": {
|
||||||
|
"version": "0.9.25",
|
||||||
|
"resolved": "https://registry.npmjs.org/svelte-dnd-action/-/svelte-dnd-action-0.9.25.tgz",
|
||||||
|
"integrity": "sha512-6cW+5b+xYn2w1KaYdzdMiWOn4wzFq9KHpWMyYwixN4M+94RFw9Sn8GiRI0EPFoT5r6/RVD3d3lZ/OjllZlpYbg==",
|
||||||
|
"dev": true,
|
||||||
|
"peerDependencies": {
|
||||||
|
"svelte": ">=3.23.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/svelte-hmr": {
|
"node_modules/svelte-hmr": {
|
||||||
"version": "0.15.3",
|
"version": "0.15.3",
|
||||||
"resolved": "https://registry.npmjs.org/svelte-hmr/-/svelte-hmr-0.15.3.tgz",
|
"resolved": "https://registry.npmjs.org/svelte-hmr/-/svelte-hmr-0.15.3.tgz",
|
||||||
|
@ -831,6 +842,15 @@
|
||||||
"svelte": "^3.19.0 || ^4.0.0"
|
"svelte": "^3.19.0 || ^4.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/uuid": {
|
||||||
|
"version": "9.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz",
|
||||||
|
"integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==",
|
||||||
|
"dev": true,
|
||||||
|
"bin": {
|
||||||
|
"uuid": "dist/bin/uuid"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/vite": {
|
"node_modules/vite": {
|
||||||
"version": "4.4.9",
|
"version": "4.4.9",
|
||||||
"resolved": "https://registry.npmjs.org/vite/-/vite-4.4.9.tgz",
|
"resolved": "https://registry.npmjs.org/vite/-/vite-4.4.9.tgz",
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@sveltejs/vite-plugin-svelte": "^2.4.2",
|
"@sveltejs/vite-plugin-svelte": "^2.4.2",
|
||||||
"svelte": "^4.0.5",
|
"svelte": "^4.0.5",
|
||||||
|
"svelte-dnd-action": "^0.9.25",
|
||||||
|
"uuid": "^9.0.0",
|
||||||
"vite": "^4.4.5"
|
"vite": "^4.4.5"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|
|
@ -7,10 +7,10 @@
|
||||||
import FilterPicker from "./FilterPicker.svelte";
|
import FilterPicker from "./FilterPicker.svelte";
|
||||||
import { FFmpeg } from "@ffmpeg/ffmpeg";
|
import { FFmpeg } from "@ffmpeg/ffmpeg";
|
||||||
import { fetchFile, toBlobURL } from "@ffmpeg/util";
|
import { fetchFile, toBlobURL } from "@ffmpeg/util";
|
||||||
|
import {dndzone} from "svelte-dnd-action";
|
||||||
|
|
||||||
const baseURL = "https://unpkg.com/@ffmpeg/core@0.12.2/dist/esm";
|
const baseURL = "https://unpkg.com/@ffmpeg/core@0.12.2/dist/esm";
|
||||||
// const baseURL = "";
|
// const baseURL = "";
|
||||||
// const videoURL = "https://ffmpegwasm.netlify.app/video/video-15s.avi";
|
|
||||||
const TIMEOUT = 40000;
|
const TIMEOUT = 40000;
|
||||||
|
|
||||||
const ffmpeg = new FFmpeg();
|
const ffmpeg = new FFmpeg();
|
||||||
|
@ -38,29 +38,37 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
async function transcode() {
|
async function transcode() {
|
||||||
// try {
|
|
||||||
message = "Start transcoding";
|
message = "Start transcoding";
|
||||||
videoValue = null;
|
videoValue = null;
|
||||||
rendering = true;
|
rendering = true;
|
||||||
for (let vid of $inputs) {
|
for (let vid of $inputs) {
|
||||||
await ffmpeg.writeFile(vid, await fetchFile("/" + vid));
|
await ffmpeg.writeFile(vid, await fetchFile("/" + vid));
|
||||||
}
|
}
|
||||||
// const infile = await ffmpeg.readFile("example.mp4");
|
|
||||||
// videoValue = URL.createObjectURL(new Blob([infile.buffer], { type: "video/mp4" }));
|
|
||||||
// console.log("VIDEO", videoValue);
|
|
||||||
const clist = commandList();
|
const clist = commandList();
|
||||||
console.log(clist);
|
console.log(clist);
|
||||||
// await ffmpeg.exec(["-hide_banner", "-i", "example.mp4", "-vf", "negate", "out.mp4", "-y"]);
|
|
||||||
await ffmpeg.exec(clist, TIMEOUT);
|
await ffmpeg.exec(clist, TIMEOUT);
|
||||||
|
// await ffmpeg.exec(["-f", "lavfi", "-i", "color=size=1280x720:rate=25:color=red", "-t", "5", "out.mp4"])
|
||||||
message = "Complete transcoding";
|
message = "Complete transcoding";
|
||||||
const data = await ffmpeg.readFile("out.mp4");
|
const data = await ffmpeg.readFile("out.mp4");
|
||||||
rendering = false;
|
rendering = false;
|
||||||
videoValue = URL.createObjectURL(new Blob([data.buffer], { type: "video/mp4" }));
|
videoValue = URL.createObjectURL(new Blob([data.buffer], { type: "video/mp4" }));
|
||||||
rendering = false;
|
rendering = false;
|
||||||
// console.log("VIDEO", videoValue);
|
}
|
||||||
// } catch (error) {
|
|
||||||
// console.log(error);
|
async function loadFFmpeg() {
|
||||||
// }
|
ffmpeg.on("log", ({ message: msg }) => {
|
||||||
|
console.log(msg);
|
||||||
|
log += msg + "\n";
|
||||||
|
logbox.scrollTop = logbox.scrollHeight;
|
||||||
|
// message = msg;
|
||||||
|
});
|
||||||
|
await ffmpeg.load({
|
||||||
|
coreURL: await toBlobURL(`${baseURL}/ffmpeg-core.js`, "text/javascript"),
|
||||||
|
wasmURL: await toBlobURL(`${baseURL}/ffmpeg-core.wasm`, "application/wasm"),
|
||||||
|
// workerURL: await toBlobURL(`${baseURL}/ffmpeg-core.worker.js`, "text/javascript"),
|
||||||
|
});
|
||||||
|
console.log(ffmpeg);
|
||||||
|
ffmpegLoaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateCommand() {
|
function updateCommand() {
|
||||||
|
@ -116,29 +124,20 @@
|
||||||
command.push("-pix_fmt");
|
command.push("-pix_fmt");
|
||||||
command.push("yuv420p");
|
command.push("yuv420p");
|
||||||
command.push("out.mp4");
|
command.push("out.mp4");
|
||||||
|
|
||||||
return command;
|
return command;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleFilterSort(e) {
|
||||||
|
filters.set(e.detail.items);
|
||||||
|
}
|
||||||
|
|
||||||
inputs.subscribe(updateCommand);
|
inputs.subscribe(updateCommand);
|
||||||
output.subscribe(updateCommand);
|
output.subscribe(updateCommand);
|
||||||
filters.subscribe(updateCommand);
|
filters.subscribe(updateCommand);
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
ffmpeg.on("log", ({ message: msg }) => {
|
loadFFmpeg();
|
||||||
console.log(msg);
|
|
||||||
log += msg + "\n";
|
|
||||||
logbox.scrollTop = logbox.scrollHeight;
|
|
||||||
// message = msg;
|
|
||||||
});
|
|
||||||
await ffmpeg.load({
|
|
||||||
// coreURL: `${baseURL}/ffmpeg-core.js`,
|
|
||||||
// wasmURL: `${baseURL}/ffmpeg-core.wasm`,
|
|
||||||
// workerURL: `${baseURL}/ffmpeg-core.worker.js`,
|
|
||||||
coreURL: await toBlobURL(`${baseURL}/ffmpeg-core.js`, "text/javascript"),
|
|
||||||
wasmURL: await toBlobURL(`${baseURL}/ffmpeg-core.wasm`, "application/wasm"),
|
|
||||||
// workerURL: await toBlobURL(`${baseURL}/ffmpeg-core.worker.js`, "text/javascript"),
|
|
||||||
});
|
|
||||||
ffmpegLoaded = true;
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -148,18 +147,16 @@
|
||||||
<p>
|
<p>
|
||||||
A tool to help you explore FFmpeg filters and options. To use: select one or more input videos
|
A tool to help you explore FFmpeg filters and options. To use: select one or more input videos
|
||||||
(there are currently two options), export and add some filters, and then hit "render" to
|
(there are currently two options), export and add some filters, and then hit "render" to
|
||||||
preview the output in browser.
|
preview the output in browser. Note: this is a work in progress, many things may still be
|
||||||
Note: this is a work in progress, many things may still be broken! By <a href="https://lav.io"
|
broken! By <a href="https://lav.io">Sam Lavigne</a>.
|
||||||
>Sam Lavigne</a
|
|
||||||
>.
|
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
<!-- {message} -->
|
<!-- {message} -->
|
||||||
<section class="command">
|
<section class="command">
|
||||||
<textarea class="actual-command" bind:this={commandRef}>{command}</textarea>
|
<textarea readonly class="actual-command" bind:this={commandRef}>{command}</textarea>
|
||||||
<div>
|
<div>
|
||||||
<button on:click={copyCommand}>Copy</button>
|
<button on:click={copyCommand}>Copy</button>
|
||||||
<button on:click={render} disabled={!ffmpegLoaded}>
|
<button on:click={render} disabled={!ffmpegLoaded || rendering}>
|
||||||
{#if ffmpegLoaded}
|
{#if ffmpegLoaded}
|
||||||
{#if rendering}
|
{#if rendering}
|
||||||
Rendering...
|
Rendering...
|
||||||
|
@ -185,10 +182,13 @@
|
||||||
|
|
||||||
<section class="log">
|
<section class="log">
|
||||||
<h3>FFmpeg Log</h3>
|
<h3>FFmpeg Log</h3>
|
||||||
<textarea class="the-log" bind:this={logbox}>{log}</textarea>
|
<textarea readonly class="the-log" bind:this={logbox}>{log}</textarea>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="preview">
|
<section class="preview">
|
||||||
|
{#if rendering}
|
||||||
|
<div class="rendering-video"><span>Rendering...</span></div>
|
||||||
|
{/if}
|
||||||
<video controls src={videoValue} />
|
<video controls src={videoValue} />
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
@ -203,10 +203,10 @@
|
||||||
<div class="filter-picker">
|
<div class="filter-picker">
|
||||||
<FilterPicker select={"video"} />
|
<FilterPicker select={"video"} />
|
||||||
</div>
|
</div>
|
||||||
<div class="filters-holder">
|
<div class="filters-holder" use:dndzone={{items:$filters}} on:consider={handleFilterSort} on:finalize={handleFilterSort}>
|
||||||
{#each $filters as f, index}
|
{#each $filters as f (f.id)}
|
||||||
<div class="filter">
|
<div class="filter">
|
||||||
<Filter bind:filter={f} {index} />
|
<Filter bind:filter={f} />
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
@ -247,6 +247,7 @@
|
||||||
|
|
||||||
.preview {
|
.preview {
|
||||||
grid-area: prv;
|
grid-area: prv;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.output {
|
.output {
|
||||||
|
@ -326,4 +327,16 @@
|
||||||
resize: none;
|
resize: none;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
.rendering-video {
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
z-index: 2;
|
||||||
|
background-color: rgba(255, 255, 255, 0.8);
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
display: grid;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
<script>
|
<script>
|
||||||
import FILTERS from "./filters.json";
|
|
||||||
import { filters } from "./stores.js";
|
import { filters } from "./stores.js";
|
||||||
|
|
||||||
export let filter = {
|
export let filter = {
|
||||||
|
@ -8,10 +7,10 @@
|
||||||
description: "",
|
description: "",
|
||||||
};
|
};
|
||||||
|
|
||||||
export let index;
|
|
||||||
let show = false;
|
let show = false;
|
||||||
|
|
||||||
function remove() {
|
function remove() {
|
||||||
|
const index = $filters.findIndex((f) => f.id === filter.id);
|
||||||
$filters.splice(index, 1);
|
$filters.splice(index, 1);
|
||||||
$filters = $filters;
|
$filters = $filters;
|
||||||
}
|
}
|
||||||
|
@ -21,7 +20,9 @@
|
||||||
<div class="head">
|
<div class="head">
|
||||||
<div class="name"><h3>{filter.name}<h3></div>
|
<div class="name"><h3>{filter.name}<h3></div>
|
||||||
<div>
|
<div>
|
||||||
|
{#if filter.params}
|
||||||
<button on:click={() => show = !show}>{show ? "Hide" : "Show"} Options</button>
|
<button on:click={() => show = !show}>{show ? "Hide" : "Show"} Options</button>
|
||||||
|
{/if}
|
||||||
<button on:click={remove}>X</button>
|
<button on:click={remove}>X</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
<script>
|
<script>
|
||||||
import uFuzzy from "@leeoniya/ufuzzy";
|
import uFuzzy from "@leeoniya/ufuzzy";
|
||||||
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
import FILTERS from "./filters.json";
|
import FILTERS from "./filters.json";
|
||||||
import { filters } from "./stores.js";
|
import { filters } from "./stores.js";
|
||||||
|
|
||||||
|
@ -27,7 +28,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function add(f) {
|
function add(f) {
|
||||||
const newFilter = { ...f };
|
const newFilter = { ...f, filterId: f.id, id: uuidv4() };
|
||||||
if (f.params) {
|
if (f.params) {
|
||||||
newFilter.params = f.params.map((p) => {
|
newFilter.params = f.params.map((p) => {
|
||||||
p.value = null;
|
p.value = null;
|
||||||
|
|
Loading…
Reference in New Issue