Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
[Функция, связанная с этой страницей, DirectShow, является устаревшей функцией. Он был заменен MediaPlayer, IMFMediaEngineи аудио и видеозахват в Media Foundation. Эти функции оптимизированы для Windows 10 и Windows 11. Майкрософт настоятельно рекомендует для нового кода использовать MediaPlayer, IMFMediaEngine и захват аудио и видео в Media Foundation вместо DirectShow, если возможно. Корпорация Майкрософт предлагает, что существующий код, использующий устаревшие API, будет перезаписан для использования новых API, если это возможно.]
Фильтр 7 (VMR-7) и фильтр отрисовщика видео смешения видео 9 (VMR-9) поддерживают режим без окон, что представляет собой значительное улучшение интерфейса IVideoWindow. В этом разделе описываются различия между режимом без окон и режимом окна, а также о том, как использовать режим без окон.
Для обеспечения обратной совместимости с существующими приложениями vmR по умолчанию используется режим окна. В оконном режиме отрисовщик создает собственное окно для отображения видео. Обычно приложение устанавливает окно видео как дочернее окно окна приложения. Существование отдельного окна видео вызывает некоторые проблемы, однако:
- Самое главное, существует вероятность взаимоблокировок, если сообщения окон отправляются между разными потоками.
- Диспетчер графов фильтров должен пересылать определенные сообщения окна, такие как WM_PAINT, в видеорендерер. Приложение должно использовать реализацию диспетчера графов фильтров IVideoWindow (а не видеовизуализатора), чтобы диспетчер графов фильтров сохранял правильное внутреннее состояние.
- Чтобы получать события мыши или клавиатуры из окна видео, приложение должно задать список получения сообщений, чтобы окно видео пересылало эти сообщения в приложение.
- Чтобы предотвратить проблемы с обрезкой, окно видео должно иметь необходимые стили окон.
Режим без окон позволяет избежать этих проблем, когда видеомикшер (VMR) выводит изображение непосредственно на клиентскую область окна приложения, используя DirectDraw для обрезки прямоугольника видео. Режим без окон значительно снижает вероятность взаимоблокировок. Кроме того, приложению не нужно задавать окно владельца или стили окон. На самом деле, когда VMR находится в безоконном режиме, он даже не предоставляет интерфейс IVideoWindow, который больше не нужен.
Чтобы использовать режим без окон, необходимо явно настроить VMR. Однако вы обнаружите, что это более гибкий и удобный способ использования, чем режим окна.
Фильтр VMR-7 и фильтр VMR-9 предоставляют разные интерфейсы, но шаги эквивалентны для каждого.
Настройка VMR для режима без окон
Чтобы переопределить поведение VMR по умолчанию, настройте VMR перед созданием графа фильтров.
VMR-7
- Создайте диспетчер графов фильтров.
- Создайте VMR-7 и добавьте его в граф фильтров.
- Вызовите IVMRFilterConfig::SetRenderingMode на VMR-7 с флагом VMRMode_Windowless.
- Запросите vmR-7 для интерфейса IVMRWindowlessControl.
- Вызов функции IVMRWindowlessControl::SetVideoClippingWindow на VMR-7. Укажите идентификатор окна, в котором должно появиться видео.
VMR-9
- Создайте диспетчер графов фильтров.
- Создайте VMR-9 и добавьте его в граф фильтров.
- Вызовите IVMRFilterConfig9::SetRenderingMode на VMR-9 с флагом VMR9Mode_Windowless.
- Запросите vmR-9 для интерфейса IVMRWindowlessControl9.
- Вызов IVMRWindowlessControl9::SetVideoClippingWindow на VMR-9. Укажите дескриптор окна, в котором должно появиться видео.
Теперь создайте остальную часть графа фильтров, вызвав IGraphBuilder::RenderFile или другие методы построения графа. Диспетчер графов фильтров автоматически использует экземпляр VMR, который вы добавили в граф. (Дополнительные сведения о том, почему это происходит, см. в статье Intelligent Connect.)
В следующем коде показана вспомогающая функция, которая создает VMR-7, добавляет ее в граф и настраивает режим без окон.
HRESULT InitWindowlessVMR(
HWND hwndApp, // Window to hold the video.
IGraphBuilder* pGraph, // Pointer to the Filter Graph Manager.
IVMRWindowlessControl** ppWc // Receives a pointer to the VMR.
)
{
if (!pGraph || !ppWc)
{
return E_POINTER;
}
IBaseFilter* pVmr = NULL;
IVMRWindowlessControl* pWc = NULL;
// Create the VMR.
HRESULT hr = CoCreateInstance(CLSID_VideoMixingRenderer, NULL,
CLSCTX_INPROC, IID_IBaseFilter, (void**)&pVmr);
if (FAILED(hr))
{
return hr;
}
// Add the VMR to the filter graph.
hr = pGraph->AddFilter(pVmr, L"Video Mixing Renderer");
if (FAILED(hr))
{
pVmr->Release();
return hr;
}
// Set the rendering mode.
IVMRFilterConfig* pConfig;
hr = pVmr->QueryInterface(IID_IVMRFilterConfig, (void**)&pConfig);
if (SUCCEEDED(hr))
{
hr = pConfig->SetRenderingMode(VMRMode_Windowless);
pConfig->Release();
}
if (SUCCEEDED(hr))
{
// Set the window.
hr = pVmr->QueryInterface(IID_IVMRWindowlessControl, (void**)&pWc);
if( SUCCEEDED(hr))
{
hr = pWc->SetVideoClippingWindow(hwndApp);
if (SUCCEEDED(hr))
{
*ppWc = pWc; // Return this as an AddRef'd pointer.
}
else
{
// An error occurred, so release the interface.
pWc->Release();
}
}
}
pVmr->Release();
return hr;
}
Эта функция предполагает, что отображается только один видеопоток и статический растровый рисунок не накладывается на видео. Дополнительные сведения см. в безоконном режиме VMR. Эта функция будет вызываться следующим образом:
IVMRWindowlessControl *pWc = NULL;
hr = InitWindowlessVMR(hwnd, pGraph, &g_pWc);
if (SUCCEEDED(hr))
{
// Build the graph. For example:
pGraph->RenderFile(wszMyFileName, 0);
// Release the VMR interface when you are done.
pWc->Release();
}
Размещение видео
После настройки VMR следующий шаг — задать положение видео. Рассмотрим два прямоугольника: исходный и назначение. Исходный прямоугольник определяет, какая часть видео будет отображаться. Прямоугольник назначения задает область в клиентской области окна, которая будет содержать видео. VMR обрезает видеоизображение по исходному прямоугольнику и растягивает обрезанное изображение, чтобы соответствовать прямоугольнику назначения.
VMR-7
- Вызовите метод IVMRWindowlessControl::SetVideoPosition, чтобы указать оба прямоугольника.
- Исходный прямоугольник должен быть равен или меньше, чем размер собственного видео; для получения собственного размера видео можно использовать метод IVMRWindowlessControl::GetNativeVideoSize.
VMR-9
- Вызовите метод IVMRWindowlessControl9::SetVideoPosition, чтобы указать оба прямоугольника.
- Исходный прямоугольник должен быть равен или меньше, чем размер собственного видео; для получения собственного размера видео можно использовать метод IVMRWindowlessControl9::GetNativeVideoSize.
Например, следующий код задает прямоугольники источника и назначения для VMR-7. Он задает исходный прямоугольник, равный всему изображению видео, и целевой прямоугольник, равный всей клиентской области окна:
// Find the native video size.
long lWidth, lHeight;
HRESULT hr = g_pWc->GetNativeVideoSize(&lWidth, &lHeight, NULL, NULL);
if (SUCCEEDED(hr))
{
RECT rcSrc, rcDest;
// Set the source rectangle.
SetRect(&rcSrc, 0, 0, lWidth, lHeight);
// Get the window client area.
GetClientRect(hwnd, &rcDest);
// Set the destination rectangle.
SetRect(&rcDest, 0, 0, rcDest.right, rcDest.bottom);
// Set the video position.
hr = g_pWc->SetVideoPosition(&rcSrc, &rcDest);
}
Если вы хотите, чтобы видео занимало меньшую часть клиентской области, измените параметр rcDest. Если вы хотите обрезать изображение видео, измените параметр rcSrc.
Обработка сообщений окна
Так как vmR не имеет собственного окна, оно должно быть уведомлено, если требуется перенакрасить или изменить размер видео. Ответьте на приведенные ниже сообщения окна, вызвав перечисленные методы VMR.
VMR-7
- WM_PAINT. Вызов IVMRWindowlessControl::RepaintVideo. Этот метод приводит к тому, что VMR-7 перерисовывает последний видеокадр.
- WM_DISPLAYCHANGE: вызов IVMRWindowlessControl::DisplayModeChanged. Этот метод уведомляет VMR-7 о том, что видео должно отображаться в новом разрешении или глубине цвета.
- WM_SIZE или WM_WINDOWPOSCHANGED: пересчитывайте положение видео и вызовите IVMRWindowlessControl::SetVideoPosition, чтобы обновить позицию при необходимости.
VMR-9
- WM_PAINT. Вызов функции IVMRWindowlessControl9::RepaintVideo. Этот метод заставляет VMR-9 перерисовать последний видеокадр.
- WM_DISPLAYCHANGE: вызов IVMRWindowlessControl9::DisplayModeChanged. Этот метод уведомляет VMR-9 о том, что видео должно отображаться в новом разрешении или глубине цвета.
- WM_SIZE или WM_WINDOWPOSCHANGED: пересчитывайте положение видео и вызывайте IVMRWindowlessControl9::SetVideoPosition, чтобы обновить позицию при необходимости.
Заметка
Сообщение WM_WINDOWPOSCHANGED обрабатывается обработчиком по умолчанию, который отправляет WM_SIZE . Но если ваше приложение перехватывает WM_WINDOWPOSCHANGED и не передает его функции DefWindowProc, вам следует вызвать функцию SetVideoPosition в обработчике WM_WINDOWPOSCHANGED, помимо обработчика WM_SIZE.
В следующем примере показан обработчик сообщений WM_PAINT. Он рисует область, определенную прямоугольником клиента, за исключением прямоугольника видео. Не рисуйте на видео-прямоугольнике, потому что VMR закрасит его, вызывая мерцание. По той же причине не устанавливайте фоновую кисть в классе окна.
void OnPaint(HWND hwnd)
{
PAINTSTRUCT ps;
HDC hdc;
RECT rcClient;
GetClientRect(hwnd, &rcClient);
hdc = BeginPaint(hwnd, &ps);
if (g_pWc != NULL)
{
// Find the region where the application can paint by subtracting
// the video destination rectangle from the client area.
// (Assume that g_rcDest was calculated previously.)
HRGN rgnClient = CreateRectRgnIndirect(&rcClient);
HRGN rgnVideo = CreateRectRgnIndirect(&g_rcDest);
CombineRgn(rgnClient, rgnClient, rgnVideo, RGN_DIFF);
// Paint on window.
HBRUSH hbr = GetSysColorBrush(COLOR_BTNFACE);
FillRgn(hdc, rgnClient, hbr);
// Clean up.
DeleteObject(hbr);
DeleteObject(rgnClient);
DeleteObject(rgnVideo);
// Request the VMR to paint the video.
HRESULT hr = g_pWc->RepaintVideo(hwnd, hdc);
}
else // There is no video, so paint the whole client area.
{
FillRect(hdc, &rc2, (HBRUSH)(COLOR_BTNFACE + 1));
}
EndPaint(hwnd, &ps);
}
Хотя вы должны отвечать на сообщения типа WM_PAINT, между сообщениями типа WM_PAINT вам не нужно предпринимать никаких действий для обновления видео. Как показано в этом примере, режим без окон позволяет рассматривать изображение видео просто как область самостоятельного рисования в окне.
Связанные разделы