Not
Åtkomst till denna sida kräver auktorisation. Du kan prova att logga in eller byta katalog.
Åtkomst till denna sida kräver auktorisation. Du kan prova att byta katalog.
[Funktionen som är associerad med den här sidan, DirectShow, är en äldre funktion. Det har ersatts av MediaPlayer, IMFMediaEngineoch Audio / Video Capture i Media Foundation. Dessa funktioner har optimerats för Windows 10 och Windows 11. Microsoft rekommenderar starkt att ny kod använder MediaPlayer, IMFMediaEngine och Audio/Video Capture i Media Foundation i stället för DirectShow, när det är möjligt. Microsoft föreslår att befintlig kod som använder äldre API:er skrivs om för att använda de nya API:erna om möjligt.]
Både Video Mixing Renderer Filter 7 (VMR-7) och Video Mixing Renderer Filter 9 (VMR-9) stöder fönsterlöst läge, vilket representerar en stor förbättring jämfört med gränssnittet IVideoWindow. I det här avsnittet beskrivs skillnaderna mellan fönsterlöst läge och fönsterläge och hur du använder fönsterlöst läge.
För att förbli bakåtkompatibel med befintliga program är VMR som standard i fönsterläge. I fönsterläge skapar renderaren ett eget fönster för att visa videon. Vanligtvis anger programmet att videofönstret är underordnat programfönstret. Förekomsten av ett separat videofönster orsakar dock vissa problem:
- Det viktigaste är att det finns en risk för dödlägen om fönstermeddelanden skickas mellan trådar.
- Filter Graph Manager måste vidarebefordra vissa fönstermeddelanden, till exempel WM_PAINT, till videoåtergivningen. Programmet måste använda Filter Graph Managers implementering av IVideoWindow (och inte Video Renderers) så att Filter Graph Manager behåller rätt interna tillstånd.
- Om applikationen ska ta emot mus- eller tangentbordshändelser från videofönstret, måste den ange en meddelandedränering, vilket gör att videofönstret vidarebefordrar dessa meddelanden till applikationen.
- För att förhindra urklippsproblem måste videofönstret ha rätt fönsterformat.
Fönsterlöst läge undviker dessa problem genom att VMR ritas direkt på programfönstrets klientområde, med DirectDraw för att klippa ut videorektangeln. Fönsterlöst läge minskar avsevärt risken för dödlägen. Programmet behöver inte heller ange ägarfönstret eller fönsterformaten. Faktum är att när VMR är i fönsterlöst läge exponerar det inte ens IVideoWindow--gränssnittet, som inte längre behövs.
Om du vill använda fönsterlöst läge måste du uttryckligen konfigurera VMR. Du kommer dock att märka att det är mer flexibelt och enklare att använda än fönsterläge.
VMR-7-filtret och VMR-9-filtret exponerar olika gränssnitt, men stegen är likvärdiga för var och en.
Konfigurera VMR för fönsterlöst läge
Om du vill åsidosätta VMR:ns standardbeteende konfigurerar du VMR innan du skapar filterdiagrammet:
VMR-7
- Skapa Filter Graph Manager.
- Skapa VMR-7 och lägg till den i filterdiagrammet.
- Anropa IVMRFilterConfig::SetRenderingMode för VMR-7 med flaggan VMRMode_Windowless.
- Fråga VMR-7 efter gränssnittet IVMRWindowlessControl.
- Anrop IVMRWindowlessControl::SetVideoClippingWindow på VMR-7. Ange ett handtag till fönstret där videon ska visas.
VMR-9
- Skapa Filter Graph Manager.
- Skapa VMR-9 och lägg till den i filterdiagrammet.
- Anropa IVMRFilterConfig9::SetRenderingMode på VMR-9 med flaggan VMR9Mode_Windowless.
- Fråga VMR-9 efter gränssnittet IVMRWindowlessControl9.
- Anropa IVMRWindowlessControl9::SetVideoClippingWindow på VMR-9. Ange ett handtag till fönstret där videon ska visas.
Skapa nu resten av filterdiagrammet genom att anropa IGraphBuilder::RenderFile eller andra diagramskapande metoder. Filter Graph Manager använder automatiskt den instans av VMR som du lade till i diagrammet. (Mer information om varför detta händer finns i Intelligent Connect.)
Följande kod visar en hjälpfunktion som skapar VMR-7, lägger till den i diagrammet och konfigurerar fönsterlöst läge.
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;
}
Den här funktionen förutsätter att du endast visar en videoström och inte blandar en statisk bitmapp över videon. Mer information finns i VMR-fönsterlöst läge. Du anropar den här funktionen på följande sätt:
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();
}
Positionera videon
När du har konfigurerat VMR är nästa steg att ange videons position. Det finns två rektanglar att tänka på, källa rektangel och mål rektangel. Källrektangeln definierar vilken del av videon som ska visas. Målrektangeln anger regionen i fönstrets klientområde som ska innehålla videon. VMR beskär videobilden till källrektangeln och sträcker ut den beskurna bilden så att den passar målrektangeln.
VMR-7
- Anropa metoden IVMRWindowlessControl::SetVideoPosition för att ange båda rektanglarna.
- Källrektangeln måste vara lika med eller mindre än den inhemska videostorleken. Du kan använda metoden IVMRWindowlessControl::GetNativeVideoSize för att hämta den inhemska videostorleken.
VMR-9
- Anropa metoden IVMRWindowlessControl9::SetVideoPosition för att ange båda rektanglarna.
- Källrektangeln måste vara lika med eller mindre än den inhemska videostorleken. Du kan använda metoden IVMRWindowlessControl9::GetNativeVideoSize för att hämta den inhemska videostorleken.
Följande kod anger till exempel käll- och målrektanglarna för VMR-7. Den anger källrektangeln lika med hela videobilden och målrektangeln är lika med hela fönstrets klientområde:
// 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);
}
Om du vill att videon ska uppta en mindre del av klientområdet, ändrar du parametern rcDest. Om du vill beskära videobilden ändrar du parametern rcSrc.
Hantera fönstermeddelanden
Eftersom VMR inte har ett eget fönster måste den meddelas om den behöver måla om eller ändra storlek på videon. Svara på följande fönstermeddelanden genom att anropa VMR-metoderna i listan.
VMR-7
- WM_PAINT. Anropa IVMRWindowlessControl::RepaintVideo. Den här metoden gör att VMR-7 målar om den senaste videoramen.
- WM_DISPLAYCHANGE: Anropa IVMRWindowlessControl::DisplayModeChanged. Den här metoden meddelar VMR-7 att videon måste visas med en ny upplösning eller ett nytt färgdjup.
- WM_SIZE eller WM_WINDOWPOSCHANGED: Beräkna om videons position och anropa IVMRWindowlessControl::SetVideoPosition för att uppdatera positionen om det behövs.
VMR-9
- WM_PAINT. Anropa IVMRWindowlessControl9::RepaintVideo. Den här metoden gör att VMR-9 målar om den senaste videoramen.
- WM_DISPLAYCHANGE: Anropa IVMRWindowlessControl9::DisplayModeChanged. Den här metoden meddelar VMR-9 att videon måste visas med en ny upplösning eller ett nytt färgdjup.
- WM_SIZE eller WM_WINDOWPOSCHANGED: Beräkna om videons position och anropa IVMRWindowlessControl9::SetVideoPosition för att uppdatera positionen om det behövs.
Not
Standardhanteraren för WM_WINDOWPOSCHANGED-meddelandet skickar ett WM_SIZE-meddelande. Men om programmet fångar upp WM_WINDOWPOSCHANGED och inte skickar det till DefWindowProcbör du anropa SetVideoPosition- i WM_WINDOWPOSCHANGED-hanteraren, förutom din WM_SIZE-hanterare.
I följande exempel visas en WM_PAINT meddelandehanterare. Den målar upp en region som definieras av klientrektangeln minus videorektangeln. Rita inte på videorektangeln eftersom VMR kommer att måla över den, vilket orsakar flimmer. Av samma anledning ska du inte ange en bakgrundspensel i din fönsterklass.
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);
}
Även om du måste svara på WM_PAINT meddelanden finns det inget du behöver göra mellan WM_PAINT meddelanden för att uppdatera videon. Som det här exemplet visar kan du i fönsterlöst läge behandla videobilden som en självritningsregion i fönstret.
Relaterade ämnen