Programmation Multimédia Cours de programmation DirectShow



Documents pareils
Programmation Multimédia Cours de programmation DirectShow

Conventions d écriture et outils de mise au point

Les chaînes de caractères

1. Structure d un programme C. 2. Commentaire: /*..texte */ On utilise aussi le commentaire du C++ qui est valable pour C: 3.

INITIATION AU LANGAGE C SUR PIC DE MICROSHIP

Le langage C. Séance n 4

Bases de programmation. Cours 5. Structurer les données

Info0101 Intro. à l'algorithmique et à la programmation. Cours 3. Le langage Java

Manuel d'installation de DVD MAKER USB2.0

SHERLOCK 7. Version du 01/09/09 JAVASCRIPT 1.5

PX8048 Convertisseur audio/vidéo VHS vers USB

Tutorial Terminal Server sous

Formations au tournage et au montage vidéo. Monter un film avec. Imovie 11

Cours d Algorithmique-Programmation 2 e partie (IAP2): programmation 24 octobre 2007impérative 1 / 44 et. structures de données simples

STATISTICA Version 12 : Instructions d'installation

Description générale de l'interface

Enregistrer 27. ENREGISTREMENT ouvre une boîte de dialogue similaire à celle qui est décrite ici. «Enregistrement» sous l'écran vidéo

Centre CPGE TSI - Safi 2010/2011. Algorithmique et programmation :

Programmation impérative

Programmation système I Les entrées/sorties

Cahier des charges. driver WIFI pour chipset Ralink RT2571W. sur hardware ARM7

EPREUVE OPTIONNELLE d INFORMATIQUE CORRIGE

Microsoft Windows NT Server

VRM Monitor. Aide en ligne

Didacticiel de mise à jour Web

Institut Supérieure Aux Etudes Technologiques De Nabeul. Département Informatique

TAGREROUT Seyf Allah TMRIM

LANDPARK NETWORK IP LANDPARK NETWORK IP VOUS PERMET D'INVENTORIER FACILEMENT VOS POSTES EN RÉSEAU

Info0604 Programmation multi-threadée. Cours 5. Programmation multi-threadée en Java

Notions fondamentales du langage C# Version 1.0

ARDUINO DOSSIER RESSOURCE POUR LA CLASSE

03/04/2007. Tâche 1 Tâche 2 Tâche 3. Système Unix. Time sharing

Travaux pratiques. Compression en codage de Huffman Organisation d un projet de programmation

A. À propos des annuaires

Durée estimée :1 journée Date de la réalisation : Description Fournisseur Référence Nombre PU HT LM35CZ, LM35AZ LM35DZ

Nouveau Web Client marquant, Cumulus Video Cloud, optimisations de la base de données, et plus..

Outils informatiques de manipulation de la vidéo et du son : une introduction

as Architecture des Systèmes d Information

IV- Comment fonctionne un ordinateur?

Guide d installation logicielle

SnapMusic Studio 715 Guide d Installation

TD Objets distribués n 3 : Windows XP et Visual Studio.NET. Introduction à.net Remoting

KL5121. Pour activer des sorties en fonction de la position d'un codeur

Programmation C++ (débutant)/instructions for, while et do...while

ETI/Domo. Français. ETI-Domo Config FR

Visio Kit. Mode d'emploi

GUIDE D INSTALLATION DES DRIVERS

TP n 2 Concepts de la programmation Objets Master 1 mention IL, semestre 2 Le type Abstrait Pile

Pour signifier qu'une classe fille hérite d'une classe mère, on utilise le mot clé extends class fille extends mère

Introduction à Java. Matthieu Herrb CNRS-LAAS. Mars

Introduction à MATLAB R

1. Introduction Création d'une macro autonome Exécuter la macro pas à pas Modifier une macro... 5

Anne Tasso. Java. Le livre de. premier langage. 10 e édition. Avec 109 exercices corrigés. Groupe Eyrolles, , ISBN :

MISE A JOUR : 04 FEVRIER 2011 PROCÉDURE D INSTALLATION. Cegid Business COMMENT INSTALLER CEGID BUSINESS V9 SOUS WINDOWS XP, VISTA ET 7

Lutter contre les virus et les attaques... 15

Projet d informatique M1BI : Compression et décompression de texte. 1 Généralités sur la compression/décompression de texte

Utilisation du BDE pour la maintenance des fichiers DBF de l'application TopoCad:

Guide de mise à niveau pas à pas vers Windows 8 CONFIDENTIEL 1/53

Processus! programme. DIMA, Systèmes Centralisés (Ph. Mauran) " Processus = suite d'actions = suite d'états obtenus = trace

Connexion à une base de données. Connexion à une base de données. Connexion à une base de données Développement d'une application

Interface PC Vivago Ultra. Pro. Guide d'utilisation

PRECAUTIONS DESCRIPTION DU PRODUIT

Prénom : Matricule : Sigle et titre du cours Groupe Trimestre INF1101 Algorithmes et structures de données Tous H2004. Loc Jeudi 29/4/2004

Mise à jour, sauvegarde et restauration de logiciels

McAfee Security-as-a-Service

Prise en main. Prise en main - 0

Chapitre 1 : La gestion dynamique de la mémoire

Introduction à la programmation concurrente

BTS S.I.O PHP OBJET. Module SLAM4. Nom du fichier : PHPRévisionObjetV2.odt Auteur : Pierre Barais

DAC. avec interface USB audio et préampli stéréo Casque CONVERTISSEUR DIGITAL VERS ANALOGIQUE. Guide d utilisation V1.1 Jan 2011

FORMATION MULTIMÉDIA LVE

Carte IEEE Version 1.0

Messages d'erreurs. Redémarrez votre PC en cliquant sur Démarrer, en sélectionnant ensuite Arrêter puis en cochant Redémarrer

TP : Gestion d une image au format PGM

Signage Manager Express Manuel utilisateur du logiciel

Windows Live Movie Maker

Guide d'utilisation du Serveur USB

Guide de l'utilisateur

Bravo! Vous venez d acquérir un routeur large bande à 4 ports Conceptronic C100BRS4H.

Installation du client Cisco VPN 5 (Windows)

Comment enregistrer simplement toute musique restituée par votre PC

CARPE. Documentation Informatique S E T R A. Version Août CARPE (Documentation Informatique) 1

2010 Ing. Punzenberger COPA-DATA GmbH. Tous droits réservés.

SQL Server Installation Center et SQL Server Management Studio

eps Network Services Alarmes IHM

(1) XDCAM Browser

Installation du client Cisco VPN 5 (Windows)

Manuel Utilisateur Version 1.6 Décembre 2001

Installation du client Cisco VPN 5 (Windows)

Formateurs : Jackie DAÖN Franck DUBOIS Médiapôle de Guyancourt

Utiliser des logiciels Windows sous Linux Ubuntu

Capture Pro Software. Démarrage. A-61640_fr

Installation Client (licence réseau) de IBM SPSS Modeler 14.2

Introduction à la programmation orientée objet, illustrée par le langage C++ Patrick Cégielski

ACTIVITÉ DE PROGRAMMATION

WINDOWS NT 2000: Travaux Pratiques. -Boîtier partage d'imprimante- Michel Cabaré Janvier 2002 ver 1.0

Dongle WiFi de QUMI Manuel de l utilisateur

Atelier n 12 : Assistance à distance

Java Licence Professionnelle CISII,

Transcription:

Programmation Multimédia Cours de programmation DirectShow Pascal Mignot / Pascal Gardeur Partie 1 : Programmation COM Chaîne de caractères sous Windows Principes directeur de DirectShow Caractéristique d un graphe Construction de Graphes Contrôles élémentaires d un graphe Informations supplémentaires sur un graphe de capture de flux. Page 1/50

COM 1. COM = Component Object Model Définition : modèle de programmation orienté objet conçu pour promouvoir l interopérabilité logicielle. Il permet la coopération entre plusieurs applications ou «composants», même si ils ont été codés dans des langages de programmations différents, par des fabricants différents ou sont utilisés sur des machines possédant des systèmes d exploitation différents. Un objet COM: dérive de IUnknown (objet de base). Objet COM : agrégation d objets dérivés de IUnknown. Exemple : IUnkown D A C B E si G = D E + C + F, alors G peut être manipulé avec l une des interfaces quelconques d un des objets qu il contient ou dont il dérive. Comme pour les objets C++ standard, chaque classe a ses méthodes spécifiques (propres). Un identificateur est associé : o à chaque classe (class-id ou CLSID). o à chaque interface (interface-id ou IID). La cohérence des références à l objet lui-même où à l une des parties qui le compose est gérée grâce à des compteurs de référence. Utilisation d un objet COM: o Initialisation : l interface COM doit être initialisé. o Création de l instance d un objet : à partir de sa CLSID et de son IID. o A partir de cette instance, on peut récupérer l interface spécifique à l une des classes dont il dérive. Chaque interface étant associée à une classe, il est possible d acquérir l une des interfaces quelconques sur l un des objets qui compose l objet lui-même. Le compteur de référence permet de multiplier le nombre d instances de cet objet en conservant des références correctes. De façon similaire, le compteur de référence peut être utilisé pour conserver des références sur l une des sous-parties de l objet. Exemple : cas de la surface dans une texture, o o Le relâchement des interfaces permet de libérer un objet dès qu on n y fait plus référence. Fin d un programme : l interface COM doit être désinitialisée. F Page 2/50

2. Fonctions de base pour l interface COM a. Initialisation de l interface COM HRESULT CoInitialize(NULL); Attention, pour une application multithreads, utiliser CoInitializeEx pour gérer la façon dont les objets pourront être partagés (voir les articles techniques sur le site à ce sujet). Au retour : S_OK / S_FALSE : réussi / déjà été initialisée. RPC_E_CHANGED_MODE : déjà été initialisée avec un mode de gestion différent. b. Création d une instance d un objet STDAPI CoCreateInstance(REFCLSID rclsid, LPUNKNOWN punkouter, DWORD dwclscontext, REFIID riid, LPVOID * ppv); Rclsid punkouter dwclscontext riid ppv : [in] Identificateur de la classe. : [in] On utilisera en général toujours NULL. : [in] CLSCTX_INPROC_SERVER, (Permet IMoniker::BindToObject). : [in] Identificateur de l interface. : [out] Pointeur sur l instance de l objet COM créé (ou NULL si erreur). Valeurs de retour S_OK : réussi. REGDB_E_CLASSNOTREG / CLASS_E_NOAGGREGATION / E_NOINTERFACE c. Désinitialisation de l interface COM void CoUninitialize(void); Libère tous les objets COM du thread courant. Exemple: ICaptureGraphBuilder2 *pcapturegraph = NULL; HRESULT h = CoInitialize(NULL);... h = CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL,CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2, (void **)&pcapturegraph);... pcapturegraph->release(); CoUninitialize(); Page 3/50

3. Interface IUnknown Une fois l objet COM créé, il expose toujours les méthodes suivantes : a. Ajout de référence : Incrémenter de 1 le compteur de référence de l objet. IUnknown::AddRef Syntaxe Retour Remarque : ULONG AddRef(VOID); b. Relâchement de référence: : le nouveau compteur de référence (pour tests). : à la création de l interface, le compteur vaut 1. A chaque nouvelle obtention d une interface ou d appels à la méthode AddRef, le compteur est incrémenté de 1. Utiliser la méthode Release pour le décrémenter Décrémenter de 1 le compteur de référence de l objet. IUnknown::Release Syntaxe Retour : ULONG Release(VOID); : le nouveau compteur de référence (pour tests). Remarque : l objet se désaloue automatiquement lorsque son compteur arrive à 0. L appel à cette méthode doit succéder l appel à AddRef, QueryInterface ou CoCreateInstance. c. Gestion des interfaces : Cette méthode permet de déterminer si l objet supporte une interface particulière. Si cela est le cas, permet d acquérir l interface sur l objet agrégé (pointeur), et incrémente son compteur de référence. IUnknown::QueryInterface Syntaxe : HRESULT QueryInterface(REFIID riid, LPVOID *ppvobj); riid : Identificateur de l interface demandée. ppvobj : Adresse du pointeur de l interface. Retour S_OK : réussi. E_NOINTERFACE : Pas d interface (peut dépendre des composants). Remarques Si l application n a plus besoin de l interface, il faut appeler le méthode Release. Exemple: // l interface COM doit avoir été initialisée. HRESULT h; ICaptureGraphBuilder2 *pcapturegraph = NULL; IGraphBuilder *pgraph = NULL; IMediaControl *pcontrol = NULL; Page 4/50

h = CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL,CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2, (void **)&pcapturegraph); h = pcapturegraph->getfiltergraph(&pgraph); h = pgraph->queryinterface(iid_imediacontrol,(void **)&pcontrol);... pcontrol->release(); pgraph->release(); pcapturegraph->release(); // l interface COM doit être désinitialisée. Page 5/50

Aparté : gestion des chaînes de caractères sous Windows Cette partie est nécessaire car certaines méthodes que nous étudierons utilisent certaines conventions particulières sur les chaînes de caractères: Il y a 2 types de caractère sous Windows : Caractères ASCII classiques (8 bits) : Type associé : char Caractères Unicode (16 bits, caractères étendus) : Type associé : wchar_t On y ajoute en général le modificateur unsigned pour manipuler directement les codes. Le nom des types associés à utiliser sous Windows : CHAR = char UCHAR = unsigned char WCHAR = wchar_t TCHAR = WCHAR si UNICODE est défini, CHAR sinon. Exemple avec écriture des types: CHAR a = a ; CHAR b[10] = "abcdef"; WCHAR c = L a ; WCHAR d[10] = L"abcdef"; TCHAR e[10] = TEXT("abcdef"); Le type TCHAR permet de générer des codes avec un type caractère variant (par exemple dans une bibliothèque en fonction de la façon dont le code principal manipule ses caractères). Type des pointeurs associés: pointeur pointeur sur une constante CHAR LPSTR LPCSTR WCHAR LPWSTR LPCWSTR TCHAR LPTSTR LPCTSTR Fonctions de manipulation des chaînes: CHAR WCHAR TCHAR printf wprintf _tprintf sprintf swprintf _stprintf fprintf fwprintf _ftprintf Idem en remplaçant printf par scanf. Les fonctions génériques suivantes s adaptent automatiquement en fonction des paramètres passés (ils doivent tous être de même type) et sont à remplacer par strcat StringCchCat ou StringCchCatEx strncat StringCchCatN ou StringCchCatNEx strcpy StringCchCopy ou StringCchCopyEx strncpy StringCchCopyN ou StringCchCopyNEx sprintf StringCchPrintf ou StringCchPrintfEx vsprintf StringCchVPrintf ou StringCchVPrintfEx strlen StringCchLength Ces fonctions sont sécurisées pour éviter les dépassements de buffer (risque de sécurité). Voir la documentation MSDN. Page 6/50

Conversion entre char et wide char: MultiByteToWideChar(CP_ACP,0,inString,inSz,outWideString,outSz); Convertit la chaîne instring (char) en outwidestring (wide char). WideCharToMultiByte(CP_ACP,0,inWideString,inSz,outString,outSz, &DefC,&UseDef); Convertit la chaîne inwidestring (wide char) en outwidestring (char). avec CP_ACP : code page (ANSI) instring / inwidestring : chaîne en entrée. outwidestring / outstring : chaîne en sortie. insz : taille de la chaîne à convertir ou -1 pour s arrêter à \0. outsz : taille de la chaîne en sortie (taille maximale du buffer). DefC : caractère par défaut à utiliser pour les caractères wide char n ayant pas équivalent en char (ou NULL : plus rapide). UseDef : utiliser le caractère par défaut (ou NULL). Exemple: WCHAR Win[10] = L abcdef, Wout[10]; CHAR Sin[10] = abcdef, Sout[10]; MultiCharToWideChar(CP_ACP, 0, Sin, -1, Wout, 10); WideCharToMultiByte(CP_ACP, 0, Win, -1, Sout, 10, NULL, NULL); Compilation en Unicode: Faire: #define UNICODE ou: Page 7/50

Principes directeurs de DirectShow Le graphe de filtres Le graphe de filtres constitue la base de toute programmation sous DirectShow. Il permet de gérer les flux de données de manière simple en structurant les traitements (appelés filtres) sous forme d un graphe orienté non cyclique: Les nœuds du graphe représentent les traitements à effectuer. Les arêtes (orientées) du graphe représentent la direction des flux entre les filtres. Il est ainsi possible d effectuer des graphes de traitement complexe avec une relative simplicité. Rôle du graphe : assembler les filtres (les connecter en veillant à la compatibilité des E/S). gérer les filtres (en acquièrant sur ceux-ci les interfaces nécessaires à leurs manipulations). contrôler et synchroniser les flux dans le graphe. Le graphe de filtres est donc un médiateur entre le programmeur et les données. Le programmeur opère donc à un niveau assez élevé de développement. Il n a pas à se soucier de la manipulation bas-niveau de données audio et vidéo. Le graphe est un objet de type COM. Les filtres Conceptuellement, un filtre peut être considéré comme une boîte noire: qui appartient à une classe spécialisée en fonction du travail à accomplir. avec des entrées et/ou des sorties. o chacune de ces entrées/sorties est conceptualisée sous forme d une borne de connexion (pin). o une borne d entrée permet de recevoir des données depuis un autre filtre. o une borne de sortie permet d envoyer des données vers un autre filtre. avec une ou plusieurs interfaces spécialisées, associées à la classe du filtre qui permettent de contrôler et de configurer le comportement du filtre. la configuration interne du filtre est assurée par une interface graphique (interne) fournie par le filtre lui-même. On distingue trois principaux types de filtres: Les filtres sources. Les filtres de transformation. Les filtres de rendu. Page 8/50

Les filtres sont des objets COMs: la classe d un filtre est définie par sa CLSID, les interfaces sont définies par leurs IIDs. Les filtres sources Un filtre source n a aucune borne d entrée, et une ou plusieurs bornes de sortie. Ce type de filtre produit un flux de données à partir: d un support numérique (fichier, CD, DVD, ) d un périphérique d acquisition (micro, webcam, caméscope numérique, tuner TV, etc ). o S il est directement supporté par Windows, le filtre correspondant existe déjà. o Pour tout nouveau matériel, à partir du moment où son pilote (driver) répond au modèle WDM (Windows Driver Model), celui-ci installe également les filtres DirectShow nécessaires à l utilisation du périphérique. d une connexion réseau (streaming). Il faut au minimum un filtre de ce type dans un graphe (pour «nourrir» le graphe avec des données). On peut utiliser autant de filtres d entrés que de sources nécessaires à l exécution de la tâche. Les filtres de transformation Un filtre de transformation modifie le flux de données qui le traverse. Il reçoit ses données en provenance d un ou de plusieurs autres filtres (sources/transformation). Il transmet le flux transformé vers un ou plusieurs autres filtres (transformation/rendu). Il a donc au moins une borne d entrée et au moins une borne de sortie. Les filtres de transformations les plus couramment utilisés sont les suivants: parser = séparer les données contenue dans un flux pour former plusieurs flux de sortie (exemple: séparer l audio de la vidéo). tee = dupliquer le flux d entrée en plusieurs flux identique de sortie. multiplexage = combiner plusieurs flux en un seul (combiner un flux vidéo et un flux audio pour ensuite les enregistrer dans un ficher par exemple) codec = convertir les données d un flux en un autre format (compression / décompression). sous-titrage = ajouter une couche de sous-titres à un flux vidéo. montage et transition L installation de nouveaux Codecs rend disponible les méthodes de compression et décompression associées sous forme de nouveau filtre. Dans certains cas, il peut être nécessaire d enregistrer manuellement ces filtres. Les filtres de rendu Un filtre de rendu est placé en fin de chaîne de traitement et permet de terminer le traitement: par un rendu: vidéo : création automatique (ou manuelle) d une fenêtre (avec son handle) et rendu du flux dans la fenêtre en utilisant DirectDraw. audio : rendu automatique en utilisant DirectAudio. Page 9/50

Toutes des ressources nécessaires sont automatiquement allouées et désallouées, la synchronisation vidéo/audio est assurée par le graphe. par l enregistrement dans un fichier. par sa transmission sur le réseau. Ce type de filtre ne possède que des bornes d entrée. Un graphe doit contenir au moins un filtre de rendu. On peut éventuellement multiplier le nombre de filtres de rendu: l audio et la vidéo sont rendus par deux filtres de rendu différents (un filtre de rendu audio et un filtre de rendu vidéo). on peut effectuer un rendu vidéo tout en enregistrant ce même flux dans un fichier. deux flux vidéo issus de deux chemins différents dans le graphe peuvent être rendu dans deux fenêtres différentes. Construction d un graphe à partir de filtres Pour construire un graphe, les filtres peuvent être assemblés avec une grande liberté à partir du moment où les contraintes suivantes sont respectées: toute branche d un graphe commence par un filtre d entrée et se termine par un filtre de sortie (cohérence du graphe). les comptabilités entre les entrées et les sorties sont respectées. Chaque entrée/sortie n accepte que certains types et format de flux de données. Autrement dit, une connexion entre deux filtres n est possible que si il existe un pin de sortie sur le premier filtre et un pin d entrée sur le sortie tels que: o le type du flux de données est le même (audio, vidéo, ) o le format du flux en sortie est compatible avec le format du flux en entrée. Un pin d entrée d un filtre peut supporter plusieurs formats différents. Remarque: toutes les pins d entrées/sortie des filtres n ont pas besoin d être connecté (certaines entrées/sorties peuvent être ignorées). Exemple de graphe des filtres Cette image d exemple est issue de GraphEdit, un programme dont on va rapidement expliquer l intérêt et le fonctionnement la section suivante. Page 10/50

GraphEdit Le GraphEdit est un utilitaire fourni par Microsoft avec le SDK (Software Development Kit) de DirectX (sous forme d extra). Utilisation pour les tests et le maquettage Il permet de s habituer à la manipulation de graphes de filtre, de construire interactivement le graphe souhaité pour l application envisagée et d effectuer directement des tests afin de vérifier que le graphe envisagé est cohérent et donne le résultat cohérent. Il est donc vivement conseillé, dans la mesure du possible, de toujours concevoir le graphe correspondant à l application multimédia souhaitée avec GraphEdit avant d écrire le code correspondant. Evidemment, le programme DirectShow du même graphe offre un niveau de flexibilité et de contrôle supérieur à celui proposé dans GraphEdit. Les fonctionnalités d aide à la conception de GraphEdit Lors de l insertion d un filtre, la liste des filtres disponibles est rangée par catégorie : Le GUID du filtre de compression MP3 est : {33D9A761-90C8-11D0-BD43-00A0C911CE86 ce qui va nous permettre d y faire référence lors de notre programme DirectShow. Les filtres de base de DirectShow disposent déjà de leur GUID sous une forme plus «humaine» (exemple: CLSID_VideoRenderer pour le filtre de rendu vidéo). Connexions entre filtres: simplement à la souris. Connexion intelligente: lorsque l on relie deux pins de format incompatible (mais de type compatible) entre deux filtres, GraphEdit insère automatiquement les filtres nécessaires. Page 11/50

Deux filtres ont été ajoutés : AVI Splitter : sépare les flux audio et vidéo (la borne non connectée correspond au flux audio). DV Video Decoder (convertisseur) qui prépare les données vidéo dans un format compatible avec le Video Renderer. Le graphe est complet et peut fonctionner tel quel. Un rendu automatique peut s effectuer à partir de n importe quel pin de sortie en utilisant le menu contextuel. GrapheEdit insère tous les filtres pour effectuer le rendu des flux provenant du filtre source (audio + vidéo si nécessaire) : Contrôle interactif du graphe GraphEdit permet de simuler de comportement du graphe en permettant son exécution de manière similaire à ce qui se fait avec un média player. Page 12/50

Caractéristiques d'un graphe Cette partie est dédiée à l'extraction de l'ensemble des propriétés sur un graphe, à savoir: l'ensemble des filtres présents dans un graphe pour chaque filtre: les propriétés et l'ensemble de ses bornes. pour chaque borne: sa direction, son nom, éventuellement à quelle autre borne elle est connectée, le format des données supportées. C'est l'ensemble de ces méthodes qui permettent de connaître: la topologie du graphe de filtres. les propriétés générales de chaque filtre. Interfaces associées: Graphe : IFilterGraph, IGraphBuilder, IGraphBuilder2 Filtre : IBaseFilter ou toute interface qui en dérive Borne : IPin 1. Enumérateurs Les objets que nous allons étudier ont une méthode pour obtenir un objet énumérateur qui permet de lister ses composants internes: pour un graphe, les filtres qu'il contient. pour un filtre, les bornes de ce filtre. pour une borne, l'ensemble des formats de média supportés. L'utilisation d'un énumérateur s'effectue dans les étapes suivantes (où les XXX sont à remplacer par les noms indiqués dans la table ci-dessous): 1. Faire appel à la méthode EnumXXXs pour récupérer l'interface sur l'énumérateur IEnumXXX. 2. Utiliser les méthodes Next/Skip/Reset de l'interface IEnumXXX pour énumérer les objets. Par la suite, on notera IEnumXXXs cette méthode d'énumération: elle permet d'obtenir une interface IEnumXXX permettant d'énumérer les objets de type XXX (voir la table ci-dessous). Classe Méthode pour obtenir l'énumérateur Enumérateur IEnumXXX Objets récupérés lors de l'énumération IXXX IFilterGraph EnumFilters IEnumFilters IBaseFilter IBaseFilter EnumPins IEnumPins IPin IPin EnumMediaTypes IEnumMediaTypes AM_MEDIA_TYPE IEnumXXX::Next Syntaxe : HRESULT Next(ULONG cobjs, IXXX **ppobjs, ULONG *pcfetched); cobjs : [in] Nombre d objets à récupérer. ppobjs : [out] tableau de taille cobjs qui sera rempli avec les pointeurs de IXXX. pcfetched : [out] Pointeur de la variable qui reçoit le nombre d objets récupérés. (peut être NULL si cobjs = 1). Retour : Valeur HRESULT (voir la doc: VFW_E_ENUM_OUT_OF_SYNC) Remarque : Cette méthode récupère cobjs pointeurs d objets, à partir de la position courante. Si la méthode réussie, les références des interfaces IXXX sont incrémentées. Il faut effectuer un Release sur les objets récupérés. Page 13/50

IEnumXXX::Skip Syntaxe : HRESULT Skip(ULONG cobjs); cpins : [in] Nombre d objets à passer. Retour : Valeur HRESULT (voir la doc) Remarque : comme pour Next, l'énumération peut devenir inconsistante. Dans ce cas, la méthode renvoie VFW_E_ENUM_OUT_OF_SYNC => faire un Reset. IEnumXXX::Reset Syntaxe : HRESULT Reset(void); Retour : S_OK; 2. Information sur un graphe Cette méthode permet d'énumérer les filtres dans un graphe. Ceci va nous permettre: 1. de connaître le nombre de filtres dans un graphe. 2. de récupérer l'interface sur chaque filtre inséré dans le graphe. 3. pour chaque filtre récupéré, on pourra alors acquérir plus d'informations sur ce filtre (voir section suivante). IFilterGraph::EnumFilters Syntaxe : HRESULT EnumFilters(IEnumFilters **ppenum); ppenum : [out] Adresse du pointeur sur l interface IEnumFilters. (Release!) Retour : Valeur HRESULT (voir la doc) 3. Information sur un filtre Les informations que l'on peut récupérer sur un filtre sont: le nom du filtre avec QueryFilterInfo. l'ensemble des bornes avec EnumPins. IBaseFilter::QueryFilterInfo Syntaxe : HRESULT QueryFilterInfo(FILTER_INFO *pinfo); pinfo : [out] Pointer sur une structure FILTER_INFO. Retour : Valeur HRESULT (voir la doc) Remarque : Release! FILTER_INFO Structure Syntaxe typedef struct _FilterInfo { WCHAR achname[max_filter_name]; IFilterGraph *pgraph; FILTER_INFO; Page 14/50

Membres achname : Nom du filtre. (terminé par NULL) pgraph : Si le filtre fait parti d un graphe, contient son pointeur. NULL sinon. Remarque : Si pgraph!= NULL => Release! Exemple: affichage des filtres insérés dans le graphe et renvoie le nombre de filtres. UINT ViewFilters(IFilterGraph *Graph) { UINT i=0; IBaseFilter *Filter = NULL; IEnumFilters *Enum = NULL; FILTER_INFO Info; Graph->EnumFilters(&Enum); while(enum->next(1,&filter,null) == S_OK) { Filter->QueryFilterInfo(&Info); printf("%d : %S\n",++i,Info.achName); SAFE_RELEASE(Info.pGraph); SAFE_RELEASE(Filter); SAFE_RELEASE(Enum); return i; Exemple 2: utilisation de la fonction ci-dessus avec un IGraphBuilder (rappel: il dérive de IFilterGraph): Méthode 1: utiliser les dynamic casts. Rappel: ceci n'est possible pour appeler une fonction f(a) avec f(b) si et seulement si B dérive de A (l'inverse produit un résultat imprévisible). IGraphBuilder *pgraph; // pgraph est construit ici ViewGraphInfo(dynamic_cast<IFilterGraph*>(pGraph)); Méthode 2: utiliser QueryInterface pour rendre compatible les objets COM, en écrivant une surcharge de la fonction: void ViewGraphInfo(IGraphBuilder *Graph) { IFilterGraph *FilterGraph; Graph->QueryInterface(IID_IFilterGraph, (void **)&FilterGraph); ViewGraphInfo(FilterGraph); SAFE_RELEASE(FilterGraph); IBaseFilter::EnumPins Avantage avec les objets COMs: devrait marcher dans les deux sens (que A dérive de B ou B dérive de A). Autrement dit, la fonction ViewFilter aurait pu être écrite pour des IGraphBuilder. Il aurait été possible dans la fonction de conversion de faire un QueryInterface sur le IFilterGraph (enrichissement des fonctionnalités de l'objet). Syntaxe : HRESULT EnumPins(IEnumPins **ppenum); ppenum : [out] Adresse du pointeur qui reçoit l interface IEnumPins. Retour : Valeur HRESULT (voir la doc) Remarque : Release! Page 15/50

4. Information sur les bornes d'un filtre Pour toute borne (pin) d'un filtre, on a les informations suivantes: le nom de la borne la direction de passage du flux sur cette borne (entrée ou sortie) l'ensemble des formats acceptés par cette borne. Si la borne est connectée: la borne (d'un autre filtre) sur laquelle elle est connectée. le format du flux actuel. Une borne contient en plus les informations techniques suivantes: un pointeur vers le filtre auquel elle appartient. une chaîne unique identifiant la borne (généralement quelques caractères). L'interface IPin est exposée par les bornes d'entrée et de sortie. Remarque: ne pas utiliser les méthodes de cette interface pour effectuer des connexions ou changer l'état de la borne. Utiliser plutôt les interfaces du graphe afin que les synchronisations nécessaires soient effectuées. Les méthodes de IPin permettant d'obtenir des informations sur une borne sont les suivants: Method ConnectedTo ConnectionMediaType QueryPinInfo QueryId QueryAccept EnumMediaTypes QueryInternalConnections QueryDirection Description Récupère la pin connectée à celle-ci. Récupère le type de la connexion courante. Récupère des informations sur la pin (nom, filtre propriétaire, direction). Récupère l identificateur de la pin. Détermine si la pin accepte un type spécifique. Enumère les types disponibles sur la pin. Récupère les pins connectés à l intérieur du filtre. Récupère la direction de la pin (entrée ou sortie). IPin::QueryPinInfo Syntaxe : HRESULT QueryPinInfo(PIN_INFO *pinfo); pinfo : [out] Pointeur sur une structure PIN_INFO. Retour : Valeur HRESULT (voir la doc) Remarque : Release! PIN_INFO Structure Syntaxe typedef struct _PinInfo { IBaseFilter *pfilter; PIN_DIRECTION dir; WCHAR achname[max_pin_name]; PIN_INFO; Membres pfilter : Pointeur sur l interface IBaseFilter du filtre propriétaire. dir : Direction de la pin (PINDIR_INPUT ou PINDIR_OUTPUT). achname : Nom de la pin. Remarque : Release! (Voir la doc) Page 16/50

Exemple: affichage des bornes d'un filtre. void ViewPinInfo(IPin *Pin) { PIN_INFO Info; Pin->QueryInfo(&Info); printf("%-3s:%s\n",(info.dir==pindir_input?"in":"out"), Info.achName); SAFE_RELEASE(Info.pFilter); void ViewPins(IBaseFilter *Filter) { IEnumPins *Enum = NULL; IPin *Pin = NULL; Filter->EnumPins(&Enum); while(enum->next(1,&pin,null) == S_OK) { ViewPinInfo(Pin); SAFE_RELEASE(Pin); SAFE_RELEASE(Enum); IPin::QueryDirection Syntaxe : HRESULT QueryDirection(PIN_DIRECTION *ppindir); ppindir : [out] Pointeur sur la structure PIN_DIRECTION. Retour Remarque IPin::QueryId : Valeur HRESULT (voir la doc) : la valeur récupérée ici est la même que celle obtenue avec QueryPinInfo dans la structure PIN_INFO. Syntaxe : HRESULT QueryId(LPWSTR *Id); Id : [out] Pointeur sur une chaîne de caractère. Retour : Valeur HRESULT (voir la doc) Remarques : La chaîne est allouée en utilisant la fonction Win32 CoTaskMemAlloc. Il faut la libérer avec CoTaskMemFree. l'id d'une borne identifie de manière unique la borne. Utiliser la fonction de désallocation indiquée ci-dessus. Exemple: Exemple: lecture de l'id LPWSTR Id; Pin->QueryId(&Id); printf("id=[%s] ",Id); // rappel: c'est un wide char. CoTaskMemFree(Id); IPin::ConnectedTo Cette méthode va nous permettre pour une borne quelconque, de savoir si elle est connectée et sur quelle autre borne elle est connectée. Syntaxe : HRESULT ConnectedTo(IPin **pppin); pppin : [out] Adresse du pointeur sur l interface IPin de l autre pin. (!= NULL). Page 17/50

Retour S_OK VFW_E_NOT_CONNECTED E_POINTER Remarque : Release! : réussi : pin non connectée. : Argument du pointeur NULL. Exemple: pour une borne, affiche la connexion void ViewLinkInfo(IPin *LocalPin) { IPin *Pin = NULL; FILTER_INFO FInfo; PIN_INFO PInfo; HRESULT h; h = LocalPin->ConnectedTo(&Pin); if (h == VFW_E_NOT_CONNECTED) WriteInfo("-> NOT_CONNECTED"); else { Pin->QueryPinInfo(&PInfo); PInfo.pFilter->QueryFilterInfo(&FInfo); WriteInfo("-> %S[%S] ", FInfo.achName,PInfo.achName); Voici la trace générée pour l'ensemble des filtres utilisées pour le rendu d'un fichier vidéo (sans son) par les fonctions ci-dessus. Les méthodes pour connaître le type de flux associé à une borne sont vues ci-dessous. Filter in graph = 4 Filter : ruby.avi 1 Out Id=[Output] Output -> AVI Splitter[input pin] Type=Stream Filter : AVI Splitter 1 In Id=[input pin] input pin -> ruby.avi[output] Type=Stream 2 Out Id=[Stream 00] Stream 00 -> AVI Decompressor[XForm In] Type=Video Filter : AVI Decompressor 1 Out Id=[Out] XForm Out -> Video Renderer[VMR Input0] Type=Video 2 In Id=[In] XForm In -> AVI Splitter[Stream 00] Type=Video Filter : Video Renderer 1 In Id=[VMR Input0] VMR Input0 -> AVI Decompressor[XForm Out] Type=Video IPin::QueryInternalConnections Sur certains filtres, des connexions internes entre bornes sont faites (exemple: sur un filtre tuner, pour connecter le tuner ou l'entrée composite sur la sortie vidéo). Syntaxe: HRESULT QueryInternalConnections(IPin **appin,ulong *npin); appin : [out] Adresse d un tableau de pointeurs d IPin (à allouer avant l'appel). npin : [in, out] En entrée, spécifie la taille du tableau. En retour, la valeur est actualisée au nombre de pointeurs retournés. Page 18/50

Retour Remarque : Release! : Valeur HRESULT (voir la doc) IPin::ConnectionMediaType Syntaxe : HRESULT ConnectionMediaType(AM_MEDIA_TYPE *pmt); Paramètre pmt : [out] Pointeur sur une structure AM_MEDIA_TYPE. Retour : Valeur HRESULT (voir la doc) Remarque : Voir l'exemple de code après la description des formats pour voir comment utiliser cette méthode. IPin::EnumMediaTypes Syntaxe : HRESULT EnumMediaTypes(IEnumMediaTypes **ppenum); ppenum : [out] Adresse du pointeur sur l interface IEnumMediaType. Retour S_OK : réussi E_OUTOFMEMORY : pas assez de mémoire E_POINTER : argument NULL. Remarques o comme d'habitude IEnumMediaTypes (interface IEnumXXX), on utilise les méthodes Next/Step/Reset. o Voir l'exemple de code après la description des formats pour voir comment utiliser cette méthode. 5. Formats supportés sur une borne AM_MEDIA_TYPE Structure Syntaxe typedef struct _MediaType { GUID majortype; GUID subtype; BOOL bfixedsizesamples; BOOL btemporalcompression; ULONG lsamplesize; GUID formattype; IUnknown *punk; ULONG cbformat; [size_is(cbformat)] BYTE *pbformat; AM_MEDIA_TYPE; Membres majortype : Globally Unique IDentifier (GUID) : le type majeur du flux. subtype : Le type mineur du flux. bfixedsizesamples : Information seulement. btemporalcompression : Information seulement. lsamplesize : Taille du sample en bytes. (0 pour les données compressées). Formattype : Structure utilisée: Format type Format structure FORMAT_None None. FORMAT_DvInfo DVINFO Page 19/50

FORMAT_MPEGVideo MPEG1VIDEOINFO FORMAT_MPEG2Video MPEG2VIDEOINFO FORMAT_VideoInfo VIDEOINFOHEADER FORMAT_VideoInfo2 VIDEOINFOHEADER2 FORMAT_WaveFormatEx WAVEFORMATEX GUID_NULL None punk : Non utilisé. cbformat : Staille du block du format, en bytes. pbformat : Pointeur sur le block du format. Remarques Quand deux pins veulent se connecter, ils négocient un type, défini par la structure AM_MEDIA_TYPE. Si elles ne se mettent pas d accord sur un type, elles ne peuvent pas se connecter. Le type majeur défini la catégorie générale (vidéo, audio, ). Le type mineur précise le type majeur (Par exemple, les types mineurs d une vidéo sont 8-bit, 16- bit, 24-bit, et 32-bit RGB). Exemple : if (pmt->formattype == FORMAT_VideoInfo) { // Check the buffer size. if (pmt->cbformat >= sizeof(videoinfoheader)) { VIDEOINFOHEADER *pvih = reinterpret_cast<videoinfoheader*>(pmt->pbformat); /* Access VIDEOINFOHEADER members through pvih. */ Major Types GUID MEDIATYPE_AnalogAudio MEDIATYPE_AnalogVideo MEDIATYPE_Audio MEDIATYPE_AUXLine21Data MEDIATYPE_File MEDIATYPE_Interleaved MEDIATYPE_LMRT MEDIATYPE_Midi MEDIATYPE_MPEG2_PES MEDIATYPE_MPEG2_SECTION MEDIATYPE_ScriptCommand MEDIATYPE_Stream MEDIATYPE_Text MEDIATYPE_Timecode MEDIATYPE_URL_STREAM MEDIATYPE_Video Description Analog audio. Analog video. Audio. Line 21 data. Used by closed captions. File. (Obsolete) Interleaved audio and video. Used for Digital Video (DV). Obsolete. Do not use. MIDI format. MPEG-2 PES packets. MPEG-2 section data Data is a script command, used by closed captions. Byte stream with no time stamps. Text. Timecode data. Obsolete. Do not use. Video. Audio Subtypes (voir la documentation pour les autres sous-types) GUID Description MEDIASUBTYPE_PCM PCM audio. MEDIASUBTYPE_PCMAudioObsolete Obsolete. Do not use. MEDIASUBTYPE_MPEG1Packet MPEG1 Audio packet. MEDIASUBTYPE_MPEG1Payload MPEG1 Audio Payload. MEDIASUBTYPE_MPEG2_AUDIO MPEG-2 audio data Page 20/50

MEDIASUBTYPE_DVD_LPCM_AUDIO MEDIASUBTYPE_MPEG2_AUDIO MEDIASUBTYPE_DRM_Audio MEDIASUBTYPE_IEEE_FLOAT MEDIASUBTYPE_DOLBY_AC3 MEDIASUBTYPE_DOLBY_AC3_SPDIF MEDIASUBTYPE_RAW_SPORT MEDIASUBTYPE_SPDIF_TAG_241h DVD audio data MPEG-2 audio data Corresponds to WAVE_FORMAT_DRM. Corresponds to WAVE_FORMAT_IEEE_FLOAT Dolby data Dolby AC3 over SPDIF. ~ MEDIASUBTYPE_DOLBY_AC3_SPDIF. ~ MEDIASUBTYPE_DOLBY_AC3_SPDIF. Exemples: o fonction libérant une structure AM_MEDIA_TYPE allouée (par exemple pour IPin::ConnectionMediaType) void FreeMediaType(AM_MEDIA_TYPE& mt) { SAFE_RELEASE(mt.pUnk); if (mt.cbformat!= 0) CoTaskMemFree((PVOID)mt.pbFormat); ZeroMemory(&mt,sizeof(AM_MEDIA_TYPE)); o fonction libérant un pointeur sur une structure de type AM_MEDIA_TYPE allouée par une méthode d'énumération des formats (par exemple lors d'un IEnumMediaTypes::Next) void DeleteMediaType(AM_MEDIA_TYPE *pmt) { if (pmt == NULL) return; FreeMediaType(*pmt); CoTaskMemFree((PVOID)pmt); o fonction affichant le major type du média d'une borne connectée (pour les 2 types les plus courants parmi les 16 possibles): void ViewPinFormatMajorType(IPin *Pin) { AM_MEDIA_TYPE mt; HRESULT s = Pin->ConnectionMediaType(&mt); if (s==vfw_e_not_connected) printf("notconnected"); GUID major = mt.majortype; FreeMediaType(mt); if (IsEqualGUID(major,MEDIATYPE_Audio)) printf("audio"); else if (IsEqualGUID(major,MEDIATYPE_Video)) printf("video"); o fonction récupérant la première borne libre de direction et de type souhaitée sur un filtre: IPin *GetPin(IBaseFilter *Filter,PIN_DIRECTION Dir,GUID FmtType){ IEnumPins *Enum = NULL; IEnumMediaTypes *EnumFmt = NULL; IPin *Pin = NULL, *Pin2=NULL; AM_MEDIA_TYPE *pmt; PIN_DIRECTION PinDir; Page 21/50

BOOL bfmttype = FALSE; Filter->EnumPins(&Enum); while(enum->next(1,&pin,null) == S_OK) { Pin->QueryDirection(&PinDir); if (PinDir!= Dir) { SAFE_RELEASE(Pin); continue; BOOL Connected = (Pin->ConnectedTo(&Pin2)!= VFW_E_NOT_CONNECTED); SAFE_RELEASE(Pin2); if (Connected) { SAFE_RELEASE(Pin); continue; Pin->EnumMediaTypes(&EnumFmt); while( EnumFmt->Next(1,&pmt,NULL) == S_OK ) { bfmttype = IsEqualGUID(pmt->majortype,FmtType); DeleteMediaType(pmt); if (bfmttype) break; SAFE_RELEASE(EnumFmt); if (bfmttype) break; SAFE_RELEASE(Pin); SAFE_RELEASE(Enum); return Pin; 6. Pour aller plus loin Pour rechercher des filtres en fonction de critères de recherche, utiliser la méthode: IFilterMapper2::EnumMatchingFilters Ne pas tenter d'utiliser cette méthode avant d'avoir abordé la partie sur l'énumération des devices sur un système. Page 22/50

1. Principes Construction de Graphe Pour construire un graphe il faut: 1. ajouter les filtres nécessaires à ceux utilisables par le graphe: IFilterGraph::AddFilter : ajouter un filtre IGraphBuilder::AddSourceFilter : ajouter un filtre qui lit un media. IFilterGraph::RemoveFilter : supprimer un filtre (avec déconnexion) attention, ces méthodes ne construisent pas le graphe (pas de connexion). 2. récupérer les filtres et les bornes que l'on souhaite utiliser pour les connexions: IFilterGraph::FindFilterByName : pour récupérer un filtre à partir de son nom. IPin::QueryAccept : pour savoir si un type de média est supporté par la borne d'un filtre. voir aussi les fonctions de récupération d'information sur un graphe pour énumérer et récupérer les filtres et les bornes. 3. effectuer les connections: IFilterGraph::ConnectDirect : connexion de deux bornes (sans intermédiaire). IFilterGraph::Disconnect : déconnexion d'une borne IGraphBuilder::Connect : connexion intelligente de deux bornes (en ajoutant éventuellement les filtres intermédiaires nécessaires). ICaptureGraphBuilder2::RenderStream : connexion semi intelligente de deux filtres (en ajoutant éventuellement un filtre intermédiaire spécifié). Les méthodes de construction du graphe suivantes permettent également de construire automatiquement les graphes de rendu pour: IGraphBuilder::Render : en spécifiant la borne de sortie dont il faut effectuer le rendu. IGraphBuilder::RenderFile : en spécifiant le nom d'un fichier multimédia. Règles générales de construction d'un graphe: 1. Un filtre doit avoir été inséré dans le graphe avant de tenter de connecter ses bornes avec un autre filtre dans le graphe. 2. Il faut arrêter le graphe pour pouvoir le modifier. Page 23/50

2. Création d'un filtre IBaseFilter *pfilter = NULL; CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void **)&pfilter); où clsid est la classe du filtre que l'on veut créer et qui est défini par: soit un identifieur de type CLSID_xxx, où xxx est le nom du filtre (voir la liste à l'entrée "DirectShow Filters" dans les "DirectShow Reference"). soit le GUID associé à la classe que l'on peut créer de la façon suivante si le filtre résulte de l'installation de composants logiciels supplémentaires (comme des codecs): i) consulter dans GraphEdit le GUID du filtre que l'on souhaite utiliser: Exemple: MPEG layer 3 Compressor : {33D9A761-90C8-11D0-BD43-00A0C911CE86 ii) définir le GUID associé: DEFINE_GUID(CLSID_MP3Compress, 0x33D9A761, 0x 90C8, 0x11D0, 0xBD, 0x43, 0x00, 0xA0, 0xC9, 0x11, 0xCE, 0x86); 2. Méthodes de construction Méthodes présentées dans cette section: IFilterGraph AddFilter Ajouter un filtre dans le graphe. RemoveFilter Supprimer un filtre dans le graphe. FindFilterByName Trouver un filtre dans le graphe en spécifiant son nom. ConnectDirect Connecter deux pins directement. Disconnect Déconnecter une pin. IGraphBuilder (hérite de IFilterGraph) Connect Connecter deux pins (avec intelligence). Render Ajouter une chaîne au filtre pour rendre le flux. RenderFile Construit un graphe qui joue un fichier. AddSourceFilter Ajouter un fichier source au graphe. IBaseFilter EnumPins FindPin Enumère les pins de ce filtre. Trouver un pin spécifique. IPin QueryAccept Détermine si la pin accepte un type spécifié. Page 24/50

a. Gestion des filtres dans le graphe IFilterGraph::AddFilter Syntaxe : HRESULT AddFilter(IBaseFilter *pfilter, LPCWSTR pname); pfilter : [in] Le filtre doit avoir été alloué avec CoCreateInstance. pname : [in] Ce nom est le nom "humain" que l'on donne au filtre. Retour : Valeur HRESULT (voir la doc) IGraphBuilder::AddSourceFilter Syntaxe : HRESULT AddSourceFilter(LPCWSTR lpwstrfilename, LPCWSTR lpwstrfiltername, IBaseFilter **ppfilter); lpwstrfilename : [in] Nom du fichier à charger. lpwstrfiltername: [in] Nom du filtre source. ppfilter : [out] Le filtre est créé lors de l'appel. Retour : Valeur HRESULT (voir la doc) Remarque : Release! IFilterGraph::RemoveFilter Syntaxe : HRESULT RemoveFilter(IBaseFilter *pfilter); pfilter : [in] Filtre à supprimer. Retour Remarque : Valeur HRESULT (voir la doc) : Il n est pas nécessaire de le déconnecter avant, mais le graphe doit être dans l état Stop. Sinon, la déconnexion (automatique) des pins risque d échouer. b. Récupération des filtres et des bornes IFilterGraph::FindFilterByName Le nom recherché est le nom humain du filtre. Syntaxe HRESULT FindFilterByName(LPCWSTR pname,ibasefilter **ppfilter); pname : [in, string] Nom du filtre à rechercher. ppfilter : [out] Adresse du pointeur sur le filtre, NULL si pas trouvé. Retour : Valeur HRESULT (voir la doc) Remarque : Release!. IBaseFilter::EnumPins = voir la partie "Information et structure d'un graphe de filtres". Page 25/50

IBaseFilter::FindPin Syntaxe : HRESULT FindPin(LPCWSTR Id, IPin **pppin ); Id : [in] Nom de la pin à rechercher. pppin : [out] Adresse du pointeur sur la pin, NULL si pas trouvé. Retour : Valeur HRESULT (voir la doc) Remarque : Release! IPin::QueryAccept Syntaxe : HRESULT QueryAccept(const AM_MEDIA_TYPE *pmt); Paramètre pmt : [in] Pointeur sur AM_MEDIA_TYPE. Retour : Valeur HRESULT (voir la doc) Remarque : Test avec S_OK; ne pas utiliser la macro SUCCEEDED. c. Connexions IGraphBuilder::Connect Syntaxe : HRESULT Connect(IPin *ppinout, IPin *ppinin); ppinout : [in] Pointeur sur la pin de sortie. ppinin : [in] Pointeur sur la pin d entrée. Retour Remarque : Valeur HRESULT (voir la doc) : Cette méthode connecte deux pins directement ou non, en ajoutant des filtres intermédiaires si nécessaire. Elle commence par essayer une connexion directe. Si elle échoue, elle va essayer tous les filtres déjà présents (dans n importe quel ordre) dans le graphe ayant une entrée déconnectée. Si elle échoue de nouveau, elle va rechercher les filtres dans le registre (dans l ordre de merit). IFilterGraph::ConnectDirect Syntaxe : HRESULT ConnectDirect(IPin *ppinout, IPin *ppinin, const AM_MEDIA_TYPE *pmt); ppinout : [in] Pointeur sur la pin de sortie. ppinin : [in] Pointeur sur la pin d entrée. pmt : [in] Optionel, peut être NULL. Retour : Valeur HRESULT (voir la doc) IFilterGraph::Disconnect Syntaxe : HRESULT Disconnect(IPin *ppin); Paramètre ppin : [in] Pointeur sur la pin à déconnecter. Retour : Valeur HRESULT (voir la doc) Page 26/50

Remarque : La méthode ne casse pas complètement la connexion. Pour ce faire, les deux bouts doivent être déconnectés. Pour supprimer le filtre entièrement, utiliser RemoveFilter. d. Rendu automatique IGraphBuilder::Render Syntaxe : HRESULT Render(IPin *ppinout); Paramètre ppinout : [in] Pointeur sur une pin de sortie. Retour : Valeur HRESULT (voir la doc) IGraphBuilder::RenderFile Syntaxe HRESULT RenderFile(LPCWSTRlpwstrFile, LPCWSTR lpwstrplaylist); lpwstrfile : [in] Nom du fichier à lire. lpwstrplaylist : [in] Réservé : doit être NULL. Retour : Valeur HRESULT (voir la doc) Remarque : Si vous l appelez une seconde fois, les fichiers seront joués en même temps. Exemple hr = pgraph->renderfile(l"c:\\media\\example.avi", 0); hr = pgraph->renderfile(l"http://example.microsoft.com/example.avi", 0); e. Exemples Rendu automatique: Un rendu simple de n importe quel fichier audio/vidéo peut être effectué avec DirectShow. Ce rendu s effectue en 3 étapes: 1. Création d un graphe de filtres (classe FilterGraph) avec l interface IGraphBuilder. 2. Appel de la méthode RenderFile du IGraphBuilder pour construire automatiquement le graphe nécessaire au rendu du filtre. 3. Récupération de l interface IMediaControl sur le graphe de filtres, et utilisation de cette interface pour contrôler le flux (méthodes Run, Stop, Pause). WCHAR *fname = L "ruby.avi"; IGraphBuilder *pgraph; CoInitialize (NULL); CoCreateInstance (CLSID_FilterGraph, NULL, CLSCTX_INPROC, IID_IGraphBuilder, (void **) &pgraph); pgraph ->RenderFile(fname, NULL); // la partie ci-dessous sera traitée dans la section suivante IMediaControl *pmctrl; pgraph->queryinterface(iid_imediacontrol, (void **)&pmctrl); pmctrl->run(); Page 27/50

MessageBox (NULL, Cliquer pour terminer, DirectShow, MB_OK); pmctrl->stop(); pmctrl->release(); // libération des ressources pgraph->release(); CoUninitialize(); Ce programme est le même si on remplace le fichier avi par n importe quel autre fichier audio (mp3) ou vidéo (divx). Le graphe généré est le suivant: Rendu manuel: On reconstruit manuellement le graphe ci-dessus: o Récupération de la première borne d'une direction donnée sur un filtre: IPin *GetPin(IBaseFilter *Filter, PIN_DIRECTION RequestedDir) { IEnumPins *Enum = NULL; IPin *Pin = NULL; PIN_DIRECTION Dir; Filter->EnumPins(&Enum); while(enum->next(1,&pin,null) == S_OK) { Pin->QueryDirection(&Dir); if (Dir == RequestedDir) break; SAFE_RELEASE(Pin); SAFE_RELEASE(Enum); return Pin; o Code de construction du graphe (obtenue par les deux lignes indiquées en bleu dans la partie précédente): IGraphBuilder *pgraph; CoInitialize (NULL); CoCreateInstance (CLSID_FilterGraph, NULL, CLSCTX_INPROC, IID_IGraphBuilder, (void **) &pgraph); WCHAR *fname = L"ruby.avi"; IBaseFilter *InputFileFilter = NULL; IBaseFilter *AviSplitter = NULL; IBaseFilter *AviDecompressor = NULL; IBaseFilter *VideoRenderer = NULL; IPin *PinOut = NULL, *PinIn = NULL; Page 28/50

// Création de la liste de filtres pgraph->addsourcefilter(fname, fname, &InputFileFilter); CoCreateInstance(CLSID_AviSplitter, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void **)&AviSplitter); CoCreateInstance(CLSID_AVIDec, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void **)&AviDecompressor); CoCreateInstance(CLSID_VideoRenderer, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void **)&VideoRenderer); // Insertion des filtres dans le graphe pgraph->addfilter(avisplitter, L"Avi Splitter"); pgraph->addfilter(avidecompressor, L"Avi Decompressor"); pgraph->addfilter(videorenderer, L"Video Renderer"); ViewGraphInfo(pGraph); // connexions PinOut= GetPin(InputFileFilter,PINDIR_OUTPUT); PinIn = GetPin(AviSplitter,PINDIR_INPUT); pgraph->connectdirect(pinout,pinin,null); SAFE_RELEASE(PinOut); SAFE_RELEASE(PinIn); PinOut= GetPin(AviSplitter,PINDIR_OUTPUT); PinIn = GetPin(AviDecompressor,PINDIR_INPUT); pgraph->connectdirect(pinout,pinin,null); SAFE_RELEASE(PinOut); SAFE_RELEASE(PinIn); PinOut= GetPin(AviDecompressor,PINDIR_OUTPUT); PinIn = GetPin(VideoRenderer,PINDIR_INPUT); pgraph->connectdirect(pinout,pinin,null); SAFE_RELEASE(PinOut); SAFE_RELEASE(PinIn); Remarques: i) la construction automatique n'est pas toujours possible (elle peut dépendre du contexte). ii) La fonction IPin *GetPin(IBaseFilter *Filter, PIN_DIRECTION Dir, GUID FmtType) est utilisable dans ce cadre mais seulement sur les bornes de sortie. En effet, une bonne partie des filtres configurent leurs major/minor type seulement qu'une fois que leur entrée est fixée. Construction automatique partielle: Sur n'importe quelle borne d'un graphe, il est possible de lancer un rendu automatique avec la méthode Render sur n'importe quelle borne n'importe où dans un graphe: WCHAR *fname = L"ruby.avi"; IBaseFilter *InputFileFilter = NULL; IPin *PinOut = NULL, *PinIn = NULL; h=pgraph->addsourcefilter(fname, fname, &InputFileFilter); PinOut = GetPin(InputFileFilter,PINDIR_OUTPUT,MEDIATYPE_Stream); pgraph->render(pinout); Page 29/50

Contrôle d'un Graphe 1. Le Média Controller L'interface IMediaControl est faite pour contrôler le flux des données à travers le graphe. Elle est disponible sur tous les objets qui dérivent de IFilterGraph. On acquière cette interface de la façon suivante: IMediaControl *pmctrl; pgraph->queryinterface(iid_imediacontrol, (void **)&pmctrl); où pgraph est un pointeur vers l'interface d'un graphe de filtres. Cette interface expose les méthodes suivantes: Note: Run Pause Stop StopWhenReady GetState o un graphe peut être dans trois états différents: Run/Pause/Stop. o Son état est "Run" si le graphe a des données qui transitent dans tous ses filtres. o Son état est "Stop" si tous les filtres du graphe sont arrêtés. o Son état est "Pause" s'il est momentanément arrêté, ou s'il est dans n'importe quel état intermédiaire (état de transition). Ce dernier cas arrive notamment lorsque les filtres sont en train de s'initialiser. IMediaControl::Run Syntaxe : HRESULT Run(void); Retour S_FALSE : Le graphe se prépare, mais certains filtres sont encore en transition. S_OK : Tous les filtres ont terminé leur transition. Remarques : Si le graphe est arrêté, il passe d abord en pause avant de se lancer. Il reste dans cet état tant qu il n y aura pas d appel à Pause ou Stop. Quand le flux se termine (fin du fichier par exemple), le graphe continue de tourner mais ne transite aucune donnée. Vous pouvez donc récupérer cet évènement pour arrêter le graphe. Si vous arrêtez le graphe en cours de route et le relancez, la reprise se fera à la position actuelle et ne recommencera pas du début. Pour ce faire, utilisez l interface IMediaSeeking. IMediaControl::Pause Syntaxe : HRESULT Pause(void); Retour: S_FALSE : Le graphe se prépare, mais certains filtres sont encore en transition. S_OK : Tous les filtres ont terminé leur transition. Remarque : Tant que le graphe est en pause, les données circulent dans les filtres et sont traitées mais ne sont pas rendues. Page 30/50

IMediaControl::Stop Syntaxe : HRESULT Stop(void); Retour : Valeur HRESULT (voir la doc) Remarque : Si le graphe est en cours d exécution, il passe d abord en pause. IMediaControl::StopWhenReady Syntaxe : HRESULT StopWhenReady(void); Retour : Valeur HRESULT (voir la doc) Remarque : Cette méthode est utile si vous voulez changer la position dans le flux pendant que le graphe est arrêté. (Voir la doc). IMediaControl::GetState Quand vous utilisez cette méthode, le graphe peut être dans un état de transition. Dans ce cas, la méthode attend que la transition se termine ou que le timeout expire. Syntaxe : HRESULT GetState(LONG mstimeout, OAFilterState *pfs); mstimeout : [in] Timeout, en millisecondes, ou INFINITE. pfs : [out] Pointeur sur FILTER_STATE. Retour S_OK : Réussi. VFW_S_STATE_INTERMEDIATE : Toujours en transition. VFW_S_CANT_CUE : En pause mais ne peut plus produire de données. E_FAIL : Echec. Remarque : Evitez un timeout INFINITE, car les threads ne peuvent pas traiter les messages. Spécifiez des temps réduits pour rester réactifs aux interactions avec l utilisateur. FILTER_STATE Enumeration Syntaxe typedef enum _FilterState { State_Stopped,State_Paused, State_Running FILTER_STATE; Exemple: utilisation du média controller pour lancer l'exécution d'un graphe. IMediaControl *pmctrl; pgraph->queryinterface(iid_imediacontrol, (void **)&pmctrl); pmctrl->run(); MessageBox (NULL, "Cliquer pour terminer", "DirectShow", MB_OK); pmctrl->stop(); pmctrl->release(); Le media controller est donc une interface très limitée qui ne permet notamment pas: o de se déplacer dans le flux de données. Ceci est pris en charge par l'interface IMediaSeeking. Page 31/50

o de gérer la répétition et plus généralement les évènements dans un flux. Ceci est pris en charge par les interfaces IMediaEvent et IMediaEventEx (avec gestionnaire d'événements Windows). 2. Position dans un flux Cette interface permet de se déplacer dans le flux de données. Tous les flux de données ne supportent pas ces changements: on l'utilise en général lors de la lecture d un fichier. Interface: Exposée par: IMediaPosition les graphes, les filtres. Exemple: IMediaPosition *pmpos; pgraph->queryinterface(iid_imediaposition, (void **)&pmpos); Dans cette interface, le temps est mesuré en seconde, et son type associé est: typedef double REFTIME; Remarque: une interface plus avancée IMediaSeeking permet des déplacements et une gestion plus avancée de la position, ou de changer le mode de déplacement dans le média (par frame, par octets, ). a. Capacités de recherche IMediaPosition::CanSeekForward et CanSeekBackward CanSeekForward : détermine si le graphe peut faire une recherche avant. CanSeekBackward : détermine si le graphe peut faire une recherche arrière. Syntaxe: HRESULT CanSeekForward(LONG *pcanseek); HRESULT CanSeekBackward(LONG *pcanseek); pcanseek : [out] OATRUE vrai si possible, et OAFALSE sinon. b. Récupération des informations Les informations que l'on peut récupérer ici sont: o la durée totale du flux. o la position courante dans le flux. o le point d'arrêt de lecture (par défaut, la fin du flux). Attention: o les valeurs récupérées sont en seconde. Page 32/50

o o la ou les valeurs retournées ne dépendent pas de la vitesse de lecture ou de temps initial de la lecture (la valeur est en position absolue par rapport au flux). pour avoir des informations plus précises sur le flux, on utilisera l'interface IMediaDet. IMediaPosition::get_Duration HRESULT get_duration(reftime *plength); IMediaPosition::get_CurrentPosition HRESULT get_currentposition(reftime *plltime); IMediaPosition::get_StopTime HRESULT get_stoptime(reftime *plltime); c. Déplacement dans le flux Cette interface peut être utilisée indépendamment de l'état du graphe. IMediaPosition::put_CurrentPosition HRESULT put_currentposition(reftime lltime); La valeur lltime est comprise entre 0 et la durée totale du flux. La valeur de retour S_FALSE indique le graphe était encore en phase de transition au moment du retour de la méthode. Voir le résultat de CanSeekForward et de CanSeekBackward pour connaître quel sont les déplacement possible. On remarquera que: o Si son état est Run, la graphe est passé en Pause le temps que le déplacement soit effectué, et la lecture reprend automatiquement. o Si graphe est en pause, les filtres doivent vider leurs buffers avant de passer à une nouvelle position. Voir IPin::BeginFlush et IPin::EndFlush. IMediaPosition::put_StopTime HRESULT put_stoptime(reftime lltime); La valeur lltime est comprise entre 0 et la durée totale du flux. Change la valeur à laquelle le flux s'arrête de jouer. Par défaut, cette marque est à la fin du flux. Elle est indépendante de la vitesse avec laquelle le flux est joué. d. Cas des données à accès non direct Pour certains types de média (bandes, streaming, ), l'accès n'est pas direct. Ceci empêche donc des accès aléatoires à l'intérieur du flux. Deux méthodes sont utilisées pour gérer ces cas: IMediaPosition::get_PrerollTime HRESULT get_prerolltime(reftime *plltime); Page 33/50