使用視窗模式
[與此頁面相關聯的功能,DirectShow是舊版功能。 它已被 MediaPlayer、IMFMediaEngine和媒體基金會的音訊/視訊擷取取代。 這些功能已針對 Windows 10 和 Windows 11 進行優化。 Microsoft強烈建議新程式代碼盡可能在媒體 基礎中使用 MediaPlayer、IMFMediaEngine 和 音訊/視訊擷取,而不是 DirectShow。 Microsoft建議使用舊版 API 的現有程式代碼,盡可能改寫成使用新的 API。]
注意
舊版 視訊轉譯器篩選 一律使用視窗模式。 VMR-7 和 VMR-9 篩選器預設會使用視窗模式,但也支援無視窗模式。
在視窗模式中,視訊轉譯器會建立自己的視窗,在其中繪製視訊畫面。 除非您另有指定,否則此視窗是具有本身框線和標題列的最上層視窗。 不過,大部分時候,您會將視訊視窗附加至應用程式視窗,讓影片整合至您的應用程式 UI。 這需要下列步驟:
- 查詢 IVideoWindow。
- 設定父視窗。
- 設定新的視窗樣式。
- 將視訊視窗置於擁有者視窗內。
- 請通知視訊視窗有 WM_MOVE 訊息。
查詢IVideoWindow
開始播放之前,請查詢篩選圖形管理員以取得 IVideoWindow 介面:
IVideoWindow *pVidWin = NULL;
pGraph->QueryInterface(IID_IVideoWindow, (void **)&pVidWin);
設定父視窗
若要設定父視窗,請使用應用程式視窗的句柄呼叫 IVideoWindow::put_Owner 方法。 此方法會採用類型為 OAHWND的變數,因此請將這個 handle 轉換為這種類型:
pVidWin->put_Owner((OAHWND)hwnd);
設定新視窗樣式
呼叫 IVideoWindow::put_WindowStyle 方法來變更視訊視窗的樣式:
pVidWin->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS);
WS_CHILD旗標會將視窗設定為子視窗,而WS_CLIPSIBLINGS旗標可防止視窗在另一個子視窗的工作區內繪製。
定位視訊視窗
若要設定視訊相對於應用程式視窗工作區的位置,請呼叫 IVideoWindow::SetWindowPosition 方法。 這個方法會採用矩形,指定視訊視窗的左邊緣、上邊緣、寬度和高度。 例如,下列程式代碼會拉伸視訊視窗,以符合父視窗的整個客戶區域。
RECT rc;
GetClientRect(hwnd, &rc);
pVidWin->SetWindowPosition(0, 0, rc.right, rc.bottom);
若要取得視訊的原生大小,請在 Filter Graph 管理員上呼叫 IBasicVideo::GetVideoSize 方法。 您可以使用該資訊來調整影片,並以維持正確的縱橫比。
回應WM_MOVE訊息
為了獲得最佳效能,在圖形暫停時,每當視窗移動,您應該通知視訊渲染器。 呼叫 IVideoWindow::NotifyOwnerMessage 方法來轉送WM_MOVE訊息:
// (Inside your WindowProc)
case WM_MOVE:
pVidWin->NotifyOwnerMessage((OAHWND)hWnd, msg, wParam, lParam);
break;
如果轉譯器使用硬體重疊,此通知會導致轉譯器更新重疊位置。 (VMR-9 不使用重疊,因此如果您使用 VMR-9,就不需要呼叫此方法。
清除
在應用程式結束之前,請停止圖形,並將視訊視窗的擁有者重設為 NULL。 否則,視窗訊息可能會傳送至錯誤的視窗,這可能會造成錯誤。 此外,隱藏視訊視窗,否則您可能會暫時在螢幕上看到視訊影像閃爍:
pControl->Stop();
pVidWin->put_Visible(OAFALSE);
pVidWin->put_Owner(NULL);
注意
如果視訊視窗的父視窗是主應用程式視窗的子視窗(換句話說,如果視訊視窗是子視窗的子視窗),則應該使用 CoCreateInstance 來建立視訊視窗,並將其加入到圖表中,而不是在 Intelligent Connect期間讓 Filter Graph Manager 自動添加視訊渲染器。 這可確保視訊視窗和子視窗同時重新繪製。 否則,子視窗可能會覆蓋在視訊視窗上。
相關主題