FFmpeg音视频处理解决方案_ffmpeg 处理视频
核心组件:
ffmpeg:主要的命令行工具,用于转码、转换格式等
ffprobe:用于分析多媒体文件信息的工具
ffplay:简单的媒体播放器
主要功能:
✅ 格式转换(转码)
✅ 视频裁剪、合并
✅ 调整分辨率、比特率
✅ 提取音频/视频
✅ 截图/生成缩略图
✅ 添加水印、字幕
✅ 流媒体处理
一、安装FFmpeg
Windows:
- 访问 https://ffmpeg.org/download.html
- 下载Windows版本,解压到指定目录
- 将bin目录添加到系统PATH环境变量
Linux (Ubuntu/Debian):
sudo apt updatesudo apt install ffmpeg
macOS:
brew install ffmpeg
二、项目配置
在application.properties或application.yml中配置FFmpeg路径:
# application.propertiesffmpeg.path=/usr/bin/ffmpeg # Linux/Mac# 或ffmpeg.path=C:\\\\ffmpeg\\\\bin\\\\ffmpeg.exe # Windows
三、依赖注入与异步处理
@Service@Slf4jpublic class VideoTranscodingService { @Value(\"${ffmpeg.path}\") private String ffmpegPath; // 注入FFmpeg路径 @Async // 异步执行,避免阻塞请求 public void transcodeVideo(Long materialId, String inputPath) { // 转码逻辑 }}
核心转码方法
- ProcessBuilder
- Process
private void transcodeToResolution(String inputPath, String outputPath, String resolution) throws Exception { List<String> command = new ArrayList<>(); command.add(ffmpegPath); command.add(\"-i\"); command.add(inputPath); // 输入文件 command.add(\"-s\"); command.add(resolution); // 目标分辨率 command.add(\"-c:v\"); command.add(\"libx264\"); // 视频编码器 command.add(\"-crf\"); command.add(\"23\"); // 视频质量 command.add(\"-c:a\"); command.add(\"aac\"); // 音频编码器 command.add(\"-b:a\"); command.add(\"128k\"); // 音频比特率 command.add(outputPath); // 输出文件 ProcessBuilder builder = new ProcessBuilder(command); Process process = builder.start(); int exitCode = process.waitFor(); // 等待转码完成 if (exitCode != 0) { throw new RuntimeException(\"FFmpeg转码失败,退出码: \" + exitCode); }}
四、控制器中上传文件视频
@RestController@RequestMapping(\"/api/video\")public class VideoController { @Autowired private VideoTranscodingService transcodingService; @PostMapping(\"/upload\") public ResponseEntity<String> uploadVideo(@RequestParam(\"file\") MultipartFile file, @RequestParam Long materialId) { try { // 1. 保存上传的文件 String uploadDir = \"uploads/\"; String originalFilename = file.getOriginalFilename(); String filePath = uploadDir + UUID.randomUUID() + \"_\" + originalFilename; File dest = new File(filePath); file.transferTo(dest); // 2. 异步启动转码 transcodingService.transcodeVideo(materialId, filePath); return ResponseEntity.ok(\"视频上传成功,转码中...\"); } catch (Exception e) { return ResponseEntity.status(500).body(\"上传失败: \" + e.getMessage()); } }}
@GetMapping(\"/status/{materialId}\")public ResponseEntity<Map<String, Object>> getTranscodingStatus(@PathVariable Long materialId) { CourseMaterial material = materialRepository.findById(materialId).orElse(null); if (material == null) { return ResponseEntity.notFound().build(); } Map<String, Object> response = new HashMap<>(); response.put(\"status\", material.getTranscodingStatus()); response.put(\"filePath\", material.getFilePath()); response.put(\"duration\", material.getDuration()); return ResponseEntity.ok(response);}