Поделиться через


Реализация панели поиска

[Функция, связанная с этой страницей DirectShow, является устаревшей функцией. Он был заменен MediaPlayer, IMFMediaEngine, и аудио/ видео захвата в Media Foundation. Эти функции оптимизированы для Windows 10 и Windows 11. Корпорация Майкрософт настоятельно рекомендует, чтобы новый код использовал MediaPlayer, IMFMediaEngine и аудио- и видеозахват в Media Foundation вместо DirectShow, когда это возможно. Корпорация Майкрософт предлагает переписать существующий код, использующий устаревшие API, чтобы по возможности использовать новые API.]

В этом разделе описывается, как реализовать панель поиска для приложения проигрывателя мультимедиа. Панель поиска реализована как элемент управления trackbar. Общие сведения о поиске в 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 и сохраните указатель интерфейса:

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 , чтобы получить позицию воспроизведения смородины, а затем вычислите позицию в процентах от длительности файла:

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;

Пользователь также может переместить панель отслеживания для поиска файла. Когда пользователь перетаскивает элемент управления trackbar или щелкает его, приложение получает событие WM_HSCROLL. Низкое слово параметра wParam — это сообщение с уведомлением на панели отслеживания. Например, TB_ENDTRACK отправляется в конце действия trackbar, а 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, оно восстанавливает граф в исходное состояние.