如何使用C#对视频进行编码/解码?

如何使用C#对视频进行编码/解码?,c#,.net,wpf,C#,.net,Wpf,有一点背景知识,我的任务是修复一些“小”错误,并维护这个解决方案,以便在我们的应用程序的两个实例之间通过网络传输视频。这个解决方案是由一个已经不在这里的人编写的,因此代码中有一些神秘之处,也有一些真正有趣的陷阱。该解决方案是使用FFMPEG编写的,用C++代码编写编码/解码相关代码以及一些流代码。然后用SWIG封装这个C++,以便它可以与C语言交互,并将视频帧传递到它们在WPF控件中使用的地方。帧被传递的主要原因是因为我们有一些自定义协议需要发送视频数据,这些协议是用C#编写的,所以当视频帧被传

有一点背景知识,我的任务是修复一些“小”错误,并维护这个解决方案,以便在我们的应用程序的两个实例之间通过网络传输视频。这个解决方案是由一个已经不在这里的人编写的,因此代码中有一些神秘之处,也有一些真正有趣的陷阱。该解决方案是使用FFMPEG编写的,用C++代码编写编码/解码相关代码以及一些流代码。然后用SWIG封装这个C++,以便它可以与C语言交互,并将视频帧传递到它们在WPF控件中使用的地方。帧被传递的主要原因是因为我们有一些自定义协议需要发送视频数据,这些协议是用C#编写的,所以当视频帧被传递时,我们将它们包装在我们自己的数据包中,并通过电线发送出去。这个解决方案是可行的,我们可以使用我们的自定义协议来流式传输视频,尽管维护和使用它有点像噩梦

我的问题是,有没有更好的办法?我正在寻找在较低级别处理视频数据的方法(C#),这样我就可以将视频帧打包到我们自己的数据包中,然后发送出去,并能够在另一端接收和重建视频。ffmpeg似乎是常见的解决方案,但我遇到了很多问题,我认为GPL/LGPL是一个问题

我希望实现的基本流程,
视频文件->编码->包内包裹->协议X上的有线发送->从包中获取视频数据->解码->渲染/保存到磁盘

您可能会尝试查看以下内容:。它是使用GPL授权的,尽管您可能能够看到他们如何编写包装器,您也可能能够编写自己的包装器,或者了解如何修复当前的解决方案

编辑:


在code.google.com上有一个类似的包装器,它使用LGPL,您可以在商业应用程序中使用它。我怀疑这两种包装的功能大致相同,尽管SharpFFmpeg更老,可能更成熟

我在使用封装到DLL中的ffmpeg时遇到了各种各样的麻烦。我的视频项目非常简单-我只需要转换器从WMV中获取一个缩略图

在尝试了您描述的内容之后,我的解决方案是将ffmpeg.exe二进制文件作为外部库复制到我的项目中。这也巧妙地绕过了任何代码许可问题,好吧

        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),但这是我唯一一个运行良好的解决方案。祝你好运

我写了VideoRenderElement,当时在WPF(v3.0)中没有有效的视频渲染方法。它使用了一些黑客技术使其工作

如果您想简化一些事情,请删除VRE并使用InteropBitmap进行渲染(WriteableBitmap可以,但效率不高)。也可以删除SWIG,使你的C++ DLL成为CLI/C++DLL,这样你就可以直接从C++中与C++对话(反之亦然)。 另一种方法是创建一个DirectShow源过滤器,其中包含传输/解码内容,您可以使用类似my的东西将其渲染到WPF中(它使用D3DImage.0 hacks)


另外,不要害怕LGPL。只要您将其保存在自己的DLL中并且不更改源代码,您就在许可证限制范围内。

您还可以查看可供下载的各种Microsoft Windows Media SDK。在几年前的一个项目中,我们使用Windows Media Format SDK从上传的视频中提取缩略图。
这些SDK还有.NET示例代码。

在我们的项目中,我们使用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();

我们正在为mediadatabase应用程序将视频文件转换为各种输出格式(divx编码的avi、flv、mp4等)。由于我们总是使用CLI应用程序进行媒体转换(谈论使用ImageMagick/GS将EPS文件光栅化为JPG),因此我们严重依赖FFMPEG-CLI

在我们的特殊环境中,我们使用“哑”UNIX服务器作为转换机器(只安装了sshd、ffmpeg、misc.ffmpeg库和samba)。它们通过PuTTy的CLI从C#(WCF webservice)通过SSH命令进行控制,以进行真正的转换

对ffmpeg的调用是通过ssh进行的,并且专门针对每个转换类型。putty CLI是通过C#的System.Diagnostics.Process命名空间启动的,输出事件和错误消息是出于日志目的处理的


互联网提供了大量关于“如何使用ffmpeg将mpg转换为flv?”等问题的资源,一些研究将对您有所帮助。因为我们讨论的是版权保护的应用程序,所以我不能发布完整的代码摘录。但它应该给你一个关于使用C#的可靠、快速视频编码后端的架构想法。

DirectShow是你的朋友。DirectShow是大多数windows“多媒体”应用程序(如媒体播放器、音频编码器等)使用的底层

即使此库是为本地开发人员创建的,您也可以通过DirectShow.net从托管世界访问它。这是一个众所周知的、稳定的DirectShow托管包装器


你唯一需要做的就是学习一点DirectShow来理解图形和过滤器的概念,然后创建自己的过滤器和图形来使用DirectShow的强大功能

为什么LGPL对您来说是个问题?即使你的应用程序是针对商业客户的,也不应该是一个问题。可能的重复:GPL/LGPL的事情是由另一位同事提出的,但他们让人觉得我们好像是在违反ho的许可证