When implementing video trimming for many videos in your workflows, you'll likely want to execute FFmpeg commands programmatically using Node.js. If you need to trim multiple videos with the same parameters (for example, extracting a specific segment from each video in a folder), you can automate the process using a Node.js script.
Below is a sample Node.js script that processes all video files in a directory, trimming each one to a specific segment. This script leverages Node's file system capabilities and child processes to efficiently handle multiple video files.
#!/usr/bin/env node
/**
* Video Batch Trimming Tool
*
* This Node.js script automates FFmpeg to process multiple video files in a directory,
* trimming each one to the same time segment. It's useful for media workflows where
* you need to extract the same portion from multiple videos.
*/
const fs = require('fs');
const path = require('path');
const { exec } = require('child_process');
const { promisify } = require('util');
const execPromise = promisify(exec);
// Check if FFmpeg is installed
async function checkFFmpeg() {
try {
await execPromise('ffmpeg -version');
return true;
} catch (error) {
return false;
}
}
// Get all video files from directory
function getVideoFiles(directory) {
const videoExtensions = ['.mp4', '.avi', '.mov', '.mkv'];
return fs.readdirSync(directory)
.filter(file => {
const ext = path.extname(file).toLowerCase();
return videoExtensions.includes(ext);
})
.map(file => path.join(directory, file));
}
// Trim a video file
async function trimVideo(inputFile, outputFile, startTime, endTime) {
try {
await execPromise(`ffmpeg -i "${inputFile}" -ss ${startTime} -to ${endTime} -c copy "${outputFile}" -hide_banner -loglevel warning`);
return true;
} catch (error) {
console.error(`Error trimming: ${error.message}`);
return false;
}
}
// Main function
async function main() {
// Check arguments
const args = process.argv.slice(2);
if (args.length !== 4) {
console.log('Usage: node trim_videos.js [input_directory] [output_directory] [start_time] [end_time]');
console.log('Example: node trim_videos.js ./raw_videos ./trimmed_videos 00:00:30 00:01:45');
process.exit(1);
}
const inputDir = args[0];
const outputDir = args[1];
const startTime = args[2];
const endTime = args[3];
// Check if FFmpeg is installed
const ffmpegInstalled = await checkFFmpeg();
if (!ffmpegInstalled) {
console.error('Error: FFmpeg is not installed. Please install it first.');
process.exit(1);
}
// Create output directory if it doesn't exist
if (!fs.existsSync(outputDir)) {
fs.mkdirSync(outputDir, { recursive: true });
}
// Get all video files
const videoFiles = getVideoFiles(inputDir);
const totalFiles = videoFiles.length;
console.log(`Found ${totalFiles} video files to process.`);
// Process each video file
for (let i = 0; i < videoFiles.length; i++) {
const videoFile = videoFiles[i];
const filename = path.basename(videoFile);
const outputFile = path.join(outputDir, `trimmed_${filename}`);
console.log(`Processing file ${i + 1} of ${totalFiles}: ${filename}`);
const success = await trimVideo(videoFile, outputFile, startTime, endTime);
if (success) {
console.log(`Successfully trimmed: ${filename} -> ${outputFile}`);
} else {
console.log(`Error trimming: ${filename}`);
}
}
console.log(`All videos processed. Trimmed videos are in ${outputDir}`);
}
// Run the main function
main().catch(error => {
console.error('An unexpected error occurred:', error);
process.exit(1);
});
This Node.js script:
- Checks if FFmpeg is installed on the system
- Accepts the command-line arguments: input directory, output directory, start time, end time
- Creates the output directory if it doesn't exist
- Finds all video files with the same extensions (.mp4, .avi, .mov, .mkv)
- Processes each video file, showing progress information
- Trims each video using FFmpeg with the same parameters
- The script uses promises to handle asynchronous operations.
How to use the script:
- Save it as
trim_videos.js
- Run it with:
node trim_videos.js ./raw_videos ./trimmed_videos 00:00:30 00:01:45
Let's break down this line of code in detail:
await execPromise(`ffmpeg -i "${inputFile}" -ss ${startTime} -to ${endTime} -c copy "${outputFile}" -hide_banner -loglevel warning`);
This single line executes an FFmpeg command from Node.js to trim a video file. Here's what each part does:
-
await
- This keyword pauses execution of the function until the Promise returned byexecPromise()
resolves or rejects. It ensures the trimming operation completes before moving on. -
execPromise
- This is a promisified version of Node'sexec
function created earlier in the code usingpromisify(exec)
. It runs shell commands and returns a Promise instead of using callbacks. -
The backtick string
`...`
- This is a template literal in JavaScript that allows embedding variables and expressions using${variable}
syntax. -
The FFmpeg command itself:
ffmpeg
- The base command that invokes the FFmpeg program-
-i "${inputFile}"
- Specifies the input file path (in quotes to handle paths with spaces) -ss ${startTime}
- Sets the start time for trimming (e.g., "00:00:30")-to ${endTime}
- Sets the end time for trimming (e.g., "00:01:45")-
-c copy
- Uses stream copying mode, which preserves the original video/audio codecs without re-encoding (making it very fast) "${outputFile}"
- Specifies the output file path (in quotes for paths with spaces)-hide_banner
- Suppresses the FFmpeg copyright header and build information-
-loglevel warning
- Reduces the verbosity of FFmpeg's output to only show warnings and errors
When executed, this command will extract the portion of the video between startTime
and
endTime
and save it as a new file at outputFile
without re-encoding the video,
which significantly speeds up the process and maintains the original quality.
Conclusion
The script will help you streamline your video processing pipeline by handling the repetitive task of trimming multiple videos to the same duration. It maintains a consistent output format and provides progress tracking as it processes each file in your collection.