video-nudity-detector
Version:
A package for detecting and blurring nudity in videos.
92 lines (81 loc) • 2.97 kB
JavaScript
const ffmpeg = require('fluent-ffmpeg');
const Pipe2Jpeg = require('pipe2jpeg');
const fs = require('fs');
const tf = require('@tensorflow/tfjs-node');
const { processPrediction } = require('./predictionProcessor');
const { blurVideo } = require('./utils');
const { loadModel } = require('./modelLoader');
const os = require('os');
/**
* Detect nudity in a video and optionally blur the detected nudity.
* @param {string} videoPath - The path to the input video.
* @param {string} outputPath - The path to the output video.
* @param {boolean} [blur=false] - Whether to blur nudity in the video. Defaults to false.
* @returns {Promise<boolean>} - Returns true if nudity is detected, otherwise false.
*/
// Set FFmpeg path for Windows
if (os.platform() === 'win32') {
ffmpeg.setFfmpegPath('C:\\ffmpeg\\bin\\ffmpeg.exe');
}
async function detectNudityInVideo(videoPath, outputPath='', blur = false) {
try {
// Validate input paths
if (!fs.existsSync(videoPath)) {
throw new Error(`Input video path does not exist: ${videoPath}`);
}
const pipe2jpeg = new Pipe2Jpeg();
let nudityDetected = false;
pipe2jpeg.on('data', async (jpegBuffer) => {
try {
const t = {};
t.buffer = tf.node.decodeJpeg(jpegBuffer, 3);
t.cast = tf.cast(t.buffer, 'float32');
t.input = tf.expandDims(t.cast, 0);
const model = await loadModel();
const [boxes, scores, classes] = await model.executeAsync(t.input, ['output1', 'output2', 'output3']);
const prediction = await processPrediction(boxes, scores, classes);
if (prediction.nude) {
nudityDetected = true;
if (blur) {
if (!fs.existsSync(outputPath)) {
throw new Error(`Output path does not exist: ${outputPath}`);
}
blurVideo(videoPath, outputPath, prediction.parts[0].box);
}
}
tf.dispose([boxes, scores, classes]);
} catch (err) {
console.error('Error processing JPEG buffer:', err);
}
});
pipe2jpeg.on('error', (err) => {
console.error('pipe2jpeg error:', err);
});
await new Promise((resolve, reject) => {
ffmpeg(videoPath)
.outputOptions([
'-loglevel quiet',
'-an', // Remove audio
'-c:v mjpeg', // Output as MJPEG
'-pix_fmt yuvj422p', // Set pixel format
'-f image2pipe',
])
.pipe(pipe2jpeg, { end: true })
.on('error', (err) => {
console.error('ffmpeg error:', err);
reject(err);
})
.on('end', () => {
console.log('ffmpeg processing finished');
resolve();
});
});
return nudityDetected;
} catch (err) {
console.error('Error in detectNudityInVideo:', err);
throw err;
}
}
module.exports = {
detectNudityInVideo,
};