Udostępnij przez


Implementowanie paska wyszukiwania

[Funkcja skojarzona z tą stroną, DirectShow, jest starszą funkcją. Został zastąpiony przez MediaPlayer, IMFMediaEnginei Audio/Video Capture w Media Foundation. Te funkcje zostały zoptymalizowane pod kątem systemów Windows 10 i Windows 11. Firma Microsoft zdecydowanie zaleca, aby nowy kod używał MediaPlayer, IMFMediaEngine i Audio/Video Capture w programie Media Foundation zamiast DirectShow, jeśli to możliwe. Firma Microsoft sugeruje, że istniejący kod, który używa starszych interfejsów API, należy przepisać go do korzystania z nowych interfejsów API, jeśli to możliwe.]

W tej sekcji opisano sposób implementowania paska wyszukiwania dla aplikacji odtwarzacza multimediów. Pasek wyszukiwania jest implementowany jako kontrolka paska śledzenia. Aby zapoznać się z omówieniem wyszukiwania w programie DirectShow, zobacz Szukanie wykresu filtru.

Po uruchomieniu aplikacji zainicjuj pasek śledzenia:

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));
}

Pasek śledzenia jest wyłączony, dopóki użytkownik nie otworzy pliku multimedialnego. Zakres suwaka jest ustawiony od 0 do 100. Podczas odtwarzania pliku aplikacja obliczy pozycję odtwarzania jako procent czasu trwania pliku i odpowiednio zaktualizuje pasek śledzenia. Na przykład pozycja paska śledzenia "50" zawsze odpowiada środku pliku.

Gdy użytkownik otworzy plik, skompiluj graf odtwarzania plików przy użyciu RenderFile. Kod do tego jest pokazany w Jak odtworzyć plik. Następnie wykonaj zapytanie dotyczące menedżera filtrów programu Graph dla interfejsu IMediaSeeking i zapisz wskaźnik interfejsu:

IMediaSeeking *g_pSeek = 0;
hr = pGraph->QueryInterface(IID_IMediaSeeking, (void**)&g_pSeek);

Aby określić, czy plik można wyszukać, wywołaj metodę IMediaSeeking::CheckCapabilities lub metodę IMediaSeeking::GetCapabilities. Te metody robią prawie to samo, ale ich semantyka jest nieco inna. W poniższym przykładzie użyto 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);
}

Flaga AM_SEEKING_CanSeekAbsolute sprawdza, czy plik źródłowy można wyszukiwać, a flaga AM_SEEKING_CanGetDuration sprawdza, czy czas trwania pliku można określić z wyprzedzeniem. Jeśli obie funkcje są obsługiwane, aplikacja włącza pasek śledzenia i pobiera czas trwania pliku.

Jeśli wykres jest możliwy do wyszukiwania, aplikacja użyje czasomierza, aby zaktualizować położenie paska śledzenia podczas odtwarzania. Po uruchomieniu grafu filtru w celu odtworzenia pliku uruchom zdarzenie czasomierza, wywołując jedną z funkcji czasomierza systemu Windows, taką jak SetTimer. Aby uzyskać więcej informacji na temat czasomierzy, zobacz temat "Czasomierze" w zestawie SDK platformy.

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;
    }
}

Użyj zdarzenia czasomierza, aby zaktualizować położenie paska śledzenia. Wywołaj IMediaSeeking::GetCurrentPosition, aby pobrać bieżące położenie odtwarzania, a następnie oblicz pozycję jako procent czasu trwania pliku.

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;

Użytkownik może również przenieść pasek śledzenia, aby wyszukać plik. Gdy użytkownik przeciąga lub klika kontrolkę suwaka, aplikacja odbiera zdarzenie WM_HSCROLL. Niskim wyrazem parametru wParam jest komunikat powiadomienia paska śledzenia. Na przykład TB_ENDTRACK jest wysyłany na końcu akcji suwaka, a TB_THUMBTRACK jest wysyłany ciągle, gdy użytkownik przeciąga suwak. Poniższy kod przedstawia jeden ze sposobów obsługi komunikatu 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;
        }
    }
}

Jeśli użytkownik przeciągnie pasek trackbar, aplikacja wystawia serię poleceń wyszukiwania, po jednym dla każdego TB_THUMBTRACK komunikatu, który otrzymuje. Aby zapewnić bezproblemowe działanie wyszukiwania, aplikacja wstrzymuje graf. Wstrzymanie odtwarzania grafu powoduje zatrzymanie odtwarzania, ale gwarantuje, że okno wideo zostanie zaktualizowane. Gdy aplikacja odbiera komunikat TB_ENDTRACK, przywraca graf do stanu pierwotnego.