Passaggio 3: Compilare il grafico filtro
[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 argomento è il passaggio 3 dell'esercitazione Riproduzione audio/video in DirectShow. Il codice completo viene visualizzato nell'argomento DirectShow Playback Example.
Il passaggio successivo consiste nel creare un grafico di filtro per riprodurre il file multimediale.
Apertura di un file multimediale
Il DShowPlayer::OpenFile
metodo apre un file multimediale per la riproduzione. Questo metodo esegue le operazioni seguenti:
- Crea un nuovo grafico di filtro (vuoto).
- Chiama IGraphBuilder::AddSourceFilter per aggiungere un filtro di origine per il file specificato.
- Esegue il rendering dei flussi nel filtro di origine.
HRESULT DShowPlayer::OpenFile(PCWSTR pszFileName)
{
IBaseFilter *pSource = NULL;
// Create a new filter graph. (This also closes the old one, if any.)
HRESULT hr = InitializeGraph();
if (FAILED(hr))
{
goto done;
}
// Add the source filter to the graph.
hr = m_pGraph->AddSourceFilter(pszFileName, NULL, &pSource);
if (FAILED(hr))
{
goto done;
}
// Try to render the streams.
hr = RenderStreams(pSource);
done:
if (FAILED(hr))
{
TearDownGraph();
}
SafeRelease(&pSource);
return hr;
}
Creazione di Filter Graph Manager
Il DShowPlayer::InitializeGraph
metodo crea un nuovo grafico di filtro. Questo metodo esegue le operazioni seguenti:
- Chiama CoCreateInstance per creare una nuova istanza di Filter Graph Manager.
- Esegue query su Filter Graph Manager per le interfacce IMediaControl e IMediaEventEx .
- Chiama IMediaEventEx::SetNotifyWindow per configurare la notifica degli eventi. Per altre informazioni, vedere Notifica eventi in DirectShow.
HRESULT DShowPlayer::InitializeGraph()
{
TearDownGraph();
// Create the Filter Graph Manager.
HRESULT hr = CoCreateInstance(CLSID_FilterGraph, NULL,
CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&m_pGraph));
if (FAILED(hr))
{
goto done;
}
hr = m_pGraph->QueryInterface(IID_PPV_ARGS(&m_pControl));
if (FAILED(hr))
{
goto done;
}
hr = m_pGraph->QueryInterface(IID_PPV_ARGS(&m_pEvent));
if (FAILED(hr))
{
goto done;
}
// Set up event notification.
hr = m_pEvent->SetNotifyWindow((OAHWND)m_hwnd, WM_GRAPH_EVENT, NULL);
if (FAILED(hr))
{
goto done;
}
m_state = STATE_STOPPED;
done:
return hr;
}
Rendering dei flussi
Il passaggio successivo consiste nel connettere il filtro di origine a uno o più filtri del renderer.
Il DShowPlayer::RenderStreams
metodo esegue i passaggi seguenti.
- Esegue query sull'interfaccia Filter Graph Manager per l'interfaccia IFilterGraph2 .
- Aggiunge un filtro del renderer video al grafico del filtro.
- Aggiunge il filtro Renderer DirectSound al grafico del filtro per supportare la riproduzione audio. Per altre informazioni sull'aggiunta di filtri al grafico dei filtri, vedere Aggiungere un filtro per CLSID.
- Enumera i pin di output nel filtro di origine. Per altre informazioni sull'enumerazione dei pin, vedere Enumerazione dei pin.
- Per ogni pin, chiama il metodo IFilterGraph2::RenderEx . Questo metodo connette il pin di output a un filtro del renderer, aggiungendo filtri intermedi se necessario (ad esempio decodificatori).
- Chiamate
CVideoRenderer::FinalizeGraph
per completare l'inizializzazione del renderer video. - Rimuove il filtro Renderer DirectSound se tale filtro non è connesso a un altro filtro. Ciò può verificarsi se il file di origine non contiene un flusso audio.
// Render the streams from a source filter.
HRESULT DShowPlayer::RenderStreams(IBaseFilter *pSource)
{
BOOL bRenderedAnyPin = FALSE;
IFilterGraph2 *pGraph2 = NULL;
IEnumPins *pEnum = NULL;
IBaseFilter *pAudioRenderer = NULL;
HRESULT hr = m_pGraph->QueryInterface(IID_PPV_ARGS(&pGraph2));
if (FAILED(hr))
{
goto done;
}
// Add the video renderer to the graph
hr = CreateVideoRenderer();
if (FAILED(hr))
{
goto done;
}
// Add the DSound Renderer to the graph.
hr = AddFilterByCLSID(m_pGraph, CLSID_DSoundRender,
&pAudioRenderer, L"Audio Renderer");
if (FAILED(hr))
{
goto done;
}
// Enumerate the pins on the source filter.
hr = pSource->EnumPins(&pEnum);
if (FAILED(hr))
{
goto done;
}
// Loop through all the pins
IPin *pPin;
while (S_OK == pEnum->Next(1, &pPin, NULL))
{
// Try to render this pin.
// It's OK if we fail some pins, if at least one pin renders.
HRESULT hr2 = pGraph2->RenderEx(pPin, AM_RENDEREX_RENDERTOEXISTINGRENDERERS, NULL);
pPin->Release();
if (SUCCEEDED(hr2))
{
bRenderedAnyPin = TRUE;
}
}
hr = m_pVideo->FinalizeGraph(m_pGraph);
if (FAILED(hr))
{
goto done;
}
// Remove the audio renderer, if not used.
BOOL bRemoved;
hr = RemoveUnconnectedRenderer(m_pGraph, pAudioRenderer, &bRemoved);
done:
SafeRelease(&pEnum);
SafeRelease(&pAudioRenderer);
SafeRelease(&pGraph2);
// If we succeeded to this point, make sure we rendered at least one
// stream.
if (SUCCEEDED(hr))
{
if (!bRenderedAnyPin)
{
hr = VFW_E_CANNOT_RENDER;
}
}
return hr;
}
Ecco il codice per la funzione, usato nell'esempio RemoveUnconnectedRenderer
precedente.
HRESULT RemoveUnconnectedRenderer(IGraphBuilder *pGraph, IBaseFilter *pRenderer, BOOL *pbRemoved)
{
IPin *pPin = NULL;
*pbRemoved = FALSE;
// Look for a connected input pin on the renderer.
HRESULT hr = FindConnectedPin(pRenderer, PINDIR_INPUT, &pPin);
SafeRelease(&pPin);
// If this function succeeds, the renderer is connected, so we don't remove it.
// If it fails, it means the renderer is not connected to anything, so
// we remove it.
if (FAILED(hr))
{
hr = pGraph->RemoveFilter(pRenderer);
*pbRemoved = TRUE;
}
return hr;
}
Rilascio del grafico filtro
Quando l'applicazione viene chiusa, deve rilasciare il grafico del filtro, come illustrato nel codice seguente.
void DShowPlayer::TearDownGraph()
{
// Stop sending event messages
if (m_pEvent)
{
m_pEvent->SetNotifyWindow((OAHWND)NULL, NULL, NULL);
}
SafeRelease(&m_pGraph);
SafeRelease(&m_pControl);
SafeRelease(&m_pEvent);
delete m_pVideo;
m_pVideo = NULL;
m_state = STATE_NO_GRAPH;
}
Passaggio 4: Aggiungere il renderer video.
Argomenti correlati