Nota
O acesso a esta página requer autorização. Podes tentar iniciar sessão ou mudar de diretório.
O acesso a esta página requer autorização. Podes tentar mudar de diretório.
[O recurso associado a esta página, DirectShow, é um recurso herdado. Foi substituído por MediaPlayer, IMFMediaEnginee Audio/Video Capture in Media Foundation. Esses recursos foram otimizados para Windows 10 e Windows 11. A Microsoft recomenda vivamente que o novo código utilize MediaPlayer, IMFMediaEngine e Captura de Áudio/Vídeo no Media Foundation em vez de DirectShow, quando possível. A Microsoft sugere que o código existente que usa as APIs herdadas seja reescrito para usar as novas APIs, se possível.]
Tanto o Video Mixing Renderer Filter 7 (VMR-7) quanto o Video Mixing Renderer Filter 9 (VMR-9) suportam modo sem janela, o que representa uma grande melhoria em relação à interfaceIVideoWindow. pt-PT: Este tópico descreve as diferenças entre o modo sem janela e o modo com janela, e como usar o modo sem janela.
Para permanecer compatível com aplicações existentes, o VMR utiliza o modo de janela como padrão. No modo de janela, o renderizador cria sua própria janela para exibir o vídeo. Normalmente, o aplicativo define a janela de vídeo como um filho da janela do aplicativo. A existência de uma janela de vídeo separada causa alguns problemas, no entanto:
- Mais importante ainda, há potencial para bloqueios se as mensagens de janelas forem enviadas entre threads.
- O Gerenciador de gráficos de filtro deve encaminhar determinadas mensagens de janela, como WM_PAINT, para o renderizador de vídeo. O aplicativo deve usar a implementação do Filter Graph Manager do IVideoWindow (e não do Video Renderer), para que o Filter Graph Manager mantenha o estado interno correto.
- Para receber eventos de mouse ou teclado da janela de vídeo, o aplicativo deve definir um canal de mensagens, permitindo que a janela de vídeo encaminhe essas mensagens para o aplicativo.
- Para evitar problemas de recorte, a janela de vídeo deve ter os estilos de janela corretos.
O modo sem janela evita esses problemas fazendo com que o VMR desenhe diretamente na área do cliente da janela do aplicativo, usando o DirectDraw para recortar o retângulo de vídeo. O modo sem janelas reduz significativamente a chance de bloqueios. Além disso, o aplicativo não precisa definir a janela do proprietário ou os estilos de janela. Na verdade, quando o VMR está no modo sem janelas, ele nem mesmo expõe o interface IVideoWindow, que não é mais necessária.
Para usar o modo sem janelas, você deve configurar explicitamente o VMR. No entanto, você descobrirá que é mais flexível e mais fácil de usar do que o modo em janela.
O filtro VMR-7 e o filtro VMR-9 expõem interfaces diferentes, mas as etapas são equivalentes para cada uma.
Configurar o VMR para o modo sem janela
Para substituir o comportamento padrão do VMR, configure o VMR antes de criar o gráfico de filtro:
VMR-7
- Crie o Gestor de Gráfico de Filtro.
- Crie o VMR-7 e adicione-o ao gráfico de filtro.
- Chame IVMRFilterConfig::SetRenderingMode no VMR-7 com a bandeira VMRMode_Windowless.
- Consulte o VMR-7 para a interface IVMRWindowlessControl.
- Chamar IVMRWindowlessControl::SetVideoClippingWindow no VMR-7. Especifique uma alça para a janela onde o vídeo deve aparecer.
VMR-9
- Crie o Gestor de Gráficos de Filtro.
- Crie o VMR-9 e adicione-o ao gráfico de filtro.
- Chame IVMRFilterConfig9::SetRenderingMode no VMR-9 com a bandeira VMR9Mode_Windowless.
- Consulte o VMR-9 para a interface IVMRWindowlessControl9.
- Chame IVMRWindowlessControl9::SetVideoClippingWindow no VMR-9. Especifique uma alça para a janela onde o vídeo deve aparecer.
Agora, crie o restante do gráfico de filtro chamando IGraphBuilder::RenderFile ou outros métodos de criação de gráficos. O Filter Graph Manager usa automaticamente a instância do VMR que você adicionou ao gráfico. (Para obter detalhes sobre por que isso acontece, consulte Intelligent Connect.)
O código a seguir mostra uma função auxiliar que cria o VMR-7, adiciona-o ao gráfico e configura o modo sem janelas.
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;
}
Esta função pressupõe que estão exibindo apenas um fluxo de vídeo e não estão misturando um bitmap estático sobre o vídeo. Para obter detalhes, consulte Modo VMR sem janela. Você chamaria essa função da seguinte maneira:
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();
}
Posicione o vídeo
Depois de configurar o VMR, o próximo passo é definir a posição do vídeo. Há dois retângulos a considerar, o retângulo de fonte e o retângulo de destino . O retângulo de origem define qual parte do vídeo deve ser exibida. O retângulo de destino especifica a região na área do cliente da janela que conterá o vídeo. O VMR corta a imagem de vídeo para o retângulo de origem e estica a imagem cortada para se ajustar ao retângulo de destino.
VMR-7
- Chame o IVMRWindowlessControl::SetVideoPosition método para especificar ambos os retângulos.
- O retângulo de origem deve ser igual ou menor que o tamanho do vídeo nativo; você pode usar o IVMRWindowlessControl::GetNativeVideoSize método para obter o tamanho de vídeo nativo.
VMR-9
- Chame o método IVMRWindowlessControl9::SetVideoPosition para especificar ambos os retângulos.
- O retângulo de origem deve ser igual ou menor que o tamanho do vídeo nativo; você pode usar o IVMRWindowlessControl9::GetNativeVideoSize método para obter o tamanho de vídeo nativo.
Por exemplo, o código a seguir define os retângulos de origem e destino para o VMR-7. Ele define o retângulo de origem igual a toda a imagem de vídeo e o retângulo de destino igual a toda a área do cliente da janela:
// 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);
}
Se você quiser que o vídeo ocupe uma parte menor da área do cliente, modifique o parâmetro rcDest. Se você quiser cortar a imagem de vídeo, modifique o rcSrc parâmetro.
Manipular mensagens da janela
Como o VMR não tem sua própria janela, ele deve ser notificado se precisar repintar ou redimensionar o vídeo. Responda às seguintes mensagens de janela chamando os métodos VMR listados.
VMR-7
- WM_PAINT. Ligue IVMRWindowlessControl::RepaintVideo. Este método faz com que o VMR-7 redesenhe o frame de vídeo mais recente.
- WM_DISPLAYCHANGE: Call IVMRWindowlessControl::DisplayModeChanged. Este método notifica o VMR-7 que o vídeo deve ser mostrado em uma nova resolução ou profundidade de cor.
- WM_SIZE ou WM_WINDOWPOSCHANGED: Recalcule a posição do vídeo e chame IVMRWindowlessControl::SetVideoPosition para atualizar a posição, se necessário.
VMR-9
- WM_PAINT. Chamada IVMRWindowlessControl9::RepaintVideo. Esse método faz com que o VMR-9 repinte o quadro de vídeo mais recente.
- WM_DISPLAYCHANGE: Call IVMRWindowlessControl9::DisplayModeChanged. Este método notifica o VMR-9 que o vídeo deve ser mostrado em uma nova resolução ou profundidade de cor.
- WM_SIZE ou WM_WINDOWPOSCHANGED: Recalcule a posição do vídeo e ligue IVMRWindowlessControl9::SetVideoPosition para atualizar a posição, se necessário.
Observação
O manipulador padrão para a mensagem WM_WINDOWPOSCHANGED envia uma mensagem WM_SIZE. Mas se o seu aplicativo interceptar WM_WINDOWPOSCHANGED e não passá-lo para DefWindowProc, você deve chamar SetVideoPosition no seu manipulador de WM_WINDOWPOSCHANGED, além do seu manipulador de WM_SIZE.
O exemplo a seguir mostra um manipulador de mensagens WM_PAINT. Ele pinta uma região definida pelo retângulo do cliente menos o retângulo de vídeo. Não desenhe no retângulo de vídeo, porque o VMR pintará sobre ele, causando cintilação. Pelo mesmo motivo, não defina um pincel de fundo na sua classe de janela.
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);
}
Embora você deva responder a WM_PAINT mensagens, não há nada que você precise fazer entre WM_PAINT mensagens para atualizar o vídeo. Como mostra este exemplo, o modo sem janela permite tratar a imagem de vídeo simplesmente como uma região de desenho automático na janela.
Tópicos relacionados