Skip to main content

ffmpeg-webcli-browser-video-editor

A browser-based video editor powered by ffmpeg.wasm for client-side video processing without server uploads

インストールへ移動

ソース情報

リポジトリ
reason-machines/devtools-skills
ソースの最終更新活動
2026年6月5日 06:55
検出された SKILL.md の言語
英語
スター
4
フォーク
0

インストール方法

デフォルトでは、最初にソースを確認する Prompt が選択されています。直接コマンドに切り替えるか、ローカルコピーをダウンロードすることもできます。

ソースファイルを確認

インストールを決める前に、SKILL.md と SkillsMP に表示されている付属ファイルをお読みください。

SKILL.md を表示中

SKILL.md
ソースの指示 · 読み取り専用プレビュー
name
ffmpeg-webcli-browser-video-editor
description
A browser-based video editor powered by ffmpeg.wasm for client-side video processing without server uploads
triggers
["how do I use ffmpeg webCLI to process videos in the browser","set up ffmpeg.wasm video editor in my web app","convert videos to GIF using ffmpeg webCLI","process videos client-side with WebAssembly","integrate browser-based video editing with ffmpeg","use ffmpeg webCLI API for video operations","implement offline video processing in the browser","create video editor with ffmpeg.wasm"]
# ffmpeg webCLI Browser Video Editor > Skill by [ara.so](https://ara.so) — Devtools Skills collection. ffmpeg webCLI is a browser-based video editor powered by ffmpeg.wasm that processes videos entirely client-side using WebAssembly. No server uploads, no backend infrastructure — all video processing happens locally in the user's browser. It supports 30+ video operations including GIF creation, format conversion, compression, trimming, filters, effects, and more. ## Installation ### Option 1: Use the Live App Access the hosted version directly: ``` https://tejaswigowda.com/ffmpeg-webCLI/ ``` ### Option 2: Clone and Run Locally ```bash git clone https://github.com/tejaswigowda/ffmpeg-webCLI.git cd ffmpeg-webCLI # Serve the files with any static server python -m http.server 8000 # or npx serve . ``` ### Option 3: Integrate into Your Project The project uses ffmpeg.wasm as its core dependency. To integrate similar functionality: ```html <!DOCTYPE html> <html> <head> <script src="https://unpkg.com/@ffmpeg/ffmpeg@0.12.7/dist/umd/ffmpeg.js"></script> </head> <body> <input type="file" id="videoInput" accept="video/*"> <button id="processBtn">Process Video</button> <video id="output" controls></video> <script src="app.js"></script> </body> </html> ``` ## Core Architecture ffmpeg webCLI uses: - **ffmpeg.wasm** — WebAssembly port of ffmpeg for browser execution - **Web Workers** — Background processing to keep UI responsive - **PWA** — Progressive Web App for offline support - **Wake Lock API** — Prevents screen sleep during processing ## Key Components ### 1. Initialize ffmpeg.wasm ```javascript const { FFmpeg } = FFmpegWASM; const { fetchFile } = FFmpegWASM; let ffmpeg = null; let loaded = false; async function loadFFmpeg() { if (loaded) return; ffmpeg = new FFmpeg(); // Log ffmpeg output ffmpeg.on('log', ({ message }) => { console.log(message); }); // Track progress ffmpeg.on('progress', ({ progress, time }) => { console.log(`Progress: ${Math.round(progress * 100)}%`); updateProgressBar(progress); }); // Load the core and wasm files await ffmpeg.load({ coreURL: 'https://unpkg.com/@ffmpeg/core@0.12.4/dist/umd/ffmpeg-core.js', wasmURL: 'https://unpkg.com/@ffmpeg/core@0.12.4/dist/umd/ffmpeg-core.wasm', }); loaded = true; console.log('FFmpeg loaded successfully'); } ``` ### 2. Load Video File into Virtual Filesystem ```javascript async function loadVideoFile(file) { await loadFFmpeg(); // Write file to ffmpeg's virtual filesystem await ffmpeg.writeFile('input.mp4', await fetchFile(file)); console.log('Video loaded into virtual filesystem'); } ``` ### 3. Convert Video to GIF ```javascript async function convertToGIF(inputFile, width = 480, fps = 10) { await loadVideoFile(inputFile); // Two-pass palette generation for best quality // Pass 1: Generate palette await ffmpeg.exec([ '-i', 'input.mp4', '-vf', `fps=${fps},scale=${width}:-1:flags=lanczos,palettegen`, 'palette.png' ]); // Pass 2: Use palette to create GIF await ffmpeg.exec([ '-i', 'input.mp4', '-i', 'palette.png', '-filter_complex', `fps=${fps},scale=${width}:-1:flags=lanczos[x];[x][1:v]paletteuse`, 'output.gif' ]); // Read the output file const data = await ffmpeg.readFile('output.gif'); return new Blob([data.buffer], { type: 'image/gif' }); } ``` ### 4. Convert Video Format ```javascript async function convertFormat(inputFile, outputFormat = 'mp4') { await loadVideoFile(inputFile); const outputFile = `output.${outputFormat}`; const formatConfigs = { mp4: ['-c:v', 'libx264', '-c:a', 'aac'], webm: ['-c:v', 'libvpx-vp9', '-c:a', 'libopus'], mkv: ['-c:v', 'libx264', '-c:a', 'aac'], mov: ['-c:v', 'libx264', '-c:a', 'aac'], avi: ['-c:v', 'libx264', '-c:a', 'aac'] }; await ffmpeg.exec([ '-i', 'input.mp4', ...formatConfigs[outputFormat], outputFile ]); const data = await ffmpeg.readFile(outputFile); return new Blob([data.buffer], { type: `video/${outputFormat}` }); } ``` ### 5. Compress Video with CRF ```javascript async function compressVideo(inputFile, crf = 23, preset = 'medium') { await loadVideoFile(inputFile); // CRF: 18 (near lossless) to 51 (maximum compression) // Preset: ultrafast, superfast, veryfast, faster, fast, medium, slow, slower, veryslow await ffmpeg.exec([ '-i', 'input.mp4', '-c:v', 'libx264', '-crf', crf.toString(), '-preset', preset, '-c:a', 'aac', 'output.mp4' ]); const data = await ffmpeg.readFile('output.mp4'); return new Blob([data.buffer], { type: 'video/mp4' }); } ``` ### 6. Trim Video ```javascript async function trimVideo(inputFile, startTime, endTime) { await loadVideoFile(inputFile); const duration = endTime - startTime; await ffmpeg.exec([ '-ss', startTime.toString(), '-i', 'input.mp4', '-t', duration.toString(), '-c', 'copy', // Stream copy for fast, lossless trim 'output.mp4' ]); const data = await ffmpeg.readFile('output.mp4'); return new Blob([data.buffer], { type: 'video/mp4' }); } ``` ### 7. Extract Audio ```javascript async function extractAudio(inputFile, format = 'mp3') { await loadVideoFile(inputFile); const outputFile = `output.${format}`; const audioConfigs = { mp3: ['-c:a', 'libmp3lame', '-q:a', '2'], aac: ['-c:a', 'aac', '-b:a', '192k'], wav: ['-c:a', 'pcm_s16le'], ogg: ['-c:a', 'libvorbis', '-q:a', '5'], flac: ['-c:a', 'flac'] }; await ffmpeg.exec([ '-i', 'input.mp4', '-vn', // No video ...audioConfigs[format], outputFile ]); const data = await ffmpeg.readFile(outputFile); return new Blob([data.buffer], { type: `audio/${format}` }); } ``` ### 8. Resize Video ```javascript async function resizeVideo(inputFile, width, height = -1) { await loadVideoFile(inputFile); // height = -1 maintains aspect ratio await ffmpeg.exec([ '-i', 'input.mp4', '-vf', `scale=${width}:${height}`, '-c:v', 'libx264', '-crf', '23', '-c:a', 'copy', 'output.mp4' ]); const data = await ffmpeg.readFile('output.mp4'); return new Blob([data.buffer], { type: 'video/mp4' }); } ``` ### 9. Change Video Speed ```javascript async function changeSpeed(inputFile, speedMultiplier) { await loadVideoFile(inputFile); const videoPTS = 1 / speedMultiplier; // Build atempo filter chain (each atempo can only do 0.5-2.0x) let atempoChain = ''; let remaining = speedMultiplier; while (remaining > 2.0) { atempoChain += 'atempo=2.0,'; remaining /= 2.0; } while (remaining < 0.5) { atempoChain += 'atempo=0.5,'; remaining /= 0.5; } atempoChain += `atempo=${remaining.toFixed(3)}`; await ffmpeg.exec([ '-i', 'input.mp4', '-filter:v', `setpts=${videoPTS}*PTS`, '-filter:a', atempoChain, '-c:v', 'libx264', '-crf', '23', 'output.mp4' ]); const data = await ffmpeg.readFile('output.mp4'); return new Blob([data.buffer], { type: 'video/mp4' }); } ``` ### 10. Rotate Video ```javascript async function rotateVideo(inputFile, rotation) { await loadVideoFile(inputFile); const rotations = { '90cw': 'transpose=1', '90ccw': 'transpose=2', '180': 'transpose=1,transpose=1', 'hflip': 'hflip', 'vflip': 'vflip', 'both': 'hflip,vflip' }; await ffmpeg.exec([ '-i', 'input.mp4', '-vf', rotations[rotation], '-c:a', 'copy', 'output.mp4' ]); const data = await ffmpeg.readFile('output.mp4'); return new Blob([data.buffer], { type: 'video/mp4' }); } ``` ### 11. Add Watermark/Logo ```javascript async function addWatermark(inputFile, logoFile, position = 'bottom-right', widthPercent = 15) { await loadVideoFile(inputFile); await ffmpeg.writeFile('logo.png', await fetchFile(logoFile)); const positions = { 'top-left': '10:10', 'top-right': 'W-w-10:10', 'bottom-left': '10:H-h-10', 'bottom-right': 'W-w-10:H-h-10', 'center': '(W-w)/2:(H-h)/2' }; const scaleFilter = `[1:v]scale=iw*${widthPercent/100}:-1[logo]`; const overlayFilter = `[0:v][logo]overlay=${positions[position]}`; await ffmpeg.exec([ '-i', 'input.mp4', '-i', 'logo.png', '-filter_complex', `${scaleFilter};${overlayFilter}`, '-c:a', 'copy', 'output.mp4' ]); const data = await ffmpeg.readFile('output.mp4'); return new Blob([data.buffer], { type: 'video/mp4' }); } ``` ### 12. Adjust Brightness/Contrast/Saturation ```javascript async function adjustColors(inputFile, brightness = 0, contrast = 1, saturation = 1, grayscale = false) { await loadVideoFile(inputFile); const sat = grayscale ? 0 : saturation; await ffmpeg.exec([ '-i', 'input.mp4',
GitHubで見る
この SKILL.md は非常に大きいため、SkillsMP では最初のセクションだけを表示しています。 GitHubで見る