[C#] FFmpeg 音視頻開發總結

来源:https://www.cnblogs.com/mrf2233/archive/2023/06/08/17442871.html
-Advertisement-
Play Games

為什麼選擇FFmpeg? 延遲低,參數可控,相關函數方便查詢,是選擇FFmpeg作為編解碼器最主要原因,如果是處理實時流,要求低延遲,最好選擇是FFmpeg。 如果需要用Opencv或者C#的Emgucv這種庫來處理視頻流,也多是用FFmpeg做編解碼然後再轉換圖像數據給Opencv去處理。用Ope ...


為什麼選擇FFmpeg?

  1. 延遲低,參數可控,相關函數方便查詢,是選擇FFmpeg作為編解碼器最主要原因,如果是處理實時流,要求低延遲,最好選擇是FFmpeg。
  2. 如果需要用Opencv或者C#的Emgucv這種庫來處理視頻流,也多是用FFmpeg做編解碼然後再轉換圖像數據給Opencv去處理。用Opencv編解碼延遲很高。
  3. 其他的庫多是基於FFmpeg封裝,如果做一個視頻播放器,像vlc這種庫是非常方便的,缺點是臃腫,需要手動剔除一些文件,當然也有一些是基於FFmpeg封裝好的視頻播放器庫,也能快速實現一個播放器。
  4. 如果是載入單Usb介面中的多Usb攝像頭,FFmpeg這時就無能為力了,經過測試使用DirectShow能夠實現。AForge一個很好的學習樣例,它將DirectShow封裝的很好,能輕鬆實現載入單Usb介面中的多Usb攝像頭(不過它很久沒更新了,目前無法設置攝像頭參數,也沒有Usb攝像頭直接錄製,所以我把它重寫了),當然使用其他DirectShow的庫也是可以的。
  5. 寫此文章時才發現CaptureManager這個2023年4月發佈的非常簡便好用的基於D3D封裝的音視頻庫,它的官方樣例非常豐富,能實現很多功能。我嘗試了運行了他的官方樣例,打開相同規格的Usb攝像頭,發覺cpu占用是FFmpeg的兩倍。

如何學習FFmpeg?

記錄一下我是如何學習FFmpeg。首先是C#使用FFmpeg基本上用的是FFmpeg.autogen這個庫。也可以使用FFmpeg.exe,先不談論FFmpeg.exe的大小,我嘗試過從exe中取數據到C#前端顯示,相同參數情況下,延遲比使用FFmpeg.autogen高,主要是不能邊播放邊錄製(可以用其它的庫來錄製,但是效率比不上只使用一個庫)。

當然如果只需要部分功能也可以自己封裝FFmpeg(太花時間了,我放棄了。如果是專門從事這一行的可以試試)。

學習FFmpeg.autogen可以先去Github上下載它的樣例(其實樣例有個小問題,後面說),學習基礎的編解碼。

後面有人把官網的C++的樣例用FFmpeg.autogen寫了一遍,我把樣例壓縮好放誇克網盤了:https://pan.quark.cn/s/c579aad1d8e0

然後是查看一些博客和Github上一些項目,瞭解編解碼整體架構,因為FFmpeg很多參考代碼都是c++的所以我基本是參考C++寫C#,寫出整體的編解碼代碼。

無論是編解碼還是開發Fliter都會涉及到很多參數設置。要查找這些參數,我先是去翻博客,最後還是去FFmpeg官網(官網文檔,編解碼參數很全),當然製作視頻濾鏡和一些其他功能,也是參考官網的參數。

對於部分基礎函數(有些函數會把幀用掉就釋放,要註意)查看FFmpeg的源碼,理解原理。

對於一些概念性的東西,我是翻閱碩博論文(一般都有總結這些)。

 C#使用FFmpeg需要註意什麼?

  1. FFmpeg.autogen是有一個缺點的,它是全靜態的,不支持多線程(這個我問作者了),所以用多進程,而用多進程渲染到同一畫面,可以參考我上一篇MAF的文章。
  2. 尤其要註意幀釋放,編解碼的幀如果沒有釋放是一定會產生記憶體泄漏的,而且速度很快。
  3. 其次是c# 要將圖像數據渲染到界面顯示,最最好使用WriteableBitmap,將WriteableBitmap和綁定到一個Image然後更新WriteableBitmap。我記得在一篇博客中提到高性能渲染,使用MoveMemory來填充WriteableBitmap的BackBuffer,核心代碼如下。
    [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        private static extern void MoveMemory(IntPtr dest, IntPtr src, uint count);
     writeableBitmap.Lock();
            unsafe
            {
                 fixed (byte* ptr = intPtr)
                  {
                    MoveMemory(writeableBitmap.BackBuffer, new IntPtr(ptr), (uint)intPtr.Length);
                   }
           }
           writeableBitmap.AddDirtyRect(new Int32Rect(0, 0, width, height));
    
    writeableBitmap.Unlock();
    這樣處理有個致命的缺點。WriteableBitamp的寬高必須為2的整數倍,即使是修正過大小,當傳入數據為特殊尺寸使用此方法時還是會出現顯示異常的情況。所以還是老實使用WriteableBitmap的WritePixels。
  4. 對於FFmpeg很多函數都是會返回錯誤信息,一定要將錯誤信息記錄到日誌,方便查找和查看(基本每個函數要加錯誤信息判斷)。
  5. 軟編碼會占用大量的CPU資源,所以最好採用硬編碼。FFmpeg有一個查找編解碼器的函數,它並不能查看硬體編碼器。如果要使用硬體加速查找編解碼器最好是用其他方式獲取系統設備或者直接一個一個打開NVDIA和QSV等加速,都失敗了再啟用軟編解碼。
  6. QSV硬編碼要求輸入的像素格式必須為AVPixelFormat.AV_PIX_FMT_NV12,如果是硬解碼出的數據,可以直接編碼,否則需要添加格式轉換。FFmepg.autogen的官方樣例中有格式轉換函數,但由於它沒有指定轉換後的格式會出問題(踩坑)。
  7. 儘量少的格式轉換,或者幀複製。這兩種方式會提高cpu和記憶體使用率同時也會有更高的延遲。
  8. 在製作FFmpeg的帶有文本的Filter時,將需要使用的字體複製到項目目錄然後指定字體位置而不是調用系統的字體(不知道是版本原因還是什麼問題,一用系統字體就會產生記憶體泄漏)。
  9.  註意編解碼數據的格式。一些老的格式,雖然解碼沒有什麼問題(ffmpeg 會有提示)但是編碼是不支持的,出現這種問題,程式會直接死掉(踩坑)。
  10. 解碼時可以通過解碼數據自動搜尋硬體解碼器,而硬體編碼需要手動指定編碼器(可以通過,查找並自動選擇GPU來實現自動選擇)。
  11. 多線程實現播放同時錄製時,最好採用幀複製ffmpeg.av_frame_clone(hwframe)不用對同一個幀進行操作。當然也可以不用多線程,同一個幀在播放完成後進行,錄製。

  暫時只想到這些,有其他的想法再更新     

如果有任何錯誤歡迎批評指正。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在 Java 中,變數是一種用於存儲數據值的占位符。變數是 Java 編程中基本的數據類型,程式中幾乎所有的操作都需要用到變數。 ...
  • ## 教程簡介 Angular 6是一個JavaScript框架,用於構建JavaScript,html和TypeScript中的Web應用程式和應用程式,它是JavaScript的超集。它是Angular的一個更新版本,相當於angular的6.x版本。 [Angular 6入門教程](https ...
  • ## 教程簡介 正則表達式不僅僅是Java的技術,在任何一門編程語言中都會存在,是一種通用的IT技術,其理念和用法在任何編程語言中基本一致,除了有一些由於語言不同而導致的一些語法不同正則表達式,主要用於匹配(查找 替換 計數)字元串中的數據的,也叫做文本匹配技術。 在Java標準庫中java.uit ...
  • Python中的`lambda`函數,或者叫匿名函數,是一個極其強大的工具。它以簡潔、優雅的語法提供了創建函數的快速方式。在本篇文章中,我們將全方位地深入研究lambda函數的用法和特點,通過理論和實例相結合的方式,讓你的Python編程技巧更上一層樓。 ...
  • # JGroups概念 在 JGroups 中,集群(cluster)是一個由多個節點組成的邏輯實體,節點可以通過一個共用的集群名稱來進行連接和通信。這個集群名稱可以在配置中指定或在運行時動態創建。 JGroups 提供了多種方式來創建集群,並使節點能夠加入到相同的集群中。下麵是一些常見的方式: 1 ...
  • 【前言】 本文自1年前的1.0版本推出以來,已被業界大量科技公司採用。同時也得到了.Net圈內多位大佬的關註+推薦,文章也被多家頂級.Net/C#公眾號轉載。 現在更新到了7.0版本,更好的服務各位.Neter。 【正文】 支持.Net/.Net Core/.Net Framework,可以部署在D ...
  • #! https://zhuanlan.zhihu.com/p/635569763 # Excel DDE Commands ## 連接參數 `Application`: `Excel` `Topic`: `System`: 整個應用。 [sheetname] 指定 worksheet。 我使用的是 ...
  • # 一個超級大的文件如何更快讀 問題起因 ![](https://img2023.cnblogs.com/blog/2415052/202306/2415052-20230608110517159-989018809.png) 一個有千萬的數據的txt文件如何發揮IO的全部性能更快的讀和寫。 ## ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...