在.net 中使用 FFmpeg?

发布于 2024-08-26 18:05:20 字数 1141 浏览 6 评论 0 原文

所以我知道这是一个相当大的挑战,但我想使用 FFmpeg 库用 C# 编写一个基本的电影播放器​​/转换器。然而,我需要克服的第一个障碍是用 C# 包装 FFmpeg 库。我已经下载了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. 将 avcodec.h 和 avformat.h(这就是我所需要的吗?)移植到c# 使用大量 DllImports 并完全用 C# 编写?

首先,考虑到我不太擅长 C++,因为我很少使用它,但我知道的足够多了。我认为 #1 可能是更好的选择的原因是,大多数 FFmpeg 教程都是用 C++ 编写的,而且与用 C# 相比,我对内存管理也有更多的控制权。

你怎么认为? 另外,您是否有任何使用 FFmpeg 的有用链接(也许是教程)?

So I know its a fairly big challenge but I want to write a basic movie player/converter in c# using the FFmpeg library. However, the first obstacle I need to overcome is wrapping the FFmpeg library in c#. I've downloaded ffmpeg but couldn't compile it on Windows, so I downloaded a precompiled version for me. Ok awesome. Then I started looking for C# wrappers.

I have looked around and have found a few wrappers such as SharpFFmpeg (http://sourceforge.net/projects/sharpffmpeg/) and ffmpeg-sharp (http://code.google.com/p/ffmpeg-sharp/). First of all, I wanted to use ffmpeg-sharp as its LGPL and SharpFFmpeg is GPL. However, it had quite a few compile errors. Turns out it was written for the mono compiler, I tried compiling it with mono but couldn't figure out how. I then started to manually fix the compiler errors myself, but came across a few scary ones and thought I'd better leave those alone. So I gave up on ffmpeg-sharp.

Then I looked at SharpFFmpeg and it looks like what I want, all the functions P/Invoked for me. However its GPL? Both the AVCodec.cs and AVFormat.cs files look like ports of avcodec.c and avformat.c which I reckon I could port myself? Then not have to worry about licencing.

But I want to get this right before I go ahead and start coding. Should I:

  1. Write my own C++ library for interacting with ffmpeg, then have my C# program talk to the C++ library in order to play/convert videos etc.

OR

  1. Port avcodec.h and avformat.h (is that all i need?) to c# by using a whole lot of DllImports and write it entirely in C#?

First of all consider that I'm not great at C++ as I rarely use it but I know enough to get around. The reason I'm thinking #1 might be the better option is that most FFmpeg tutorials are in C++ and I'd also have more control over memory management than if I was to do it in c#.

What do you think?
Also would you happen to have any useful links (perhaps a tutorial) for using FFmpeg?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

花开雨落又逢春i 2024-09-02 18:05:20

最初的问题现在已有 5 年多了。与此同时,现在有来自 ffmpeg 的 WinRT 解决方案和来自 微软

The original question is now more than 5 years old. In the meantime there is now a solution for a WinRT solution from ffmpeg and an integration sample from Microsoft.

萌面超妹 2024-09-02 18:05:20

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

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

a few other managed wrappers for you to check out

Writing your own interop wrappers can be a time-consuming and difficult process in .NET. There are some advantages to writing a C++ library for the interop - particularly as it allows you to greatly simplify the interface that the C# code. However, if you are only needing a subset of the library, it might make your life easier to just do the interop in C#.

贩梦商人 2024-09-02 18:05:20

您可以使用这个 nuget 包:

Install-Package Xabe.FFmpeg

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

您可以在 Xabe.FFmpeg 中找到更多信息。

更多信息在 文档

转换很简单:

var conversion = await FFmpeg.Conversions.FromSnippet.ToMp4(Resources.MkvWithAudio, output);
await conversion.Start();

You can use this nuget package:

Install-Package Xabe.FFmpeg

I'm trying to make easy to use, cross-platform FFmpeg wrapper.

You can find more information about this at Xabe.FFmpeg

More info in documentation

Conversion is simple:

var conversion = await FFmpeg.Conversions.FromSnippet.ToMp4(Resources.MkvWithAudio, output);
await conversion.Start();
熊抱啵儿 2024-09-02 18:05:20

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

您可以尝试我的 FFMpeg .NET 包装器:Video Converter for .NET(我是该库的作者)。它将 FFMpeg.exe 嵌入到 DLL 中以方便部署,并且不会违反 GPL 规则(FFMpeg 未链接,包装器在使用 System.Diagnostics.Process 的单独进程中调用它)。

GPL-compiled ffmpeg can be used from non-GPL program (commercial project) only if it is invoked in the separate process as command line utility; all wrappers that are linked with ffmpeg library (including Microsoft's FFMpegInterop) can use only LGPL build of ffmpeg.

You may try my .NET wrapper for FFMpeg: Video Converter for .NET (I'm an author of this library). It embeds FFMpeg.exe into the DLL for easy deployment and doesn't break GPL rules (FFMpeg is NOT linked and wrapper invokes it in the separate process with System.Diagnostics.Process).

面如桃花 2024-09-02 18:05:20

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

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

在线程控制器中,您有类似“

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

哪个是您正在运行的线程列表”之类的内容,我使用计时器来对这些线程进行 Pole 操作,如果 Pole'ing 不适合您的应用程序,您还可以设置一个事件。
在本例中thw类Thrdffmpeg包含,

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 的函数的其他部分,但此处未使用。
urationSeconds - 由仅收集视频持续时间的线程填充。
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();
        }
    }

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

使用这种方法,我慢慢地构建了我认为我会使用的几乎所有视频和静态功能,所有这些功能都包含在一个类中,并且该类作为文本文件可以在 Lunux 和 Windows 版本上使用,只有一小部分预处理指令。

A solution that is viable for both Linux and Windows is to just get used to using console ffmpeg in your code. I stack up threads, write a simple thread controller class, then you can easily make use of what ever functionality of ffmpeg you want to use.

As an example, this contains sections use ffmpeg to create a thumbnail from a time that I specify.

In the thread controller you have something like

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

Which is the list of threads that you are running, I make use of a timer to Pole these threads, you can also set up an event if Pole'ing is not suitable for your application.
In this case thw class Thrdffmpeg contains,

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

FFmpegStuff contains the various ffmpeg functionality, thrd is obviously the thread.

A property in FfmpegStuff is the class FilesToProcess, which is used to pass information to the called process, and receive information once the thread has stopped.

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 (I use a database) tells the threaded process which video to use taken from the database.
fname is used in other parts of my functions that use FilesToProcess, but not used here.
durationSeconds - is filled in by the threads that just collect video duration.
imgFiles is used to return any thumbnails that were created.

I do not want to get bogged down in my code when the purpose of this is to encourage the use of ffmpeg in easily controlled threads.

Now we have our pieces we can add to our threads list, so in our controller we do something like,

        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();
        }

Now Pole'ing our threads becomes a simple task,

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();
        }
    }

Putting your own events onto into the controller class works well, but in video work, when my own code is not actually doing any of the video file processing, poling then invoking an event in the controlling class works just as well.

Using this method I have slowly built up just about every video and stills function I think I will ever use, all contained in the one class, and that class as a text file is useable on the Lunux and Windows version, with just a small number of pre-process directives.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文