實作搜尋列
[與此頁面相關的功能 DirectShow是舊版功能。 它已被 MediaPlayer、 IMFMediaEngine和 Media Foundation 中的音訊/視訊擷取取代。 這些功能已針對Windows 10和Windows 11進行優化。 Microsoft 強烈建議新程式碼盡可能使用 MediaPlayer、 IMFMediaEngine 和 音訊/視訊擷取 ,而不是 DirectShow。 Microsoft 建議使用舊版 API 的現有程式碼盡可能重寫為使用新的 API。
本節說明如何實作媒體播放機應用程式的搜尋列。 搜尋列會實作為追蹤列控制項。 如需在 DirectShow 中搜尋的概觀,請參閱 搜尋篩選圖表。
應用程式啟動時,初始化追蹤列:
void InitSlider(HWND hwnd)
{
// Initialize the trackbar range, but disable the
// control until the user opens a file.
hScroll = GetDlgItem(hwnd, IDC_SLIDER1);
EnableWindow(hScroll, FALSE);
SendMessage(hScroll, TBM_SETRANGE, TRUE, MAKELONG(0, 100));
}
追蹤欄會停用,直到使用者開啟媒體檔案為止。 追蹤列範圍是從 0 設定為 100。 在檔案播放期間,應用程式會將播放位置計算為檔案持續時間的百分比,並據以更新追蹤列。 例如,追蹤列位置 「50」 一律對應至檔案中間。
當使用者開啟檔案時,請使用 RenderFile建置檔案播放圖表。 此程式碼會顯示 在如何播放檔案中。 然後查詢 IMediaSeeking 介面的 Filter Graph 管理員,並儲存介面指標:
IMediaSeeking *g_pSeek = 0;
hr = pGraph->QueryInterface(IID_IMediaSeeking, (void**)&g_pSeek);
若要判斷檔案是否可搜尋,請呼叫 IMediaSeeking::CheckCapabilities 方法或 IMediaSeeking::GetCapabilities 方法。 這些方法幾乎會執行相同的動作,但其語意稍有不同。 下列範例使用 CheckCapabilites:
// Determine if the source is seekable.
BOOL bCanSeek = FALSE;
DWORD caps = AM_SEEKING_CanSeekAbsolute | AM_SEEKING_CanGetDuration;
bCanSeek = (S_OK == pSeek->CheckCapabilities(&caps));
if (bCanSeek)
{
// Enable the trackbar.
EnableWindow(hScroll, TRUE);
// Find the file duration.
pSeek->GetDuration(&g_rtTotalTime);
}
AM_SEEKING_CanSeekAbsolute旗標會檢查來源檔案是否可搜尋,而AM_SEEKING_CanGetDuration旗標會檢查是否可以事先判斷檔案的持續時間。 如果同時支援這兩個功能,應用程式會啟用追蹤欄並擷取檔案持續時間。
如果可搜尋圖表,應用程式將會使用計時器在播放期間更新追蹤列位置。 當您執行篩選圖形來播放檔案時,請呼叫其中一個 Windows 計時器函式來啟動計時器事件,例如 SetTimer。 如需計時器的詳細資訊,請參閱平臺 SDK 中的主題。
void StartPlayback(HWND hwnd)
{
pControl->Run();
if (bCanSeek)
{
StopTimer(); // Make sure an old timer is not still active.
nTimerID = SetTimer(hwnd, IDT_TIMER1, TICK_FREQ, (TIMERPROC)NULL);
if (nTimerID == 0)
{
/* Handle Error */
}
}
}
void StopTimer()
{
if (wTimerID != 0)
{
KillTimer(g_hwnd, wTimerID);
wTimerID = 0;
}
}
使用計時器事件來更新追蹤列的位置。 呼叫 IMediaSeeking::GetCurrentPosition 以擷取 Currant 播放位置,然後將位置計算為檔案持續時間的百分比:
case WM_TIMER:
if (wParam == IDT_TIMER1)
{
// Timer should not be running unless we really can seek.
ASSERT(bCanSeek == TRUE);
REFERENCE_TIME timeNow;
if (SUCCEEDED(pSeek->GetCurrentPosition(&timeNow)))
{
long sliderTick = (long)((timeNow * 100) / g_rtTotalTime);
SendMessage( hScroll, TBM_SETPOS, TRUE, sliderTick );
}
}
break;
使用者也可以移動追蹤欄來搜尋檔案。 當使用者拖曳或按一下追蹤列控制項時,應用程式會收到WM_HSCROLL事件。 wParam參數的低字是追蹤列通知訊息。 例如,TB_ENDTRACK會在追蹤列動作的結尾傳送,而使用者拖曳追蹤列時會持續傳送TB_THUMBTRACK。 下列程式碼示範處理WM_HSCROLL訊息的其中一種方式:
static OAFilterState state;
static BOOL bStartOfScroll = TRUE;
case WM_HSCROLL:
short int userReq = LOWORD(wParam);
if (userReq == TB_ENDTRACK || userReq == TB_THUMBTRACK)
{
DWORD dwPosition = SendMessage(hTrackbar, TBM_GETPOS, 0, 0);
// Pause when the scroll action begins.
if (bStartOfScroll)
{
pControl->GetState(10, &state);
bStartOfScroll = FALSE;
pControl->Pause();
}
// Update the position continuously.
REFERENCE_TIME newTime = (g_rtTotalTime/100) * dwPosition;
pSeek->SetPositions(&newTime, AM_SEEKING_AbsolutePositioning,
NULL, AM_SEEKING_NoPositioning);
// Restore the state at the end.
if (userReq == TB_ENDTRACK)
{
if (state == State_Stopped)
pControl->Stop();
else if (state == State_Running)
pControl->Run();
bStartOfScroll = TRUE;
}
}
}
如果使用者拖曳追蹤列,應用程式會發出一系列的搜尋命令,每個TB_THUMBTRACK訊息都會發出一個。 為了讓搜尋作業盡可能順暢,應用程式會暫停圖形。 暫停圖表會停止播放,但可確保影片視窗已更新。 當應用程式收到TB_ENDTRACK訊息時,它會將圖形還原為其原始狀態。