如何用FFmpeg先裁剪视频再添加多区域boxblur模糊?
解决FFmpeg裁剪+多区域boxblur模糊的命令组合问题
核心思路
把视频裁剪和多区域模糊合并到同一个filter_complex滤镜链中,避免生成中间文件,同时保证逻辑清晰。本质是先对原视频做全局裁剪,再基于裁剪后的视频依次生成每个模糊区域的图层,最后叠加到裁剪后的视频上。
正确的FFmpeg命令语法
假设你需要:
- 全局裁剪:宽
800、高600、起始位置(50,50) - 两个模糊区域:
- 区域1:
200x200,位置(100,100),模糊度10 - 区域2:
150x150,位置(300,200),模糊度8
- 区域1:
对应的完整filter_complex参数如下:
[0:v]crop=800:600:50:50[cropped]; [cropped]crop=200:200:100:100,boxblur=10[blur1]; [cropped]crop=150:150:300:200,boxblur=8[blur2]; [cropped][blur1]overlay=100:100[temp]; [temp][blur2]overlay=300:200[v]
语法拆解
[0:v]crop=800:600:50:50[cropped]:对原视频输入流做全局裁剪,输出裁剪后的视频流[cropped][cropped]crop=200:200:100:100,boxblur=10[blur1]:从裁剪后的视频中截出第一个区域,添加模糊效果,输出模糊图层[blur1][cropped]crop=150:150:300:200,boxblur=8[blur2]:同理生成第二个模糊图层[blur2][cropped][blur1]overlay=100:100[temp]:把[blur1]叠加到裁剪后的视频上,得到中间流[temp][temp][blur2]overlay=300:200[v]:把[blur2]叠加到中间流上,得到最终输出流[v]
Node.js中实现多区域模糊的完整代码
以下代码用child_process直接调用FFmpeg,支持动态配置任意数量的模糊区域:
const { spawn } = require('child_process'); const fs = require('fs'); const path = require('path'); // 基础配置 const inputVideoPath = './input.mp4'; const tempDir = './temp'; const progressLogPath = path.join(tempDir, 'process.log'); const outputVideoPath = path.join(tempDir, 'final-output.mp4'); // 裁剪参数(基于原视频坐标系) const cropConfig = { width: 800, height: 600, x: 50, y: 50 }; // 多区域模糊配置(基于裁剪后的视频坐标系) const blurRegions = [ { w: 200, h: 200, x: 100, y: 100, blur: 10 }, { w: 150, h: 150, x: 300, y: 200, blur: 8 }, { w: 100, h: 100, x: 500, y: 300, blur: 12 } ]; // 动态构建filter_complex字符串 const filterParts = []; // 第一步:全局裁剪 filterParts.push(`[0:v]crop=${cropConfig.width}:${cropConfig.height}:${cropConfig.x}:${cropConfig.y}[cropped]`); let currentStream = 'cropped'; blurRegions.forEach((region, idx) => { const blurStream = `blur${idx + 1}`; const tempStream = `temp${idx + 1}`; // 生成当前区域的模糊图层 filterParts.push(`[${currentStream}]crop=${region.w}:${region.h}:${region.x}:${region.y},boxblur=${region.blur}[${blurStream}]`); // 叠加到当前视频流上 filterParts.push(`[${currentStream}][${blurStream}]overlay=${region.x}:${region.y}[${tempStream}]`); // 更新当前流为叠加后的结果 currentStream = tempStream; }); // 最终输出流命名为[v] filterParts.push(`[${currentStream}]copy[v]`); const filterComplex = filterParts.join('; '); // 构建FFmpeg命令参数 const ffmpegArgs = [ '-i', inputVideoPath, '-filter_complex', filterComplex, '-map', '[v]', '-preset', 'fast', '-progress', progressLogPath, outputVideoPath ]; // 执行FFmpeg命令 const ffmpegProcess = spawn('ffmpeg', ffmpegArgs); // 日志输出 ffmpegProcess.stdout.on('data', (data) => console.log(`FFmpeg stdout: ${data}`)); ffmpegProcess.stderr.on('data', (data) => console.error(`FFmpeg stderr: ${data}`)); // 处理完成后读取视频文件 ffmpegProcess.on('close', (code) => { if (code === 0) { console.log('视频处理完成'); fs.readFile(outputVideoPath, (err, data) => { if (err) throw err; console.log('已读取处理后的视频文件,大小:', data.length, '字节'); // 后续业务逻辑 }); } else { console.error(`FFmpeg执行失败,退出码:${code}`); } });
注意事项
- 模糊区域的坐标是基于裁剪后的视频,不是原视频,因为全局裁剪是第一步
- 如果模糊区域有重叠,后叠加的区域会显示在最上层
boxblur参数可以细化为boxblur=luma_radius:luma_power:chroma_radius:chroma_power,比如boxblur=10:2会让模糊更柔和- 确保你的FFmpeg版本支持
boxblur滤镜(大多数默认版本都支持)
内容的提问来源于stack exchange,提问作者Radespy
相关产品推荐
相关产品推荐

