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

时间:2009-12-02 17:54:40

标签: c# .net wpf

有一点背景,我被赋予了修复一些“小”错误的任务,并维护这个解决方案,以便在我们的两个应用程序实例之间通过网络传输视频。解决方案是由不在场的人编写的,所以代码中有一些神秘感以及一些非常有趣的陷阱。该解决方案是使用ffmpeg编写的,其中编写了C ++代码以包装编码/解码相关代码以及一些流代码。然后用SWIG封装这个C ++,以便它可以与C#互操作,并使用生成在WPF控件中的VideoRendererElement将视频帧传递到它们呈现的位置。帧被传递的主要原因是因为我们需要一些自定义协议来发送视频数据并使用C#编写,所以当视频帧传递出来时我们将它们包装在我们自己的数据包中并通过线路发送出去。这个解决方案很有效,我们可以使用我们的自定义协议来传输视频,尽管维护和使用它是一件噩梦。

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

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

7 个答案:

答案 0 :(得分:6)

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

即使此库是为本机开发人员制作的,您也可以通过DirectShow.net从托管世界访问它。 http://directshownet.sourceforge.net这是DirectShow的一个众所周知且稳定的托管包装器。

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

答案 1 :(得分:4)

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

答案 2 :(得分:2)

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

答案 3 :(得分:0)

您可能会尝试查看SharpFFmpeg。它是使用GPL许可的,尽管您可能能够看到他们如何编写包装器,您可以编写自己的包装,或者获得有关如何修复当前解决方案的想法。

编辑:

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

答案 4 :(得分:0)

当没有有效的方法在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中并且不更改源,您就在许可限制范围内。

答案 5 :(得分:0)

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

答案 6 :(得分:0)

我们正在为我们的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进行的,并且专门用于每个TransformationType。 putty CLI是通过C#的System.Diagnostics.Process命名空间启动的,输出和错误消息的事件是为了记录目的而处理的。

互联网提供了很多关于“如何使用ffmpeg将mpg转换为flv?”等问题的资源,一些研究可以帮助你。由于我们正在谈论版权申请,我无法发布完整的代码摘录。但它应该为您提供有关使用C#的可靠,快速视频编码后端的架构概念。