Cómo reproducir un archivo

[La característica asociada a esta página, DirectShow, es una característica heredada. Se ha reemplazado por MediaPlayer, IMFMediaEngine y Captura de audio/vídeo en Media Foundation. Esas características se han optimizado para Windows 10 y Windows 11. Microsoft recomienda encarecidamente que el nuevo código use MediaPlayer, IMFMediaEngine y Audio/Video Capture en Media Foundation en lugar de DirectShow, siempre que sea posible. Microsoft sugiere que el código existente que usa las API heredadas se reescriba para usar las nuevas API si es posible.

Este artículo está pensado para darle el sabor de la programación de DirectShow. Presenta una sencilla aplicación de consola que reproduce un archivo de audio o vídeo. El programa es sólo unas pocas líneas de largo, pero muestra algunas de las potencias de la programación de DirectShow.

Como se describe en el artículo Introducción a la programación de aplicaciones de DirectShow , una aplicación DirectShow siempre realiza los mismos pasos básicos:

  1. Cree una instancia del Administrador de gráficos de filtros.
  2. Use el Administrador de gráficos de filtros para crear un grafo de filtro.
  3. Ejecute el gráfico, lo que hace que los datos se muevan a través de los filtros.

Para compilar y vincular el código de este tema, incluya el archivo de encabezado Dshow.h y el vínculo al archivo de biblioteca estática strmiids.lib. Para obtener más información, vea Compilar aplicaciones directShow.

Comience llamando a CoInitialize o CoInitializeEx para inicializar la biblioteca COM:

HRESULT hr = CoInitialize(NULL);
if (FAILED(hr))
{
    // Add error-handling code here. (Omitted for clarity.)
}

Para simplificar las cosas, en este ejemplo se omite el valor devuelto, pero siempre debe comprobar el valor HRESULT de cualquier llamada al método.

A continuación, llame a CoCreateInstance para crear el Administrador de gráficos de filtros:

IGraphBuilder *pGraph;
HRESULT hr = CoCreateInstance(CLSID_FilterGraph, NULL, 
    CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&pGraph);

Como se muestra, el identificador de clase (CLSID) es CLSID_FilterGraph. El Administrador de gráficos de filtros lo proporciona un archivo DLL en proceso, por lo que el contexto de ejecución se CLSCTX_INPROC_SERVER. DirectShow admite el modelo de subprocesos libres, por lo que también puede llamar a CoInitializeEx con la marca COINIT_MULTITHREADED .

La llamada a CoCreateInstance devuelve la interfaz IGraphBuilder , que contiene principalmente métodos para compilar el gráfico de filtros. Se necesitan otras dos interfaces para este ejemplo:

  • IMediaControl controla el streaming. Contiene métodos para detener e iniciar el gráfico.
  • IMediaEvent tiene métodos para obtener eventos del Administrador de graph de filtros. En este ejemplo, la interfaz se usa para esperar a que se complete la reproducción.

El Administrador de gráficos de filtros expone ambas interfaces. Use el puntero IGraphBuilder devuelto para consultarlos:

IMediaControl *pControl;
IMediaEvent   *pEvent;
hr = pGraph->QueryInterface(IID_IMediaControl, (void **)&pControl);
hr = pGraph->QueryInterface(IID_IMediaEvent, (void **)&pEvent);

Ahora puede compilar el gráfico de filtros. Para la reproducción de archivos, esto se realiza mediante una llamada de método único:

hr = pGraph->RenderFile(L"C:\\Example.avi", NULL);

El método IGraphBuilder::RenderFile crea un grafo de filtro que puede reproducir el archivo especificado. El primer parámetro es el nombre de archivo, representado como una cadena de caracteres anchos (2 bytes). El segundo parámetro está reservado y debe ser igual a NULL.

Este método puede producir un error si el archivo especificado no existe o no se reconoce el formato de archivo. Suponiendo que el método se realiza correctamente, sin embargo, el gráfico de filtros ya está listo para su reproducción. Para ejecutar el grafo, llame al método IMediaControl::Run :

hr = pControl->Run();

Cuando se ejecuta el grafo de filtro, los datos se mueven por los filtros y se representan como vídeo y audio. La reproducción se produce en un subproceso independiente. Puede esperar a que se complete la reproducción llamando al método IMediaEvent::WaitForCompletion :

long evCode = 0;
pEvent->WaitForCompletion(INFINITE, &evCode);

Este método se bloquea hasta que se realiza la reproducción del archivo o hasta que transcurre el intervalo de tiempo de espera especificado. El valor INFINITE significa que la aplicación se bloquea indefinidamente hasta que el archivo haya terminado de reproducirse. Para obtener un ejemplo más realista del control de eventos, consulte Responder a eventos.

Cuando finalice la aplicación, libere los punteros de interfaz y cierre la biblioteca COM:

pControl->Release();
pEvent->Release();
pGraph->Release();
CoUninitialize();

Código de ejemplo

Este es el código completo del ejemplo descrito en este artículo:

#include <dshow.h>
void main(void)
{
    IGraphBuilder *pGraph = NULL;
    IMediaControl *pControl = NULL;
    IMediaEvent   *pEvent = NULL;

    // Initialize the COM library.
    HRESULT hr = CoInitialize(NULL);
    if (FAILED(hr))
    {
        printf("ERROR - Could not initialize COM library");
        return;
    }

    // Create the filter graph manager and query for interfaces.
    hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, 
                        IID_IGraphBuilder, (void **)&pGraph);
    if (FAILED(hr))
    {
        printf("ERROR - Could not create the Filter Graph Manager.");
        return;
    }

    hr = pGraph->QueryInterface(IID_IMediaControl, (void **)&pControl);
    hr = pGraph->QueryInterface(IID_IMediaEvent, (void **)&pEvent);

    // Build the graph. IMPORTANT: Change this string to a file on your system.
    hr = pGraph->RenderFile(L"C:\\Example.avi", NULL);
    if (SUCCEEDED(hr))
    {
        // Run the graph.
        hr = pControl->Run();
        if (SUCCEEDED(hr))
        {
            // Wait for completion.
            long evCode;
            pEvent->WaitForCompletion(INFINITE, &evCode);

            // Note: Do not use INFINITE in a real application, because it
            // can block indefinitely.
        }
    }
    pControl->Release();
    pEvent->Release();
    pGraph->Release();
    CoUninitialize();
}

Tareas básicas de DirectShow