寫入檔案
[與此頁面 相關的功能 DirectShow是舊版功能。 它已被 MediaPlayer、 IMFMediaEngine和 Media Foundation 中的音訊/視訊擷取取代。 這些功能已針對Windows 10和Windows 11進行優化。 Microsoft 強烈建議新程式碼盡可能使用 MediaPlayer、 IMFMediaEngine 和 音訊/視訊擷取 ,而不是 DirectShow。 Microsoft 建議盡可能重寫使用舊版 API 的現有程式碼,以使用新的 API。]
若要寫入檔案,只要呼叫 IMediaControl::Run 方法,即可執行篩選圖形。 等候播放完成,並藉由呼叫 IMediaControl::Stop來明確停止圖形;否則檔案未正確寫入。
若要顯示檔案寫入作業的進度,請查詢 IMediaSeeking 介面的 Mux 篩選器。 呼叫 IMediaSeeking::GetDuration 方法來擷取檔案的持續時間。 在圖形執行時定期呼叫 IMediaSeeking::GetCurrentPosition 方法,以擷取資料流程中的圖形目前位置。 目前的位置除以持續時間,可讓百分比完成。
注意
應用程式通常會查詢篩選圖形管理員是否有 IMediaSeeking,但寫入檔案是此規則的例外狀況。 Filter Graph 管理員會從開始位置計算目前的位置,以及圖形執行的時間長度,這適用于檔案播放,但不適用於檔案寫入。 因此,若要取得精確的結果,您應該從 MUX 篩選器擷取位置。
下列程式碼會取得檔案的持續時間、啟動計時器來更新應用程式 UI,並執行篩選圖形。 (為了清楚起見,會省略錯誤檢查。)
IMediaSeeking *pSeek = NULL;
IMediaEventEx *pEvent = NULL;
IMediaControl *pControl = NULL;
REFERENCE_TIME rtTotal;
// Query for interfaces. Remember to release them later.
hr = pMux->QueryInterface(IID_IMediaSeeking, (void**)&pSeek);
hr = pGraph->QueryInterface(IID_IMediaEventEx, (void**)&pEvent);
hr = pGraph->QueryInterface(IID_IMediaControl, (void**)&pControl);
// Error checking is omitted for clarity.
// Set the DirectShow event notification window.
hr = pEvent->SetNotifyWindow((OAHWND)hwnd, WM_GRAPHNOTIFY, 0);
// Set the range of the progress bar to the file length (in seconds).
hr = pSeek->GetDuration(&rtTotal);
SendDlgItemMessage(hwnd, IDC_PROGRESS1, PBM_SETRANGE, 0,
MAKELPARAM(0, rtTotal / 10000000));
// Start the timer.
UINT_PTR res = SetTimer(hwnd, nIDEvent, 100, NULL);
// Run the graph.
pControl->Run();
當應用程式收到計時器事件時,可以使用目前的位置來更新 UI:
void OnTimer(HWND hDlg, IMediaSeeking *pSeek)
{
REFERENCE_TIME rtNow;
HRESULT hr = pSeek->GetCurrentPosition(&rtNow);
if (SUCCEEDED(hr))
{
SendDlgItemMessage(hDlg, IDC_PROGRESS1, PBM_SETPOS, rtNow/10000000, 0);
}
}
當應用程式收到 DirectShow 完成事件時,它應該停止圖形,如下列程式碼所示:
// Application window procedure
LRESULT CALLBACK WndProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
/* ... */
case WM_GRAPHNOTIFY:
DoHandleEvent();
break;
/* ... */
}
}
void DoHandleEvent()
{
long evCode, param1, param2;
bool bComplete = false;
if (!pEvent) return;
// Get all the events, and see we're done.
while (SUCCEEDED(pEvent->GetEvent(&evCode, ¶m1, ¶m2, 0))
{
pEvent->FreeEventParams(evCode, param1, param2);
switch(evCode)
{
case EC_USERABORT:
case EC_ERRORABORT:
case EC_COMPLETE:
bComplete = true;
break;
}
}
if (bComplete)
{
pControl->Stop(); // Important! You must stop the graph!
// Turn off event notification.
pEvent->SetNotifyWindow(NULL, 0, 0);
pEvent->Release();
pEvent = NULL;
// Reset the progress bar to zero and get rid of the timer.
SendDlgItemMessage(IDC_PROGRESS1, PBM_SETPOS, 0, 0);
KillTimer(hwnd, nIDEvent);
}
}