目前QQ、剪影等都有照片制作成视频的功能。研究一段时间,始终不得要点。目前能实现的方式有h5动感影集、webv格式视频以及传统的ffmpeg进行照片合成剪辑。H5动感影集没办法导出成视频、webv对于视频的编辑依托于js。因此最终选择了利用ffmpeg来实现。由于语言使用的是C#,所以只能利用windows命令来调用。如果使用nodejs,可以使用封装好的方法fluent-ffmpeg。
对于ffmpeg的各类命令,可以在网上搜索出来。但是大都是满足某一场景,最好还是自己研究参数。进入ffmpeg的官网,里面对每一个属性都有说明和示例。http://ffmpeg.org/ffmpeg-all.html
本示例实现的是多张照片合成一个视频。照片实现的效果有渐入渐出、放大、移动、模糊处理,视频可以添加背景音乐。整体思路是,读取某一文件夹中的所有照片,逐个加入ffmpeg动效参数,然后拼接成一个长的命令字符串,使用Process命令行调用ffmpeg执行该命令。
具体效果如下:
核心代码如下:
public static string GetCommand(string[] files)
{//string[] files = Directory.GetFiles("d:/yb/ffmpeg/pic/", "*.jpg");StringBuilder sbFile = new StringBuilder();StringBuilder sbFilter = new StringBuilder();StringBuilder sbConcat = new StringBuilder();int w = 540;int h = 720;int second = 4;for (int i = 0; i < files.Length; i++){sbFile.Append(string.Format("-i {0} ", files[i]));Image img = Image.FromFile(files[i]);int th = img.Height * w / img.Width;int offset = (second - 1) * i;string fade = string.Empty;if (offset > 0){fade = string.Format(",fade =in:d = 1:alpha = 1,setpts = PTS - STARTPTS + {0} / TB", offset);}// 如果是宽图片,则需要添加模糊背景,采用横向滚动的方式if (th < h * 0.8){sbFilter.Append(string.Format(" [{0}]zoompan=d={1}:s={2}x{3}, boxblur=10{4}[bg{5}];", i, second * 25, w, h, fade, i));sbFilter.Append(string.Format("[{0}]zoompan=z='{1}':x='if(lte(on,-1),(iw-iw/zoom)/2,x+{2})':d={3}:s={4}x{5}{6}[v{7}];", i, 1.5, (1.5 - 1) * w / ((second+1) * 25), second * 25, w, th, fade, i));if (i > 0){sbConcat.Append(string.Format("[c{0}][bg{1}]overlay[cc{2}];", i - 1, i, i));sbConcat.Append(string.Format("[cc{0}][v{1}]overlay=y=(H-h)/2[c{2}];", i, i, i));}else{sbConcat.Append(string.Format("[bg0][v0]overlay=y=(H-h)/2[c0];"));}}else{//长图,假设比例合适//sbFilter.Append(string.Format(" [{0}]zoompan=d={1}, boxblur=10{2}[bg{3}];", i, second * 25, fade, i));//sbFilter.Append(string.Format("[{0}]zoompan=z='{1}':x='if(lte(on,-1),(iw-iw/zoom)/2,x+{2})':d={3}:s={5}x{6}{7}[v{8}];", i, 1.3, (1.3 - 1) * w / (second + 1), second * 25, w, th, fade, i));string[] effects = { "z='min(max(zoom,pzoom)+0.0015,1.5)'", "z='if(lte(zoom,1.0),1.5,max(1.001,zoom-0.0015))':y='ih*(1-max(zoom,pzoom))'", "z='1.5':x='if(lte(on,-1),(iw-iw/zoom)/2,x+1.25)'", "z='1.5':y='if(lte(on,-1),(ih-ih/zoom)/2,y+1.25)'" };// Random rn = new Random();string effect = effects[i%4];sbFilter.Append(string.Format(" [{0}] zoompan =d = {1}:{2}:s={3}x{4}{5}[{6}];", i, 125, effect, w, h, fade, i == 0 ? "c0" : "v" + i));if (i > 0){sbConcat.Append(string.Format("[c{0}][v{1}]overlay[c{2}];", i - 1, i, i));}}}sbFile.Append("-i d:/yb/ffmpeg/music/02.mp3 ");string concat = sbConcat.ToString();concat = concat.Substring(0, concat.LastIndexOf('['));string result = string.Format("-y {0} -filter_complex \"{1} {2}, format=yuv420p[v]\" -map \"[v]\" -map {3}:a -shortest -movflags +faststart {4}", sbFile.ToString(), sbFilter.ToString(), concat, files.Length, "d:/yb/ffmpeg/video/" + DateTime.Now.ToString("HHmmss") + ".mp4");return result;
}
重点参数解释:
模糊化效果
string.Format(" [{0}]zoompan=d={1}:s={2}x{3}, boxblur=10{4}[bg{5}];", i, second * 25, w, h, fade, i)
[0]:代表操作第一个图片;
[bg0]:代表将[0]第一个图片做成的视频命名为bg0;
zoompan:主要使用该属性来实现效果,d为总帧数,默认的fps为25帧,如果要设置一个5s的效果,那么d就可以设置为125;当然如果为了提高流畅度,可以这样设置一个5s的效果zoompan=d=300:fps=60; s代表第一个照片输出的尺寸,固定尺寸后可以放大再 进行移动。以上的命令字符串代表让第n个照片boxblue模糊后作为底层;
sbFilter.Append(string.Format(" [{0}]zoompan=d={1}:s={2}x{3}, boxblur=10{4}[bg{5}];", i, second * 25, w, h, fade, i));
sbFilter.Append(string.Format("[{0}]zoompan=z=’{1}’:x=‘if(lte(on,-1),(iw-iw/zoom)/2,x+{2})’:d={3}:s={4}x{5}{6}[v{7}];", i, 1.5, (1.5 - 1) * w / ((second+1) * 25), second * 25, w, th, fade, i));
let:小于等于;gte:大于等于。
将图片首先以背景模糊输出,然后在同一时间段覆盖上图片动效。效果如下:
sbConcat.Append(string.Format("[c{0}][bg{1}]overlay[cc{2}];", i - 1, i, i));
sbConcat.Append(string.Format("[cc{0}][v{1}]overlay=y=(H-h)/2[c{2}];", i, i, i));
合并视频,此处采用的是overlay覆盖合并,concat是顺序合并。将c0视频覆盖在bg0视频上,合并后的视频命名为cc0;将cc0视频合并到v0视频上,位置是垂直居中;
fade = string.Format(",fade =in:d = 1:alpha = 1,setpts = PTS - STARTPTS + {0} / TB", offset);
fade是渐入渐出的控制;in/out渐入/减出;d=1为渐变时间持续1s;setpts 是为了让第一个视频渐出的时间和第二个视频渐入的时间进行重叠,不至于突然变黑很突兀。setpts = PTS - STARTPTS + {0} / TB,offset是第二个视频渐入的时间,比如两个5s的视频,该值应该这是为4,在第4秒进行渐入;
代码可在此处下载https://download.csdn.net/download/wuwo333/12500865