Aprendizaje cuando se produce un evento
[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 procesar eventos directShow, una aplicación necesita una manera de averiguar cuándo los eventos están esperando en la cola. Filter Graph Manager proporciona dos maneras de hacerlo:
- Notificación de ventana: Filter Graph Manager envía un mensaje de Windows definido por el usuario a una ventana de aplicación cada vez que hay un nuevo evento.
- Señalización de eventos: Filter Graph Manager indica un evento de Windows si hay eventos DirectShow en la cola y restablece el evento si la cola está vacía.
Una aplicación puede usar cualquiera de las técnicas. La notificación de ventana suele ser más sencilla.
Notificación de ventana
Para configurar la notificación de ventana, llame al método IMediaEventEx::SetNotifyWindow y especifique un mensaje privado. Las aplicaciones pueden usar números de mensaje en el intervalo de WM_APP a través de 0xBFFF como mensajes privados. Cada vez que el Administrador de gráficos de filtros coloca una nueva notificación de eventos en la cola, publica este mensaje en la ventana designada. La aplicación responde al mensaje desde el bucle de mensajes de la ventana.
En el ejemplo de código siguiente se muestra cómo establecer la ventana de notificación.
#define WM_GRAPHNOTIFY WM_APP + 1 // Private message.
pEvent->SetNotifyWindow((OAHWND)g_hwnd, WM_GRAPHNOTIFY, 0);
El mensaje es un mensaje normal de Windows y se publica por separado de la cola de notificaciones de eventos directShow. La ventaja de este enfoque es que la mayoría de las aplicaciones ya implementan un bucle de mensajes. Por lo tanto, puede incorporar el control de eventos directShow sin mucho trabajo adicional.
En el ejemplo de código siguiente se muestra un esquema de cómo responder al mensaje de notificación. Para obtener un ejemplo completo, vea Responder a eventos.
LRESULT CALLBACK WindowProc( HWND hwnd, UINT msg, UINT wParam, LONG lParam)
{
switch (msg)
{
case WM_GRAPHNOTIFY:
HandleEvent(); // Application-defined function.
break;
// Handle other Windows messages here too.
}
return (DefWindowProc(hwnd, msg, wParam, lParam));
}
Dado que la notificación de eventos y el bucle de mensajes son asincrónicos, la cola puede contener más de un evento en el momento en que la aplicación responde al mensaje. Además, los eventos a veces se pueden borrar de la cola si se vuelven no válidos. Por lo tanto, en el código de control de eventos, llame a IAMMediaEvent::GetEvent hasta que devuelva un código de error, lo que indica que la cola está vacía.
Antes de liberar el puntero IMediaEventEx , cancele la notificación de eventos llamando a SetNotifyWindow con un puntero NULL . En el código de procesamiento de eventos, compruebe si el puntero IMediaEventEx es válido antes de llamar a GetEvent. Estos pasos impiden un posible error, en el que la aplicación recibe la notificación de eventos después de haber publicado el puntero IMediaEventEx .
Señalización de eventos
Filter Graph Manager mantiene un evento de restablecimiento manual que refleja el estado de la cola de eventos. Si la cola contiene notificaciones de eventos pendientes, Filter Graph Manager indica el evento de restablecimiento manual. Si la cola está vacía, una llamada al método IMediaEvent::GetEvent restablece el evento. Una aplicación puede usar este evento para determinar el estado de la cola.
Nota:
La terminología puede resultar confusa aquí. El evento de restablecimiento manual es el tipo de evento creado por la función CreateEvent de Windows; no tiene nada que ver con los eventos definidos por DirectShow.
Llame al método IMediaEvent::GetEventHandle para obtener un identificador para el evento de restablecimiento manual. Espere a que el evento se señale llamando a una función como WaitForMultipleObjects. Una vez que se señaliza el evento, llame a IMediaEvent::GetEvent para obtener el evento DirectShow.
En el ejemplo de código siguiente se muestra este método. Obtiene el identificador de eventos y, a continuación, espera en intervalos de 100 milisegundos para que se señale el evento. Si se señala el evento, llama a GetEvent e imprime el código de evento y los parámetros de evento en la ventana de la consola. El bucle finaliza cuando se produce el evento EC_COMPLETE , lo que indica que la reproducción se ha completado.
HANDLE hEvent;
long evCode, param1, param2;
BOOLEAN bDone = FALSE;
HRESULT hr = S_OK;
hr = pEvent->GetEventHandle((OAEVENT*)&hEvent);
if (FAILED(hr))
{
/* Insert failure-handling code here. */
}
while(!bDone)
{
if (WAIT_OBJECT_0 == WaitForSingleObject(hEvent, 100))
{
while (S_OK == pEvent->GetEvent(&evCode, ¶m1, ¶m2, 0))
{
printf("Event code: %#04x\n Params: %d, %d\n", evCode, param1, param2);
pEvent->FreeEventParams(evCode, param1, param2);
bDone = (EC_COMPLETE == evCode);
}
}
}
Dado que el gráfico de filtros establece o restablece automáticamente el evento cuando corresponda, la aplicación no debe hacerlo. Además, al liberar el gráfico de filtros, el gráfico de filtros cierra el identificador de eventos, por lo que no use el identificador de eventos después de ese punto.