Share via


Gravando o arquivo

[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.]

Para gravar o arquivo, basta executar o grafo de filtro chamando o método IMediaControl::Run . Aguarde a conclusão da reprodução e interrompa explicitamente o grafo chamando IMediaControl::Stop; caso contrário, o arquivo não é gravado corretamente.

Para exibir o progresso da operação de gravação de arquivos, consulte o filtro Mux para a interface IMediaSeeking . Chame o método IMediaSeeking::GetDuration para recuperar a duração do arquivo. Periodicamente, enquanto o grafo estiver em execução, chame o método IMediaSeeking::GetCurrentPosition para recuperar a posição atual do grafo no fluxo. A posição atual dividida por duração fornece a porcentagem concluída.

Observação

Um aplicativo geralmente consulta o Gerenciador de Grafo de Filtro para IMediaSeeking, mas a gravação de arquivo é uma exceção a essa regra. O Gerenciador de Grafo de Filtro calcula a posição atual da posição inicial e por quanto tempo o grafo está em execução, o que é preciso para reprodução de arquivo, mas não para gravação de arquivo. Portanto, para obter um resultado preciso, você deve recuperar a posição do filtro MUX.

 

O código a seguir obtém a duração do arquivo, inicia um temporizador para atualizar a interface do usuário do aplicativo e executa o grafo de filtro. (A verificação de erros é omitida para maior clareza.)

IMediaSeeking *pSeek = NULL;
IMediaEventEx *pEvent = NULL;
IMediaControl *pControl = NULL;
REFERENCE_TIME rtTotal;

// Query for interfaces. Remember to release them later.
hr = pMux->QueryInterface(IID_IMediaSeeking, (void**)&pSeek);
hr = pGraph->QueryInterface(IID_IMediaEventEx, (void**)&pEvent);
hr = pGraph->QueryInterface(IID_IMediaControl, (void**)&pControl);

// Error checking is omitted for clarity.

// Set the DirectShow event notification window.
hr = pEvent->SetNotifyWindow((OAHWND)hwnd, WM_GRAPHNOTIFY, 0);

// Set the range of the progress bar to the file length (in seconds).
hr = pSeek->GetDuration(&rtTotal);
SendDlgItemMessage(hwnd, IDC_PROGRESS1, PBM_SETRANGE, 0, 
   MAKELPARAM(0, rtTotal / 10000000));
// Start the timer.
UINT_PTR res = SetTimer(hwnd, nIDEvent, 100, NULL);
// Run the graph.
pControl->Run();

Quando o aplicativo recebe um evento de temporizador, ele pode atualizar a interface do usuário com a posição atual:

void OnTimer(HWND hDlg, IMediaSeeking *pSeek)
{
    REFERENCE_TIME rtNow;
    HRESULT hr = pSeek->GetCurrentPosition(&rtNow);
    if (SUCCEEDED(hr))
    {
        SendDlgItemMessage(hDlg, IDC_PROGRESS1, PBM_SETPOS, rtNow/10000000, 0);
    }
}

Quando o aplicativo recebe um evento de conclusão do DirectShow, ele deve interromper o grafo, conforme mostrado no seguinte código:

// Application window procedure
LRESULT CALLBACK WndProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
    /*  ...  */
    case WM_GRAPHNOTIFY:
        DoHandleEvent();
        break;
    /*  ...  */
    }
}

void DoHandleEvent()
{
    long evCode, param1, param2;
    bool bComplete = false;
    if (!pEvent) return;

    // Get all the events, and see we're done.
    while (SUCCEEDED(pEvent->GetEvent(&evCode, &param1, &param2, 0))
    {
        pEvent->FreeEventParams(evCode, param1, param2);
        switch(evCode)
        {
            case EC_USERABORT:
            case EC_ERRORABORT:
            case EC_COMPLETE:
                bComplete = true;
                break;
        }
    }
    if (bComplete)
    {
        pControl->Stop(); // Important! You must stop the graph!

        // Turn off event notification.
        pEvent->SetNotifyWindow(NULL, 0, 0);
        pEvent->Release();
        pEvent = NULL;
        // Reset the progress bar to zero and get rid of the timer.
        SendDlgItemMessage(IDC_PROGRESS1, PBM_SETPOS, 0, 0);
        KillTimer(hwnd, nIDEvent);
    }
}