[英]How to encode/decode video using C#?
有一點背景,我被賦予了修復一些“小”錯誤的任務,並維護這個解決方案,以便在我們的應用程序的兩個實例之間通過網絡傳輸視頻。 解決方案是由不在場的人編寫的,所以代碼中有一些神秘感以及一些非常有趣的陷阱。 該解決方案是使用ffmpeg編寫的,其中編寫了C ++代碼以包裝編碼/解碼相關代碼以及一些流代碼。 然后用SWIG封裝這個C ++,以便它可以與C#互操作,並使用生活在WPF控件中的VideoRendererElement將視頻幀傳遞到它們呈現的位置 。 幀被傳遞的主要原因是因為我們需要一些自定義協議來發送視頻數據並使用C#編寫,所以當視頻幀傳遞出來時我們將它們包裝在我們自己的數據包中並通過線路發送出去。 這個解決方案有效,我們可以使用我們的自定義協議流式傳輸視頻,盡管維護和使用它是一件噩夢。
我的問題是有更好的方法來解決這個問題嗎? 我正在尋找在較低級別使用視頻數據(在C#中)工作的方法,這樣我就可以拍攝視頻幀並將它們打包在我們自己的數據包中並發送出去,並能夠接收和重建視頻另一邊。 ffmpeg似乎是常見的解決方案,但我遇到了很多問題,我認為GPL / LGPL是一個問題。
我想要實現的基本流程,視頻文件 - >編碼 - >包裹在數據包中 - >在協議X上通過線路發送 - >從數據包中獲取視頻數據 - >解碼 - >渲染/保存到磁盤
DirectShow是你的朋友。 DirectShow是大多數Windows“多媒體”應用程序(如媒體播放器,音頻編碼器等)使用的低級層。
即使這個庫是為本機開發人員制作的,也可以通過DirectShow.net從托管世界訪問它。 http://directshownet.sourceforge.net這是一個眾所周知且穩定的DirectShow托管包裝器。
你要做的唯一事情是學習一點DirectShow來理解圖形和過濾器的概念,然后創建自己的過濾器和圖形來使用DirectShow的強大功能!
在我們的項目中,我們使用Microsoft Expression Encoder。 它不是免費的。 它可以將視頻轉換為不同的格式和大小,提取縮略圖等。
這是一個例子:
using Microsoft.Expression.Encoder;
//...
//skiped
//...
MediaItem mediaItem = new MediaItem(videoToEncode.SourceFilePath);
mediaItem.ApplyPreset(PresetFilePath);
Job job = new Job();
job.ApplyPreset(PresetFilePath); // path to preset file, where settings of bit-rate, codec etc
job.MediaItems.Add(mediaItem);
job.EncodeProgress += OnProgress;
job.EncodeCompleted += EncodeCompleted;
job.DefaultMediaOutputFileName = "{OriginalFilename}.encoded.{DefaultExtension}";
job.CreateSubfolder = false;
job.OutputDirectory = videoToEncode.EncodedFilePath;
job.Encode();
使用ffmpeg包裝到DLL中時遇到了各種各樣的麻煩。 我的視頻項目非常簡單 - 我只需要轉換器從WMV中獲取一個縮略圖。
在嘗試了你描述的內容之后,我的解決方案就是將ffmpeg.exe二進制文件作為外部庫復制到我的項目中。 這也巧妙地解決了任何代碼許可問題,AFAIK ......
Guid temp = Guid.NewGuid();
// just throw our ffmpeg commands at cmd.exe
System.Diagnostics.ProcessStartInfo psi =
new System.Diagnostics.ProcessStartInfo("cmd.exe");
psi.WorkingDirectory = Page.MapPath(@"~\Lib\ffmpeg.rev12665");
psi.UseShellExecute = false;
psi.RedirectStandardError = true;
psi.RedirectStandardOutput = true;
psi.RedirectStandardInput = true;
System.Diagnostics.Process ps = System.Diagnostics.Process.Start(psi);
StreamReader outputReader = ps.StandardOutput;
StreamReader errorReader = ps.StandardError;
StreamWriter inputWrite = ps.StandardInput;
// uses extra cheap logging facility
inputWrite.WriteLine("echo \"Ripping " + copiedFile + " " +
temp.ToString() + "\" >> log.txt");
inputWrite.WriteLine("ffmpeg.exe -i \"" + copiedFile +
"\" -f image2 -vframes 1 -y -ss 2 tmp\\" + temp.ToString() +
".jpg");
inputWrite.WriteLine("exit");
ps.WaitForExit(3000);
if (ps.HasExited)
{
string thumbFile = Page.MapPath(@"~\Lib\ffmpeg.rev12665\tmp") +
@"\" + temp.ToString() + ".jpg";
// ...
}
您的ffmpeg命令行可能與我的示例有很大不同,但這是我發現縮略圖最穩定的方式。 我在網上找到的關於ffmpeg的其他東西特別沒有這個解決方案(基於cmd.exe),但這是我唯一一個運行良好的解決方案。 祝好運!
您可能會嘗試看的是SharpFFmpeg 。 它是使用GPL許可的,盡管您可能能夠看到他們如何編寫包裝器,您可以編寫自己的包裝,或者獲得有關如何修復當前解決方案的想法。
編輯:
在code.google.com上有一個名為ffmpeg-sharp的類似包裝器,它使用LGPL - 您可以在商業應用程序中使用它。 我懷疑這兩個包裝器的功能大致相同,盡管SharpFFmpeg更老,可能更成熟。
當沒有有效的方法在WPF(v3.0)中呈現視頻時,我寫回了VideoRendererElement。 它使用一些hackery使它工作。
如果您想稍微簡化一下,請刪除VRE並使用InteropBitmap進行渲染(WriteableBitmap沒問題,但效率不高)。 同時刪除SWIG並使您的C ++ DLL成為CLI / C ++ DLL,這樣您就可以直接與C#中的C ++通信(反之亦然)。
你可以去的另一條路線是創建一個包含傳輸/解碼內容的DirectShow源過濾器,你可以使用類似我的WPF MediaKit將它渲染到WPF中(它使用D3DImage.0。hacks)。
另外,不要害怕LGPL。 只要您將其保留在自己的DLL中並且不更改源,您就在許可限制范圍內。
您還可以查看可供下載的各種Microsoft Windows Media SDK。 在幾年前的一個項目中,我們使用Windows Media Format SDK從上傳的視頻中提取縮略圖。 這些SDK還具有.NET示例代碼。
我們正在為我們的mediadatabase應用程序將視頻文件轉換為各種輸出格式(divx編碼的avi,flv,mp4等)。 由於我們始終使用CLI應用程序進行媒體轉換(談論使用ImageMagick / GS將EPS文件柵格化為JPG),因此我們非常依賴FFMPEG-CLI。
在我們的特殊環境中,我們使用“啞”UNIX服務器作為轉換機器(只安裝了sshd,ffmpeg,misc .ffmpee庫和samba)。 它們通過PuTTy的CLI從C#(WCF webservice)通過SSH命令進行控制,以進行真正的轉換。
對ffmpeg的調用是通過ssh進行的,並且專門用於每個TransformationType。 putty CLI是通過C#的System.Diagnostics.Process命名空間啟動的,輸出和錯誤消息的事件是為了記錄目的而處理的。
互聯網提供了很多關於“如何使用ffmpeg將mpg轉換為flv?”等問題的資源,一些研究將幫助你。 由於我們正在談論版權申請,我無法發布完整的代碼摘錄。 但它應該為您提供有關使用C#的可靠,快速視頻編碼后端的架構概念。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.