c# - ¿Usando FFmpeg en.net?
video (6)
GPL-compiled ffmpeg se puede utilizar desde un programa que no sea GPL (proyecto comercial) solo si se invoca en el proceso separado como utilidad de línea de comandos; todos los contenedores vinculados con la biblioteca ffmpeg (incluido FFMpegInterop de Microsoft) solo pueden usar la compilación LGPL de ffmpeg.
Puede probar mi .NET wrapper para FFMpeg: Video Converter para .NET (soy autor de esta biblioteca). Incorpora FFMpeg.exe en la DLL para una fácil implementación y no rompe las reglas de GPL (FFMpeg NO está vinculado y wrapper lo invoca en el proceso por separado con System.Diagnostics.Process).
Así que sé que es un desafío bastante grande, pero quiero escribir un reproductor / convertidor de películas básico en c # utilizando la biblioteca FFmpeg. Sin embargo, el primer obstáculo que necesito superar es envolver la biblioteca de FFmpeg en c #. He descargado ffmpeg pero no pude compilarlo en Windows, así que descargué una versión precompilada para mí. Bien impresionante. Luego comencé a buscar envoltorios de C #.
He mirado alrededor y he encontrado algunos envoltorios como SharpFFmpeg ( http://sourceforge.net/projects/sharpffmpeg/ ) y ffmpeg-sharp ( http://code.google.com/p/ffmpeg-sharp/ ). Antes que nada, quería usar ffmpeg-sharp como su LGPL y SharpFFmpeg como GPL. Sin embargo, tenía bastantes errores de compilación. Resulta que fue escrito para el compilador mono, intenté compilarlo con mono pero no pude entender cómo. Luego, comencé a corregir manualmente los errores del compilador, pero encontré algunos que daban miedo y pensé que sería mejor dejarlos en paz. Así que me di por vencido en ffmpeg-sharp.
Luego miré SharpFFmpeg y parece lo que quiero, todas las funciones P / Invocadas para mí. Sin embargo, su GPL? Tanto los archivos AVCodec.cs como AVFormat.cs se ven como puertos de avcodec.c y avformat.c, que creo que podría portarme a mí mismo. Entonces no tiene que preocuparse por la licencia.
Pero quiero hacerlo bien antes de continuar y comenzar a codificar. Debería:
- Escribir mi propia biblioteca C ++ para interactuar con ffmpeg, luego hacer que mi programa C # hable con la biblioteca C ++ para reproducir / convertir videos, etc.
O
- Port avcodec.h y avformat.h (¿eso es todo lo que necesito?) A c # usando un montón de DllImports y escríbelo por completo en C #.
En primer lugar, considere que no soy muy bueno en C ++ ya que rara vez lo uso, pero sé lo suficiente como para moverme. La razón por la que creo que # 1 podría ser la mejor opción es porque la mayoría de los tutoriales de FFmpeg están en C ++ y también tengo más control sobre la administración de la memoria que si tuviera que hacerlo en c #.
¿Qué piensas? Además, ¿podría tener algún enlace útil (tal vez un tutorial) para usar FFmpeg?
Puede probar un contenedor simple de ffmpeg .NET desde aquí: http://ivolo.mit.edu/post/Convert-Audio-Video-to-Any-Format-using-C.aspx
Puedes usar este paquete nuget:
Install-Package Xabe.FFmpeg
Estoy tratando de hacer una envoltura FFmpeg fácil de usar y multiplataforma.
Puede encontrar más información sobre esto en Xabe.FFmpeg
Más información en documentation
La conversión es simple:
IConversionResult result = await Conversion.ToMp4(Resources.MkvWithAudio, output).Start();
Una solución que es viable tanto para Linux como para Windows es simplemente acostumbrarse a usar la consola ffmpeg en su código. Apilo hilos, escribo una clase de controlador de hilo simple, luego puede hacer uso fácilmente de la funcionalidad de ffmpeg que quiera usar.
Como ejemplo, esto contiene secciones que usan ffmpeg para crear una miniatura a partir de una hora que especifico.
En el controlador de hilo tiene algo así como
List<ThrdFfmpeg> threads = new List<ThrdFfmpeg>();
¿Cuál es la lista de hilos que está ejecutando? Utilizo un temporizador para polarizar estos hilos, también puede configurar un evento si Pole''ing no es adecuado para su aplicación. En este caso, la clase Thrdffmpeg contiene,
public class ThrdFfmpeg
{
public FfmpegStuff ffm { get; set; }
public Thread thrd { get; set; }
}
FFmpegStuff contiene varias funcionalidades de ffmpeg, thrd es obviamente el hilo.
Una propiedad en FfmpegStuff es la clase FilesToProcess, que se utiliza para pasar información al proceso llamado y recibir información una vez que el hilo se ha detenido.
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 (utilizo una base de datos) le dice al proceso enhebrado qué video usar tomado de la base de datos. fname se usa en otras partes de mis funciones que usan FilesToProcess, pero no se usan aquí. durationSeconds: se completa con los hilos que solo recopilan la duración del video. imgFiles se utiliza para devolver las miniaturas que se crearon.
No quiero empantanarme en mi código cuando el propósito de esto es fomentar el uso de ffmpeg en hilos fácilmente controlados.
Ahora tenemos nuestras piezas que podemos agregar a nuestra lista de hilos, así que en nuestro controlador hacemos algo como,
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();
}
Ahora Pole''ing nuestros hilos se convierte en una tarea simple,
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();
}
}
Poner sus propios eventos en la clase de controlador funciona bien, pero en el trabajo de video, cuando mi propio código no está procesando el archivo de video, el uso de poling y la invocación de un evento en la clase de control funcionan igual de bien.
Usando este método, he construido lentamente casi todas las funciones de video y fotogramas que creo que usaré alguna vez, todas contenidas en una clase, y esa clase como un archivo de texto es utilizable en la versión de Lunux y Windows, con solo un pequeño número de las directivas previas al proceso.
unas cuantas otras envolturas administradas para que revisen
Escribir sus propias envolturas de interoperabilidad puede ser un proceso largo y difícil en .NET. La escritura de una biblioteca C ++ para la interoperabilidad presenta algunas ventajas, especialmente porque le permite simplificar enormemente la interfaz que tiene el código C #. Sin embargo, si solo necesita un subconjunto de la biblioteca, puede hacer su vida más fácil hacer la interoperabilidad en C #.