get-video-info
Extract detailed technical information from video files, including resolution, duration, format, and codec data for analysis and processing.
Instructions
Get detailed information about a video file
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| videoPath | Yes | Path to the video file to analyze |
Implementation Reference
- src/mcp-ffmpeg.ts:366-462 (handler)The handler function executes the core logic: resolves video path, checks file existence, requests user permission, executes ffprobe to retrieve JSON metadata, parses it, and formats detailed information about format, duration, size, bitrate, and streams (video/audio codecs, resolution, framerate, etc.) into readable text.async ({ videoPath }) => { try { // Resolve the absolute path const absVideoPath = path.resolve(videoPath); // Check if file exists try { await fs.access(absVideoPath); } catch (error) { return { isError: true, content: [{ type: "text" as const, text: `Error: Video file not found at ${absVideoPath}` }] }; } // Format command for permission request const permissionMessage = `Analyze video file ${path.basename(absVideoPath)}`; // Ask for permission const permitted = await askPermission(permissionMessage); if (!permitted) { return { isError: true, content: [{ type: "text" as const, text: "Permission denied by user" }] }; } // Build FFprobe command to get video information in JSON format const command = `ffprobe -v quiet -print_format json -show_format -show_streams "${absVideoPath}"`; // Execute FFprobe command const { stdout, stderr } = await execAsync(command); // Parse the JSON output const videoInfo = JSON.parse(stdout); // Format the output in a readable way let formattedInfo = `Video Information for: ${path.basename(absVideoPath)}\n\n`; // Format information if (videoInfo.format) { formattedInfo += `Format: ${videoInfo.format.format_name}\n`; formattedInfo += `Duration: ${videoInfo.format.duration} seconds\n`; formattedInfo += `Size: ${(parseInt(videoInfo.format.size) / (1024 * 1024)).toFixed(2)} MB\n`; formattedInfo += `Bitrate: ${(parseInt(videoInfo.format.bit_rate) / 1000).toFixed(2)} kbps\n\n`; } // Stream information if (videoInfo.streams && videoInfo.streams.length > 0) { formattedInfo += `Streams:\n`; videoInfo.streams.forEach((stream: any, index: number) => { formattedInfo += `\nStream #${index} (${stream.codec_type}):\n`; if (stream.codec_type === 'video') { formattedInfo += ` Codec: ${stream.codec_name}\n`; formattedInfo += ` Resolution: ${stream.width}x${stream.height}\n`; formattedInfo += ` Frame rate: ${stream.r_frame_rate}\n`; if (stream.bit_rate) { formattedInfo += ` Bitrate: ${(parseInt(stream.bit_rate) / 1000).toFixed(2)} kbps\n`; } } else if (stream.codec_type === 'audio') { formattedInfo += ` Codec: ${stream.codec_name}\n`; formattedInfo += ` Sample rate: ${stream.sample_rate} Hz\n`; formattedInfo += ` Channels: ${stream.channels}\n`; if (stream.bit_rate) { formattedInfo += ` Bitrate: ${(parseInt(stream.bit_rate) / 1000).toFixed(2)} kbps\n`; } } }); } return { content: [{ type: "text" as const, text: formattedInfo }] }; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); return { isError: true, content: [{ type: "text" as const, text: `Error getting video information: ${errorMessage}` }] }; } } );
- src/mcp-ffmpeg.ts:363-365 (schema)Zod schema defining the input parameter: videoPath (string) - path to the video file.{ videoPath: z.string().describe("Path to the video file to analyze") },
- src/mcp-ffmpeg.ts:360-362 (registration)Registration of the 'get-video-info' tool on the MCP server with name, description, schema, and handler.server.tool( "get-video-info", "Get detailed information about a video file",
- src/mcp-ffmpeg.ts:30-56 (helper)Helper function used by the tool to request user permission via desktop notification before analyzing the video.async function askPermission(action: string): Promise<boolean> { // Skip notification if DISABLE_NOTIFICATIONS is set if (process.env.DISABLE_NOTIFICATIONS === 'true') { console.log(`Auto-allowing action (notifications disabled): ${action}`); return true; } return new Promise((resolve) => { notifier.notify({ title: 'FFmpeg Processor Permission Request', message: `${action}`, wait: true, timeout: 60, actions: 'Allow', closeLabel: 'Deny' }, (err, response, metadata) => { if (err) { console.error('Error showing notification:', err); resolve(false); return; } const buttonPressed = metadata?.activationValue || response; resolve(buttonPressed !== 'Deny'); }); }); }