Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
[Функция, связанная с этой страницей, DirectShow, является устаревшей функцией. Он был заменен MediaPlayer, IMFMediaEngineи аудио и видеозахват в Media Foundation. Эти функции оптимизированы для Windows 10 и Windows 11. Корпорация Майкрософт настоятельно рекомендует использовать новый код MediaPlayer, IMFMediaEngine и захват аудио и видео в Media Foundation вместо DirectShow, по возможности. Корпорация Майкрософт предлагает, что существующий код, использующий устаревшие API, будет перезаписан для использования новых API, если это возможно.]
В этом разделе рассматривается шаг 4 урока, воспроизведение звука и видео в DirectShow. Полный код показан в разделе примере воспроизведения DirectShow.
DirectShow предоставляет несколько различных фильтров, отрисовывающих видео:
- расширенный фильтр отрисовщика видео (EVR)
- фильтр отрисовщика видео 9 (VMR-9)
- фильтр микширования видео 7 (VMR-7)
Дополнительные сведения о различиях между этими фильтрами см. в разделе Выбор правого отрисовщика видео.
В этом руководстве каждый фильтр отрисовщика видео упаковывается в класс, который абстрагирует некоторые различия между ними. Все эти классы являются производными от абстрактного базового класса с именем CVideoRenderer. Объявление CVideoRenderer отображается на шаге 2. Объявление CVideoRenderer и производных классов.
Следующий метод пытается поочерёдно создать каждый видеорендер, начиная с EVR, затем VMR-9 и, наконец, VMR-7.
HRESULT DShowPlayer::CreateVideoRenderer()
{
HRESULT hr = E_FAIL;
enum { Try_EVR, Try_VMR9, Try_VMR7 };
for (DWORD i = Try_EVR; i <= Try_VMR7; i++)
{
switch (i)
{
case Try_EVR:
m_pVideo = new (std::nothrow) CEVR();
break;
case Try_VMR9:
m_pVideo = new (std::nothrow) CVMR9();
break;
case Try_VMR7:
m_pVideo = new (std::nothrow) CVMR7();
break;
}
if (m_pVideo == NULL)
{
hr = E_OUTOFMEMORY;
break;
}
hr = m_pVideo->AddToGraph(m_pGraph, m_hwnd);
if (SUCCEEDED(hr))
{
break;
}
delete m_pVideo;
m_pVideo = NULL;
}
return hr;
}
Фильтр EVR
Следующий код создает фильтр EVR и добавляет его в граф фильтров. Функция AddFilterByCLSID, используемая в этом примере, показана в разделе Добавление фильтра по CLSID.
HRESULT CEVR::AddToGraph(IGraphBuilder *pGraph, HWND hwnd)
{
IBaseFilter *pEVR = NULL;
HRESULT hr = AddFilterByCLSID(pGraph, CLSID_EnhancedVideoRenderer,
&pEVR, L"EVR");
if (FAILED(hr))
{
goto done;
}
hr = InitializeEVR(pEVR, hwnd, &m_pVideoDisplay);
if (FAILED(hr))
{
goto done;
}
// Note: Because IMFVideoDisplayControl is a service interface,
// you cannot QI the pointer to get back the IBaseFilter pointer.
// Therefore, we need to cache the IBaseFilter pointer.
m_pEVR = pEVR;
m_pEVR->AddRef();
done:
SafeRelease(&pEVR);
return hr;
}
Функция InitializeEVR инициализирует фильтр EVR. Эта функция выполняет следующие действия.
- Запрашивает фильтр для интерфейса IMFGetService.
- Вызывает IMFGetService::GetService, чтобы получить указатель на интерфейс IMFVideoDisplayControl.
- Вызывает IMFVideoDisplayControl::SetVideoWindow, чтобы задать окно видео.
- Вызывает IMFVideoDisplayControl::SetAspectRatioMode, чтобы настроить EVR для сохранения пропорций видео.
В следующем коде показана функция InitializeEVR.
HRESULT InitializeEVR(
IBaseFilter *pEVR, // Pointer to the EVR
HWND hwnd, // Clipping window
IMFVideoDisplayControl** ppDisplayControl
)
{
IMFGetService *pGS = NULL;
IMFVideoDisplayControl *pDisplay = NULL;
HRESULT hr = pEVR->QueryInterface(IID_PPV_ARGS(&pGS));
if (FAILED(hr))
{
goto done;
}
hr = pGS->GetService(MR_VIDEO_RENDER_SERVICE, IID_PPV_ARGS(&pDisplay));
if (FAILED(hr))
{
goto done;
}
// Set the clipping window.
hr = pDisplay->SetVideoWindow(hwnd);
if (FAILED(hr))
{
goto done;
}
// Preserve aspect ratio by letter-boxing
hr = pDisplay->SetAspectRatioMode(MFVideoARMode_PreservePicture);
if (FAILED(hr))
{
goto done;
}
// Return the IMFVideoDisplayControl pointer to the caller.
*ppDisplayControl = pDisplay;
(*ppDisplayControl)->AddRef();
done:
SafeRelease(&pGS);
SafeRelease(&pDisplay);
return hr;
}
После построения графа DShowPlayer::RenderStreams вызывает CVideoRenderer::FinalizeGraph. Этот метод выполняет любую окончательную инициализацию или очистку. В следующем коде показана реализация этого метода CEVR.
HRESULT CEVR::FinalizeGraph(IGraphBuilder *pGraph)
{
if (m_pEVR == NULL)
{
return S_OK;
}
BOOL bRemoved;
HRESULT hr = RemoveUnconnectedRenderer(pGraph, m_pEVR, &bRemoved);
if (bRemoved)
{
SafeRelease(&m_pEVR);
SafeRelease(&m_pVideoDisplay);
}
return hr;
}
Если EVR не подключен к другому фильтру, этот метод удаляет EVR из графа. Это может произойти, если файл мультимедиа не содержит видеопоток.
Фильтр VMR-9
Следующий код создает фильтр VMR-9 и добавляет его в граф фильтров.
HRESULT CVMR9::AddToGraph(IGraphBuilder *pGraph, HWND hwnd)
{
IBaseFilter *pVMR = NULL;
HRESULT hr = AddFilterByCLSID(pGraph, CLSID_VideoMixingRenderer9,
&pVMR, L"VMR-9");
if (SUCCEEDED(hr))
{
// Set windowless mode on the VMR. This must be done before the VMR
// is connected.
hr = InitWindowlessVMR9(pVMR, hwnd, &m_pWindowless);
}
SafeRelease(&pVMR);
return hr;
}
Функция InitWindowlessVMR9 инициализирует VMR-9 для режима без окон. (Дополнительные сведения о режиме без окон см. в режиме без окон VMR.) Эта функция выполняет следующие действия.
- Запрашивает фильтр VMR-9 для интерфейса IVMRFilterConfig 9.
- Вызывает метод IVMRFilterConfig9::SetRenderingMode, чтобы задать режим без окон.
- Запрашивает фильтр VMR-9 для интерфейса IVMRWindowlessControl9.
- Вызывает метод IVMRWindowlessControl9::SetVideoClippingWindow, чтобы задать окно видео.
- Чтобы сохранить пропорции видео, вызывается метод IVMRWindowlessControl9::SetAspectRatioMode.
В следующем коде показана функция InitWindowlessVMR9.
HRESULT InitWindowlessVMR9(
IBaseFilter *pVMR, // Pointer to the VMR
HWND hwnd, // Clipping window
IVMRWindowlessControl9** ppWC // Receives a pointer to the VMR.
)
{
IVMRFilterConfig9 * pConfig = NULL;
IVMRWindowlessControl9 *pWC = NULL;
// Set the rendering mode.
HRESULT hr = pVMR->QueryInterface(IID_PPV_ARGS(&pConfig));
if (FAILED(hr))
{
goto done;
}
hr = pConfig->SetRenderingMode(VMR9Mode_Windowless);
if (FAILED(hr))
{
goto done;
}
// Query for the windowless control interface.
hr = pVMR->QueryInterface(IID_PPV_ARGS(&pWC));
if (FAILED(hr))
{
goto done;
}
// Set the clipping window.
hr = pWC->SetVideoClippingWindow(hwnd);
if (FAILED(hr))
{
goto done;
}
// Preserve aspect ratio by letter-boxing
hr = pWC->SetAspectRatioMode(VMR9ARMode_LetterBox);
if (FAILED(hr))
{
goto done;
}
// Return the IVMRWindowlessControl pointer to the caller.
*ppWC = pWC;
(*ppWC)->AddRef();
done:
SafeRelease(&pConfig);
SafeRelease(&pWC);
return hr;
}
Метод CVMR9::FinalizeGraph проверяет, подключен ли фильтр VMR-9, а если нет, удаляет его из графа фильтров.
HRESULT CVMR9::FinalizeGraph(IGraphBuilder *pGraph)
{
if (m_pWindowless == NULL)
{
return S_OK;
}
IBaseFilter *pFilter = NULL;
HRESULT hr = m_pWindowless->QueryInterface(IID_PPV_ARGS(&pFilter));
if (FAILED(hr))
{
goto done;
}
BOOL bRemoved;
hr = RemoveUnconnectedRenderer(pGraph, pFilter, &bRemoved);
// If we removed the VMR, then we also need to release our
// pointer to the VMR's windowless control interface.
if (bRemoved)
{
SafeRelease(&m_pWindowless);
}
done:
SafeRelease(&pFilter);
return hr;
}
Фильтр VMR-7
Шаги для фильтра VMR-7 почти идентичны шагам для VMR-9, за исключением того, что используются интерфейсы VMR-7. Следующий код создает фильтр VMR-7 и добавляет его в граф фильтров.
HRESULT CVMR7::AddToGraph(IGraphBuilder *pGraph, HWND hwnd)
{
IBaseFilter *pVMR = NULL;
HRESULT hr = AddFilterByCLSID(pGraph, CLSID_VideoMixingRenderer,
&pVMR, L"VMR-7");
if (SUCCEEDED(hr))
{
// Set windowless mode on the VMR. This must be done before the VMR
// is connected.
hr = InitWindowlessVMR(pVMR, hwnd, &m_pWindowless);
}
SafeRelease(&pVMR);
return hr;
}
Функция InitWindowlessVMR инициализирует vmR-7 для режима без окон. Эта функция выполняет следующие действия.
- Запрашивает фильтр VMR-7 для интерфейса IVMRFilterConfig.
- Вызывает метод IVMRFilterConfig::SetRenderingMode, чтобы задать режим без окон.
- Запрашивает фильтр VMR-7 для интерфейса IVMRWindowlessControl.
- Вызывает метод IVMRWindowlessControl::SetVideoClippingWindow, чтобы задать окно видео.
- Вызывает метод IVMRWindowlessControl::SetAspectRatioMode, чтобы сохранить пропорции видео.
В следующем коде показана функция InitWindowlessVMR.
HRESULT InitWindowlessVMR(
IBaseFilter *pVMR, // Pointer to the VMR
HWND hwnd, // Clipping window
IVMRWindowlessControl** ppWC // Receives a pointer to the VMR.
)
{
IVMRFilterConfig* pConfig = NULL;
IVMRWindowlessControl *pWC = NULL;
// Set the rendering mode.
HRESULT hr = pVMR->QueryInterface(IID_PPV_ARGS(&pConfig));
if (FAILED(hr))
{
goto done;
}
hr = pConfig->SetRenderingMode(VMRMode_Windowless);
if (FAILED(hr))
{
goto done;
}
// Query for the windowless control interface.
hr = pVMR->QueryInterface(IID_PPV_ARGS(&pWC));
if (FAILED(hr))
{
goto done;
}
// Set the clipping window.
hr = pWC->SetVideoClippingWindow(hwnd);
if (FAILED(hr))
{
goto done;
}
// Preserve aspect ratio by letter-boxing
hr = pWC->SetAspectRatioMode(VMR_ARMODE_LETTER_BOX);
if (FAILED(hr))
{
goto done;
}
// Return the IVMRWindowlessControl pointer to the caller.
*ppWC = pWC;
(*ppWC)->AddRef();
done:
SafeRelease(&pConfig);
SafeRelease(&pWC);
return hr;
}
Метод CVMR7::FinalizeGraph проверяет, подключен ли фильтр VMR-7, а если нет, удаляет его из графа фильтров.
HRESULT CVMR7::FinalizeGraph(IGraphBuilder *pGraph)
{
if (m_pWindowless == NULL)
{
return S_OK;
}
IBaseFilter *pFilter = NULL;
HRESULT hr = m_pWindowless->QueryInterface(IID_PPV_ARGS(&pFilter));
if (FAILED(hr))
{
goto done;
}
BOOL bRemoved;
hr = RemoveUnconnectedRenderer(pGraph, pFilter, &bRemoved);
// If we removed the VMR, then we also need to release our
// pointer to the VMR's windowless control interface.
if (bRemoved)
{
SafeRelease(&m_pWindowless);
}
done:
SafeRelease(&pFilter);
return hr;
}
Связанные разделы