shinobi-video-synopsis
Version:
Create Video Synopsis from provided videos. Frames are extracted from each video provided and backgrounds are subtracted around moving elements and merged into a single video for quick review.
69 lines (68 loc) • 2.77 kB
JavaScript
const {
stripNamePng,
createBaseFolder,
} = require('./utils.js');
const fs = require('fs');
const gm = require('gm').subClass({imageMagick: true})
const flattenImage = (gmImageBuffer,filename) => {
return new Promise((resolve,reject) => {
gmImageBuffer.flatten().write(filename, (err) => {
resolve(err)
});
})
}
exports.mergeFramePairs = (options) => {
const engine = options.engine
const videoNames = options.videoNames || []
const subtractedBackgrounds = options.subtractedBackgroundsDirectory
const mergedFrames = options.mergedFramesDirectory
const firstFrameDirectory = options.firstFrameDirectory
const onFrameComplete = options.onFrameComplete || function(){}
const response = {
startedAt: new Date(),
videoNames: videoNames,
numberOfVideos: videoNames.length,
numberOfFrames: 0,
}
return new Promise(async (resolve,reject) => {
var backgroundPath = firstFrameDirectory + fs.readdirSync(firstFrameDirectory)[0]
var videoImages = {}
var videoImagePairs = []
videoNames.forEach((videoName) => {
const videoFolder = subtractedBackgrounds + videoName + '/'
videoImages[videoName] = fs.readdirSync(videoFolder)
videoImages[videoName].forEach((filename) => {
const n = stripNamePng(filename)
if(!videoImagePairs[n])videoImagePairs[n] = []
videoImagePairs[n].push(videoFolder + filename)
})
})
if(videoImagePairs.length > 0){
for (var i = 0; i < videoImagePairs.length; i++) {
const pair = videoImagePairs[i]
var newImage = gm()
.in('-geometry', '+0+0')
.in(backgroundPath)
for (var ii = 0; ii < pair.length; ii++) {
const imagePath = pair[ii]
newImage.in('-geometry', '+0+0').in(imagePath)
}
engine.logStderr(`${mergedFrames}${i}.jpg`)
const error = await flattenImage(newImage,`${mergedFrames}${i}.jpg`)
if(error){
engine.logStderr(error)
}
++response.numberOfFrames
engine.logStderr(i === videoImagePairs.length - 1,i, videoImagePairs.length - 1)
onFrameComplete(i,videoImagePairs.length)
if(i === videoImagePairs.length - 1 || engine.cancelledProcess){
response.endedAt = new Date()
response.timeSpent = response.endedAt - response.startedAt
resolve(response)
}
}
}else{
resolve(response)
}
})
}