步驟 3:建置篩選圖形
[與此頁面相關聯的功能,DirectShow是舊版功能。 它已被 MediaPlayer、IMF媒體引擎和媒体基础中的音频/视频捕获 取代。 這些功能已針對 Windows 10 和 Windows 11 進行優化。 Microsoft強烈建議新程式代碼盡可能使用MediaPlayer、IMFMediaEngine 和 Media Foundation中的音訊/視訊擷取,而不是 DirectShow。 Microsoft建議使用舊版 API 的現有程式代碼,盡可能改寫成使用新的 API。]
本主題是 DirectShow 中音訊/視訊播放教學課程的步驟 3。 完整的程式代碼會顯示在 DirectShow 播放範例 主題中,。
下一個步驟是建置篩選圖形以播放媒體檔案。
開啟媒體檔案
DShowPlayer::OpenFile
方法會開啟媒體檔案以供播放。 此方法會執行下列動作:
- 建立新的 (空白) 篩選圖表。
- 呼叫 IGraphBuilder::AddSourceFilter,以新增指定檔案的來源篩選。
- 在來源篩選器上呈現資料流。
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;
}
建立篩選器圖形管理器
DShowPlayer::InitializeGraph
方法會建立新的篩選圖形。 此方法會執行下列動作:
- 呼叫 CoCreateInstance,以建立 Filter Graph Manager的新實例。
- 查詢 IMediaControl 和 IMediaEventEx 介面的 Filter Graph 管理員。
- 呼叫 IMediaEventEx::SetNotifyWindow 來設定事件通知。 如需詳細資訊,請參閱 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;
}
轉譯數據流
下一個步驟是將來源篩選連接到一或多個轉譯器篩選。
DShowPlayer::RenderStreams
方法會執行下列步驟。
- 查詢篩選器圖形管理員的 IFilterGraph2 介面。
- 將影片轉譯器篩選新增至篩選圖形。
- 將 DirectSound Renderer Filter 新增至篩選圖形,以支援音訊播放。 如需將篩選新增至篩選圖形的詳細資訊,請參閱 依 CLSID 新增篩選。
- 列舉來源過濾器上的輸出接腳。 如需列舉針腳的詳細資訊,請參閱 列舉針腳。
- 針對每個接腳,呼叫 IFilterGraph2::RenderEx 方法。 此方法將輸出接腳連接到渲染器過濾器,並視需要新增中間過濾器(例如解碼器)。
- 呼叫
CVideoRenderer::FinalizeGraph
以完成視訊轉譯器初始化。 - 如果 DirectSound Renderer 濾鏡未連接到其他濾鏡,則移除該濾鏡。 如果來源檔案不包含音訊數據流,就會發生這種情況。
// 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;
}
以下是上一個範例中使用的 RemoveUnconnectedRenderer
函式程序代碼。
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;
}
釋放篩選圖形
當應用程式結束時,它必須釋放篩選圖形,如下列程式代碼所示。
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;
}
下一步:步驟 4:新增影片轉譯器。
相關主題