2008-09-01 7 views
19

Me gustaría abrir un pequeño archivo de video y asignar cada fotogramas en la memoria (para aplicar algunos filtros personalizados). No quiero manejar el códec de video, prefiero dejar que la biblioteca maneje eso para mí.C++: ¿Cuál es la biblioteca más fácil de abrir archivo de video

He intentado utilizar Direct Show con el filtro SampleGrabber (utilizando esta muestra http://msdn.microsoft.com/en-us/library/ms787867(VS.85).aspx), pero solo conseguí algunos fotogramas (¡no todos los fotogramas!). Soy bastante nuevo en la programación de software de video, tal vez no estoy usando la mejor biblioteca, o lo estoy haciendo mal.

me ha pegado una parte de mi código (principalmente un copiar/pegar modificado a partir del ejemplo de MSDN), desafortunadamente no grabb los 25 primeros fotogramas como se esperaba ...

[...] 

hr = pGrabber->SetOneShot(TRUE); 
hr = pGrabber->SetBufferSamples(TRUE); 

pControl->Run(); // Run the graph. 
pEvent->WaitForCompletion(INFINITE, &evCode); // Wait till it's done. 

// Find the required buffer size. 
long cbBuffer = 0; 
hr = pGrabber->GetCurrentBuffer(&cbBuffer, NULL); 

for(int i = 0 ; i < 25 ; ++i) 
{ 
    pControl->Run(); // Run the graph. 
    pEvent->WaitForCompletion(INFINITE, &evCode); // Wait till it's done. 

    char *pBuffer = new char[cbBuffer]; 
    hr = pGrabber->GetCurrentBuffer(&cbBuffer, (long*)pBuffer); 

    AM_MEDIA_TYPE mt; 
    hr = pGrabber->GetConnectedMediaType(&mt); 
    VIDEOINFOHEADER *pVih; 
    pVih = (VIDEOINFOHEADER*)mt.pbFormat; 

    [...] 
} 

[...] 

¿Hay alguien, con experiencia en software de video, ¿quién me puede aconsejar sobre el código u otra biblioteca más simple?

Gracias

Editar: enlaces MSDN parece no funcionar (see the bug)

Respuesta

26

Actualmente estos son los marcos de vídeo más populares disponibles en plataformas Win32:

  1. Video para Windows: Marco de ventanas viejas procedentes de la edad de Win95, pero sigue siendo ampliamente utilizado, ya que es muy sencillo de utilizar. Desafortunadamente solo admite archivos AVI para los que se ha instalado el códec VFW adecuado.

  2. DirectShow: estándar WinXP framework, básicamente puede cargar todos los formatos que puede reproducir con Windows Media Player. Bastante difícil de usar

  3. Ffmpeg: más precisamente libavcodec y libavformat que viene con la utilidad multimedia de código abierto Ffmpeg. Es extremadamente potente y puede leer muchos formatos (casi todo lo que puede jugar con VLC), incluso si no tiene el códec instalado en el sistema. Es bastante complicado de usar, pero siempre puedes inspirarte con el código de ffplay que viene con él o con otras implementaciones en software de código abierto. De todos modos, creo que es mucho más fácil de usar que DS (y mucho más rápido). Debe estar configurado por MinGW en Windows, pero todos los pasos se explican muy bien here (en este momento el enlace está caído, espero que no esté muerto).

  4. QuickTime: el marco de Apple no es la mejor solución para la plataforma Windows, ya que necesita la aplicación QuickTime para instalarse y también el códec QuickTime adecuado para cada formato; no es compatible con muchos formatos, pero es bastante común en el campo profesional (por lo que algunos códecs son en realidad solo para QuickTime). No debería ser demasiado difícil de implementar.

  5. Gstreamer: último marco de código abierto. No sé mucho al respecto, supongo que abarca algunos de los otros sistemas (pero no estoy seguro).

Todos estos marcos se han implementado como back-end en OpenCv Highgui, excepto para DirectShow. El marco predeterminado para Win32 OpenCV es usar VFW (y por lo tanto solo puede abrir algunos archivos AVI), si quieres usar los demás, debes descargar el CVS en lugar del lanzamiento oficial y aún así hacer algo de piratería en el código y de todos modos no demasiado completo, por ejemplo, el backend FFMPEG no permite buscar en la transmisión. Si desea utilizar QuickTime con OpenCV, this puede ayudarlo.

2

he utilizado OpenCV para cargar archivos de vídeo y procesarlos. También es útil para muchos tipos de procesamiento de video, incluidos los útiles para la visión por computadora.

1

Intente utilizar la biblioteca OpenCV. Definitivamente tiene las capacidades que necesita.

This guide tiene una sección sobre el acceso a cuadros de un archivo de video.

2

El uso del modelo "Devolución de llamada" de SampleGrabber puede brindarle mejores resultados. Vea el ejemplo en Samples \ C++ \ DirectShow \ Editing \ GrabBitmaps.

También hay mucha información en Samples \ C++ \ DirectShow \ Filters \ Grabber2 \ grabber_text.txt y readme.txt.

1

Si fuera por archivos AVI, leería los datos del archivo AVI y extraería los marcos. Ahora usa el administrador de compresión de video para descomprimirlo.

El formato de archivo AVI es muy simple, consulte: http://msdn.microsoft.com/en-us/library/dd318187(VS.85).aspx (y use google).

Una vez que tenga el archivo abierto, simplemente extraiga cada cuadro y páselo a ICDecompress() para descomprimirlo.

Parece mucho trabajo, pero es la forma más confiable.

Si eso es demasiado trabajo, o si quieres más que archivos AVI, utiliza ffmpeg.

1

OpenCV es la mejor solución si el video en su caso solo necesita generar una secuencia de imágenes. Si estás dispuesto a hacer un procesamiento de video real, por lo que ViDeo es igual a "Visual Audio", necesitas seguir el ritmo de los que ofrece "martjno". Las nuevas soluciones de Windows también incluyen 3 nuevas posibilidades:

  1. Windows Media Foundation: sucesor de DirectShow; limpiaran interfaz
  2. Windows Media Encoder 9: no sólo incluyen el Programm, también las bibliotecas de los buques para la codificación
  3. de Windows Expresión 4: Sucesor de 2.

Última 2 son soluciones de sólo comercial , pero el primero es gratis. Para codificar WMF, debe instalar el SDK de Windows.

1

Sé que es muy tentador en C++ obtener un desglose adecuado de los archivos de video y simplemente hágalo usted mismo. Pero a pesar de que la información está disponible, es un proceso tan largo construir clases para entregar cada formato de archivo, y hacerlo fácilmente modificable para tener en cuenta los futuros cambios de estructura, que francamente no vale la pena el esfuerzo.

En lugar de eso, recomiendo ffmpeg. Recibió una mención anterior, pero dice que es difícil, no es difícil. Hay muchas más opciones de las que la mayoría de la gente necesitaría, lo que hace que parezca más difícil de lo que es. Para la mayoría de las operaciones, puedes dejar que ffmpeg lo resuelva solo.

Por ejemplo, una conversión de archivos ffmpeg -i inputFile.mp4 outputFile.avi

Decidir desde el principio que va a tener operaciones ffmpeg se ejecutan en un hilo, o más precisamente una biblioteca hilo.Pero haz que tu propia clase de subprocesos lo ajuste para que puedas tener tus propios EventAgs y los métodos para verificar el hilo hayan finalizado. Algo así como: -

ThreadLibManager() 
{ 
    List<MyThreads> listOfActiveThreads; 
    public AddThread(MyThreads); 
} 
Your thread class is something like:- 
class MyThread 
{ 
public Thread threadForThisInstance { get; set; } 
public MyFFMpegTools mpegTools { get; set; } 
} 
MyFFMpegTools performs many different video operations, so you want your own event 
args to tell your parent code precisely what type of operation has just raised and 
event. 
enum MyFmpegArgs 
{ 
public int thisThreadID { get; set; } //Set as a new MyThread is added to the List<> 
public MyFfmpegType operationType {get; set;} 
//output paths etc that the parent handler will need to find output files 
} 
enum MyFfmpegType 
{ 
    FF_CONVERTFILE = 0, FF_CREATETHUMBNAIL, FF_EXTRACTFRAMES ... 
} 

Aquí es un pequeño fragmento de mi clase de herramienta ffmpeg, esta parte la recopilación de información acerca de un vídeo. Pongo FFmpeg en una ubicación particular y, al inicio del software, se asegura de que esté allí. Para esta versión la he movido al escritorio, estoy bastante seguro de haber escrito la ruta correcta para ti (realmente odio el sistema de carpetas especiales de MS, así que lo ignoro tanto como puedo).

De todos modos, es un ejemplo del uso de ffmpeg sin ventana.

 public string GetVideoInfo(FileInfo fi) 
    { 
     outputBuilder.Clear(); 
     string strCommand = string.Concat(" -i \"", fi.FullName, "\""); 
     string ffPath = 
    System.Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\ffmpeg.exe"; 
     string oStr = ""; 

     try 
     { 
      Process build = new Process(); 
      //build.StartInfo.WorkingDirectory = @"dir"; 
      build.StartInfo.Arguments = strCommand; 
      build.StartInfo.FileName = ffPath; 

      build.StartInfo.UseShellExecute = false; 
      build.StartInfo.RedirectStandardOutput = true; 
      build.StartInfo.RedirectStandardError = true; 
      build.StartInfo.CreateNoWindow = true; 
      build.ErrorDataReceived += build_ErrorDataReceived; 
      build.OutputDataReceived += build_ErrorDataReceived; 
      build.EnableRaisingEvents = true; 
      build.Start(); 
      build.BeginOutputReadLine(); 
      build.BeginErrorReadLine(); 
      build.WaitForExit(); 


      string findThis = "start"; 
      int offset = 0; 
      foreach (string str in outputBuilder) 
      { 
       if (str.Contains("Duration")) 
       { 
        offset = str.IndexOf(findThis); 
        oStr = str.Substring(0, offset); 
       } 
      } 
     } 
     catch 
     { 
      oStr = "Error collecting file information"; 
     } 

     return oStr; 
    } 
    private void build_ErrorDataReceived(object sender, DataReceivedEventArgs e) 
    { 
     string strMessage = e.Data; 
     if (outputBuilder != null && strMessage != null) 
     { 
      outputBuilder.Add(string.Concat(strMessage, "\n")); 
     } 
    } 
Cuestiones relacionadas