C#程式呼叫FFmpeg操作音視訊

追逐時光者發表於2022-01-11

專案背景

  因為公司需要對音視訊做一些操作,比如說對系統使用者的發音和背景視訊進行合成,以及對多個音視訊之間進行合成,還有就是在指定的源背景音訊中按照對應的規則在視訊的多少秒鐘內插入一段客戶發音等一些複雜的音視訊操作。本篇文章主要講解的是使用C#程式(Process)呼叫FFmpeg.exe進行視訊合併,音訊合併,音訊與視訊合併成視訊這幾個簡單的音視訊操作,還有些複雜的音視訊操作後續有時間慢慢補上。

FFmpeg介紹

來源百度百科?

  FFmpeg是一套可以用來記錄、轉換數字音訊、視訊,並能將其轉化為流的開源計算機程式。採用LGPL或GPL許可證。它提供了錄製、轉換以及流化音視訊的完整解決方案。它包含了非常先進的音訊/視訊編解碼庫libavcodec,為了保證高可移植性和編解碼質量,libavcodec裡很多code都是從頭開發的。

  FFmpeg在Linux平臺下開發,但它同樣也可以在其它作業系統環境中編譯執行,包括Windows、Mac等多平臺。這個專案最早由Fabrice Bellard發起,2004年至2015年間由Michael Niedermayer主要負責維護。許多FFmpeg的開發人員都來自MPlayer專案,而且當前FFmpeg也是放在MPlayer專案組的伺服器上。專案的名稱來自MPEG視訊編碼標準,前面的"FF"代表"Fast Forward"。 FFmpeg編碼庫可以使用GPU加速。

FFmpeg相關教程

開始之初你首先要了解FFmpeg是什麼,有哪些常用的命令和實用的功能。

部落格示例原始碼

https://github.com/YSGStudyHards/FFmpegAudioAndVideoMerge?

下載FFmpeg.exe安裝包

首先把下載下來的FFmpeg.exe放在你指定的目錄資料夾中,方便C#程式呼叫。

ffmpeg.exe 安裝包: https://www.gyan.dev/ffmpeg/builds/ffmpeg-release-essentials.zip? (74MB)

C#程式呼叫FFmpeg操作音視訊

namespace FFmpegAudioAndVideoMerge
{
    class Program
    {
        static void Main(string[] args)
        {
            var physicalPath = "E:\\FFmpegAudioAndVideoMerge\\FFmpegAudioAndVideoMerge\\files\\";

            //視訊合併
            VideoCombine(physicalPath + "video1.mp4", physicalPath + "video2.mp4", physicalPath + "merageVideoyy.mp4");

            //音訊合併
            var audioMergeList = new List<string>();
            audioMergeList.Add(physicalPath + "music1.mp3");
            audioMergeList.Add(physicalPath + "music2.mp3");
            audioMergeList.Add(physicalPath + "music3.mp3");
            AudioMerge(physicalPath, audioMergeList);

            //音訊與視訊合併成視訊
            AudioAndVideoMerge(physicalPath);
        }

        #region 視訊合併
        /// <summary>
        /// 視訊合併
        /// </summary>
        /// <param name="video1">合併視訊1</param>
        /// <param name="video2">合併視訊2</param>
        /// <param name="saveFilePath">儲存檔名</param>
        /// <returns></returns>
        public static void VideoCombine(string video1, string video2, string saveFilePath)
        {
            string strTmp1 = video1 + ".ts";
            string strTmp2 = video2 + ".ts";
            string strCmd1 = " -i " + video1 + " -c copy -bsf:v h264_mp4toannexb -f mpegts " + strTmp1 + " -y ";
            string strCmd2 = " -i " + video2 + " -c copy -bsf:v h264_mp4toannexb -f mpegts " + strTmp2 + " -y ";

            string videoMerge = " -i \"concat:" + strTmp1 + "|" +
                strTmp2 + "\" -c copy -bsf:a aac_adtstoasc -movflags +faststart " + saveFilePath + " -y ";

            //1、轉換檔案型別,由於不是所有型別的視訊檔案都支援直接合並,需要先轉換格式
            CommandManager(strCmd1);
            CommandManager(strCmd2);

            //2、視訊合併
            CommandManager(videoMerge);
        }
        #endregion

        #region 音訊合併
        /// <summary>
        /// 音訊合併
        /// </summary>
        public static void AudioMerge(string physicalPath, List<string> mergeFile)
        {
            //將多個音訊混合成一個音訊檔案輸出 http://www.ffmpeg.org/ffmpeg-all.html#amix

            //ffmpeg -i INPUT1 -i INPUT2 -i INPUT3 -filter_complex amix=inputs=3:duration=first:dropout_transition=3 OUTPUT

            //合併兩個音訊
            //ffmpeg -i input1.mp3 -i input2.mp3 -filter_complex amerge -ac 2 - c:a libmp3lame -q:a 4 output.mp3

            //獲取視訊中的音訊
            //ffmpeg -i input.mp4 -vn -y -acodec copy output.m4a

            //去掉視訊中的音訊
            //ffmpeg -i input.mp4 -an output.mp4

            // https://www.cnblogs.com/simadi/p/10649345.html
            // ffmpeg -i "concat:123.mp3|124.mp3" -acodec copy output.mp3
            // 解釋:-i代表輸入引數
            // contact: 123.mp3 | 124.mp3代表著需要連線到一起的音訊檔案 -acodec copy output.mp3 重新編碼並複製到新檔案中

            string mergeCommandStr = $"-i \"concat:{string.Join("|", mergeFile.ToArray())}\" -acodec copy {physicalPath}AudioMerge.mp3  -y";
            CommandManager(mergeCommandStr);
        }
        #endregion

        #region 音訊與視訊合併成視訊
        /// <summary>
        /// 音訊與視訊合併成視訊
        /// </summary>
        /// <param name="physicalPath">物理路徑</param>
        public static void AudioAndVideoMerge(string physicalPath)
        {
            //1、視訊檔案中沒有音訊。
            //ffmpeg -i video.mp4 -i audio.wav -c:v copy -c:a aac -strict experimental output.mp4
            //string mergeCommandStr = $"-i {physicalPath}video2.mp4 -i {physicalPath}music1.mp3 -c:v copy -c:a aac -strict experimental {physicalPath}output.mp4  -y";

            //video.mp4,audio.wav分別是要合併的視訊和音訊,output.mp4是合併後輸出的音視訊檔案。
            //2、下面的命令是用audio音訊替換video中的音訊 ffmpeg -i video.mp4 -i audio.wav -c:v copy -c:a aac -strict experimental -map 0:v:0 -map 1:a: 0 output.mp4
            string mergeCommandStr = $"-i {physicalPath}video3.mp4 -i {physicalPath}AudioMerge.mp3 -c:v copy -c:a aac -strict experimental -map 0:v:0 -map 1:a:0 {physicalPath}AudioAndVideoMerge.mp4  -y";

            //3、c++音訊視訊合併(視訊檔案中沒有音訊的情況下)
            //"ffmpeg -i /tmp/mergeMp3/392118469203595327/392118469203595327.aac  -i /tmp/mergeMp3/392118469203595327/bg.mp4 -c copy -bsf:a aac_adtstoasc /tmp/mergeMp3/392118469203595327/392118469203595327.mp4 -y"
            //string mergeCommandStr3 = $"-i {physicalPath}video5.mp4  -i {physicalPath}AudioMerge.mp3 -c copy -bsf:a aac_adtstoasc {physicalPath}AudioAndVideoMerge1.mp4 -y";

            CommandManager(mergeCommandStr);
        }
        #endregion


        /// <summary>
        /// 執行
        /// C# Process程式呼叫 https://docs.microsoft.com/zh-cn/dotnet/api/system.diagnostics.process?view=net-5.0
        /// </summary>
        /// <param name="commandStr">執行命令</param>
        public static void CommandManager(string commandStr)
        {
            try
            {
                using (Process process = new Process())
                {
                    process.StartInfo.FileName = "D:\\FFmpeg\\bin\\ffmpeg.exe";//要執行的程式名稱(屬性,獲取或設定要啟動的應用程式或文件。FileName 屬性不需要表示可執行檔案。 它可以是其副檔名已經與系統上安裝的應用程式關聯的任何檔案型別。)
                    process.StartInfo.Arguments = " " + commandStr;//啟動該程式時傳遞的命令列引數
                    process.StartInfo.UseShellExecute = false;
                    process.StartInfo.RedirectStandardInput = false;//可能接受來自呼叫程式的輸入資訊  
                    process.StartInfo.RedirectStandardOutput = false;//由呼叫程式獲取輸出資訊   
                    process.StartInfo.RedirectStandardError = false;//重定向標準錯誤輸出
                    process.StartInfo.CreateNoWindow = false;//不顯示程式視窗
                    process.Start();//啟動程式
                    process.WaitForExit();//等待程式執行完退出程式(避免程式佔用檔案或者是合成檔案還未生成)*
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
        }
    
}
}

 

相關文章