Implementación de una barra de búsqueda

[La característica asociada a esta página, DirectShow, es una característica heredada. Se ha reemplazado por MediaPlayer, IMFMediaEngine y Captura de audio/vídeo en Media Foundation. Esas características se han optimizado para Windows 10 y Windows 11. Microsoft recomienda encarecidamente que el nuevo código use MediaPlayer, IMFMediaEngine y Audio/Video Capture en Media Foundation en lugar de DirectShow, siempre que sea posible. Microsoft sugiere que el código existente que usa las API heredadas se reescriba para usar las nuevas API si es posible.

En esta sección se describe cómo implementar una barra de búsqueda para una aplicación de reproductor multimedia. La barra de búsqueda se implementa como un control de barra de seguimiento. Para obtener información general sobre la búsqueda en DirectShow, vea Buscar el gráfico de filtros.

Cuando se inicie la aplicación, inicialice la barra de seguimiento:

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

La barra de seguimiento está deshabilitada hasta que el usuario abre un archivo multimedia. El intervalo de la barra de seguimiento se establece de 0 a 100. Durante la reproducción de archivos, la aplicación calculará la posición de reproducción como un porcentaje de la duración del archivo y actualizará la barra de seguimiento según corresponda. Por ejemplo, la posición de la barra de seguimiento "50" siempre corresponde al centro del archivo.

Cuando el usuario abra un archivo, compile un gráfico de reproducción de archivos mediante RenderFile. El código para esto se muestra en Cómo reproducir un archivo. A continuación, consulte el Administrador de gráficos de filtros para la interfaz IMediaSeeking y almacene el puntero de interfaz:

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

Para determinar si el archivo es buscable, llame al método IMediaSeeking::CheckCapabilities o al método IMediaSeeking::GetCapabilities . Estos métodos hacen casi lo mismo, pero su semántica es ligeramente diferente. En el ejemplo siguiente se 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);
}

La marca AM_SEEKING_CanSeekAbsolute comprueba si se puede buscar el archivo de origen y la marca AM_SEEKING_CanGetDuration comprueba si la duración del archivo se puede determinar de antemano. Si se admiten ambas funcionalidades, la aplicación habilita la barra de seguimiento y recupera la duración del archivo.

Si el gráfico es buscable, la aplicación usará un temporizador para actualizar la posición de la barra de seguimiento durante la reproducción. Al ejecutar el gráfico de filtros para reproducir el archivo, inicie el evento de temporizador llamando a una de las funciones del temporizador de Windows, como SetTimer. Para obtener más información sobre los temporizadores, consulte el tema "Temporizadores" en platform 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;
    }
}

Use el evento de temporizador para actualizar la posición de la barra de seguimiento. Llame a IMediaSeeking::GetCurrentPosition para recuperar la posición de reproducción currant y, a continuación, calcule la posición como un porcentaje de la duración del archivo:

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;

El usuario también puede mover la barra de seguimiento para buscar el archivo. Cuando el usuario arrastra o hace clic en el control de la barra de seguimiento, la aplicación recibe un evento de WM_HSCROLL. La palabra baja del parámetro wParam es el mensaje de notificación de la barra de seguimiento. Por ejemplo, TB_ENDTRACK se envía al final de la acción de la barra de seguimiento y TB_THUMBTRACK se envía continuamente mientras el usuario arrastra la barra de seguimiento. El código siguiente muestra una manera de controlar el mensaje de 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;
        }
    }
}

Si el usuario arrastra la barra de seguimiento, la aplicación emite una serie de comandos seek, uno para cada TB_THUMBTRACK mensaje que recibe. Para que las operaciones de búsqueda sean lo más fluidas posible, la aplicación pausa el gráfico. La pausa del gráfico detiene la reproducción, pero garantiza que se actualice la ventana de vídeo. Cuando la aplicación recibe el mensaje TB_ENDTRACK, restaura el grafo a su estado original.