在.net 中使用 FFmpeg?

所以我知道这是一个相当大的挑战,但是我想使用 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。然而,它有相当多的编译错误。原来它是为 mono 编译器编写的,我试着用 mono 编译它,但不知道怎么编译。然后我开始自己手动修复编译器错误,但是遇到了一些可怕的错误,我想我最好不要去管它们。所以我放弃了 fmpeg-Sharp。

然后我查看 SharpFFmpeg,它看起来像我想要的,所有的函数 P/为我调用。然而它的 GPL?这两个 AVCodec.cs 和 AVFormat.cs 文件看起来都像 avcodec.c 和 avform.c 的端口,我认为我可以自己移植?那就不用担心执照的问题了。

但是在我开始编程之前,我想先搞清楚这一点。我应该:

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

或者

  1. 端口 avcodec.h 和 avform.h (这就是我需要的全部吗?)通过使用大量的 DllImports 并完全用 C # 写出来?

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

你觉得怎么样? 您是否碰巧有使用 FFmpeg 的有用链接(也许是一个教程) ?

155270 次浏览

还有一些其他的托管包装要检查

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

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

你可以试试我的。NET 包装器用于 FFMpeg: 用于.NET 的视频转换器(我是这个库的作者)。它将 FFMpeg.exe 嵌入到 DLL 中以便于部署,并且不违反 GPL 规则(FFMpeg 没有链接,而且包装器在 System 的单独进程中调用它。诊断。程序)。

最初的问题现在已经超过5年了。与此同时,现在有一个来自 Fmpeg的 WinRT 解决方案和来自 微软的集成示例。

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

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

在线程控制器中,类似于

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

这是你正在运行的线程列表,我使用一个计时器来极点这些线程,你也可以设置一个事件,如果极点不适合你的应用程序。 在这种情况下,thw 类 Thrdffmpeg 包含,

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

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

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 的函数的其他部分,但这里不使用。 DurationSecond-由收集视频持续时间的线程填充。 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 版本中使用,只需要少量的预处理指令。

你可以使用下面这个 nuget 软件包:

Install-Package Xabe.FFmpeg

我试图使用容易,跨平台的 FFmpeg 包装器。

你可以在 Xabe FFmpeg找到更多关于这方面的信息

更多信息在 文件

转换很简单:

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