史林楓:C#.NET利用ffmpeg操作視頻實戰(格式轉換,加水印 一步到位)


ffmpeg.exe是大名鼎鼎的視頻處理軟件,以命令行參數形式運行。網上也有很多關於ffmpeg的資料介紹。但是在用C#做實際開發時,卻遇到了幾個問題及注意事項,比如如何無損處理視頻?如何在轉換格式的同時添加水印,以提升處理效率?,ffmpeg的版本應該選擇什么版本?。今天史林峰將用實戰的方式來探索C#操作ffmpeg的奧秘。

關於ffmpeg的使用及其參數命令,這里就不做過多介紹了。主要以項目實戰中為主。

因工作需要,筆者手頭有近300部短視頻需要處理,在網上找了不少工具,雖然能用,但是用起來卻有一種Hold不住的感覺。要么是處理后有軟件水印或片花,要么是不能直接批量一次性處理完,視頻要一個一個地去設置。

這里主要需求是給現有的視頻做格式轉換,如果視頻格式已經滿足要求,就直接在指定位置加水印(png圖片),在處理完之后,為了解決磁盤空間,在視頻處理完成之后要刪除原視頻。筆者對C#語言是最熟知的,因此選用C# Winform做一個簡易的視頻批處理軟件。

先上一張完工的項目截圖:

 

 

在指定目錄中讀取視頻,然后一件處理即可(中間的截取秒數的參數,屬於視頻剪切,暫時沒有這塊功能)

 

現有的視頻均為flv格式的,通過C#調用ffmpeg,轉換為mp4格式,並添加水印

C#調用ffmpeg的方法封裝如下:

 1 /// <summary>
 2 /// 視頻處理器ffmpeg.exe的位置  3 /// </summary>
 4 public string FFmpegPath { get; set; }  5    6 /// <summary>
 7 /// 調用ffmpeg.exe 執行命令  8 /// </summary>
 9 /// <param name="Parameters">命令參數</param>
10 /// <returns>返回執行結果</returns>
11 private string RunProcess(string Parameters) 12 { 13 //創建一個ProcessStartInfo對象 並設置相關屬性
14 var oInfo = new ProcessStartInfo(FFmpegPath, Parameters); 15 oInfo.UseShellExecute = false; 16 oInfo.CreateNoWindow = true; 17 oInfo.RedirectStandardOutput = true; 18 oInfo.RedirectStandardError = true; 19 oInfo.RedirectStandardInput = true; 20   21 //創建一個字符串和StreamReader 用來獲取處理結果
22 string output = null; 23 StreamReader srOutput = null; 24   25 try
26 { 27     //調用ffmpeg開始處理命令
28     var proc = Process.Start(oInfo); 29   30     proc.WaitForExit(); 31   32   33     //獲取輸出流
34     srOutput = proc.StandardError; 35   36     //轉換成string
37     output = srOutput.ReadToEnd(); 38   39     //關閉處理程序
40     proc.Close(); 41 } 42 catch (Exception) 43 { 44     output = string.Empty; 45 } 46 finally
47 { 48     //釋放資源
49     if (srOutput != null) 50     { 51         srOutput.Close(); 52         srOutput.Dispose(); 53     } 54 } 55 return output; 56 }
View Code

 

轉換格式的命令參數:-i orignal.flv -y -b 1024k -acodec copy -f mp4 newFile.mp4

添加水印的命令參數:-i orignal.flv -i water.png -filter_complex \"overlay=10:10\" newFile.flv

參數簡要說明和細節提示:

orignal.flv : 要處理的原始視頻文件(最好是絕對路徑)
-y : 覆蓋已有文件(注意,加水印不可覆蓋原始文件,否則只能生成1秒的視頻)
-b:視頻的碼率 這里設置1024k 基本可滿足無損處理 如不設置-b參數則默認為200k 視頻會非常模糊
-acodec copy : 保持音頻質量不變
-f mp4 : 表示轉換的視頻格式
 
-i water.png : 水印圖片路徑
overlay=10:10 : 水印距離視頻的左上角坐標
其他位置參數:
右上角:main_w-overlay_w-10:10
左下角:10:main_h-overlay_h-10
右下角:main_w-overlay_w-10:main_h-overlay_h-10
 
newFile.mp4  要保存的文件路徑

 

上面這個方法就是核心處理。筆者在實際執行的過程中,發現了以下問題:

 

  在使用cmd窗口執行以上命令時(cmd中參數前面要加 ffmpeg 注意文件位置),可以成功處理,但在運行Winform測試的時候,發現只有一個大小為0kb的新文件生成,但遲遲不見處理。給人一種假死的現象。而當筆者關掉調試的Winform程序時,過幾秒鍾,貌似ffmpeg.exe 又起作用了,文件處理成功了。這個不得其解。(在調用處理程序時,新開了一個線程執行的)

排查情況:

  可能是ffmpeg的版本問題,於是下載了2.8.2版本(應該是最新的),測試,沒有任何變化

  檢查程序的調用流程,將調用過程cmd窗口顯示出來。結果一片空白,什么也沒有,依然是沒有效果。

最后在經過各種資料的查找之后,在不經意間看到有人說 proc.WaitForExit(); 這句執行會造成程序一直處於等待狀態。是的,沒錯,以前做類似程序調用也是這樣做的,也沒出現過這種問題。於是,抱着試試看的態度,注釋了這一句。當然,程序不再等待執行完畢,proc.Close(); 這一句也要注釋一下。測試結果成功!!(懂得底層原理的大牛,望告知一二)

 

問題解決了,但是還有一個處理效率的問題:如何更快的處理?

筆者嘗試了各種命令的組合,發現對於不同版本的ffmpeg,有的參數是不能使用的,就筆者使用的2.8.2版本最終 找了一個比較好的解決方案:

可以選擇使用以下命令參數:

-i orignal.flv -i water.png -filter_complex \"overlay=10:10\" -y -b 1024k -acodec copy -f mp4

 

-i orignal.flv -i water.png -filter_complex \"overlay=10:10\" -b 1024k -acodec copy

 

上面一個適合同時轉換格式和加水印

下面一個適合只加水印,不做格式轉換

這些核心問題解決了,剩下的就是文件的讀取,保存,判斷等等細節了。

 

總結:                                                          

  1. C#調用ffmpeg時 不要使用proc.WaitForExit();方法,否則會假死

  2. ffmpeg的版本最好使用最新版本,並參考命令參數說明

  3. 無損轉換,無損加水印 要注意保證視頻的碼率 和音頻的參數(直接copy,視頻不能這樣寫-avcodec copy  會報錯,只能用-b設置視頻碼率) 

  4. 一步到位的處理方法(轉換的同時加水印,參考上面的命令參數)

 

程序開發好之后,筆者不用再苦逼地一個一個去設置,處理了,電腦開着,顯示器關閉,只聽見主機嗷嗷叫的處理,等吃完飯,所有事情均已搞定。。。

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM