濾鏡(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'