Implementando uma barra de busca

[O recurso associado a esta página, DirectShow, é um recurso herdado. Ele foi substituído por MediaPlayer, IMFMediaEngine e Captura de Áudio/Vídeo na Media Foundation. Esses recursos foram otimizados para Windows 10 e Windows 11. A Microsoft recomenda fortemente que o novo código use MediaPlayer, IMFMediaEngine e Captura de Áudio/Vídeo no Media Foundation em vez de DirectShow, quando possível. A Microsoft sugere que o código existente que usa as APIs herdadas seja reescrito para usar as novas APIs, se possível.]

Esta seção descreve como implementar uma barra de busca para um aplicativo media-player. A barra de busca é implementada como um controle de barra de controle. Para obter uma visão geral da busca no DirectShow, consulte Procurando o grafo de filtro.

Quando o aplicativo for iniciado, inicialize a barra de controle:

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

A barra de controle é desabilitada até que o usuário abra um arquivo de mídia. O intervalo da barra de controle é definido de 0 a 100. Durante a reprodução do arquivo, o aplicativo calculará a posição de reprodução como uma porcentagem da duração do arquivo e atualizará a barra de controle adequadamente. Por exemplo, a posição da barra de controle "50" sempre corresponde ao meio do arquivo.

Quando o usuário abrir um arquivo, crie um grafo de reprodução de arquivo usando RenderFile. O código para isso é mostrado em Como reproduzir um arquivo. Em seguida, consulte o Gerenciador de Grafo de Filtro para a interface IMediaSeeking e armazene o ponteiro da interface:

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

Para determinar se o arquivo é pesquisável, chame o método IMediaSeeking::CheckCapabilities ou o método IMediaSeeking::GetCapabilities . Esses métodos fazem quase a mesma coisa, mas sua semântica é um pouco diferente. O exemplo a seguir usa 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);
}

O sinalizador AM_SEEKING_CanSeekAbsolute verifica se o arquivo de origem é buscado e o sinalizador AM_SEEKING_CanGetDuration verifica se a duração do arquivo pode ser determinada com antecedência. Se houver suporte para ambos os recursos, o aplicativo habilitará a barra de controle e recuperará a duração do arquivo.

Se o grafo for buscado, o aplicativo usará um temporizador para atualizar a posição da barra de controle durante a reprodução. Ao executar o grafo de filtro para reproduzir o arquivo, inicie o evento de temporizador chamando uma das funções do temporizador do Windows, como SetTimer. Para obter mais informações sobre temporizadores, consulte o tópico "Temporizadores" no SDK da Plataforma.

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

Use o evento de temporizador para atualizar a posição da barra de controle. Chame IMediaSeeking::GetCurrentPosition para recuperar a posição de reprodução de groselha e calcule a posição como uma porcentagem da duração do arquivo:

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;

O usuário também pode mover a barra de controle para procurar o arquivo. Quando o usuário arrasta ou clica no controle trackbar, o aplicativo recebe um evento WM_HSCROLL. A palavra baixa do parâmetro wParam é a mensagem de notificação de barra de controle. Por exemplo, TB_ENDTRACK é enviado no final da ação de barra de controle e TB_THUMBTRACK é enviado continuamente enquanto o usuário arrasta a barra de controle. O código a seguir mostra uma maneira de lidar com a mensagem 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;
        }
    }
}

Se o usuário arrastar a barra de controle, o aplicativo emitirá uma série de comandos seek, um para cada TB_THUMBTRACK mensagem recebida. Para tornar as operações de busca o mais suaves possível, o aplicativo pausa o grafo. Pausar o grafo interrompe a reprodução, mas garante que a janela de vídeo seja atualizada. Quando o aplicativo recebe a mensagem TB_ENDTRACK, ele restaura o grafo para seu estado original.