Escritura del archivo
[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.
Para escribir el archivo, basta con ejecutar el grafo de filtro llamando al método IMediaControl::Run . Espere a que la reproducción se complete y detenga explícitamente el gráfico llamando a IMediaControl::Stop; de lo contrario, el archivo no está escrito correctamente.
Para mostrar el progreso de la operación de escritura de archivos, consulte el filtro Mux para la interfaz IMediaSeeking . Llame al método IMediaSeeking::GetDuration para recuperar la duración del archivo. Periódicamente mientras se ejecuta el grafo, llame al método IMediaSeeking::GetCurrentPosition para recuperar la posición actual del grafo en la secuencia. La posición actual dividida por duración proporciona el porcentaje completado.
Nota:
Normalmente, una aplicación consulta el Administrador de gráficos de filtros para IMediaSeeking, pero la escritura de archivos es una excepción a esta regla. El Administrador de gráficos de filtros calcula la posición actual a partir de la posición inicial y cuánto tiempo se ha estado ejecutando el grafo, que es preciso para la reproducción de archivos, pero no para la escritura de archivos. Por lo tanto, para obtener un resultado preciso, debe recuperar la posición del filtro MUX.
El código siguiente obtiene la duración del archivo, inicia un temporizador para actualizar la interfaz de usuario de la aplicación y ejecuta el gráfico de filtros. (Se omite la comprobación de errores para mayor claridad).
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();
Cuando la aplicación recibe un evento de temporizador, puede actualizar la interfaz de usuario con la posición actual:
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);
}
}
Cuando la aplicación recibe un evento de finalización de DirectShow, debe detener el gráfico, como se muestra en el código siguiente:
// 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);
}
}