滤镜(filter)详细介绍参考官方文档,主要使用了libavfilter库进行音视频处理。
常用的滤镜功能,像图像加水印/字幕、去logo、图形旋转缩放等,但滤镜不仅仅包括视频部分,还包括音频处理的,像变声变调、声场控制(重低音/留声机/摇滚等效果)。
下面介绍滤镜类中常用命令,该博文长期更新。
Key1. 去除水印
该需求实现分为两步:step1.确认水印位置和效果;step2.位置和效果反复调整合适了,再转码。
step1. ffplay -i Tuesday00.mp4 -vf delogo=x=30:y=40:w=350:h=60:show=1,scale=640x480
其中,参数"-vf"指视频的滤镜处理(video filter),后面跟参数(水印区域:x/y/w/h,是否圈住区域:show,缩放处理:scale),注意各子处理模块间(delogo与scale)用"逗号"分隔,子处理模块内的各参数用“冒号”分割。
如果不想缩放处理,但是视频w/h太大了,以至于超出了显示器显示区域的范围,可以控制播放窗口的大小。使用-x或-y指定播放窗口的宽或高。
step2. ffmpeg -i Tuesday00.mp4 -vf delogo=x=30:y=40:w=350:h=60:show=0,scale=640x480 -c:v libx264 -c:a copy output.mp4
尝试了多次,确定好区域后,可以进行转码了。注意一点,show要关掉(show=0,否则delogo区域出现绿框),video转码参数(-c:v libx264)可以不带,系统默认使用x264编码。
Key2. 去除某个时间段的水印
在上面Key2.step2命令中增加时间控制信息: -ss 5 -t 10(从第5秒开始,持续10s,共10秒钟长的视频)
ffmpeg -i Tuesday00.mp4 -ss 5 -t 10 -vf delogo=x=30:y=40:w=350:h=60:show=0,scale=640x480 -c:v libx264 -c:a copy output.mp4
注意:“-ss 5 -t 10”参数,对于ffmpeg来说,放在input_file前和后貌似没什么差别,都是转成10秒钟长度的视频文件。
另外一点增强型需求:假如有多个时间段需要去除水印,例如,第0-15秒之间某个区域需要去除,还有20-30秒之间的另外一个区域水印去除。
这个需求的方法还没找到,有知道的同学们麻烦告知一下。目前我使用了比较笨的方法,就是多次转码。
Key3. 同时去除多个区域的水印
在Key1中的step1命令中再增加一个delogo参数,即命令为:ffplay -i Tuesday00.mp4 -vf delogo=x=30:y=40:w=350:h=60:show=1,delogo=x=230:y=240:w=350:h=60:show=1 -y 300
确定好位置后,再用ffmpeg转码:ffmpeg -i Tuesday00.mp4 -vf delogo=x=30:y=40:w=350:h=60:show=1,delogo=x=230:y=240:w=350:h=60:show=1 output.mp4
Key4. 添加文字水印
与Key1类型,先用ffplay确认位置和效果,再用ffmpeg进行滤镜+转码。
step1. ffplay -i Tuesday00.mp4 -vf "drawtext=fontfile=msyh.ttc:text='Hello,world':x=30:y=60:fontsize=120:fontcolor=yellow"
注意,本地的字体文件(fontfile=msyh.ttc)可以不指定,找不到了用系统使用默认的。
step2. ffmpeg -i Tuesday00.mp4 -vf "drawtext=fontfile=msyh.ttc:text='Hello,world':x=30:y=60:fontsize=120:fontcolor=yellow" output.mp4
Key5. 给视频添加封面
其实是将指定图片作为视频的前几帧(只指定为第一帧时,有的平台可能不使用首帧作为缩略图则达不到效果)。核心思想是,图片转为包含若干帧图像的视频流,再跟主视频合并。
step1. ffmpeg.exe -r 25 -loop 1 -i img.jpg -vcodec libx264 -s 720x1280 -frames 25 -r 25 img_25f.mp4
其中,参数"-r 25 -loop 1"代表以25fps速度反复读取输入文件。参数"-frames 25"指只编码25帧,"-r 25"指定输出文件帧率为25fps。那么命令结果是,生成了1秒钟的视频文件(用工具分析文件,会发现:第一帧的关键帧size较大,后面的B/P帧非常小,只有几十Bytes大小,因为h264编码p或b帧时,使用的帧间编码技术,参考了第一帧I帧内容编码而来)。
step2. ffmpeg -f concat -i concat.txt -c copy output.mp4
其中,参数"-f concat"指视频合并;参数"-i concat.txt"指定输入文件列表,如下格式:
file input1.mp4
file input2.mp4
注意:如果合并时出现如下异常:[concat @ 0x2690e00] DTS 4079 < 8156 out of order0:02:43.12 bitrate= 676.2kbits/s
可以这样做:把两个mp4视频分别抽取出裸流,保存为两个独立的h264文件,再合并,这样就不会出现合并时的dts异常问题了(因为裸码流根本没有pts/dts)。
抽取出裸码流命令为:命令为:ffmpeg -i input.mp4 -c:v copy -an output.mp4
Key6. 将视频放在黑板上
另外一种说法是,将视频放在幕布上。
ffmpeg -i input.mp4 -vf pad=720:1280:100:200:black output.mp4
其中,参数"pad=720:1280:100:200"指定了幕布的宽/高以及视频(左上角)放置在该幕布中的位置(如果放在幕布左上角,参数为pad=720:1280:0:0),参数"black"指定了幕布的颜色。
另外一点需注意,输入视频size不能超过了幕布size,否则出错(Padded dimensions cannot be smaller than input dimensions.),但允许视频(经过变换后)右下角坐标超过幕布右下角坐标。
Key7. 视频等比例缩放后置于幕布上
目标与上面的类似,但有一些差异:Key6中的视频宽度和高度可能都小于幕布size,导致使用滤镜后得到的视频,四个周边都有黑框,而本条目标是将视频宽度缩放到幕布的宽度,再贴到幕布上,留下只有上面和下面是黑色的电影效果。
ffmpeg -i input.mp4 -vf "scale=720:(ih*720/iw),pad=720:1280:0:(1280-(ih*720/iw))/2:black" -y output.mp4 // 将视频等比例缩放到720的宽度,再贴到幕布(720x1280)中央。
ffmpeg -i input.mp4 -vf "scale=720:(ih*ow/iw),pad=720:1280:0:(oh-(ih*ow/iw))/2:black" -y output.mp4 //上条命令的简写,其中iw、ih指输入(input.mp4文件)的宽高,ow、oh指(pad——幕布)输出的宽高。
注意一点,如果在视频在幕布上超出了幕布的宽或高,则视频在宽(x轴、水平方向)或高(y轴、垂直方向)方向上会自动居中对齐,因此参数"(oh-(ih*ow/iw))/2"用来手动指定垂直方向上居中对齐略有些复杂,可以也不用写这么复杂,例如直接写成"oh"或"-1",就会自动上下居中了。
Key8. 滚动的字幕
类似于点视台放的电视剧下面的流动广告或通知。
ffmpeg -i input.mp4 -vf "drawtext=text='李公公给老佛爷讲段子': y=10:x=(mod(5*n\,w+tw)-tw):fontsize=60:fontcolor=yellow:shadowy=10" -y output.mp4
其中,drawtext的参数"y=10:x=(mod(5*n\,w+tw)-tw)"为字幕(的首字)的位置:始终固定在同一个高度上,但水平方向上是移动的,n指第几帧图像,5*n指移动速度(5pix/f),符号“\”用于指示后面的特殊符号“,”,w/h指输入视频的宽高,tw指总字宽(fontsize控制,即字数x字体宽fontsize),mod指数学上的求余。因此,经计算后该position范围为[-tw, w],效果为:一排字从视频左端开始显现,到视频右边消失,之后再从左边显现,呈现出循环显示的特点。
参数"shadowy=10"指阴影在垂直方向上的偏移距离。
注意一点,中文字体的fontsize跟视频size是匹配的,但是英文字体不是匹配的。简单说来,如果视频宽为600,字体fontsize=60,那么中文字符串如果有10个字,则恰好铺满视频宽度,如果是英文字符串,则需要更多字才能铺满视频宽度。
Key9. 视频裁剪(crop)处理
该需求类似于,一张纸片或布,只需要中间的一部分(矩形区域),其他区域都裁掉不要。
ffmpeg -i input.mp4 -vf crop=1280:720:0:0 output.mp4
其中,crop的参数格式为w:h:x:y,w、h为输出视频的宽和高,x、y标记输入视频中的某点,将该点作为基准点,向右下进行裁剪得到输出视频。如果x y不写的话,默认居中剪切。
Key10. 添加居中字幕,字体缩小后再放大
先用ffplay验证效果,再使用ffmpeg转码(转码命令略,后续只给出ffplay的命令)。
ffplay -i input.mp4 -vf drawtext=text='hello\,world':x=\(w-text_w\)/2:y=\(h-text_h\)/2:fontsize=abs\(\(300\-2\*n\)\):fontcolor=yellow:fix_bounds=1
Key11. 四窗口画面,只使用两个窗口显示视频
ffplay -i Tuesday02.mp4 -vf "split [main][tmp]; [main] scale=iw/2:ih/2 [a]; [tmp] scale=iw/2:ih/2, pad=iw*2:ih*2:iw:0:black [b]; [b][a] overlay=0:H/2"
注意:参数"overlay=0:H/2",由于两个输入视频,不能使用iw或ih,因为不知道使用哪个的,而用大写的W/H表示第一个(主)的宽/高,小写的w/h表示第二个(次)的宽/高。
显示效果如下:
Key12. 16:9的视频方便手机竖屏播放,上下部分虚化
ffplay.exe -i dajiangdongqu_symphony.mp4 -vf "split[fg0][bg0];[bg0]scale=720:1280,boxblur=10:10[bg1];[fg0]scale=720:(720*ih/iw)[fg1];[bg1][fg1]overlay=0:(H-h)/2,setdar=9/16"
手机竖屏播放时,普通720p(1280x720)只会在屏幕中间显示,上下部分黑屏。如果想让上下的黑屏用虚化的效果调换掉,即变化后的视频分辨率近似为手机LCD分辨率,又能恰好铺满桌面而又不产生非等比例拉伸效果,即抖音上常见的竖屏视频效果。
需要说明几点:
1. bg1为最终的背景,即虚化后的图像,其先进行缩放到720*1280的scale操作,再进行虚化blur。
2. fg1为最终的前景,其由原始视频等比例缩放而来,例如:1920x1080的图形,缩放得到720*x的图形,如果不希望图像被被拉伸(即等比例缩放),那么可得出x=720*1080/1920,即720*ih/iw操作。
3. 目前手机LCD的分辨率,一般为9:16(例如720x1280,方便电影大片横屏播放),后来手机的刘海慢慢消失,宽高比例慢慢变成了9:18乃至9:20,但主流的高/宽比例仍是2左右,因此生成的视频的分辨率,最好接近这个比例。从抖音上下载的片子,目前看到的都是720x1280的尺寸。
4. setdar=9/16的目的,需要经过播放验证才能明白其中道理。虽然生成的片子是720x1280,但播放器播放时还可能参考显示比例(DisplayAspectRatio)这个参数(从技术角度上讲,该值在sps-vui中定义),一些播放器会根据这个参数来强制对图形进行拉伸处理。例如,解码后得到的图像为720x1280,如果DAR=16:9,则会再把本来竖着的图像压扁后再进行播放,这样的播放体验就不太好了。
Key13. 为视频添加图片水印
ffplay.exe -i djdq.mp4 -vf "movie=haha.jpg[wm];[in][wm] overlay=0:0"
几点说明:
1. movie=haha.jpg[wm] //指定图片水印路径,wm——WaterMark
2. [in][wm] //输入的片源(即djdq.mp4),以及水印(由前面指定的,即movie=haha.jpg)
3. overlay=0:0 //图片水印(左上角)放在视频中的位置,0:0指左上角,W/2:H/2指视频中间位置上开始叠加图片
另外一种方式,在右下角加水印:ffplay -i input.mp4 -i logo.png -filter_complex 'overlay=main_w-overlay_w-10:main_h-overlay_h-10'