Apprentissage lorsqu’un événement se produit

[La fonctionnalité associée à cette page, DirectShow, est une fonctionnalité héritée. Il a été remplacé par MediaPlayer, IMFMediaEngine et Audio/Video Capture in Media Foundation. Ces fonctionnalités ont été optimisées pour Windows 10 et Windows 11. Microsoft recommande vivement que le nouveau code utilise MediaPlayer, IMFMediaEngine et Audio/Video Capture dans Media Foundation au lieu de DirectShow, si possible. Microsoft suggère que le code existant qui utilise les API héritées soit réécrit pour utiliser les nouvelles API si possible.]

Pour traiter les événements DirectShow, une application a besoin d’un moyen de savoir quand les événements sont en attente dans la file d’attente. Le Gestionnaire de graphe de filtres offre deux façons de procéder :

  • Notification de fenêtre : Le Gestionnaire de graphe de filtres envoie un message Windows défini par l’utilisateur à une fenêtre d’application chaque fois qu’il y a un nouvel événement.
  • Signalisation d’événements : Le Gestionnaire de graphe de filtre signale un événement Windows s’il existe des événements DirectShow dans la file d’attente et réinitialise l’événement si la file d’attente est vide.

Une application peut utiliser l’une ou l’autre technique. La notification de fenêtre est généralement plus simple.

Notification de fenêtre

Pour configurer la notification de fenêtre, appelez la méthode IMediaEventEx::SetNotifyWindow et spécifiez un message privé. Les applications peuvent utiliser des numéros de message entre WM_APP et 0xBFFF en tant que messages privés. Chaque fois que le Gestionnaire de graphe de filtres place une nouvelle notification d’événement dans la file d’attente, il publie ce message dans la fenêtre désignée. L’application répond au message à partir de la boucle de message de la fenêtre.

L’exemple de code suivant montre comment définir la fenêtre de notification.

#define WM_GRAPHNOTIFY WM_APP + 1   // Private message.
pEvent->SetNotifyWindow((OAHWND)g_hwnd, WM_GRAPHNOTIFY, 0);

Le message est un message Windows ordinaire et est publié séparément de la file d’attente des notifications d’événements DirectShow. L’avantage de cette approche est que la plupart des applications implémentent déjà une boucle de message. Par conséquent, vous pouvez incorporer la gestion des événements DirectShow sans beaucoup de travail supplémentaire.

L’exemple de code suivant montre comment répondre au message de notification. Pour obtenir un exemple complet, consultez Réponse aux événements.

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

Étant donné que la notification d’événement et la boucle de message sont toutes deux asynchrones, la file d’attente peut contenir plusieurs événements au moment où votre application répond au message. En outre, les événements peuvent parfois être effacés de la file d’attente s’ils deviennent non valides. Par conséquent, dans votre code de gestion des événements, appelez IAMMediaEvent::GetEvent jusqu’à ce qu’il retourne un code d’échec, indiquant que la file d’attente est vide.

Avant de libérer le pointeur IMediaEventEx , annulez la notification d’événement en appelant SetNotifyWindow avec un pointeur NULL . Dans votre code de traitement des événements, case activée si votre pointeur IMediaEventEx est valide avant d’appeler GetEvent. Ces étapes empêchent une erreur possible, dans laquelle l’application reçoit la notification d’événement après avoir libéré le pointeur IMediaEventEx .

Signalisation d’événements

Le Gestionnaire de graphe de filtre conserve un événement de réinitialisation manuelle qui reflète l’état de la file d’attente d’événements. Si la file d’attente contient des notifications d’événements en attente, le Gestionnaire de graphes de filtre signale l’événement de réinitialisation manuelle. Si la file d’attente est vide, un appel à la méthode IMediaEvent::GetEvent réinitialise l’événement. Une application peut utiliser cet événement pour déterminer l’état de la file d’attente.

Notes

La terminologie peut prêter à confusion ici. L’événement de réinitialisation manuelle est le type d’événement créé par la fonction Windows CreateEvent ; elle n’a rien à voir avec les événements définis par DirectShow.

 

Appelez la méthode IMediaEvent::GetEventHandle pour obtenir un handle pour l’événement de réinitialisation manuelle. Attendez que l’événement soit signalé en appelant une fonction telle que WaitForMultipleObjects. Une fois l’événement signalé, appelez IMediaEvent::GetEvent pour obtenir l’événement DirectShow.

L'exemple de code suivant illustre cette approche. Il obtient le handle d’événement, puis attend par intervalles de 100 millisecondes que l’événement soit signalé. Si l’événement est signalé, il appelle GetEvent et imprime le code d’événement et les paramètres d’événement dans la fenêtre de console. La boucle se termine lorsque l’événement EC_COMPLETE se produit, indiquant que la lecture est terminée.

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, &param1, &param2, 0)) 
        {
            printf("Event code: %#04x\n Params: %d, %d\n", evCode, param1, param2);
            pEvent->FreeEventParams(evCode, param1, param2);
            bDone = (EC_COMPLETE == evCode);
        }
    }
} 

Étant donné que le graphique de filtre définit ou réinitialise automatiquement l’événement le cas échéant, votre application ne doit pas le faire. En outre, lorsque vous relâchez le graphique de filtre, le graphique de filtre ferme le handle d’événement. Par conséquent, n’utilisez pas le handle d’événement après ce point.