Share via


Réponse aux événements

[La fonctionnalité associée à cette page, DirectShow, est une fonctionnalité héritée. Il a été remplacé par MediaPlayer, IMFMediaEngine et Audio/Video Capture dans Media Foundation. Ces fonctionnalités ont été optimisées pour Windows 10 et Windows 11. Microsoft recommande vivement au nouveau code d’utiliser MediaPlayer, IMFMediaEngine et La capture audio/vidéo dans Media Foundation au lieu de DirectShow, lorsque cela est 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.]

Cet article explique comment répondre aux événements qui se produisent dans un graphique de filtre.

Fonctionnement de la notification d’événement

Pendant l’exécution d’une application DirectShow, des événements peuvent se produire dans le graphe de filtre. Par exemple, un filtre peut rencontrer une erreur de diffusion en continu. Les filtres alertent le Gestionnaire de graphes de filtre en envoyant des événements, qui se composent d’un code d’événement et de deux paramètres d’événement. Le code d’événement indique le type d’événement et les paramètres de l’événement fournissent des informations supplémentaires. La signification des paramètres dépend du code d’événement. Pour obtenir la liste complète des codes d’événement, consultez Codes de notification d’événement.

Certains événements sont gérés en mode silencieux par le Gestionnaire de graphes de filtre, sans que l’application en soit avertie. D’autres événements sont placés sur une file d’attente pour l’application. Selon l’application, vous devrez peut-être gérer différents événements. Cet article se concentre sur trois événements qui sont très courants :

Utilisation de la notification d’événement

Une application peut demander au Gestionnaire de graphes de filtre d’envoyer un message Windows à une fenêtre désignée chaque fois qu’un nouvel événement se produit. Cela permet à l’application de répondre à l’intérieur de la boucle de message de la fenêtre. Tout d’abord, définissez le message qui sera envoyé à la fenêtre d’application. Les applications peuvent utiliser des numéros de message dans la plage de WM_APP à 0xBFFF en tant que messages privés :

#define WM_GRAPHNOTIFY  WM_APP + 1

Ensuite, interrogez le Gestionnaire de graphes de filtre pour l’interface IMediaEventEx et appelez la méthode IMediaEventEx::SetNotifyWindow :

IMediaEventEx *g_pEvent = NULL;
g_pGraph->QueryInterface(IID_IMediaEventEx, (void **)&g_pEvent);
g_pEvent->SetNotifyWindow((OAHWND)g_hwnd, WM_GRAPHNOTIFY, 0);

Cette méthode désigne la fenêtre spécifiée (g_hwnd) comme destinataire du message. Appelez la méthode après avoir créé le graphe de filtre, mais avant d’exécuter le graphe.

WM_GRAPHNOTIFY est un message Windows ordinaire. Chaque fois que le Gestionnaire de graphes de filtre place un nouvel événement sur la file d’attente d’événements, il publie un message WM_GRAPHNOTIFY dans la fenêtre d’application désignée. Le paramètre lParam du message est égal au troisième paramètre dans SetNotifyWindow. Ce paramètre vous permet d’envoyer des données instance avec le message. Le paramètre wParam du message de fenêtre est toujours égal à zéro.

Dans la fonction WindowProc de votre application, ajoutez une instruction case pour le message WM_GRAPHNOTIFY :

case WM_GRAPHNOTIFY:
    HandleGraphEvent();
    break;

Dans la fonction de gestionnaire d’événements, appelez la méthode IMediaEvent::GetEvent pour récupérer les événements de la file d’attente :

void HandleGraphEvent()
{
    // Disregard if we don't have an IMediaEventEx pointer.
    if (g_pEvent == NULL)
    {
        return;
    }
    // Get all the events
    long evCode;
    LONG_PTR param1, param2;
    HRESULT hr;
    while (SUCCEEDED(g_pEvent->GetEvent(&evCode, &param1, &param2, 0)))
    {
        g_pEvent->FreeEventParams(evCode, param1, param2);
        switch (evCode)
        {
        case EC_COMPLETE:  // Fall through.
        case EC_USERABORT: // Fall through.
        case EC_ERRORABORT:
            CleanUp();
            PostQuitMessage(0);
            return;
        }
    } 
}

La méthode GetEvent récupère le code d’événement et les deux paramètres d’événement. Le quatrième paramètre GetEvent spécifie la durée d’attente d’un événement, en millisecondes. Étant donné que l’application appelle cette méthode en réponse à un message WM_GRAPHNOTIFY, l’événement est déjà mis en file d’attente. Par conséquent, nous définissons la valeur de délai d’attente sur zéro.

La notification d’événement et la boucle de message étant asynchrones, la file d’attente peut contenir plusieurs événements au moment où votre application répond au message. En outre, le Gestionnaire de graphes de filtre peut supprimer certains événements de la file d’attente, s’ils deviennent non valides. Par conséquent, vous devez appeler GetEvent jusqu’à ce qu’il retourne un code d’échec, indiquant que la file d’attente est vide.

Dans cet exemple, l’application répond à EC_COMPLETE, EC_USERABORT et EC_ERRORABORT en appelant la fonction CleanUp définie par l’application, ce qui entraîne la mise hors service de l’application. L’exemple ignore les deux paramètres d’événement. Après avoir récupéré un événement, appelez IMediaEvent::FreeEventParams à toutes les ressources gratuites associées aux paramètres d’événement.

Notez qu’un événement EC_COMPLETE n’entraîne pas l’arrêt du graphe de filtre. L’application peut arrêter ou suspendre le graphe. Si vous arrêtez le graphique, les filtres libèrent toutes les ressources qu’ils détiennent. Si vous suspendez le graphique, les filtres continuent de contenir des ressources. En outre, lorsqu’un convertisseur vidéo s’interrompt, il affiche une image statique de l’image la plus récente.

Avant de libérer le pointeur IMediaEventEx , annulez la notification d’événement en appelant SetNotifyWindow avec un handle de fenêtre NULL :

// Disable event notification before releasing the graph.
g_pEvent->SetNotifyWindow(NULL, 0, 0);
g_pEvent->Release();
g_pEvent = NULL;

Dans le gestionnaire de messages WM_GRAPHNOTIFY, case activée le pointeur IMediaEventEx avant d’appelerGetEvent :

if (g_pEvent == NULL) return;

Cela empêche une erreur possible qui peut se produire si l’application reçoit la notification d’événement après avoir libéré le pointeur.

Tâches directshow de base

Notification d’événement dans DirectShow