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, ¶m1, ¶m2, 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);
}
}