Come riprodurre un file

[La funzionalità associata a questa pagina, DirectShow, è una funzionalità legacy. È stata sostituita da MediaPlayer, FMMediaEngine e Audio/Video Capture in Media Foundation. Queste funzionalità sono state ottimizzate per Windows 10 e Windows 11. Microsoft consiglia vivamente che il nuovo codice usi MediaPlayer, FMMediaEngine e Audio/Video Capture in Media Foundation anziché DirectShow, quando possibile. Microsoft suggerisce che il codice esistente che usa le API legacy venga riscritto per usare le nuove API, se possibile.

Questo articolo è destinato a offrire il sapore della programmazione DirectShow. Presenta un'applicazione console semplice che riproduce un file audio o video. Il programma è lungo solo alcune righe, ma dimostra alcune delle potenzialità della programmazione DirectShow.

Come descritto nell'articolo Introduzione alla programmazione dell'applicazione DirectShow , un'applicazione DirectShow esegue sempre gli stessi passaggi di base:

  1. Creare un'istanza di Filter Graph Manager.
  2. Usare Filter Graph Manager per compilare un grafico di filtro.
  3. Eseguire il grafico, causando lo spostamento dei dati attraverso i filtri.

Per compilare e collegare il codice in questo argomento, includere il file di intestazione Dshow.h e il collegamento al file di libreria statica strmiids.lib. Per altre informazioni, vedere Compilazione di applicazioni DirectShow.

Iniziare chiamando CoInitialize o CoInitializeEx per inizializzare la libreria COM:

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

Per mantenere le cose semplici, questo esempio ignora il valore restituito, ma è consigliabile controllare sempre il valore HRESULT da qualsiasi chiamata al metodo.

Chiamare quindi CoCreateInstance per creare Filter Graph Manager:

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

Come illustrato, l'identificatore di classe (CLSID) è CLSID_FilterGraph. Filter Graph Manager viene fornito da una DLL in-process, quindi il contesto di esecuzione è CLSCTX_INPROC_SERVER. DirectShow supporta il modello di threading gratuito, quindi è anche possibile chiamare CoInitializeEx con il flag di COINIT_MULTITHREADED .

La chiamata a CoCreateInstance restituisce l'interfaccia IGraphBuilder , che contiene principalmente metodi per la compilazione del grafico del filtro. Per questo esempio sono necessarie due altre interfacce:

  • IMediaControl controlla lo streaming. Contiene metodi per arrestare e avviare il grafico.
  • IMediaEvent include metodi per ottenere eventi da Filter Graph Manager. In questo esempio l'interfaccia viene usata per attendere il completamento della riproduzione.

Entrambe queste interfacce vengono esposte da Filter Graph Manager. Usare il puntatore IGraphBuilder restituito per eseguirne una query:

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

È ora possibile compilare il grafico del filtro. Per la riproduzione dei file, questa operazione viene eseguita da una singola chiamata al metodo:

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

Il metodo IGraphBuilder::RenderFile compila un grafico di filtro che può riprodurre il file specificato. Il primo parametro è il nome del file, rappresentato come stringa di caratteri wide (2 byte). Il secondo parametro è riservato e deve essere uguale a NULL.

Questo metodo può non riuscire se il file specificato non esiste o il formato di file non è riconosciuto. Supponendo che il metodo abbia esito positivo, tuttavia, il grafico del filtro è ora pronto per la riproduzione. Per eseguire il grafico, chiamare il metodo IMediaControl::Run :

hr = pControl->Run();

Quando viene eseguito il grafico del filtro, i dati si spostano attraverso i filtri e vengono visualizzati come video e audio. La riproduzione si verifica in un thread separato. È possibile attendere il completamento della riproduzione chiamando il metodo IMediaEvent::WaitForCompletion :

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

Questo metodo blocca fino a quando il file non viene eseguito o fino al termine dell'intervallo di timeout specificato. Il valore INFINITE indica che l'applicazione blocca in modo indefinito fino a quando il file non viene eseguito. Per un esempio più realistico di gestione degli eventi, vedere Risposta agli eventi.

Al termine dell'applicazione, rilasciare i puntatori dell'interfaccia e chiudere la libreria COM:

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

Codice di esempio

Ecco il codice completo per l'esempio descritto in questo articolo:

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

Attività DirectShow di base