Add video.mjs
This commit is contained in:
commit
3d41bc9345
103
video.mjs
Normal file
103
video.mjs
Normal file
@ -0,0 +1,103 @@
|
||||
import ffmpeg from 'fluent-ffmpeg';
|
||||
import sharp from 'sharp';
|
||||
import chalk from 'chalk';
|
||||
import { exec } from 'child_process';
|
||||
import fs from 'fs';
|
||||
|
||||
const args = process.argv.slice(2);
|
||||
|
||||
const videoPathIndex = args.indexOf('--path');
|
||||
if (videoPathIndex === -1 || !args[videoPathIndex + 1]) {
|
||||
console.error('Please provide the video path using --path');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const fpsIndex = args.indexOf('--fps');
|
||||
const resolutionIndex = args.indexOf('--resolution');
|
||||
|
||||
const videoPath = args[videoPathIndex + 1];
|
||||
const frameRate = fpsIndex !== -1 ? parseInt(args[fpsIndex + 1]) || 10 : 10;
|
||||
const resolutionSetting = resolutionIndex !== -1 ? args[resolutionIndex + 1] : 'current';
|
||||
|
||||
console.log(`Made with <3 by Lisa Honkay (lisahonkay@gmail.com)`);
|
||||
console.log(`Processing video: ${videoPath}`);
|
||||
console.log(`Using FPS: ${frameRate}`);
|
||||
console.log(`Resolution: ${resolutionSetting}`);
|
||||
|
||||
const resolutionFilter = resolutionSetting === 'current' ? 'scale=iw:ih' : `scale=${resolutionSetting}`;
|
||||
|
||||
const framePathPattern = 'frames_%04d.png';
|
||||
ffmpeg(videoPath)
|
||||
.outputOptions('-vf', `fps=${frameRate},${resolutionFilter}`)
|
||||
.outputOptions('-q:v', '2')
|
||||
.saveToFile(framePathPattern)
|
||||
.on('end', () => {
|
||||
console.log('All frames processed.');
|
||||
processFrames();
|
||||
});
|
||||
|
||||
let frameQueue = [];
|
||||
|
||||
function processFrames() {
|
||||
exec(`ls ${framePathPattern.replace('%04d', '*')} | sort`, (error, stdout) => {
|
||||
if (error) {
|
||||
console.error('Error listing frames:', error);
|
||||
return;
|
||||
}
|
||||
frameQueue = stdout.split('\n').filter(file => file);
|
||||
console.log(`Loaded ${frameQueue.length} frames.`);
|
||||
playFrames();
|
||||
});
|
||||
}
|
||||
|
||||
function playFrames() {
|
||||
let index = 0;
|
||||
|
||||
function renderFrame() {
|
||||
if (index >= frameQueue.length) {
|
||||
console.log('Playback finished.');
|
||||
return;
|
||||
}
|
||||
|
||||
console.time('FrameRender');
|
||||
sharp(frameQueue[index])
|
||||
.toBuffer()
|
||||
.then(imageBuffer => sharp(imageBuffer).raw().toBuffer({ resolveWithObject: true }))
|
||||
.then(({ data, info }) => {
|
||||
console.timeEnd('FrameRender');
|
||||
|
||||
const terminalWidth = process.stdout.columns || 80;
|
||||
const terminalHeight = process.stdout.rows || 24;
|
||||
const aspectRatio = info.width / info.height;
|
||||
const targetWidth = Math.max(20, terminalWidth - 2);
|
||||
const targetHeight = Math.min(Math.floor(targetWidth / aspectRatio), terminalHeight - 2);
|
||||
|
||||
let output = '';
|
||||
for (let y = 0; y < targetHeight; y++) {
|
||||
for (let x = 0; x < targetWidth; x++) {
|
||||
const idx = (Math.floor(y * info.height / targetHeight) * info.width + Math.floor(x * info.width / targetWidth)) * 3;
|
||||
const r = data[idx];
|
||||
const g = data[idx + 1];
|
||||
const b = data[idx + 2];
|
||||
output += chalk.rgb(r, g, b)('█');
|
||||
}
|
||||
output += '\n';
|
||||
}
|
||||
|
||||
process.stdout.cursorTo(0, 0);
|
||||
process.stdout.write(output);
|
||||
|
||||
fs.unlink(frameQueue[index], err => {
|
||||
if (err) console.error('Error deleting frame:', err);
|
||||
});
|
||||
|
||||
index++;
|
||||
process.nextTick(renderFrame);
|
||||
})
|
||||
.catch(error => console.error('Error processing frame:', error));
|
||||
}
|
||||
|
||||
setTimeout(renderFrame, 4000);
|
||||
}
|
||||
|
||||
console.log('Extracting frames, this may take a moment...');
|
Loading…
x
Reference in New Issue
Block a user