contaigents
Version:
Modular AI Content Ecosystem with Audio Generation
168 lines (167 loc) ⢠8.04 kB
JavaScript
import { FFmpegTool } from '../services/tools/FFmpegTool.js';
import path from 'path';
import fs from 'fs/promises';
export async function testShotDetection() {
console.log('š¬ Testing Video Shot Detection with FFmpeg');
console.log('==================================================\n');
const baseDir = process.cwd();
const ffmpegTool = new FFmpegTool(baseDir);
const testVideo = 'demo/video/multishotvideo.mov';
// Check if test video exists
try {
await fs.access(path.join(baseDir, testVideo));
console.log(`ā
Test video found: ${testVideo}\n`);
}
catch (error) {
console.log(`ā Test video not found: ${testVideo}`);
console.log('Please ensure the test video exists before running this test.\n');
return;
}
// Test 1: Detect shots and output timestamps
console.log('š Test 1: Shot Detection - Timestamps Output');
console.log('šÆ Detecting shot boundaries and saving timestamps...');
try {
const timestampsResult = await ffmpegTool.execute({
operation: 'detect_shots',
input_file: testVideo,
output_file: 'demo/shot_timestamps.txt',
scene_threshold: '0.3',
output_format: 'timestamps'
});
if (timestampsResult.success) {
console.log('ā
Timestamps detection completed!');
console.log(`š Output: ${timestampsResult.data?.output_file}`);
console.log(`ā±ļø Execution time: ${timestampsResult.data?.execution_time}ms\n`);
// Try to read and display the first few timestamps
try {
const timestampsContent = await fs.readFile(path.join(baseDir, 'demo/shot_timestamps.txt'), 'utf-8');
const timestamps = timestampsContent.trim().split('\n').filter(line => line.trim());
console.log(`šÆ Found ${timestamps.length} shot boundaries:`);
timestamps.slice(0, 10).forEach((timestamp, index) => {
console.log(` ${index + 1}. ${parseFloat(timestamp).toFixed(2)}s`);
});
if (timestamps.length > 10) {
console.log(` ... and ${timestamps.length - 10} more\n`);
}
else {
console.log('');
}
}
catch (readError) {
console.log('š Timestamps file created but could not read content\n');
}
}
else {
console.log(`ā Timestamps detection failed: ${timestampsResult.error}\n`);
}
}
catch (error) {
console.log(`ā Test 1 failed: ${error.message}\n`);
}
// Test 2: Detect shots with different threshold
console.log('š Test 2: Shot Detection - Lower Threshold (More Sensitive)');
console.log('šÆ Using lower threshold (0.1) to detect more subtle changes...');
try {
const sensitiveResult = await ffmpegTool.execute({
operation: 'detect_shots',
input_file: testVideo,
output_file: 'demo/shot_timestamps_sensitive.txt',
scene_threshold: '0.1',
output_format: 'timestamps'
});
if (sensitiveResult.success) {
console.log('ā
Sensitive detection completed!');
console.log(`š Output: ${sensitiveResult.data?.output_file}`);
console.log(`ā±ļø Execution time: ${sensitiveResult.data?.execution_time}ms\n`);
}
else {
console.log(`ā Sensitive detection failed: ${sensitiveResult.error}\n`);
}
}
catch (error) {
console.log(`ā Test 2 failed: ${error.message}\n`);
}
// Test 3: Metadata output
console.log('š Test 3: Shot Detection - Metadata Output');
console.log('šÆ Generating detailed metadata about shot boundaries...');
try {
const metadataResult = await ffmpegTool.execute({
operation: 'detect_shots',
input_file: testVideo,
output_file: 'demo/shot_metadata.txt',
scene_threshold: '0.3',
output_format: 'metadata'
});
if (metadataResult.success) {
console.log('ā
Metadata detection completed!');
console.log(`š Output: ${metadataResult.data?.output_file}`);
console.log(`ā±ļø Execution time: ${metadataResult.data?.execution_time}ms\n`);
}
else {
console.log(`ā Metadata detection failed: ${metadataResult.error}\n`);
}
}
catch (error) {
console.log(`ā Test 3 failed: ${error.message}\n`);
}
// Test 4: Demonstrate splitting workflow
console.log('š Test 4: Complete Splitting Workflow');
console.log('ļæ½ Demonstrating how to split video using detected timestamps...');
try {
// Read the timestamps we detected earlier
const timestampsContent = await fs.readFile(path.join(baseDir, 'demo/shot_timestamps.txt'), 'utf-8');
const timestamps = timestampsContent.trim().split('\n').filter(line => line.trim()).map(t => parseFloat(t));
if (timestamps.length > 0) {
console.log(`š Found ${timestamps.length} shot boundaries, creating ${timestamps.length + 1} segments:`);
// Create first segment (start to first boundary)
const firstSegmentResult = await ffmpegTool.execute({
operation: 'trim',
input_file: testVideo,
output_file: 'demo/segment_001.mp4',
start_time: '0',
end_time: timestamps[0].toString()
});
if (firstSegmentResult.success) {
console.log(`ā
Segment 1: 0s ā ${timestamps[0].toFixed(2)}s`);
}
// Create middle segments
for (let i = 0; i < timestamps.length - 1; i++) {
const segmentResult = await ffmpegTool.execute({
operation: 'trim',
input_file: testVideo,
output_file: `demo/segment_${String(i + 2).padStart(3, '0')}.mp4`,
start_time: timestamps[i].toString(),
end_time: timestamps[i + 1].toString()
});
if (segmentResult.success) {
console.log(`ā
Segment ${i + 2}: ${timestamps[i].toFixed(2)}s ā ${timestamps[i + 1].toFixed(2)}s`);
}
}
console.log('š¬ Video successfully split into segments based on shot detection!\n');
}
}
catch (error) {
console.log(`ā Splitting workflow failed: ${error.message}\n`);
}
console.log('ļæ½š Shot Detection Tests Completed!');
console.log('\nš” Usage Tips:');
console.log(' ⢠Lower scene_threshold (0.1-0.2) = More sensitive, detects subtle changes');
console.log(' ⢠Higher scene_threshold (0.4-0.6) = Less sensitive, only major scene changes');
console.log(' ⢠timestamps format = Simple list of shot boundary times');
console.log(' ⢠metadata format = Detailed information about each shot');
console.log('\nš§ Complete Workflow for Video Splitting:');
console.log(' 1. detect_shots ā get timestamps.txt');
console.log(' 2. Read timestamps from file');
console.log(' 3. Use trim operation for each segment');
console.log(' 4. Result: Individual video files for each shot');
console.log('\nšÆ Integration Examples:');
console.log(' ⢠Auto-segment content for video editing workflows');
console.log(' ⢠Analyze video structure for content summarization');
console.log(' ⢠Create highlight reels by detecting scene changes');
console.log(' ⢠Generate video thumbnails at shot boundaries');
console.log(' ⢠Build automated video processing pipelines');
}
// Run the test if this file is executed directly
if (import.meta.url === `file://${process.argv[1]}`) {
testShotDetection().catch(console.error);
}