Skip to main content
Glama

convert_video

Convert video files between formats like MP4, AVI, MOV, WMV, MKV, WEBM, and M4V. Adjust quality, resolution, bitrate, and frame rate for optimized playback across devices.

Instructions

将视频文件转换为指定格式。支持MP4、AVI、MOV、WMV、FLV、MKV、WEBM、M4V等主流格式之间的相互转换。

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
inputPathYes输入视频文件的完整路径
outputFormatYes目标输出格式
outputPathNo输出文件路径(可选,如果不指定则自动生成)
qualityNo视频质量预设(可选)
resolutionNo输出分辨率,格式为"宽度x高度",如"1920x1080"(可选)
videoBitrateNo视频码率,单位kbps(可选)
audioBitrateNo音频码率,单位kbps(可选)
frameRateNo输出帧率,单位fps(可选)
overwriteNo是否覆盖已存在的输出文件(默认false)

Implementation Reference

  • The primary handler function for the 'convert_video' MCP tool. It validates inputs, builds conversion options, calls FFmpegService.convertVideo, and returns detailed results including input/output info.
    export async function handleConvertVideo(args: ConvertVideoArgs): Promise<any> {
      const ffmpegService = FFmpegService.getInstance();
      const validator = ValidatorService.getInstance();
    
      try {
        // 验证输入文件
        const inputValidation = await validator.validateVideoFile(args.inputPath);
        if (!inputValidation.isValid) {
          return {
            success: false,
            error: `输入文件验证失败: ${inputValidation.error}`
          };
        }
    
        // 验证输出格式
        const formatValidation = validator.validateOutputFormat(args.outputFormat);
        if (!formatValidation.isValid) {
          return {
            success: false,
            error: formatValidation.error
          };
        }
    
        // 生成输出路径(如果未指定)
        let outputPath = args.outputPath;
        if (!outputPath) {
          const inputDir = path.dirname(args.inputPath);
          const inputName = path.parse(args.inputPath).name;
          outputPath = path.join(inputDir, `${inputName}_converted.${args.outputFormat}`);
        }
    
        // 验证输出路径
        const outputValidation = await validator.validateOutputPath(outputPath, args.overwrite || false);
        if (!outputValidation.isValid) {
          return {
            success: false,
            error: outputValidation.error
          };
        }
    
        // 构建转换选项
        const conversionOptions: any = {
          outputFormat: args.outputFormat as VideoFormat,
          overwrite: args.overwrite || false
        };
    
        // 添加可选参数
        if (args.quality) {
          conversionOptions.quality = args.quality;
        }
    
        if (args.resolution) {
          const resolutionValidation = validator.validateResolution(args.resolution);
          if (!resolutionValidation.isValid) {
            return {
              success: false,
              error: resolutionValidation.error
            };
          }
          conversionOptions.resolution = {
            width: resolutionValidation.width!,
            height: resolutionValidation.height!
          };
        }
    
        if (args.videoBitrate) {
          const bitrateValidation = validator.validateBitrate(args.videoBitrate, 'video');
          if (!bitrateValidation.isValid) {
            return {
              success: false,
              error: bitrateValidation.error
            };
          }
          conversionOptions.videoBitrate = args.videoBitrate;
        }
    
        if (args.audioBitrate) {
          const bitrateValidation = validator.validateBitrate(args.audioBitrate, 'audio');
          if (!bitrateValidation.isValid) {
            return {
              success: false,
              error: bitrateValidation.error
            };
          }
          conversionOptions.audioBitrate = args.audioBitrate;
        }
    
        if (args.frameRate) {
          const frameRateValidation = validator.validateFrameRate(args.frameRate);
          if (!frameRateValidation.isValid) {
            return {
              success: false,
              error: frameRateValidation.error
            };
          }
          conversionOptions.frameRate = args.frameRate;
        }
    
        // 获取输入文件信息
        const inputInfo = await ffmpegService.getVideoInfo(args.inputPath);
    
        // 执行转换
        console.log(`开始转换视频: ${args.inputPath} -> ${outputPath}`);
        
        const result = await ffmpegService.convertVideo(
          args.inputPath,
          outputPath,
          conversionOptions,
          (progress) => {
            console.log(`转换进度: ${progress.progress}% (${progress.status})`);
          }
        );
    
        // 获取输出文件信息
        const outputInfo = await ffmpegService.getVideoInfo(result);
    
        return {
          success: true,
          message: '视频转换完成',
          data: {
            inputPath: args.inputPath,
            outputPath: result,
            inputInfo: {
              format: inputInfo.format,
              size: `${(inputInfo.size / (1024 * 1024)).toFixed(2)} MB`,
              duration: `${Math.round(inputInfo.duration)} 秒`,
              resolution: inputInfo.video ? `${inputInfo.video.width}x${inputInfo.video.height}` : '未知',
              videoCodec: inputInfo.video?.codec || '未知',
              audioCodec: inputInfo.audio?.codec || '未知'
            },
            outputInfo: {
              format: outputInfo.format,
              size: `${(outputInfo.size / (1024 * 1024)).toFixed(2)} MB`,
              duration: `${Math.round(outputInfo.duration)} 秒`,
              resolution: outputInfo.video ? `${outputInfo.video.width}x${outputInfo.video.height}` : '未知',
              videoCodec: outputInfo.video?.codec || '未知',
              audioCodec: outputInfo.audio?.codec || '未知'
            },
            conversionOptions
          }
        };
    
      } catch (error: any) {
        console.error('视频转换失败:', error);
        return {
          success: false,
          error: `转换失败: ${error.message}`
        };
      }
    }
  • Tool specification for 'convert_video' including name, description, and detailed inputSchema for validation.
    export const convertVideoTool: Tool = {
      name: 'convert_video',
      description: '将视频文件转换为指定格式。支持MP4、AVI、MOV、WMV、FLV、MKV、WEBM、M4V等主流格式之间的相互转换。',
      inputSchema: {
        type: 'object',
        properties: {
          inputPath: {
            type: 'string',
            description: '输入视频文件的完整路径'
          },
          outputFormat: {
            type: 'string',
            enum: ['mp4', 'avi', 'mov', 'wmv', 'mkv', 'webm', 'm4v'],
            description: '目标输出格式'
          },
          outputPath: {
            type: 'string',
            description: '输出文件路径(可选,如果不指定则自动生成)'
          },
          quality: {
            type: 'string',
            enum: ['low', 'medium', 'high', 'ultra'],
            description: '视频质量预设(可选)'
          },
          resolution: {
            type: 'string',
            description: '输出分辨率,格式为"宽度x高度",如"1920x1080"(可选)'
          },
          videoBitrate: {
            type: 'number',
            description: '视频码率,单位kbps(可选)'
          },
          audioBitrate: {
            type: 'number',
            description: '音频码率,单位kbps(可选)'
          },
          frameRate: {
            type: 'number',
            description: '输出帧率,单位fps(可选)'
          },
          overwrite: {
            type: 'boolean',
            description: '是否覆盖已存在的输出文件(默认false)'
          }
        },
        required: ['inputPath', 'outputFormat']
      }
    };
  • Maps the 'convert_video' tool name to its handler function handleConvertVideo, used by the MCP server.
    export const toolHandlers = {
      convert_video: handleConvertVideo,
      get_video_info: handleGetVideoInfo,
      batch_convert: handleBatchConvert
    };
  • src/index.ts:64-117 (registration)
    MCP server request handler for tool calls, which dispatches to toolHandlers[name] including 'convert_video'.
    // 处理工具调用请求
    this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
      const { name, arguments: args } = request.params;
    
      try {
        // 检查工具是否存在
        if (!(name in toolHandlers)) {
          throw new McpError(
            ErrorCode.MethodNotFound,
            `未知的工具: ${name}`
          );
        }
    
        // 验证参数
        if (!args || typeof args !== 'object') {
          throw new McpError(
            ErrorCode.InvalidParams,
            '工具参数必须是一个对象'
          );
        }
    
        console.log(`正在执行工具: ${name}`);
        console.log('参数:', JSON.stringify(args, null, 2));
    
        // 调用对应的工具处理器
        const handler = toolHandlers[name as keyof typeof toolHandlers];
        const result = await handler(args as any);
    
        console.log(`工具 ${name} 执行完成`);
    
        return {
          content: [
            {
              type: 'text',
              text: JSON.stringify(result, null, 2)
            }
          ]
        };
    
      } catch (error: any) {
        console.error(`工具 ${name} 执行失败:`, error);
    
        // 如果是MCP错误,直接抛出
        if (error instanceof McpError) {
          throw error;
        }
    
        // 包装其他错误
        throw new McpError(
          ErrorCode.InternalError,
          `工具执行失败: ${error.message}`
        );
      }
    });
  • Core FFmpeg service method that performs the actual video format conversion, called by the tool handler.
    async convertVideo(
      inputPath: string,
      outputPath: string,
      options: ConversionOptions,
      onProgress?: (progress: ConversionProgress) => void
    ): Promise<string> {
      const taskId = this.generateTaskId();
      
      // 检查输入文件是否存在
      try {
        await fs.access(inputPath);
      } catch {
        throw new Error(`输入文件不存在: ${inputPath}`);
      }
    
      // 确保输出目录存在
      const outputDir = path.dirname(outputPath);
      await fs.mkdir(outputDir, { recursive: true });
    
      // 检查输出文件是否已存在
      if (!options.overwrite) {
        try {
          await fs.access(outputPath);
          throw new Error(`输出文件已存在: ${outputPath}`);
        } catch (err: any) {
          if (err.code !== 'ENOENT') {
            throw err;
          }
        }
      }
    
      return new Promise((resolve, reject) => {
        const progress: ConversionProgress = {
          taskId,
          inputPath,
          outputPath,
          progress: 0,
          status: 'pending',
          startTime: new Date(),
        };
    
        this.activeConversions.set(taskId, progress);
    
        let command = ffmpeg(inputPath);
    
        // 应用转换选项
        command = this.applyConversionOptions(command, options);
    
        command
          .output(outputPath)
          .on('start', (commandLine) => {
            console.log('开始转换:', commandLine);
            progress.status = 'processing';
            onProgress?.(progress);
          })
          .on('progress', (progressInfo) => {
            progress.progress = Math.round(progressInfo.percent || 0);
            onProgress?.(progress);
          })
          .on('end', async () => {
            try {
              // 验证输出文件是否完整
              await this.validateOutputFile(outputPath);
              
              progress.status = 'completed';
              progress.progress = 100;
              progress.endTime = new Date();
              this.activeConversions.delete(taskId);
              onProgress?.(progress);
              resolve(outputPath);
            } catch (validationError: any) {
              progress.status = 'failed';
              progress.error = `输出文件验证失败: ${validationError.message}`;
              progress.endTime = new Date();
              this.activeConversions.delete(taskId);
              onProgress?.(progress);
              reject(new Error(`转换完成但文件验证失败: ${validationError.message}`));
            }
          })
          .on('error', (err) => {
            progress.status = 'failed';
            progress.error = err.message;
            progress.endTime = new Date();
            this.activeConversions.delete(taskId);
            onProgress?.(progress);
            
            // 提供更详细的错误信息
            let errorMessage = `视频转换失败: ${err.message}`;
            
            // 针对常见错误提供解决建议
            if (err.message.includes('moov atom not found')) {
              errorMessage += '\n建议: 输入文件可能损坏或格式不完整,请检查源文件';
            } else if (err.message.includes('Invalid data found')) {
              errorMessage += '\n建议: 输入文件格式可能不受支持或文件已损坏';
            } else if (err.message.includes('No such file or directory')) {
              errorMessage += '\n建议: 请检查输入文件路径是否正确';
            } else if (err.message.includes('Permission denied')) {
              errorMessage += '\n建议: 请检查文件权限或确保输出目录可写';
            } else if (err.message.includes('codec not found')) {
              errorMessage += '\n建议: 缺少必要的编解码器,请检查FFmpeg安装';
            }
            
            reject(new Error(errorMessage));
          })
          .run();
      });
    }
Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/pickstar-2002/video-convert-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server