Share via


Autres convertisseurs vidéo

[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.]

Cette rubrique explique comment écrire un convertisseur vidéo personnalisé pour DirectShow.

Notes

Au lieu d’écrire un convertisseur vidéo personnalisé, il est recommandé d’écrire un présentateur-allocateur de plug-in pour le convertisseur vidéo de mixage (VMR) ou le convertisseur vidéo amélioré (EVR). Cette approche vous offre tous les avantages de VMR/EVR, notamment la prise en charge de l’accélération vidéo DirectX (DXVA), le désentlacement matériel et la mise à pas à pas d’images, et est susceptible d’être plus robuste qu’un convertisseur vidéo personnalisé. Pour plus d'informations, voir les rubriques suivantes :

 

Écriture d’un autre renderer

Microsoft DirectShow fournit un convertisseur vidéo basé sur une fenêtre ; il fournit également un convertisseur plein écran dans l’installation au moment de l’exécution. Vous pouvez utiliser les classes de base DirectShow pour écrire d’autres convertisseurs vidéo. Pour que d’autres convertisseurs interagissent correctement avec les applications basées sur DirectShow, les renderers doivent respecter les instructions décrites dans cet article. Vous pouvez utiliser les classes CBaseRenderer et CBaseVideoRenderer pour vous aider à suivre ces instructions lors de l’implémentation d’un autre rendu vidéo. En raison du développement continu de DirectShow, passez régulièrement en revue votre implémentation pour vous assurer que les convertisseurs sont compatibles avec la version la plus récente de DirectShow.

Cette rubrique décrit de nombreuses notifications qu’un convertisseur est responsable de la gestion. Un bref examen des notifications DirectShow peut vous aider à définir l’étape. Il existe essentiellement trois types de notifications qui se produisent dans DirectShow :

  • Les notifications de flux, qui sont des événements qui se produisent dans le flux multimédia et qui sont passés d’un filtre à l’autre. Il peut s’agir de notifications de début de vidage, de vidage de fin ou de fin de flux et sont envoyées en appelant la méthode appropriée sur la broche d’entrée du filtre en aval (par exemple , IPin::BeginFlush).
  • Filtrer les notifications de graphique, qui sont des événements envoyés d’un filtre au Gestionnaire de graphes de filtre, comme EC_COMPLETE. Pour ce faire, appelez la méthode IMediaEventSink::Notify sur le Gestionnaire de graphes de filtre.
  • Notifications d’application, qui sont récupérées à partir du Gestionnaire de filtre graph par l’application de contrôle. Une application appelle la méthode IMediaEvent::GetEvent sur filter Graph Manager pour récupérer ces événements. Souvent, le Gestionnaire de graphes de filtre transmet les événements qu’il reçoit à l’application.

Cette rubrique traite de la responsabilité du filtre de rendu dans la gestion des notifications de flux qu’il reçoit et dans l’envoi de notifications de graphe de filtre appropriées.

Gestion des notifications de fin de flux et de vidage

Une notification de fin de flux commence à un filtre amont (tel que le filtre source) lorsque ce filtre détecte qu’il ne peut plus envoyer de données. Il est transmis à tous les filtres du graphe et se termine finalement au renderer, qui est chargé d’envoyer par la suite une notification EC_COMPLETE au Gestionnaire de graphe de filtre. Les renderers ont des responsabilités spéciales lorsqu’il s’agit de gérer ces notifications.

Un convertisseur reçoit une notification de fin de flux lorsque la méthode IPin::EndOfStream de sa broche d’entrée est appelée par le filtre amont. Un convertisseur doit noter cette notification et continuer à afficher toutes les données qu’il a déjà reçues. Une fois toutes les données restantes reçues, le convertisseur doit envoyer une notification EC_COMPLETE au Gestionnaire de graphes de filtre. La notification EC_COMPLETE ne doit être envoyée qu’une seule fois par un convertisseur chaque fois qu’elle atteint la fin d’un flux. En outre, EC_COMPLETE notifications ne doivent jamais être envoyées, sauf lorsque le graphe de filtre est en cours d’exécution. Par conséquent, si le graphe de filtre est suspendu lorsqu’un filtre source envoie une notification de fin de flux, EC_COMPLETE ne doit pas être envoyé tant que le graphe de filtre n’est pas finalement exécuté.

Tous les appels aux méthodes IMemInputPin::Receive ou IMemInputPin::ReceiveMultiple après qu’une notification de fin de flux est signalée doivent être rejetés. E_UNEXPECTED est le message d’erreur le plus approprié à retourner dans ce cas.

Lorsqu’un graphe de filtre est arrêté, toute notification de fin de flux mise en cache doit être effacée et ne doit pas être envoyée au démarrage suivant. Cela est dû au fait que le Gestionnaire de graphes de filtre met toujours en pause tous les filtres juste avant de les exécuter afin qu’un vidage approprié se produise. Par exemple, si le graphe de filtre est suspendu et qu’une notification de fin de flux est reçue, puis que le graphe de filtre est arrêté, le convertisseur ne doit pas envoyer de notification EC_COMPLETE lors de son exécution ultérieure. Si aucune recherche n’a eu lieu, le filtre source envoie automatiquement une autre notification de fin de flux pendant l’état de pause qui précède un état d’exécution. Si, en revanche, une recherche s’est produite pendant l’arrêt du graphe de filtre, le filtre source peut avoir des données à envoyer, de sorte qu’il n’envoie pas de notification de fin de flux.

Les convertisseurs vidéo dépendent souvent des notifications de fin de flux pour plus que l’envoi de notifications EC_COMPLETE . Par exemple, si la lecture d’un flux est terminée (c’est-à-dire qu’une notification de fin de flux est envoyée) et qu’une autre fenêtre est déplacée sur une fenêtre de convertisseur vidéo, un certain nombre de messages de fenêtre WM_PAINT sont générés. La pratique classique pour exécuter des convertisseurs vidéo consiste à s’abstenir de repeindre l’image actuelle à la réception de WM_PAINT messages (en supposant qu’une autre image à dessiner sera reçue). Toutefois, lorsque la notification de fin de flux a été envoyée, le convertisseur est en attente ; il est toujours en cours d’exécution, mais sait qu’il ne recevra pas de données supplémentaires. Dans ces circonstances, le convertisseur dessine habituellement la zone de lecture en noir.

La gestion du vidage est une complication supplémentaire pour les convertisseurs. Le vidage est effectué à l’aide d’une paire de méthodes IPinappelées BeginFlush et EndFlush. Le vidage est essentiellement un état supplémentaire que le convertisseur doit gérer. Il est illégal pour un filtre source d’appeler BeginFlush sans appeler EndFlush, donc espérons que l’état est court et discret; toutefois, le convertisseur doit gérer correctement les données ou les notifications qu’il reçoit pendant la transition de vidage.

Toutes les données reçues après l’appel de BeginFlush doivent être rejetées immédiatement en retournant S_FALSE. En outre, toute notification de fin de flux mise en cache doit également être effacée lorsqu’un renderer est vidé. Un convertisseur est généralement vidé en réponse à une recherche. Le vidage garantit que les anciennes données sont effacées du graphe de filtre avant l’envoi de nouveaux échantillons. (En règle générale, la lecture de deux sections d’un flux, l’une après l’autre, est mieux gérée par le biais de commandes différées plutôt que d’attendre qu’une section se termine et d’émettre une commande de recherche.)

Gestion des changements d’état et de l’achèvement de la pause

Un filtre de convertisseur se comporte comme n’importe quel autre filtre dans le graphe de filtre lorsque son état est modifié, à l’exception suivante. Après avoir été suspendu, certaines données sont mises en file d’attente pour le convertisseur, prêtes à être rendues lors de l’exécution ultérieure. Lorsque le convertisseur vidéo est arrêté, il conserve ces données mises en file d’attente. Il s’agit d’une exception à la règle DirectShow selon laquelle aucune ressource ne doit être conservée par des filtres pendant l’arrêt du graphe de filtre.

La raison de cette exception est qu’en conservant des ressources, le convertisseur aura toujours une image avec laquelle repeindre la fenêtre s’il reçoit un message WM_PAINT . Il a également une image pour satisfaire les méthodes, telles que CBaseControlVideo::GetStaticImage, qui demandent une copie de l’image actuelle. Un autre effet de la conservation des ressources est que la conservation de l’image empêche la décompression de l’allocateur, ce qui rend le changement d’état suivant beaucoup plus rapide, car les mémoires tampons d’image sont déjà allouées.

Un convertisseur vidéo doit restituer et libérer des exemples uniquement pendant l’exécution. Pendant la pause, le filtre peut les restituer (par exemple, lors du dessin d’une image d’affiche statique dans une fenêtre), mais ne doit pas les libérer. Les convertisseurs audio n’effectuent aucun rendu pendant la pause (même s’ils peuvent effectuer d’autres activités, telles que la préparation de l’appareil de vague, par exemple). L’heure à laquelle les exemples doivent être rendus est obtenue en combinant l’heure de flux dans l’exemple avec l’heure de référence passée en tant que paramètre à la méthode IMediaControl::Run . Les renderers doivent rejeter les échantillons dont les heures de début sont inférieures ou égales à l’heure de fin.

Lorsqu’une application interrompt un graphe de filtre, le graphe de filtre ne retourne pas à partir de sa méthode IMediaControl::P ause tant que les données ne sont pas mises en file d’attente au niveau des convertisseurs. Pour ce faire, lorsqu’un convertisseur est suspendu, il doit retourner S_FALSE s’il n’y a pas de données en attente d’être rendues. S’il a des données en file d’attente, il peut retourner S_OK.

Le Gestionnaire de graphiques de filtre vérifie toutes les valeurs de retour lors de la suspension d’un graphe de filtre pour s’assurer que les données sont mises en file d’attente dans les convertisseurs. Si un ou plusieurs filtres ne sont pas prêts, le Gestionnaire de filtres graphes interroge les filtres dans le graphique en appelant IMediaFilter::GetState. La méthode GetState prend un paramètre de délai d’attente. Un filtre (généralement un convertisseur) qui attend toujours que les données arrivent avant d’effectuer le changement d’état retourne VFW_S_STATE_INTERMEDIATE si la méthode GetState expire. Une fois que les données arrivent au convertisseur, GetState doit être retourné immédiatement avec S_OK.

Dans l’état intermédiaire et terminé, l’état du filtre signalé est State_Paused. Seule la valeur de retour indique si le filtre est vraiment prêt ou non. Si, pendant qu’un convertisseur attend que les données arrivent, son filtre source envoie une notification de fin de flux, cela doit également terminer le changement d’état.

Une fois que tous les filtres ont effectivement des données en attente d’être rendues, le graphe de filtre termine sa modification d’état de pause.

Gestion de l’arrêt

Les convertisseurs vidéo doivent gérer correctement les événements d’arrêt de l’utilisateur. Cela implique de masquer correctement la fenêtre et de savoir quoi faire si une fenêtre est ensuite forcée à s’afficher. En outre, les convertisseurs vidéo doivent informer le Gestionnaire de graphe de filtre lorsque sa fenêtre est détruite (ou, plus précisément, lorsque le convertisseur est supprimé du graphe de filtre) pour libérer des ressources.

Si l’utilisateur ferme la fenêtre vidéo (pour instance en appuyant sur ALT+F4), la convention consiste à masquer immédiatement la fenêtre et à envoyer une notification EC_USERABORT au Gestionnaire de graphe de filtre. Cette notification est transmise à l’application, ce qui arrête la lecture du graphique. Après avoir envoyé EC_USERABORT, un convertisseur vidéo doit rejeter tous les échantillons supplémentaires qui lui sont remis.

L’indicateur arrêté par le graphe doit être laissé activé par le renderer jusqu’à ce qu’il soit arrêté par la suite, à quel moment il doit être réinitialisé afin qu’une application puisse remplacer l’action de l’utilisateur et continuer à lire le graphe si elle le souhaite. Si vous appuyez sur ALT+F4 pendant l’exécution de la vidéo, la fenêtre est masquée et tous les autres exemples remis seront rejetés. Si la fenêtre est ensuite affichée (peut-être via IVideoWindow::p ut_Visible), aucune EC_REPAINT notifications ne doit être générée.

Le convertisseur vidéo doit également envoyer la notification EC_WINDOW_DESTROYED au graphe de filtre lorsque le convertisseur vidéo se termine. En fait, il est préférable de gérer cela lorsque la méthode IBaseFilter::JoinFilterGraph du convertisseur est appelée avec un paramètre null (indiquant que le convertisseur est sur le point d’être supprimé du graphe de filtre), plutôt que d’attendre que la fenêtre vidéo réelle soit détruite. L’envoi de cette notification permet au serveur de distribution de plug-in dans le Gestionnaire graph de filtre de transmettre des ressources qui dépendent du focus de fenêtre à d’autres filtres, tels que les périphériques audio.

Gestion des modifications de format dynamique

Dans certains cas, le filtre amont du convertisseur peut essayer de modifier le format vidéo pendant la lecture de la vidéo. C’est le plus souvent le décompresseur vidéo qui initie un changement de format dynamique.

Un filtre amont qui tente de modifier dynamiquement les formats doit toujours appeler la méthode IPin::QueryAccept sur la broche d’entrée du convertisseur. Un convertisseur vidéo dispose d’une certaine marge de manœuvre quant aux types de modifications de format dynamiques qu’il doit prendre en charge. Au minimum, il doit autoriser le filtre amont à modifier les palettes. Lorsqu’un filtre amont modifie des types de médias, il attache le type de média au premier exemple fourni dans le nouveau format. Si le convertisseur contient des exemples dans une file d’attente pour le rendu, il ne doit pas modifier le format tant qu’il n’a pas rendu l’exemple avec le changement de type.

Un convertisseur vidéo peut également demander un changement de format à partir du décodeur. Par exemple, il peut demander au décodeur de fournir un format compatible DirectDraw avec un biHeight négatif. Lorsque le convertisseur est suspendu, il doit appeler QueryAccept sur le amont broche pour voir les formats que le décodeur peut fournir. Le décodeur peut ne pas énumérer tous les types qu’il peut accepter. Toutefois, le convertisseur doit proposer certains types même si le décodeur ne les publie pas.

Si le décodeur peut basculer vers le format demandé, il retourne S_OK à partir de QueryAccept. Le convertisseur attache ensuite le nouveau type de média à l’exemple de média suivant sur l’amont’allocateur. Pour que cela fonctionne, le convertisseur doit fournir un allocateur personnalisé qui implémente une méthode privée pour attacher le type de média à l’exemple suivant. (Dans cette méthode privée, appelez IMediaSample::SetMediaType pour définir le type.)

La broche d’entrée du convertisseur doit retourner l’allocateur personnalisé du convertisseur dans la méthode IMemInputPin::GetAllocator . Remplacez IMemInputPin::NotifyAllocator afin qu’il échoue si le filtre amont n’utilise pas l’allocateur du convertisseur.

Avec certains décodeurs, en définissant biHeight sur un nombre positif sur les types YUV, le décodeur dessine l’image à l’envers. (Cette erreur est incorrecte et doit être considérée comme un bogue dans le décodeur.)

Chaque fois qu’un changement de format est détecté par le convertisseur vidéo, il doit envoyer une notification EC_DISPLAY_CHANGED . La plupart des convertisseurs vidéo sélectionnent un format pendant la connexion afin que le format puisse être dessiné efficacement via GDI. Si l’utilisateur change le mode d’affichage actuel sans redémarrer l’ordinateur, un convertisseur peut se trouver avec une connexion au format d’image incorrecte et doit envoyer cette notification. Le premier paramètre doit être la broche qui doit être reconnecté. Le Gestionnaire de graphe de filtre organise l’arrêt du graphe de filtre et la reconnexion de l’épingle. Lors de la reconnexion suivante, le convertisseur peut accepter un format plus approprié.

Chaque fois qu’un convertisseur vidéo détecte un changement de palette dans le flux, il doit envoyer la notification EC_PALETTE_CHANGED au Gestionnaire de graphes de filtre. Les convertisseurs vidéo DirectShow détectent si une palette a vraiment changé dans le format dynamique ou non. Les convertisseurs vidéo effectuent cette opération non seulement pour filtrer le nombre de notifications EC_PALETTE_CHANGED envoyées, mais également pour réduire la quantité de création, d’installation et de suppression de palettes requises.

Enfin, le convertisseur vidéo peut également détecter que la taille de la vidéo a changé, auquel cas, il doit envoyer la notification EC_VIDEO_SIZE_CHANGED . Une application peut utiliser cette notification pour négocier de l’espace dans un document composé. Les dimensions réelles de la vidéo sont disponibles via l’interface de contrôle IBasicVideo . Les convertisseurs DirectShow détectent si la vidéo a réellement changé de taille ou non avant l’envoi de ces événements.

Gestion des propriétés persistantes

Toutes les propriétés définies via les interfaces IBasicVideo et IVideoWindow sont destinées à être persistantes entre les connexions. Par conséquent, la déconnexion et la reconnexion d’un convertisseur ne doivent afficher aucun effet sur la taille, la position ou les styles de fenêtre. Toutefois, si les dimensions de la vidéo changent entre les connexions, le convertisseur doit réinitialiser les rectangles source et de destination à leurs valeurs par défaut. Les positions source et de destination sont définies via l’interface IBasicVideo .

IBasicVideo et IVideoWindow fournissent tous deux un accès suffisant aux propriétés pour permettre à une application d’enregistrer et de restaurer toutes les données de l’interface dans un format persistant. Cela sera utile pour les applications qui doivent enregistrer la configuration et les propriétés exactes des graphiques de filtre pendant une session d’édition et les restaurer ultérieurement.

Gestion des notifications EC_REPAINT

La notification EC_REPAINT est envoyée uniquement lorsque le convertisseur est suspendu ou arrêté. Cette notification signale au Gestionnaire de graphes de filtre que le convertisseur a besoin de données. Si le graphe de filtre est arrêté lorsqu’il reçoit l’une de ces notifications, il suspend le graphe de filtre, attend que tous les filtres reçoivent des données (en appelant GetState), puis l’arrête à nouveau. Lorsqu’il est arrêté, un convertisseur vidéo doit s’accrocher à l’image afin que les messages WM_PAINT suivants puissent être gérés.

Par conséquent, si un convertisseur vidéo reçoit un message WM_PAINT lorsqu’il est arrêté ou suspendu, et qu’il n’a rien pour peindre sa fenêtre, il doit envoyer EC_REPAINT au Gestionnaire de graphe de filtre. Si une notification EC_REPAINT est reçue en pause, le Gestionnaire de graphes de filtre appelle IMediaPosition::p ut_CurrentPosition avec la position actuelle (autrement dit, recherche la position actuelle). Ainsi, les filtres sources vident le graphe de filtre et entraîne l’envoi de nouvelles données via le graphe de filtre.

Un convertisseur ne doit envoyer qu’une seule de ces notifications à la fois. Par conséquent, une fois que le convertisseur a envoyé une notification, il doit s’assurer qu’il n’en est plus envoyé tant que certains échantillons n’ont pas été remis. La méthode classique consiste à disposer d’un indicateur indiquant qu’un repeint peut être envoyé, qui est désactivé après l’envoi d’une notification de EC_REPAINT . Cet indicateur doit être réinitialisé une fois les données remises ou lorsque la broche d’entrée est vidée, mais pas si la fin du flux est signalée sur la broche d’entrée.

Si le convertisseur ne surveille pas ses notifications de EC_REPAINT , il inonde le Gestionnaire de graphes de filtres avec EC_REPAINT demandes (qui sont relativement coûteuses à traiter). Par exemple, si un convertisseur n’a aucune image à dessiner et qu’une autre fenêtre est déplacée sur la fenêtre du convertisseur lors d’une opération de glissement total, le convertisseur reçoit plusieurs messages WM_PAINT . Seul le premier d’entre eux doit générer une notification d’événement EC_REPAINT du convertisseur vers le Gestionnaire de graphes de filtre.

Un convertisseur doit envoyer sa broche d’entrée comme premier paramètre à la notification EC_REPAINT . Ce faisant, la broche de sortie jointe est interrogée pour IMediaEventSink et, si elle est prise en charge, la notification EC_REPAINT y est envoyée en premier. Cela permet aux broches de sortie de gérer les repaints avant que le graphe de filtre ne soit touché. Cette opération ne sera pas effectuée si le graphe de filtre est arrêté, car aucune mémoire tampon n’est disponible à partir de l’allocateur du convertisseur décompressé.

Si la broche de sortie ne peut pas gérer la requête et que le graphe de filtre est en cours d’exécution, la notification EC_REPAINT est ignorée. Une broche de sortie doit retourner S_OK de IMediaEventSink::Notify pour signaler qu’elle a traité la demande de repaint avec succès. La broche de sortie est appelée sur le thread de travail Filter Graph Manager, ce qui évite que le convertisseur appelle directement la broche de sortie et évite ainsi les problèmes d’interblocage. Si le graphe de filtre est arrêté ou suspendu et que la sortie ne gère pas la requête, le traitement par défaut est effectué.

Gestion des notifications en mode Full-Screen

Le serveur de distribution de plug-in IVideoWindow (PID) dans le graphe de filtre gère la lecture en plein écran. Il permet d’échanger un convertisseur vidéo contre un convertisseur plein écran spécialisé, d’étendre une fenêtre d’un convertisseur en plein écran ou de faire en sorte que le convertisseur implémente la lecture en plein écran directement. Pour interagir dans des protocoles en plein écran, un convertisseur vidéo doit envoyer une notification EC_ACTIVATE chaque fois que sa fenêtre est activée ou désactivée. En d’autres termes, une notification EC_ACTIVATE doit être envoyée pour chaque message WM_ACTIVATEAPP qu’un convertisseur reçoit.

Lorsqu’un convertisseur est utilisé en mode plein écran, ces notifications gèrent le basculement vers et hors de ce mode plein écran. La désactivation de fenêtre se produit généralement lorsqu’un utilisateur appuie sur ALT+TAB pour basculer vers une autre fenêtre, ce que le convertisseur en plein écran DirectShow utilise comme indicateur pour revenir au mode de rendu classique.

Lorsque la notification EC_ACTIVATE est envoyée au Gestionnaire de graphes de filtre lors du basculement du mode plein écran, le Gestionnaire de graphes de filtre envoie une notification EC_FULLSCREEN_LOST à l’application de contrôle. L’application peut utiliser cette notification pour restaurer l’état d’un bouton plein écran, par exemple. Les notifications EC_ACTIVATE sont utilisées en interne par DirectShow pour gérer le basculement en plein écran des signaux à partir des convertisseurs vidéo.

Résumé des notifications

Cette section répertorie les notifications de graphe de filtre qu’un convertisseur peut envoyer.

Notification d'événement Description
EC_ACTIVATE Envoyé par les convertisseurs vidéo en mode plein écran pour chaque WM_ACTIVATEAPP message reçu.
EC_COMPLETE Envoyé par les convertisseurs une fois que toutes les données ont été rendues.
EC_DISPLAY_CHANGED Envoyé par les convertisseurs vidéo lorsqu’un format d’affichage change.
EC_PALETTE_CHANGED Envoyé chaque fois qu’un convertisseur vidéo détecte un changement de palette dans le flux.
EC_REPAINT Envoyé par des convertisseurs vidéo arrêtés ou suspendus lorsqu’un message WM_PAINT est reçu et qu’il n’y a pas de données à afficher. Le Gestionnaire de graphes de filtre génère ainsi un cadre à peindre pour l’affichage.
EC_USERABORT Envoyé par les convertisseurs vidéo pour signaler une fermeture demandée par l’utilisateur (par exemple, un utilisateur fermant la fenêtre vidéo).
EC_VIDEO_SIZE_CHANGED Envoyé par les convertisseurs vidéo chaque fois qu’une modification de la taille de la vidéo native est détectée.
EC_WINDOW_DESTROYED Envoyé par les convertisseurs vidéo lorsque le filtre est supprimé ou détruit afin que les ressources qui dépendent du focus de fenêtre puissent être passées à d’autres filtres.

 

Écriture de convertisseurs vidéo