FFmpeg command line tool(Android中使用FFmpeg命令行)
- 官網地址:ffmpeg.org/
- Android端,不想編譯,可以直接使用ffmpeg-android-java
關于轉碼:
網絡限制了視頻傳輸的帶寬。由于帶寬限制,這就要求我們在傳輸之前通過實時視頻轉碼將視頻數據轉換成帶寬效率更高的格式。轉碼的意義在于可以在視頻質量幾乎不損失的前提下節省大量的網絡帶寬。FFmpeg主要就是做轉碼這件事情。
FFmpeg轉碼流程示意圖:
_______ ______________ | | | | | input | demuxer | encoded data | decoder | file | ---------> | packets | -----+ |_______| |______________| |v_________| || decoded || frames ||_________|________ ______________ | | | | | | | output | <-------- | encoded data | <----+ | file | muxer | packets | encoder |________| |______________| 復制代碼基本命令解釋:
-
-y => 覆蓋輸出
-
-i => 輸入源頭,比如一個視頻的絕對路徑:/sdcard/....,輸出我們也是寫絕對路徑
-
-f => 輸出格式,如果省略就取輸出錄制的后綴名為輸出格式,比如輸入mp4格式:-y -i input -f mp4 output
-
-c:v => 針對視頻流的編碼 ,等介于-vcodec
-
-c:a => 針對音頻流的編碼,等介于-acodec
-
-c:v h264 => 指定視頻流h264編碼方式,有時候也寫成libx264,FFmpeg也可以識別
-
-c:a aac => 指定音頻流aac編碼方式
-
copy => 不編碼,如-c:v copy就是對視頻流不編碼,注意:如果加了不必要的編碼操作,會影響執行效率。
-
-an => 禁用音頻
-
-vn => 禁用視頻
-
-x264-params keyint=10 => 為視頻設置關鍵幀,每隔10幀生成一個關鍵幀
-
-crf => 動態碼率,壓縮效果佳,不是一味追求體積,畫質佳,H.264的CRF數字范圍在0~51,23是默認值。
-
-b:v => 靜態碼率,壓縮效率比較爆炸,一味控制體積
-
-filter_complex => 濾鏡,簡單濾鏡是-vf,常用的有變速濾鏡,水印濾鏡等
-
-map => 可以理解為流的過濾器:
- -map[0:v] 就是選擇第一輸入源的視頻流,流向輸出。
- -map[1:a] 就是選擇第二輸入源的音頻流,流向輸出。
-
-max_muxing_queue_size=>如果視頻比較大,需要指定這個值比較大(比如9999),否則程序執行會中斷。
-
-fps 幀率
-
-vframes 幀數
-
-r幀率
-
-preset
- preset和crd參數一樣,會影響壓縮效果,preset可以很大程度影響程序的執行速度,每條命令都可以加,一般加載命令尾部,output之前:
preset描述 ultrafast 編碼速度最快 ,壓縮效果最差 superfast ··· veryfast ··· faster ··· fast ··· medium – default preset slow ··· slower ··· veryslow 編碼速度最慢 ,壓縮效果從最好 -
h264編碼相關,涉及CRF,Preset等,Encode/H.264
合并多個視頻
-
使用concat協議:把視頻轉成ts流,contact合并多個ts生成視頻:
- ts流涉及到一個參數:h264_mp4toannexb
Concat protocol
視頻音頻流變速
- How to speed up / slow down a video 視頻速度變成原來的兩倍:
ffmpeg -i input.mkv -filter:v "setpts=0.5*PTS" output.mkv 音頻速度變成原來的兩倍: ffmpeg -i input.mkv -filter:a "atempo=2.0" -vn output.mkv 如果是音頻和視頻一致加速兩杯: 這里會涉及到濾鏡的概念和-map指令的使用,輸入有多個流,我們就可能用到-map指定: 假設有音頻流和視頻流:
如果只有視頻流:
-y -i input -vf [0:v]setpts=" + 1d/speed + "*PTS" output 復制代碼裁剪時長
- -ss 裁剪開始時間,單位秒
- -t 需要裁剪多長時間,單位秒 從第一秒,裁剪3秒視頻生成新視頻 -y -i input.mp4 -s 1 -t 3 ouput.mp4
生成縮率圖
- 這里涉及兩個指令-vframes ,-fps;
- -vframes是幀數
- -fps是幀率,(frames per second),時間(秒)fps=vframs -生成某個時刻的縮率圖: ffmpeg -i input.flv -ss 00:00:14.435 -vframes 1 out.png 每秒生成一張圖片,命名為thumb1.png,thumb2.png,thumb3.png.....(輸出是絕對路徑) ffmpeg -i input -vf fps=1 thumb%d.png 每秒生成兩張圖片,命名為thumb001.png,thumb002.png,thumb003.png,-s指令來指定分辨率100100..... ffmpeg -i input -s 100X100 -vf fps=2 thumb%3d.png
圖片生成幻燈片(多圖合成視頻)
- 如何輸出的圖片是規則的,img001png,img002.pmg,img003.pn... 我生成每秒10幀的幻燈片,默認是25幀每秒: ffmpeg -framerate 10 -i img%03d.png output.mp4 注意:如果生成是h264的視頻,加上 -vf format=yuv420p 或者 -pix_fmt yuv420p可以防止某些播放器無法解碼視頻。 生成幻燈片相關
- 如果文件名是不規則,也可以使用concat協議:
- 先生成一個text文件,寫上對應的file和duration(時長):duration 5 file '/path/to/cat.png' duration 1 file '/path/to/rat.png' duration 3 file '/path/to/tapeworm.png' duration 2 file '/path/to/tapeworm.png' 復制代碼
- ffmpeg -f concat -i input.txt -vsync vfr -pix_fmt yuv420p output.mp4
更改分辨率
- ffmpeg -i input -s width*height -c:v h264 output
從視頻中裁剪一塊區域出來
在起點(x,y)的地方裁剪下長高為wh的區域對應的視頻(坐標系:以視頻左上角為原點,向右為正方向,向下為正方向) ffmpeg -i -vf crop=w:h:x:y output crop指令
水印
- 疊加一張靜態圖,overlay是picture左上角對應的坐標,(坐標系:以視頻左上角為原點,向右為正方向,向下為正方向): ffmpeg -i input -i picture -filter_complex overlay=0:0 output
- 疊加GIF,如果想要GIF無限循環,使用這條指令(否則可以用上面的指令): ffmpeg -i input -ignore_loop 0 -i gif -filter_complex overlay=shortest=1 如果需要加坐標: ffmpeg -i input -ignore_loop 0 -i gif -filter_complex overlay=x:y:shortest=1
GIF
從視頻前兩秒片段中抽出一張幀率是10的GIF ffmpeg -i INPUT -ss 0 -t 2 -r 10 out.gif 上門的指令生成的GIF是比較模糊的,如果要生成高清的GIF: 先生成調色板,再利用調色板生成GIF,假設fps=10, ffmpeg -i INPUT -r 10 -vf fps=10,scale=300:-1:flags=lanczos,palettegen colorPalette.png scale是縮放的意思,這里是設置寬為300,-1是保持寬高比. ffmpeg -i input -i colorPalette.png -r 10 -lavfi fps=10,scale=300:-1:flags=lanczos[x];[x][1:v]paletteuse 得到清晰GIF相關
Android 使用:
-
生成一個Shell命令數組,丟給FFmpeg可執行文件處理即可 tips:文檔上的命令都是用空格隔開,其實把他理解成數組就好,重點是數組內的元素不要錯即可;
String ffmpegSplitWord = "如果是空格容易出錯,盡量是一個不容易和其他命令出突的字符(盡量和文件名不沖突)";StringBuilder sb = new StringBuilder("-y");sb.append(ffmpegSplitWord + "-i");sb.append(ffmpegSplitWord + input.toString());sb.append(ffmpegSplitWord + "-c:v");sb.append(ffmpegSplitWord + "libx264");sb.append(ffmpegSplitWord + "-x264-params");sb.append(ffmpegSplitWord + "keyint=" + Constant.Camerasettings.keyint);setBitRate(ffmpegSplitWord, sb);setPreset(ffmpegSplitWord, sb);sb.append(ffmpegSplitWord + output.toString());String ffmpeg_s = sb.toString();String[] command=ffmpeg_s.split(ffmpegSplitWord);try {FFmpeg.getInstance(IApplication.getInstance()).execute(command, new ExecuteBinaryResponseHandler() {@Overridepublic void onFailure(String s) {}@Overridepublic void onSuccess(String s) {}@Overridepublic void onProgress(String s) {}@Overridepublic void onStart() {}@Overridepublic void onFinish() {}});} catch (FFmpegCommandAlreadyRunningException e) {} 復制代碼
如何獲取處理進度:
- FFmpeg在處理的過程會打印出一些信息,比如 frame= 1 fps=0.0 q=0.0 size= 0kB time=00:01:02.71 bitrate= 0.0kbits/s speed=2.88x 我們可以拿到time信息,這是處理到哪個時間點的信息,把他專程秒,處理視頻時長,就可以得到處理進度。
總結
以上是生活随笔為你收集整理的FFmpeg command line tool(Android中使用FFmpeg命令行)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 基于Unity3d 引擎的Android
- 下一篇: VIM常用技巧总结