Skip to content

Instantly share code, notes, and snippets.

@hlfshell
Created April 7, 2017 14:20
Show Gist options
  • Save hlfshell/cb46bbda507f2ed3e0d24a11d5da2a6c to your computer and use it in GitHub Desktop.
Save hlfshell/cb46bbda507f2ed3e0d24a11d5da2a6c to your computer and use it in GitHub Desktop.
Recording video with ffmpeg w/ node on Windows - record for T seconds, get all recording devices (parsed), and add an overlay
const spawn = require('child_process').spawn;
const exec = require('child_process').exec;
const terminate = require('terminate');
const ffmpeg = {
camera: "",
audio: "",
//Make sure to set the camera and audio target devices prior to calling this function. See
//devicesList() to get the device strings you'll need.
//Why exec over spawn? Normally I'd prefer spawn, but for some reason the
//process never dies under spawn and it refuses to listen to kill messages
//Also note that time, t, is in seconds, NOT MILLISECONDS.
//The camera takes a bit to turn on, and there's extra time after the recording to "process"
//the video, so take that into account
record: function(opts, cb){
if(typeof opts == "function"){
cb = opts;
opts = {};
} else if(typeof opts == "string"){
opts = { output: opts };
} else if(typeof opts == "number"){
opts = { duration: opts };
}
if(!opts.duration) opts.duration = 5;
if(!opts.output) opts.output = "out.mkv";
console.log('ffmpeg -t ' + opts.duration + '-f dshow -i video="' + this.camera + '":audio="' + this.audio + '" ' + opts.output);
var ffmpegRecord = exec('ffmpeg -t ' + opts.duration + ' -f dshow -video_size 1280x720 -rtbufsize 702000k -i video="' + this.camera + '":audio="' + this.audio + '" ' + opts.output);
// ffmpegRecord.stdout.on("data", data =>{
// console.log(">> ", data.toString());
// });
// ffmpegRecord.stderr.on("data", data =>{
// console.log("@@ ", data.toString());
// });
ffmpegRecord.on("close", code =>{
if(cb) cb();
});
},
//This returns an object with video and audio devices (there may be overlap)
//Use the device names returned exactly in the command above to trigger recording
devicesList: function(cb){
var ffmpegDevices = spawn("ffmpeg", ["-list_devices", "true", "-f", "dshow", "-i", "dummy"]);
var result = "";
ffmpegDevices.stdout.on("data", data =>{
result += data.toString();
});
ffmpegDevices.stderr.on("data", data =>{
result += data.toString();
});
ffmpegDevices.on("close", code =>{
//parse the response
devices = { video: [], audio: [] };
var resultVideos = result.split("DirectShow video devices")[1].split("DirectShow audio devices")[0];
var resultAudio = result.split("DirectShow audio devices")[1];
resultVideos = resultVideos.split('\n');
resultVideos.shift();
var deviceLines = [];
resultVideos.forEach((line, index)=>{
if(index % 2 == 0) deviceLines.push(line);
});
//Get rid of last line.
deviceLines.pop();
//All the names are after a '] "' and BEFORE a ' "\r'
deviceLines.forEach((line, index)=>{
devices.video.push(line.split('] "')[1].split('"\r')[0]);
});
//Now audio devices
resultAudio = resultAudio.split('\n');
resultAudio.shift();
var deviceLines = [];
resultAudio.forEach((line, index)=>{
if(index % 2 == 0) deviceLines.push(line);
});
deviceLines.pop();
deviceLines.forEach((line, index)=>{
devices.audio.push(line.split('] "')[1].split('"\r')[0]);
});
cb(devices);
});
},
//This will add an overlay over the entirety of the video, assuming its the same size. The 0:0 is the position. The -c:a uses the audio from the video track.
addOverlay: function(overlay, cb){
var ffmpegOverlay = exec('ffmpeg -i out.mp4 -i ' + overlay + ' -filter_complex "[0:v][1:v] overlay=0:0\'" -pix_fmt yuv420p -c:a copy out-overlay.mp4');
ffmpegOverlay.on("close", function(){
if(cb) cb();
});
}
}
module.exports = ffmpeg;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment