在.net中使用FFmpeg?

问题描述 投票:59回答:6

所以我知道这是一个相当大的挑战,但我想使用FFmpeg库在c#中编写一个基本的电影播放器​​/转换器。但是,我需要克服的第一个障碍是将FFmpeg库包装在c#中。我已经下载了ffmpeg但无法在Windows上编译它,所以我为我下载了一个预编译版本。太棒了。然后我开始寻找C#包装器。

我环顾四周,发现了一些包装,如SharpFFmpeg(http://sourceforge.net/projects/sharpffmpeg/)和ffmpeg-sharp(http://code.google.com/p/ffmpeg-sharp/)。首先,我想使用ffmpeg-sharp作为其LGPL而SharpFFmpeg是GPL。但是,它有很多编译错误。事实证明它是为单声道编译器编写的,我尝试用单声道编译它但无法弄清楚如何。然后我开始自己手动修复编译器错误,但遇到了一些可怕的错误,并认为我最好不要单独留下它们。所以我放弃了ffmpeg-sharp。

然后我看着SharpFFmpeg,它看起来像我想要的,所有P / Invoked函数。不过它的GPL? AVCodec.cs和AVFormat.cs文件看起来像avcodec.c和avformat.c的端口,我估计我可以移植自己?然后不必担心许可。

但是我想在开始编码之前做到这一点。我是不是该:

  1. 编写我自己的C ++库以与ffmpeg交互,然后让我的C#程序与C ++库通信以播放/转换视频等。

要么

  1. 通过使用大量的DllImports将端口avcodec.h和avformat.h(这就是我需要的全部吗?)到c#中并完全用C#编写?

首先要考虑的是我在C ++方面并不擅长,因为我很少使用它,但我知道它足以绕过它。我认为#1的原因可能是更好的选择,因为大多数FFmpeg教程都是用C ++编写的,而且我对内存管理的控制也比我在c#中做的要多。

你怎么看?您是否也碰巧使用FFmpeg有任何有用的链接(也许是教程)?

c# video ffmpeg
6个回答
29
投票

最初的问题现在已经超过5年了。与此同时,现在有一个来自ffmpeg的WinRT解决方案和来自Microsoft的集成样本的解决方案。


23
投票

一些其他托管包装供您查看

在.NET中编写自己的interop包装器可能是一个耗时且困难的过程。为互操作编写C ++库有一些优点 - 特别是因为它允许您大大简化C#代码的接口。但是,如果您只需要库的一个子集,那么在C#中进行互操作可能会让您的生活变得更轻松。


5
投票

GPL编译的ffmpeg只有在作为命令行实用程序的单独进程中调用时,才能从非GPL程序(商业项目)中使用;与ffmpeg库链接的所有包装器(包括Microsoft的FFMpegInterop)只能使用ffmpeg的LGPL构建。

你可以试试FFMpeg的.NET包装器:Video Converter for .NET(我是这个库的作者)。它将FFMpeg.exe嵌入到DLL中以便于部署,并且不会破坏GPL规则(FFMpeg未链接,并且包装器在与System.Diagnostics.Process的单独进程中调用它)。


5
投票

你可以使用这个nuget包:

Install-Package Xabe.FFmpeg

我正在尝试使用易于使用的跨平台FFmpeg包装器。

你可以在Xabe.FFmpeg找到更多相关信息

更多信息在documentation

转换很简单:

IConversionResult result = await Conversion.ToMp4(Resources.MkvWithAudio, output).Start();

2
投票

你可以从这里尝试一个简单的ffmpeg包装器:http://ivolo.mit.edu/post/Convert-Audio-Video-to-Any-Format-using-C.aspx


2
投票

对于Linux和Windows都可行的解决方案就是习惯在代码中使用控制台ffmpeg。我堆叠线程,编写一个简单的线程控制器类,然后你可以轻松地使用你想要使用的ffmpeg的功能。

例如,这包含使用ffmpeg从我指定的时间创建缩略图的部分。

在线程控制器中你有类似的东西

List<ThrdFfmpeg> threads = new List<ThrdFfmpeg>();

哪个是您运行的线程列表,我使用计时器来查找这些线程,如果Pole'ing不适合您的应用程序,您也可以设置一个事件。在这种情况下,thwffmpeg类包含,

public class ThrdFfmpeg
{
    public FfmpegStuff ffm { get; set; }
    public Thread thrd { get; set; }
}

FFmpegStuff包含各种ffmpeg功能,thrd显然是线程。

FfmpegStuff中的属性是FilesToProcess类,用于将信息传递给被调用进程,并在线程停止后接收信息。

public class FileToProcess
{
    public int videoID { get; set; }
    public string fname { get; set; }
    public int durationSeconds { get; set; }
    public List<string> imgFiles { get; set; }
}

VideoID(我使用数据库)告诉线程进程从数据库中取出哪个视频。 fname用于我的函数的其他使用FilesToProcess的部分,但这里没有使用。 durationSeconds - 由刚刚收集视频持续时间的线程填充。 imgFiles用于返回所创建的任何缩略图。

当我的目的是鼓励在易于控制的线程中使用ffmpeg时,我不想陷入我的代码中。

现在我们有我们可以添加到我们的线程列表中的部分,所以在我们的控制器中我们做了类似的事情,

        AddThread()
        {
        ThrdFfmpeg thrd;
        FileToProcess ftp;

        foreach(FileToProcess ff in  `dbhelper.GetFileNames(txtCategory.Text))`
        {
            //make a thread for each
            ftp = new FileToProcess();
            ftp = ff;
            ftp.imgFiles = new List<string>();
            thrd = new ThrdFfmpeg();
            thrd.ffm = new FfmpegStuff();
            thrd.ffm.filetoprocess = ftp;
            thrd.thrd = new   `System.Threading.Thread(thrd.ffm.CollectVideoLength);`

         threads.Add(thrd);
        }
        if(timerNotStarted)
             StartThreadTimer();
        }

现在,我们的线程成为一项简单的任务,

private void timerThreads_Tick(object sender, EventArgs e)
    {
        int runningCount = 0;
        int finishedThreads = 0;
        foreach(ThrdFfmpeg thrd in threads)
        {
            switch (thrd.thrd.ThreadState)
            {
                case System.Threading.ThreadState.Running:
                    ++runningCount;


 //Note that you can still view data progress here,
    //but remember that you must use your safety checks
    //here more than anywhere else in your code, make sure the data
    //is readable and of the right sort, before you read it.
                    break;
                case System.Threading.ThreadState.StopRequested:
                    break;
                case System.Threading.ThreadState.SuspendRequested:
                    break;
                case System.Threading.ThreadState.Background:
                    break;
                case System.Threading.ThreadState.Unstarted:


//Any threads that have been added but not yet started, start now
                    thrd.thrd.Start();
                    ++runningCount;
                    break;
                case System.Threading.ThreadState.Stopped:
                    ++finishedThreads;


//You can now safely read the results, in this case the
   //data contained in FilesToProcess
   //Such as
                    ThumbnailsReadyEvent( thrd.ffm );
                    break;
                case System.Threading.ThreadState.WaitSleepJoin:
                    break;
                case System.Threading.ThreadState.Suspended:
                    break;
                case System.Threading.ThreadState.AbortRequested:
                    break;
                case System.Threading.ThreadState.Aborted:
                    break;
                default:
                    break;
            }
        }


        if(flash)
        {//just a simple indicator so that I can see
         //that at least one thread is still running
            lbThreadStatus.BackColor = Color.White;
            flash = false;
        }
        else
        {
            lbThreadStatus.BackColor = this.BackColor;
            flash = true;
        }
        if(finishedThreads >= threads.Count())
        {

            StopThreadTimer();
            ShowSample();
            MakeJoinedThumb();
        }
    }

将您自己的事件放入控制器类中效果很好,但在视频工作中,当我自己的代码实际上没有进行任何视频文件处理时,poling然后调用控制类中的事件也可以。

使用这种方法,我已经慢慢建立了几乎所有视频和静止功能,我认为我将使用,所有这些都包含在一个类中,并且该类作为文本文件可用于Lunux和Windows版本,只有少量预处理指令。

© www.soinside.com 2019 - 2024. All rights reserved.