Batch convert videos to AV1 codec
About 122 Words
Reads
Runtime:
Using FFmpeg alone
1 2 3
| ffmpeg -i "input.mp4" \ -vf "colorspace=iall=bt709:all=bt709:fast=1" \ -c:v libsvtav1 -crf 30 -preset 8 -c:a copy "output.mkv"
|
Parameter | Description |
---|
-i "input.mp4" | Specifies the input file, in this case "input.mp4" . |
-vf "colorspace=iall=bt709:all=bt709:fast=1" | Applies the colorspace video filter: |
| - iall=bt709 : Assume the input is in BT.709 color space (ignore metadata). |
| - all=bt709 : Convert the output to BT.709 color space. |
| - fast=1 : Enable fast mode for better performance with slight precision loss. |
-c:v libsvtav1 | Sets the video codec to libsvtav1 , which uses the SVT-AV1 encoder. |
-crf 30 | Constant Rate Factor: controls quality. Higher value = smaller size, lower quality (range typically 0–63). |
-preset 8 | Encoding speed preset; 8 usually means veryslow , yielding better compression at the cost of speed. |
-c:a copy | Copies the audio stream without re-encoding. |
"output.mkv" | Specifies the output file name as output.mkv . |
Batch Conversion Using Node.js
1
| node toAV1.js /dir-to-your-videos/
|
The converted AV1-encoded video file will be saved in the dist
folder under the original video directory after the process completes.
toAV1.js1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
| const fs = require("fs"); const path = require("path"); const { spawn } = require("child_process"); const trash = require("trash");
const inputDir = process.argv[2];
if (!inputDir || !fs.existsSync(inputDir)) { console.error("❌ Please provide a valid directory path."); process.exit(1); }
const VIDEO_EXTS = [".mp4", ".mov", ".mkv", ".avi", ".webm", ".m4v"];
const distDir = path.join(inputDir, "dist"); if (!fs.existsSync(distDir)) { fs.mkdirSync(distDir); }
async function encodeVideo(filePath, indexStr) { const fileName = path.basename(filePath); const baseName = path.parse(fileName).name; const outputPath = path.join(distDir, `${baseName}.mkv`);
return new Promise((resolve, reject) => { console.log( `🎬 Encoding ${indexStr} : ${fileName} → ${path.relative(inputDir, outputPath)}` );
const ffmpeg = spawn( "ffmpeg", [ "-i", filePath, "-vf", "colorspace=iall=bt709:all=bt709:fast=1", "-c:v", "libsvtav1", "-crf", "30", "-preset", "8", "-c:a", "copy", outputPath, ], { stdio: "inherit" } );
ffmpeg.on("close", async (code) => { if (code === 0) { console.log(`✅ ${indexStr} Encoding completed: ${fileName}`); try { await trash([filePath]); console.log(`🗑️ The original file has been moved to the trash: ${fileName}`); } catch (err) { console.error(`⚠️ Failed to move to trash: ${err.message}`); } resolve(); } else { console.error(`❌ Encoding failed: ${fileName}`); reject(new Error(`FFmpeg Exit Code: ${code}`)); } }); }); }
(async () => { const files = fs .readdirSync(inputDir) .filter((file) => VIDEO_EXTS.includes(path.extname(file).toLowerCase())) .map((file) => path.join(inputDir, file));
if (files.length === 0) { console.log("📭 Video File Not Found"); return; }
for (const [index, file] of files.entries()) { try { const indexStr = `${index}/${files.length}` await encodeVideo(file, indexStr); } catch (err) { console.error(`❌ Failed: ${err.message}`); } }
console.log("🏁 All Done!"); })();
|