【问题标题】:How to encode/decode video using C#?如何使用 C# 编码/解码视频?
【发布时间】:2010-12-22 12:33:30
【问题描述】:

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

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

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

【问题讨论】:

  • 为什么 LGPL 对您来说是个问题?即使您的应用程序是针对商业客户的,也不应该成为问题。
  • GPL/LGPL 的事情是由另一位同事提出的,但他们听起来好像我们使用 ffmpeg 及其一些依赖库的方式违反了许可。至于重复的帖子,如果可能的话,我正试图摆脱 ffmpeg,而尖锐的 ffmpeg 似乎不起作用或不再受支持。
  • 如果不研究 SharpFFmpeg,我不能说。有些项目达到了一定程度的成熟度,不再发现错误 - zlib 浮现在脑海中。如果您想避免使用 ffmpeg,请注意,做您想做的事情可能需要做很多工作。网络传输部分可能是最简单的部分。
  • 你看过 AVBlocks.NET 吗?有关更多详细信息,请查看 Bitbucket 上 AVBlocks-Samples 存储库中的 VideoConverter 和其他 .NET 示例。

标签: c# .net wpf


【解决方案1】:

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

编辑:

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

【讨论】:

    【解决方案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】:

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

      如果您想稍微简化一下,请删除 VRE 并使用 InteropBitmap 进行渲染(WriteableBitmap 可以,但效率不高)。同时删除 SWIG 并将您的 C++ dll 设为 CLI/C++ dll,这样您就可以直接从 C# 与您的 C++ 对话(反之亦然)。

      您可以采用的另一条路线是创建一个包含传输/解码内容的 DirectShow 源过滤器,您可以使用我的 WPF MediaKit 之类的东西将其渲染到 WPF 中(它使用 D3DImage。0 hacks)。

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

      【讨论】:

        【解决方案4】:

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

        【讨论】:

          【解决方案5】:

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

          【讨论】:

          • 我下载了 Expression Encoder 的免费版本并使用了 API、示例并查看了反射器中的库以尝试了解这是否可行。它看起来确实是一个不错的解决方案,但我仍然不确定我是否能够获得通过自定义协议控制流式传输所需的东西。我确实发现 LiveJob 对象有一个属性 OutputFormat,看起来它可以通过自定义流实现的方式实现,因此最终可能会起作用。
          【解决方案6】:

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

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

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

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

          【讨论】:

            【解决方案7】:

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

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

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

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2015-03-08
              • 2011-06-16
              • 2020-03-28
              • 2016-01-19
              • 2013-06-25
              • 2016-10-07
              相关资源
              最近更新 更多