Programmation Multimédia Cours de programmation DirectShow
Transcription
Programmation Multimédia Cours de programmation DirectShow
Programmation Multimédia Master d'Informatique 2004-2005 Programmation Multimédia Cours de programmation DirectShow Pascal Mignot / Pascal Gardeur Partie 2: 1. Typologie et principes généraux sur les filtres 2. Installation de nouveaux filtres 3. Compression 4. Filtres de sortie 5. Périphériques matériels et interactions avec DirectShow 6. Enumération des filtres disponibles sur un système 7. Gestion des périphériques d'acquisition 8. Contrôle du rendu 9. Debug de DirectShow Annexes A : Montage Vidéo B : Contrôle d'un caméscope numérique C : Contrôle d'une carte Tuner TV D : Contrôle d'un DVD Reproduction et diffusion interdites. Page 1/71 Université de Reims Champagne-Ardennes Programmation Multimédia Master d'Informatique 2004-2005 Typologie et principes généraux sur les filtres Nous présentons dans cette section une partie des filtres DirectShow les plus directement utilisables. L'installation de codecs et de filtres particuliers (cf le SDK) permet d'accroître le nombre de filtres disponibles. 1) Filtres génériques a) filtres sources File Source (Async) (CLSID_AsyncReader) Lecture de fichier asynchrone (bref classique) File Source (URL) (CLSID_URLReader) Lecture d'un flux depuis une URL. b) filtres passants Smart Tee (CLSID_SmartTee) Duplication de l'entrée (une entrée, 2 sorties : capture et preview) Infinite Pin Tee (CLSID_InfTee) Duplication multiple de l'entrée (une entrée, n sorties) Sample Grabber (CLSID_SampleGrabber) Capture des échantillons (passant) c) filtres de rendu File Writer (CLSID_FileWriter) Si le flux n'a pas été converti dans un format reconnaissable, il ne pourra pas être relu (pour l'audio, utiliser wavDest; pour la vidéo, utiliser l'avi Muxer). Null Renderer (CLSID_NullRenderer) Equivalent de /dev/null dans un graphe. 2) Filtres de gestion audio a) Parser/decoder Page 2/71 Université de Reims Champagne-Ardennes Programmation Multimédia Master d'Informatique 2004-2005 WAVE Parser (CLSID_WAVEParser) ACM Wrapper (CLSID_ACMWrapper) Le type de ce filtre est instancié à sa création (quel codec, codage/décodage) Wave Dest (cf le SDK) Permet de transformer un flux PCM/audio en flux .wav b) Filtres transformants DMO Wrapper (CLSID_DMOWrapperFilter) Permet d'utiliser des Direct Media Objects dans un graphe Remarques: • les effets DirectSound (en rendu ou en capture) sont utilisables avec DirectShow sous forme de DMO. • lors de l'installation de certains produits (par exemple Sound Forge), les filtres audio de l'application sont disponibles sous forme de filtre DirectShow. c) Filtres de rendu Default Audio Renderer (WaveOut) (CLSID_AudioRender) DirectSound Renderer (CLSID_DSoundRender) d) Manipulation de flux au format Midi MIDI Parser (cf doc) Midi Renderer (CLSID_AVIMIDIRender) e) Filtre de capture Audio Capture (analogique micro/cd/midi) CLSID_AudioInputMixerProperties f) Utilisations classiques • • • • Lecture d'un fichier audio au format WAV File Source Wave Parser Audio Renderer Lecture d'un fichier audio au format mp3 File Source MPeG1 Splitter ACM Wrapper Wave Parser Audio Renderer Remarque: l'ACM Wrapper filter s'instancie comme un décodeur mp3. Rappel: mp3 = MPeG1 audio layer 3 Lecture d'un fichier audio au format midi File Source Midi Parser Midi Renderer Capture audio Page 3/71 Université de Reims Champagne-Ardennes Programmation Multimédia • Master d'Informatique 2004-2005 Conversion d'un fichier wav en fichier mp3 File Source Wave Parser ACM Wrapper Wave Dest File Writer Remarque: l'ACM Wrapper filter s'instancie comme un encodeur mp3. 3) Filtres de gestion vidéo a) Gestions internes Video Renderer (Video Mixing Renderer 7) Video Mixing Renderer 9 Color Space Converter Change le format de couleur (entre RGB8, RGB555, RGB565, RGB24, RGB32) b) Format AVI Lecture: Avi Splitter (CLSID_AviSplitter) AVI Decompressor (CLSID_AVIDec) Instance d'un décodeur VCM Ecriture: AVI Compressor Instance d'un encodeur VCM AVI Mux (CLSID_AviDest) Utilisations classiques: • Lecture d'un fichier AVI (audio au format PCM) Page 4/71 Université de Reims Champagne-Ardennes Programmation Multimédia • Master d'Informatique 2004-2005 Changement du format d'un fichier AVI (l'audio restant au format PCM) c) Format MPeG1 (svcd et super VideoCD) MPEG-1 Stream Splitter Sépare l'audio et la vidéo d'un flux mpeg1 MPEG-1 Video Decoder MPEG-1 Audio Decoder Remarque: le muxer et les encoder MPeG1 ne font par partie de DirectShow (installer les codecs adéquats dans ce but). Utilisation classique: File Source MPeG1 Stream Splitter video audio MPeG1 Video Decoder MPeG1 Audio Decoder d) Format MPeG2 et DVD MPEG-2 Demultiplexer (CLSID_MPEG2Demultiplexer) Séparation d'un flux mpeg2 MPEG-2 Sections and Tables (CLSID_Mpeg2Data) Données mpeg2 (caractéristique des services, droit d'abonnements, …) MPEG-2 Splitter (CLSID_MMSPLITTER) DVD Navigator Remarque: le muxer et les encoder MPeG2 ne font par partie de DirectShow (installer les codecs adéquats dans ce but). Page 5/71 Université de Reims Champagne-Ardennes Programmation Multimédia Master d'Informatique 2004-2005 Utilisation classique: Voir en annexe pour plus de précision. e) Format ASF WM ASF Writer (CLSID_WMAsfWriter) Ecriture dans un fichier au format ASF WM ASF Reader (CLSID_WMAsfReader) Lecture dans un fichier au format ASF Utilisation classique: f) Incrustation / Télétext / Sous-titres Page 6/71 Université de Reims Champagne-Ardennes Programmation Multimédia Master d'Informatique 2004-2005 Overlay Mixer (CLSID_OverlayMixer) Overlay Mixer 2 (CLSID_OverlayMixer2) World Standard Teletext Decoder (CLSID_WSTDecoder) Synchronized Accessible Media Interchange (CC) Parser Line 21 Decoder (DVD video/CC decoder) 4) Capture vidéo a) Capture vidéo (caméra & webcam) WDM Video Capture (CLSID_VideoInputDeviceCategory) VFW Capture Filter (CLSID_VfwCapture) Remarque: les périphériques de capture vidéo expose généralement une borne de Capture et une borne de Preview. La borne de Preview peut dégrader ses performances de façon à conserver la qualité de la borne de Capture. Dans le cas où la borne de Preview n'est pas disponible, on utilise le filtre suivant. Ce filtre peut être utilisé dans n'importe quel autre cadre similaire. Smart Tee filter (CLSID_SmartTee) Duplique l'entrée vidéo (une entree, deux sorties: capture + renderer) b) Capture vidéo analogique Deux filtres permettent de récupérer les données en provenance d'un tuner TV: Page 7/71 Université de Reims Champagne-Ardennes Programmation Multimédia • • Master d'Informatique 2004-2005 TV Audio (CLSID_TVAudioFilter) audio analogique TV Tuner (CLSID_TVTunerFilter) vidéo analogique WDM Analog Video Crossbar (TV tuner) (CLSID_CrossbarFilterPropertyPage) A noter que des connections internes doivent être faites de façon à relier les entrées vidéo et audio disponibles vers la sortie vidéo et audio du Crossbar. Voir en annexe pour plus de précision. c) Caméscope numérique Les caméscopes numériques stockent les informations sous forme de flux (dvsd) qui inclus l'audio et la vidéo sous forme interlacée. Le passage sous forme interlacée (muxer/splitter) se fait avec les deux filtres suivants: DV Splitter (CLSID_DVSplitter) DV Muxer (CLSID_DVMux) AVI type I et II: Type II : fichier avi classique. Type I : fichier DV. Type I AVI splitter Type II AVI splitter Page 8/71 DV splitter video audio DV Muxer video audio AVI Mux AVI Mux Type II Type I Université de Reims Champagne-Ardennes Programmation Multimédia Master d'Informatique 2004-2005 Accès aux périphériques: Instance d'un filtre WDM Video Capture de catégorie "CLSID_VideoInputDeviceCategory" ou "AM_KSCATEGORY_RENDER". Filtres de codage/décodage DV DV Video Encoder (CLSID_DVVideoEnc) DV Video Decoder (CLSID_DVVideoCodec) Utilisations classiques: • DV out (lecture d'une cassette numérique) • DV in (enregistrement sur une cassette numérique) Voir en annexe pour plus de précision. d) Broadcast Driver Architecture (BDA) Page 9/71 Université de Reims Champagne-Ardennes Programmation Multimédia Master d'Informatique 2004-2005 4. Propriétés Les propriétés d'une grande partie des périphériques peuvent afficher une boite de dialogue permettant de configurer le filtre. La fonction suivante permet d'afficher l'interface de configuration du filtre (certaines n'ont de sens qu'en mode debug). HRESULT ShowPropertyDialog(IBaseFilter *Filter, HWND hwnd) { ISpecifyPropertyPages *Prop; HRESULT h = Filter->QueryInterface(IID_ISpecifyPropertyPages, (void **)&Prop); if FAILED(h) return h; FILTER_INFO FilterInfo; h = Filter->QueryFilterInfo(&FilterInfo); IUnknown *FilterUnk = NULL; Filter->QueryInterface(IID_IUnknown, (void **)&FilterUnk); // Show the page. CAUUID caGUID; Prop->GetPages(&caGUID); SAFE_RELEASE(Prop); OleCreatePropertyFrame( hwnd, 0, 0, FilterInfo.achName, 1, &FilterUnk, caGUID.cElems, caGUID.pElems, 0, 0, NULL // // // // // // // // // Parent window Reserved Caption for the dialog box Number of objects (just the filter) Array of object pointers. Number of property pages Array of property page CLSIDs Locale identifier Reserved ); Page 10/71 Université de Reims Champagne-Ardennes Programmation Multimédia Master d'Informatique 2004-2005 // Clean up. SAFE_RELEASE(FilterUnk); SAFE_RELEASE(FilterInfo.pGraph); CoTaskMemFree(caGUID.pElems); return S_OK; } Voir la documentation pour l'explication des fonctions/méthodes ci-dessous. Exemple: résultat de l'appel de la fonction précédente sur un filter ACM Wrapper de type compression mp3 permet de choisir interactivement les taux de compression utilisés. Page 11/71 Université de Reims Champagne-Ardennes Programmation Multimédia Master d'Informatique 2004-2005 Installation de nouveaux filtres Pour de nombreuses applications, il devient nécessaire de développer de nouveaux filtres et/ou d'utiliser des filtres qui ne sont pas installés par défaut sur le système. 1. Installation d'un filtre à partir de son code source Exemple: le filtre wavdest contenu dans le SDK dans le répertoire: SDK\Samples\C++\DirectShow\Filters\WavDest\ Cette procédure peut être appliquée pour tout filtre similaire (soit du SDK, soit écrit par l'utilisateur). Ce filtre permet d'écrire un fichier au format wav (non compressé). Installation de ce filtre comme un codec: 1. compiler le filtre (en version release) 2. copier wavdest.ax dans \windows\system32. 3. enregistrer le filtre comme un composant windows avec: regserv32.exe wavdest.ax (à effectuer depuis \windows\system32) Installation du filtre pour l'utiliser dans un programme DirectShow: 1. compiler le filtre (en version release) 2. copier wavdest.lib dans SDKDX9\Lib. 3. créer un fichier wavdest.h contenant la définition du CLSID du filtre (voir au début du fichier wavdest.cpp); autrement dit contenant: #include <initguid.h> #define INITGUID DEFINE_GUID( CLSID_WavDest , 0x3c78b8e2, 0x6c4d, 0x11d1, 0xad, 0xe2, 0x0, 0x0, 0xf8, 0x75, 0x4b, 0x99 ); 4. copier ce fichier wavdest.h dans SDKDX9\include. Utilisation de ce filtre dans un programme DirectShow: 1. ajouter: #include <wavdest.h> 2. ajouter: #pragma comment(lib,"wavdest.lib") 3. créer le filtre avec comme interface IID_BaseFilter et comme classe CLSID_WavDest. Page 12/71 Université de Reims Champagne-Ardennes Programmation Multimédia Master d'Informatique 2004-2005 2. Installation d'un filtre à partir d'une source externe Exemple: le filtre de compression mp3 de Elecard basé sur Lame. http://www.elecard.com/ftp/pub/directshow/lame_dshow.zip Cette procédure peut être appliquée pour tout filtre .ax. Installation de ce filtre comme un codec: 1. copier wavdest.ax dans \windows\system32. 2. enregistrer le filtre comme un composant windows avec: regserv32.exe wavdest.ax (à effectuer depuis \windows\system32) Utilisation de ce filtre dans un code DirectShow: 1. Récupérer le GUID associé à ce filtre dans GraphEdit Par défaut, les filtres insérés de cette façon se trouvent dans les DirectShow filters: On trouve deux GUIDs associés à ce filtre (bas de la fenêtre): • Page 13/71 083863F1-70DE-11D0-BD40-00A0C911CE86 : qui correspond à la CLSID d'un filtre DirectShow (CLSID_LegacyAmFilterCategory) Université de Reims Champagne-Ardennes Programmation Multimédia • Master d'Informatique 2004-2005 B8D27088-DF5F-4B7C-98DC-0E91A1696286 : qui correspond à la CLSID de ce filtre. 2. Dans le code C++, il faut définir le GUID de la façon suivante: #include <initguid.h> #define INITGUID DEFINE_GUID(CLSID_CompMP3, 0xb8d27088, 0xdf5f, 0x4b7c, 0x98, 0xdc, 0x0e, 0x91, 0xa1, 0x69, 0x62, 0x86 ); Remarque: le nom CLSID_CompMP3 est au choix de l'utilisateur. 4. créer le filtre avec comme interface IID_BaseFilter et comme classe CLSID_CompMP3. 3. Filtres disponibles Il est également possible de rechercher un filtre particulier sur le système par énumération, et l'utiliser sans connaître au préalable son GUID. Il sera ainsi possible: • de récupérer les codecs (filtre de codage/décodage audio/vidéo) installés sur le système. Exemple: mp3, divX, … • de récupérer les filtres d'entrée associés aux périphériques (PnP ou non). Pour les périphériques PnP, les filtres deviennent disponibles dès que le périphérique est connecté. • de récupérer les filtres de sortie (renderer) pour le rendu sur des périphériques particuliers. Page 14/71 Université de Reims Champagne-Ardennes Programmation Multimédia Master d'Informatique 2004-2005 Compression 1. Codecs codec = COmpressor-DECompressor (audio ou vidéo) Sous DirectShow, les codecs sont implémentés de différentes façons: • sous forme d'ACM ou de VCM utilisable avec les filtres "AVI Decompressor" & "AVI Compressor". ACM = Audio Compression Manager (gestion des codecs audio) VCM = Video Compression Manager (gestion des codesc vidéo) Cette façon d'implémenter les codes est considérée comme obsolète. • sous forme de filtre DirectShow directement. La majorité des codecs sont actuellement implémentés sous cette forme, car ils sont le plus simplement et directement utilisable dans DirectShow. On peut récupérer la liste de ces codes avec le Device Enumerator (ICreateDevEnum). Installation sous forme de .ax. • sous forme de DirectX Media Object (DMO) Façon recommandé d'implémenter les Codecs car ils peuvent être utilisé dans à la fois dans DirectShow (filtre "DMO Wrapper") et dans les autres applications. Installation sous forme de .dll. 2. Parenthèse sur la compression vidéo Les compresseurs vidéo utilisent souvent trois types de frames différentes: o Intraframe : une image décrite entièrement par elle-même. Son taux de compression (rapport de taille entre l'image naturelle et l'image traitée) est relativement faible. Egalement connue sous le nom de keyframe (frame de référence) o Predicted frame : une image décrite en utilisant les différences entre cette image et l'image suivante. Le taux de compression est plus élevé que celui des Intraframes. o Bidirectionnal frame: une image décrite en utilisant à la fois les différences entre l'image précédente et l'image suivante. Le taux de compression est supérieur à l'image prédite. Page 15/71 Université de Reims Champagne-Ardennes Programmation Multimédia Master d'Informatique 2004-2005 Dans un flux MPEG, le débit exprime le nombre de bit utilisé pendant une seconde par le décodeur. On exprime la portée de la compression par le débit. Plus le débit est élevé, plus la qualité de la séquence obtenue est bonne. Le corolaire est que la taille fichier obtenue est de plus en plus importante. Si le débit est constant dans le temps, on parlera alors de codage CBR (Constant Bit Rate), sinon on parlera de VBR (Variable Bit Rate). Dans ce dernier cas, le débit varie en fonction de la complexité des informations à traiter. 3. Configuration de la compression a. Interface IAMVfwCompressDialogs Les filtres de type VCM (CLSID_VideoCompressorCategory) peuvent exposer l'interface IAMVfwCompressDialogs. Attention, si le retour de QueryInterface n'est pas S_OK, l'interface n'est pas disponible. Deux fenêtres peuvent être définie: Config, About. Une fois l'interface obtenue, on appelle la méthode ShowDialog pour afficher la fenêtre souhaitée: IAMVfwCompressDialogs::ShowDialog Syntaxe: HRESULT ShowDialog(int iDialog, HWND hwnd); Paramètres VfwCompressDialog_Config iDialog : [in] VfwCompressDialog_About pour le "à propos". hwnd : [in] Handle de la fenêtre propriétaire. pour configurer, Retour: S_OK Remarque: Tant que la boite de dialogue est affichée, vous ne pouvez pas traiter les données (pause ou run). Les membres VfwCompressDialog_QueryConfig et VfwCompressDialog_QueryAbout précise si les boites de dialogues sont disponible ou non pour ce filtre. Il est possible de configurer plus précisément le filtre sous réserve de connaître la structure de données qu'il utilise avec les méthodes SetState/GetState. Page 16/71 Université de Reims Champagne-Ardennes Programmation Multimédia Master d'Informatique 2004-2005 b. Interface IAMVideoCompression Les filtres suivants exposent l'interface IAMVideoCompression: o DV Video Encoder (CLSID_DVVideoEnc) sur le filtre o MJPEG Compressor (CLSID_MJPGEnc) sur la borne de sortie. o WDM Video Capture (CLSID_VideoInputDeviceCategory) sur le filtre. o AVI Compressor (CLSID_VideoCompressorCategory) sur la borne de sortie (et IAMVfwCompressDialogs sur le filtre lui-même). o VFW Capture (CLSID_VideoInputDeviceCategory) sur la borne de sortie. o DMO Wrapper (CLSID_DMOWrapperFilter) sur la borne de sortie. Cette interface permet de configurer de manière assez générale un filtre vidéo en fixant: o le taux de keyframe: put/get_KeyFrameRate n = une frame de référence est utilisée toutes les n frames. o le taux de frame prédite par keyframe : put/get_PFramesPerKeyFrame p = nombre de frame prédite sur les n (compression MPEG) o la qualité de la compression : put/get_Quality. o la largeur de la fenêtre : put/get_WindowSize, (en nombre de frames) sur lequel le taux est calculé. La méthode GetInfo permet de connaître les paramètres supportés. Les méthodes OverrideKeyFrame/OverrideFrameSize permettent de modifier pour certaines frames le comportement moyen. Aucune boite de dialogue graphique n'est exposée par cette interface. Page 17/71 Université de Reims Champagne-Ardennes Programmation Multimédia Master d'Informatique 2004-2005 Filtres de sortie 1. Filtres de rendu vidéo a. Filtres de base • Video Renderer Filtre par défaut de rendu vidéo: ce filtre est supporté par toutes les plateformes. Classe: CLSID_VideoRenderer • Video Mixing Renderer 7 (VMR7) Sous XP seulement: utilise DirectDraw7. Classe: CLSID_VideoMixingRenderer ou CLSID_VideoRendererDefault A préférer pour les applications n'effectuant que du rendu vidéo. • Video Mixing Renderer 9 (VMR9) Sur toute plateforme supportant DirectX9. Classe: CLSID_VideoMixingRenderer9 A préférer pour les applications mélangeant vidéo et 3D. • Overlay Mixer Ancien rendu avec sous-titre (overlay = écriture directe dans la mémoire vidéo). Remarque: le rendu des sous-titres peut être effectué avec d'autres filtres. Classe: CLSID_OverlayMixer Ces filtres de rendu vidéo peuvent opérer dans deux modes différents: • mode fenêtré (windowed) : le renderer crée sa propre fenêtre. Cette fenêtre peut être attachée à l'application. • mode non-fenêtré (windowless) : supporté par VMR7 et VMR9. L'affichage doit être géré par l'application. b. Contrôles de base Les interfaces suivantes sont disponibles sur les renderers ci-dessus: Interface IBasicVideo: propriété générale de la vidéo • • • • Page 18/71 récupère la taille de la source vidéo (VideoHeight/VideoWidth/VideoSize), les statistiques du rendu (AvgTimePerFrame/BitErrorRate/BitRate) capture d'écran de l'image courante. fixe/récupère les rectangles source et destination du flux. Université de Reims Champagne-Ardennes Programmation Multimédia Master d'Informatique 2004-2005 Interface IBasicVideo2: IBasicVideo + récupère l'aspect ratio. Interface IVideoWindow: gestion des propriétés de la fenêtre: • • • • focus, état (maximisation, minimisation, iconifié, …), position et taille. mode fenêtré/plein écran récupération du handle associé à la fenêtre (pour l'intégrer dans une application). c. Gestion du rendu et multistream Les interfaces suivantes sont pour le VMR (des interfaces similaires existent aussi en général pour le VMR9). IVMRFilterConfig: configure comment est effectué le rendu: o nombres de stream à mixer à l'entrée du renderer. o mode de rendu (windowed/windowless/renderless) o le compositeur (mixer personnalisable) IVMRDeinterlaceControl: fixe la méthode de dé-entrelacement (par stream). IVMRMixerControl: contrôle de la façon dont sont mixés l'ensemble des streams: o pour chaque stream, la portion de fenêtre occupée, sa profondeur (calques), l'ajustement de l'intensité et des couleurs (VMR9 seulement + driver). o en fixant la couleur de fond. IVMRMonitorConfig : choix du moniteur utilisé pour le rendu. d. Exemple: duplication d'une vidéo dans un fenêtre Page 19/71 Université de Reims Champagne-Ardennes Programmation Multimédia Master d'Informatique 2004-2005 CoInitialize (NULL); IGraphBuilder *pGraph; CoCreateInstance (CLSID_FilterGraph, NULL, CLSCTX_INPROC, IID_IGraphBuilder, (void **) &pGraph); // Ajout des filtres dans le graphe IBaseFilter *FileFilter, *RenderFilter, *TeeFilter; pGraph->AddSourceFilter(fname, fname, &FileFilter); CoCreateInstance (CLSID_VideoMixingRenderer9, NULL, CLSCTX_INPROC, IID_IBaseFilter, (void **) &RenderFilter); pGraph->AddFilter(RenderFilter,L"VideoRender"); // Configuration du nombre de stream du video render // (A faire avant toute connexion) IVMRFilterConfig9 *FilterConfig; RenderFilter->QueryInterface(IID_IVMRFilterConfig9, (void**)&FilterConfig); FilterConfig->SetNumberOfStreams(2); // Récupération de bornes a connecter et déconnection IPin *Pout,*Pin,*Ptee; Pout = GetPin(FileFilter,PINDIR_OUTPUT); Pin = GetPin(RenderFilter,PINDIR_INPUT); pGraph->Connect(Pout,Pin); Pin->ConnectedTo(&Pout); pGraph->Disconnect(Pin); pGraph->Disconnect(Pout); // Insertion d'un TEE CoCreateInstance (CLSID_SmartTee, NULL, CLSCTX_INPROC, IID_IBaseFilter, (void **) &TeeFilter); pGraph->AddFilter(TeeFilter,L"Tee"); // Connexion a l'entrée du tee Ptee = GetPin(TeeFilter,PINDIR_INPUT); pGraph->Connect(Pout,Ptee); SAFE_RELEASE(Ptee); // Connexion en sortie du tee Ptee = GetPin(TeeFilter,PINDIR_OUTPUT); pGraph->Connect(Ptee,Pin); SAFE_RELEASE(Ptee); // Deuxième connexion en sortie du tee SAFE_RELEASE(Pin); Pin = GetIthPin(RenderFilter,PINDIR_INPUT,2); Ptee = GetIthPin(TeeFilter,PINDIR_OUTPUT,2); pGraph->Connect(Ptee,Pin); SAFE_RELEASE(Ptee); SAFE_RELEASE(Pin); SAFE_RELEASE(Pout); // Récupération du contrôleur de mixage IVMRMixerControl9 *Mixer = NULL; IBasicVideo *Base = NULL; IVideoWindow *Window = NULL; RenderFilter->QueryInterface(IID_IVMRMixerControl9,(void**)&Mixer); RenderFilter->QueryInterface(IID_IBasicVideo,(void**)&Base); RenderFilter->QueryInterface(IID_IVideoWindow,(void**)&Window); Page 20/71 Université de Reims Champagne-Ardennes Programmation Multimédia Master d'Informatique 2004-2005 long W,H; Base->GetVideoSize(&W,&H); Window->put_Width(2*W); VMR9NormalizedRect R0 = { 0.f, 0.f, 0.5f, 1.f}, R1 = {0.5f, 0.f, 1.f, 1.f}; Mixer->SetOutputRect(0,&R0); Mixer->SetOutputRect(1,&R1); // Ajouter ici les commandes de contrôles du graphe Voir aussi les exemples blender du SDK en VMR et en VMR9. d. VMR9 et 3D L'intérêt de VMR9 est qu'il permet de faire des liens direct avec DX9, et en particulier le 3D. Inclure d3d9.h et vmr9.h de directX 9. 2. Filtres de rendu audio a. Filtres de base • Audio Renderer (WaveOut) : CLSID_AudioRender Rendu du son en utilisant WaveOut (pas de mixage) • DirectSound Renderer Filter (Défaut) : CLSID_DSoundRender Rendu du son avec DirectSound • Midi Renderer : CLSID_AVIMIDIRender Pour le rendu de fichier au format midi (doit être précédé du Midi Parser). b. Contrôles de base Interface IBasicAudio : fixe ou récupère la balance et le volume (interface triviale). Interface IAMAudioRendererStats : lecture des statistiques de l'audio-renderer. Voir la documentation pour les autres interfaces permettant de contrôler le rendu audio. c. Contrôles DirectSound Interface IAMDirectSound : fixe le focus. Interface IDirectSound3DBuffer : cf le cours Direct Sound 3D. Interface IDirectSound3dListener: cf le cours Direct Sound 3D. Page 21/71 Université de Reims Champagne-Ardennes Programmation Multimédia Master d'Informatique 2004-2005 3. Rendu dans un fichier a. Filtres de base • File Writer : CLSID_FileWriter Ce filtre doit être précédé d'un filtre qui transforme le flux audio/vidéo en flux de données. Ceci est effectué par: Audio : wavdest (Samples\C++\DirectShow\Filters\WavDest) Vidéo : Avi Mux (classe CLSID_AviDest) • ASF Writer : CLSID_WMAsfWriter. Le Windows Media SDK doit être installé. b. Contrôles de base sur le FileWriter Interface IFileSinkFilter : Permet de préciser le nom du fichier en sortie. Création s’il n’existe pas, écrasement s’il existe. c. Exemple d'écriture dans un fichier L'exemple suivant prend un fichier avi (compressé ou non) et réécrit le même en supprimant la bande son. Principe: 1. connecter un filtre de lecture à un AviMux. 2. connecter l'AviMux au FileWriter. On ne peut pas connecter directement le filtre de lecture au FileWriter car ce dernier n’accepte pas n'importe quel type de flux de données. L'AviMux prend en entrée un flux avi (vidéo+audio) et renvoie en sortie le fichier correspondant sous forme d'un flux de données. WCHAR *fname = L"a.avi"; CoInitialize (NULL); IGraphBuilder *pGraph; CoCreateInstance (CLSID_FilterGraph, NULL, CLSCTX_INPROC, IID_IGraphBuilder, (void **) &pGraph); // Ajout des filtres dans le graphe IBaseFilter *FileRead = NULL, *AviMux = NULL, *FileWriter = NULL; pGraph->AddSourceFilter(fname, fname, &FileRead); CoCreateInstance(CLSID_AviDest, NULL, CLSCTX_INPROC, IID_IBaseFilter, (void **) &AviMux); pGraph->AddFilter(AviMux,L"AviMux"); Page 22/71 Université de Reims Champagne-Ardennes Programmation Multimédia Master d'Informatique 2004-2005 CoCreateInstance(CLSID_FileWriter, NULL, CLSCTX_INPROC, IID_IBaseFilter, (void **) &FileWriter); pGraph->AddFilter(FileWriter,L"FileWriter"); IFileSinkFilter *FileSink; FileWriter->QueryInterface(IID_IFileSinkFilter, (void**)&FileSink); FileSink->SetFileName(L"hummer.avi",NULL); // Récupération des bornes a connecter IPin *Pout,*Pin; Pout = GetPin(FileRead,PINDIR_OUTPUT); Pin = GetPin(AviMux,PINDIR_INPUT); pGraph->Connect(Pout,Pin); SAFE_RELEASE(Pin); SAFE_RELEASE(Pout); // Deuxième connexion en sortie du tee Pout = GetPin(AviMux,PINDIR_OUTPUT); Pin = GetPin(FileWriter,PINDIR_INPUT); pGraph->Connect(Pout,Pin); SAFE_RELEASE(Pin); SAFE_RELEASE(Pout); // Ajouter ici le contrôle du graphe 4. Rendu Null Les flux à l'entrée de ce filtre sont perdus. A utiliser lorsque l'on ne souhaite pas effectuer de rendu, mais qu'un filtre utilisé dans le graphe a besoin de voir sa borne de sortie connecté pour fonctionner correctement. Prendre comme habitude de terminer les graphes par un filtre de rendu. Ce filtre n'expose aucune interface spécifique pour le configurer. Classe: CLSID_NullRenderer Page 23/71 Université de Reims Champagne-Ardennes Programmation Multimédia Master d'Informatique 2004-2005 Périphériques matériels et interactions avec DirectShow Sous DirectShow, on accède aux différents périphériques matériels grâce à des filtres. Nous donnons ici une idée de la façon dont DirectShow interagit avec les différents matériels audio et vidéo en expliquant les différentes associations entre les périphériques et les filtres qui leurs sont associés. 1. Le matériel de capture et de mixage audio (les cartes son) Les cartes son possèdent généralement un ensemble de connecteurs pour connecter des enceintes, des microphones, etc … Ces cartes ont la possibilité matérielle de pouvoir contrôler, sur chacun de ces ports, différentes caractéristiques, telles que le volume, la balance ou encore le niveau des basses. Sous DirectShow, les entrées de la carte son et les éléments permettant d’effectuer ces modifications dessus, sont encapsulés dans le filtre de Capture Audio. Toute carte son peut être reconnue et « récupérée » par l’énumérateur de périphériques systèmes. 2. Les périphériques VfW (Video for Windows) Le filtre VFW Capture supporte les anciennes cartes de capture vidéo dites Video for Windows. Lorsqu’une telle carte est présente (et bien sûr, reconnue par le système d’exploitation), elle peut, tout comme les périphériques de capture audio, être ajoutés au graphe de filtres par l’intermédiaire de l’énumérateur de périphériques systèmes. 3. Les périphériques WDM Streaming Les plus récents décodeurs et cartes de capture sont conformes à la spécification du Windows Driver Model. De tels dispositifs possèdent plus de fonctionnalités que les périphériques VfW. Les cartes d’acquisition vidéo WDM peuvent être dotées de nouvelles possibilités de réglages comme le fait de pouvoir énumérer les différents formats de capture, de sélectionner une entrée à utiliser, d’obtenir le contrôle sur des paramètres vidéo (tels que la luminosité ou le contraste). Afin de pouvoir intégrer ce types de matériel, DirectShow fournit un filtre nommé KsProxy (surnommé le filtre « couteau suisse » du fait qu’il réalise plusieurs choses différentes). KsProxy n’apparaît pas dans un graphe sous ce nom mais prend toujours le nom du périphérique tel qu’il est définit dans la base de registres. Même si seule une carte est installée sur le système, il se peut que celle-ci contienne « plusieurs périphériques » (associés à plusieurs fonctionnalités différentes de ce périphérique). Dans Page 24/71 Université de Reims Champagne-Ardennes Programmation Multimédia Master d'Informatique 2004-2005 ce cas, chaque périphérique sera représenté par un filtre différent (ces filtres seront tous des instances différentes de KsProxy). Une application utilise l’énumérateur de périphériques systèmes pour trouver les monikers sur les périphériques WDM. KsProxy est instancié lors de l’appel à BindToObject sur le moniker. Comme KsProxy peut représenter tous types de périphériques WDM, il doit interroger le pilote afin de déterminer quel « ensemble de propriétés » est supporté. Un « ensemble de propriétés » étant une liste de structures de données utilisées par les pilotes WDM et par quelques filtres en mode utilisateur tels que certains décodeurs logiciels MPEG-2. KsProxy se configure automatiquement pour exposer les interfaces correspondantes aux « ensembles de propriétés ». KsProxy traduit les appels aux méthodes COM en « ensemble de propriétés » et les envois au pilote. Les fabricants de tels matériels peuvent étendre KsProxy en fournissant des plug-ins (objets COM), lesquels étant des interfaces adaptées aux fonctionnalités spécifiques du périphérique. Tous ces détails son cachés à l’application qui contrôle KsProxy de la même façon que tout autre filtre DirectShow. 4. Kernel Streaming Les périphériques WDM supportent le « kernel streaming ». Dans ce mode, les données sont entièrement « canalisées » en mode noyau sans avoir à basculer en mode utilisateur (rappel: basculer d’un mode à l’autre coûte cher au niveau de la gestion des ressources). Le kernel streaming permet d’obtenir un meilleur débit sans utiliser trop de ressource processeur. Les filtres basés sur WDM peuvent utiliser cela pour transporter des données multimédia directement d’un périphérique matériel à un autre (éventuellement sur des périphériques différents), sans avoir à copier les données en mémoire principale du système. Du point de vue de l’application, tout se passe comme si les données passent d’un filtre à un autre en mode utilisateur. En réalité, lorsque le graphe et les traitements le permettent, les données sont canalisées de filtre à filtre (i.e. périphérique à périphérique) en mode noyau et ceci jusqu’à la carte graphique. Dans certains cas, comme la capture dans un fichier, le passage des données en mode utilisateur est nécessaire en certains points, mais les basculements générés ne sont pas forcément synonymes de recopie complète des données dans la mémoire système. Page 25/71 Université de Reims Champagne-Ardennes Programmation Multimédia Master d'Informatique 2004-2005 Enumération des filtres disponibles sur un système La recherche des filtres disponibles sur le système s’effectue avec les étapes suivantes: 1. Accès à l’interface ICreateDevEnum d’énumération. 2. Création d’un énumérateur de classe (IEnumMoniker) en spécifiant la catégorie d’objet à énumérer. 3. Pour chaque objet énuméré dans la classe (IMoniker), récupération de l’ensemble des propriétés de l’objet (IPropertyBag) à partir d’une version inactive de l’objet. 4. Pour l’objet recherché, instanciation de l’objet (version active). Moniker : objet COM qui fait référence à une instance spécifique d’un autre objet par son nom. Un moniker va permettre de localiser, activer et obtenir l’accès à un objet identifié sans connaître les informations spécifiques relatifs à celui-ci. Property Bag: ensemble des propriétés d’un objet. On accède aux propriétés par leurs noms (WCHAR). Les propriétés toujours présentes pour les devices sont: FriendlyName Description DevicePath : son nom : sa description (camcorder) : son « chemin » système (unique même pour plusieurs devices de même type branché). 1. Enumérateur de classe Choix du type d’énumération et récupération de l’interface d’énumération des Monikers. Type : ICreateDevEnum CLSID = SystemDeviceEnum, IID = ICreateDevEnum : Page 26/71 Université de Reims Champagne-Ardennes Programmation Multimédia Master d'Informatique 2004-2005 Exemple: ICreateDevEnum *pSysDevEnum = NULL; CoCreateInstance(CLSID_SystemDeviceEnum,NULL,CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void **)&pSysDevEnum); Cette objet n’a accès qu’à une seule méthode: CreateClassEnumerator Syntaxe HRESULT CreateClassEnumerator( EFCLSID clsidDeviceClass, EnumMoniker **ppEnumMoniker, WORD dwFlags ); Paramètres clsidDeviceClass ppEnumMoniker dwFlags : [in] CLSID de la catégorie. : [out] Adresse du pointeur sur IEnumMoniker. : [in] Si 0, énumération de tous les filtres dans la catégorie. Description Flag CDEF_DEVMON_CMGR_DEVICE CDEF_DEVMON_DMO CDEF_DEVMON_FILTER CDEF_DEVMON_PNP_DEVICE Codecs audio et vidéo, compatible avec ACM et VCM. DirectX Media Objects (DMOs). Filtres DirectShow par défaut. Matériel Plug and Play branché. Retour : Valeur HRESULT (voir la doc). Remarque : Tester le retour avec S_OK et pas la macro SUCCEEDED. 2. Catégories de filtres Ces catégories apparaissent dans GraphEdit lors de l’insertion de nouveau filtres. Elles sont définies dans « Uuids.h », inclure « Dshow.h ». Nom Audio Capture Sources Audio Compressors Audio Renderers Device Control Filters DirectShow Filters External Renderers Midi Renderers Video Capture Sources Video Compressors Video Effects (1 input) Video Effects (2 inputs) WDM Streaming Capture Devices WDM Streaming Crossbar Devices WDM Streaming Rendering Devices WDM Streaming Tee/Splitter Devices WDM Streaming TV Audio Devices WDM Streaming TV Tuner Devices WDM Streaming VBI Codecs ActiveMovie Filter Categories Page 27/71 CLSID CLSID_AudioInputDeviceCategory CLSID_AudioCompressorCategory CLSID_AudioRendererCategory CLSID_DeviceControlCategory CLSID_LegacyAmFilterCategory CLSID_TransmitCategory CLSID_MidiRendererCategory CLSID_VideoInputDeviceCategory CLSID_VideoCompressorCategory CLSID_VideoEffects1Category CLSID_VideoEffects2Category AM_KSCATEGORY_CAPTURE AM_KSCATEGORY_CROSSBAR AM_KSCATEGORY_RENDER AM_KSCATEGORY_SPLITTER AM_KSCATEGORY_TVAUDIO AM_KSCATEGORY_TVTUNER AM_KSCATEGORY_VBICODEC CLSID_ActiveMovieCategories Merit MERIT_DO_NOT_USE MERIT_DO_NOT_USE MERIT_NORMAL MERIT_DO_NOT_USE MERIT_NORMAL MERIT_DO_NOT_USE MERIT_NORMAL MERIT_DO_NOT_USE MERIT_DO_NOT_USE MERIT_DO_NOT_USE MERIT_DO_NOT_USE MERIT_DO_NOT_USE MERIT_DO_NOT_USE MERIT_DO_NOT_USE MERIT_DO_NOT_USE MERIT_DO_NOT_USE MERIT_DO_NOT_USE MERIT_DO_NOT_USE Not applicable Université de Reims Champagne-Ardennes Programmation Multimédia Master d'Informatique 2004-2005 Les catégories suivantes sont définies dans « Ks.h ». Nom WDM Streaming Communication Transforms WDM Streaming Data Transforms WDM Streaming Interface Transforms WDM Streaming Mixer Devices CLSID Merit KSCATEGORY_COMMUNICATIONSTRANSFORM MERIT_DO_NOT_USE KSCATEGORY_DATATRANSFORM MERIT_DO_NOT_USE KSCATEGORY_INTERFACETRANSFORM MERIT_DO_NOT_USE KSCATEGORY_MIXER MERIT_DO_NOT_USE La catégorie suivante est définie dans « Ksmedia.h ». Nom WDM Streaming System Audio Devices CLSID Merit KSCATEGORY_AUDIO_DEVICE MERIT_DO_NOT_USE Les catégories suivantes sont définies dans « Bdamedia.h ». Nom BDA CP/CA Filters Category BDA Network Providers BDA Receiver Components BDA Rendering Filters BDA Source Filters BDA Transport Information Renderers CLSID Merit CLSID_CPCAFiltersCategory MERIT_NORMAL KSCATEGORY_BDA_NETWORK_PROVIDER MERIT_NORMAL KSCATEGORY_BDA_RECEIVER_COMPONENT MERIT_NORMAL KSCATEGORY_IP_SINK MERIT_DO_NOT_USE KSCATEGORY_BDA_NETWORK_TUNER MERIT_DO_NOT_USE KSCATEGORY_BDA_TRANSPORT_ MERIT_NORMAL INFORMATION L’ordre d’inclusion est le suivant : #include <ks.h> #include <ksmedia.h> #include <bdamedia.h> Acronymes: WDM = Windows Driver Model. BDA = Broadcast Driver Architecture (video broadcasting: satellite, cable) MERIT: Lorsque le GraphManager effectue des connections (intelligent connect) entre deux filtres, le MERIT indique si ce filtre peut être utilisé comme filtre intermédiaire: MERIT_PREFERRED MERIT_NORMAL MERIT_UNLIKELY MERIT_DO_NOT_USE Page 28/71 : préférer ce filtre : filtre utilisable : essayer de ne pas l'utiliser : ne pas utiliser Université de Reims Champagne-Ardennes Programmation Multimédia Master d'Informatique 2004-2005 3. Enumération de Monikers (IEnumMoniker) Remarque: on est encore dans le cas d'une classe de type IEnumXXX. On utilise principalement les 2 méthodes suivantes : • IEnumMoniker::Next • IEnumMoniker::Reset Utilisation: on fait une boucle while effectuant un Next sur l’IEnumMoniker. • Chaque Next permet de récupérer le Moniker suivant (ou plusieurs). • Ce Moniker peut être utilisé pour récupérer l’objet auquel il faut référence. • Si on ne conserve pas le Moniker, faire un Release avec le Next suivant. • On arrête l’énumération des Monikers dès que Next renvoit S_FALSE : On est arrivé sur le dernier Moniker, S’il s’agissait du premier Next, il n’y a pas d’objet de ce type. Utilisation: lorsque l’on demande à l’utilisateur de choisir l’objet qu’il désire, Reset permet de reparcourir la liste des objets. Attention, la liste des objets est susceptible de changer entre la première et deuxième lecture, ne pas se référer seulement au numéro d’index du choix (utiliser plutôt le DevicePath). 4. Utilisation d’un Moniker Il y a deux modes d'utilisation d'un Moniker: 1. IMoniker::BindToStorage : accès aux propriétés de l'objet. 2. IMoniker::BindToObject : accès à l'objet et activation de l'objet. Une fois le Moniker associé à l’objet récupéré. a. Accès aux propriétés de l'objet Pour nous l’objectif sera de récupérer les propriétés de l’objet associé au Moniker sans l’initialiser. i. Instanciation mémoire de l'objet Syntaxe : HRESULT BindToStorage(IBindCtx *pbc, IMoniker *pmkToLeft, REFIID riid, void **ppvObj); Paramètres pbc pmkToLeft riid Page 29/71 : [in] On utilisera NULL. : [in] On utilisera NULL. : [in] On utilisera toujours IID_IPropertyBag pour récupérer l’ensemble de propriétés associé au Moniker. Université de Reims Champagne-Ardennes Programmation Multimédia ppvObj Master d'Informatique 2004-2005 : [out] Pour nous, il s’agira de l’adresse d’un IPropertyBag (prendre soin de l’initialiser à NULL avant l’appel, mais il devrait être aussi NULL après l’appel en cas d’erreur). Rappel: faire appel à Release pour libérer le PropertyBag (avant tout nouveau BindToStorage ou en fin d’utilisation). Retour: E_OUTOFMEMORY, S_OK. Il y a d’autres messages de retour, mais leurs interprétations dépassent l’objectif du cours. ii. Lecture des propriétés contenues dans un IPropertyBag On utilise la méthode Read pour lire le « FriendlyName » contenu dans le PropertyBag. Syntaxe: HRESULT Read(LPCOLESTR pszPropName, VARIANT *pVar, IErrorLog *pErrorLog); Paramètres pszPropName pVar pErrorLog : [in] Adresse du nom de la propriété à lire. Ne peut être NULL. : [in, out] VARIANT recevant la valeur. : [in, out] Code d’erreur en retour. Peut être NULL. Retour : S_OK ou autre (voir la doc). Variable de type VARIANT : VARIANT : type défini essentiellement par les champs suivants: vt : type de l’objet stocké dans la structure. v : union de variable de presque tous les types. Après une lecture de données avec une variable de type VARIANT, le champs vt est rempli avec une valeur indiquant le type de données lu. Exemple: si v est de type VARIANT, si v.vt == VT_BSTR, alors la variable a lu une chaîne de caractères le champs v.bstrVal contient cette chaîne de caractères Principales fonctions utilisées sur un type Variant: VariantInit(&v); initialisation d’un variant. VariantClear(&v); libère les ressources allouées par l’utilisation d’un variant. Page 30/71 Université de Reims Champagne-Ardennes Programmation Multimédia Master d'Informatique 2004-2005 b. Instanciation et initialisation de l'objet Pour nous l’objectif sera de récupérer les propriétés de l’objet associé au Moniker en l’initialisant. Syntaxe : HRESULT BindToObject( IBindCtx * pbc, IMoniker * pmkToLeft, REFIID riidResult, void ** ppvResult ); Paramètres pbc pmkToLeft riidResult ppvResult : [in] On utilisera NULL. : [in] On utilisera NULL. : [in] On utilisera toujours un IID_IBaseFilter pour récupérer le filtre DirectShow dans la classe de filtre dans laquelle on effectue l’énumération. : [out] Pour nous, il s’agira d’un IBaseFilter qui correspondra au filtre choisi parmi ceux énuméré par le Moniker dans la classe. Prendre soin de l’initialiser à NULL avant l’appel, mais il devrait être aussi NULL après l’appel en cas d’erreur. Rappel: faire appel à Release pour libérer l’objet créé en fin d’utilisation. Retour : E_UNEXPECTED, E_OUTOFMEMORY, S_OK. Il y a d’autres messages de retour, mais leurs interprétations dépassent l’objectif du cours. Exemple 1: affichage dans le terminal de l’ensemble des Devices d’un type donné: HRESULT ShowFilters(REFCLSID clsidDeviceClass, DWORD flag) { HRESULT h; int i=0; ICreateDevEnum *pSysDevEnum = NULL; IEnumMoniker *pEnumCat = NULL; IMoniker *pMoniker = NULL; IPropertyBag *pPropBag = NULL; // création de l’énumérateur de devices h = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void **)&pSysDevEnum); if ( h != S_OK ) goto ShowFilterExit; // création de l’énumérateur de Moniker h = pSysDevEnum->CreateClassEnumerator(clsidDeviceClass, &pEnumCat, flag); if ( h != S_OK ) goto ShowFilterExit; // énumération des Monikers while (pEnumCat->Next(1, &pMoniker, NULL) == S_OK) { h = pMoniker->BindToStorage(NULL,NULL, IID_IPropertyBag,(void **)&pPropBag); if ( h != S_OK ) goto ShowFilterExit; VARIANT var; VariantInit(&var); h = pPropBag->Read( L"FriendlyName", &var, NULL ); if ( h == S_OK ) wprintf(L"%02d : %s\n",++i,var.bstrVal); VariantClear(&var); Page 31/71 Université de Reims Champagne-Ardennes Programmation Multimédia Master d'Informatique 2004-2005 SAFE_RELEASE(pPropBag); pMoniker->Release(); } ShowFilterExit: SAFE_RELEASE(pMoniker); SAFE_RELEASE(pEnumCat); SAFE_RELEASE(pSysDevEnum); return h; } Exemple d’utilisation: ShowFilters(CLSID_VideoInputDeviceCategory, 0); Exemple 2: choix d’un Device IBaseFilter *GetIthFilterInClass(UINT i,REFCLSID devclass,DWORD flag){ HRESULT s; IBaseFilter *Found = NULL; ICreateDevEnum *CreateDevEnum = NULL; s = CoCreateInstance(CLSID_SystemDeviceEnum, NULL,CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void**)&CreateDevEnum); if FAILED(s) goto End; UINT n = CountClassEnumerator(CreateDevEnum,devclass,flag); if ((n==0) || (i>=n)) goto End; IEnumMoniker *EnumMoniker = NULL; s=CreateDevEnum->CreateClassEnumerator(devclass, &EnumMoniker, flag); if (s != S_OK) goto End; if (i>0) { s=EnumMoniker->Skip(i); if (s != S_OK) goto EndEnum; } IMoniker *Moniker = NULL; s = EnumMoniker->Next(1, &Moniker, NULL); if (s != S_OK) goto EndEnum; s = Moniker->BindToObject(NULL, NULL, IID_IBaseFilter, (void**)&Found); SAFE_RELEASE(Moniker); EndEnum: SAFE_RELEASE(EnumMoniker); End: SAFE_RELEASE(CreateDevEnum); return Found; } Page 32/71 Université de Reims Champagne-Ardennes Programmation Multimédia Master d'Informatique 2004-2005 Gestion des périphériques d'acquisition 1. Filtre de capture Lorsque l'on dispose d'un filtre de capture, il y a potentiellement plusieurs bornes de sortie. Un périphérique multifonction peut ainsi exposer de nombreuses bornes. Le problème qui se produit dans ce cas, est qu'il ne suffit plus, comme pour les filtres classiques, de connaître le type de flux accepté par la borne et sa direction. Afin de résoudre ce problème, il est possible d'interroger directement le Driver afin de connaître la sémantique de chacune des bornes. Ceci se fait, comme nous l'avons déjà étudié avec DirectSound, grâce aux IKsPropertySet. La démarche est la suivante: • pour le filtre de capture considéré, énumérer ses bornes. • pour chaque borne, o récupérer l'interface IKsPropertySet. Si cette interface n'est pas disponible, il ne sera pas possible de récupérer la sémantique de la borne. o effectuer un Get pour lire la propriété correspondant à: GUID = AMPROPSETID_Pin PropertyID = AMPROPERTY_PIN_CATEGORY Exemple: HRESULT GetPinCategory(IPin *pPin, GUID *pPinCategory){ HRESULT hr; IKsPropertySet *pKs; hr = pPin->QueryInterface(IID_IKsPropertySet, (void **)&pKs); if (FAILED(hr)) { // The pin does not support IKsPropertySet. return hr; } // Try to retrieve the pin category. DWORD cbReturned; hr = pKs->Get(AMPROPSETID_Pin, AMPROPERTY_PIN_CATEGORY, NULL, 0, pPinCategory, sizeof(GUID), &cbReturned); // If this succeeded, pPinCategory now contains the category GUID. pKs->Release(); return hr; } Page 33/71 Université de Reims Champagne-Ardennes Programmation Multimédia Master d'Informatique 2004-2005 Les catégories des bornes sont définies dans la liste suivante (définies dans uuids.h): GUID PIN_CATEGORY_ANALOGVIDEOIN PIN_CATEGORY_CAPTURE PIN_CATEGORY_CC PIN_CATEGORY_EDS PIN_CATEGORY_NABTS PIN_CATEGORY_PREVIEW PIN_CATEGORY_STILL PIN_CATEGORY_TELETEXT PIN_CATEGORY_TIMECODE PIN_CATEGORY_VBI PIN_CATEGORY_VIDEOPORT PIN_CATEGORY_VIDEOPORT_VBI PINNAME_VIDEO_CC_CAPTURE Description Input pin of the capture filter that takes analog and digitizes it. Capture pin. Pin providing closed captioning data from Line 21. Pin providing Extended Data Services (Line 21, even fields). Pin providing North American Videotext Standard data. Preview pin. Pin that provides a still image. The filter's capture pin must be connected before the still-image pin is connected. Pin providing teletext (a closed captioning variant). Pin providing timecode data. Pin providing vertical blanking interval data. Output pin to be connected to input pin zero on the Overlay Mixer. Pin to be connected to the VBI Surface Allocator, the VBI surface allocator filter that is needed to allocate the correct video memory for things like closed captioning overlays in scenarios where a video port is being used. PCI, IEEE 1394, and USB scenarios do not use this filter. For more information, see Microsoft TV Technologies. Hardware slicing closed-captioning pin 2. Graphe de capture Classe: CLSID_CaptureGraphBuilder2 Interface: IID_ICaptureGraphBuilder2 Cette classe de graphe expose des méthodes spécifiques destinées à faciliter la construction des graphes de capture. a. Utilisation de base En utilisation basique, le CaptureGraphBuilder s'utilise en quatre phases: 1. Créer l'objet CaptureGraphBuilder (CoCreateInstance). 2. Fixer le nom du fichier de sortie (ICaptureGraphBuilder2::SetOutputFileName) cela permet de créer automatiquement le Muxer et le FileSinker nécessaire à la sauvegarde du flux. 3. Insérer ce filtre dans le graphe contrôlé par le CaptureGraphBuilder (après avec récupéré un pointeur sur ce dernier dans le CaptureGraphBuilder). 4. Avec le CaptureGraphBuilder, pour chaque type de flux (audio et/ou vidéo), effectuer un rendu du flux vers le Muxer. Il est possible d'ajouter un codec intermédiaire de compression. ICaptureGraphBuilder2::SetOutputFileName Remarques: • LPCOLESTR est pareil qu'un LPWSTR. Page 34/71 Université de Reims Champagne-Ardennes Programmation Multimédia • • • Master d'Informatique 2004-2005 cette méthode associe un graphe au ICaptureGraphBuilder2 (i.e. la graphe n'est pas associé à la création du CaptureGraphBuilder). le Mux permet de mélanger les flux audio et vidéo. Il faudra effectuer les connections pour chacun de ces flux. le FileSinker est connecté sur le Mux, et permet de sauvegarder le flux en sortie du Mux. ICaptureGraphBuilder2::GetFiltergraph ICaptureGraphBuilder2::RenderStream Examples // Vidéo: pBuilder->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video, pCaptureFilter, NULL, NULL); // Audio: pBuilder->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Audio, pCaptureFilter, NULL, NULL); pBuilder->SetOutputFileName(&MEDIASUBTYPE_Avi, L"C:\\Example.avi", &ppf, &pSink); pBuilder->RenderStream(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, pCaptureFilter, NULL, ppf); pBuilder->RenderStream(NULL, NULL, pSrc, pCompressor, pMux); pBuilder->RenderStream(NULL, NULL, pSrc, NULL, pMux); c. Utilisation avancée • AllocCapFile et CopyCaptureFile pour créer des caches • FindInterface et FindPin pour retrouver une interface ou une borne dans le graphe de capture. ICaptureGraphBuilder2::FindPin Syntaxe : HRESULT FindPin(IUnknown *pSource, PIN_DIRECTION pindir, const GUID *pCategory, const GUID *pType, BOOL fUnconnected, int num, IPin **ppPin); Cette méthode peut remplacer avantageusement la fonction GetIthPin donnée dans la partie sur la construction d'un graphe. Exemple: liste de toutes les bornes d'entrée audio disponible sur un dispositif de capture. UINT i=0; do { IPin *Pin = NULL; h = Capture->FindPin(Stream,PINDIR_INPUT, NULL,&MEDIATYPE_AnalogAudio,TRUE,i,&Pin); Page 35/71 Université de Reims Champagne-Ardennes Programmation Multimédia Master d'Informatique 2004-2005 if (h == S_OK) { ViewPinInfo(Pin,i+1); SAFE_RELEASE(Pin); } else printf("FindPin %s\n",DXGetErrorString9(h)); i++; } while(h == S_OK); 2. Capture audio a. Exemple: enregistrement à partir d'un micro dans un fichier Dans ce cas, une construction manuelle est obligatoire car le filtre WavDest n'est pas considéré comme le muxer approprié par défaut (fait pour l'enregistrement vidéo). IGraphBuilder ICaptureGraphBuilder2 IBaseFilter IFileSinkFilter CoInitialize (NULL); *Graph = NULL; *Capture = NULL; *Stream, *WavDest, *FileWriter; *Sink; // GraphBuilder et Graph CoCreateInstance (CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC,IID_ICaptureGraphBuilder2,(void **)&Capture); CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&Graph); Capture->SetFiltergraph(Graph); // Récupération du filtre de capture FiltersEnumerator(CLSID_AudioInputDeviceCategory,0); Stream = GetIthFilterInClass(0,CLSID_AudioInputDeviceCategory,0); Graph->AddFilter(Stream,L"Micro"); // Création du filtre muxer pour l'audio CoCreateInstance(CLSID_WavDest, NULL, CLSCTX_INPROC, IID_IBaseFilter, (void **) &WavDest); Graph->AddFilter(WavDest,L"WaveDest"); // Connexion du filtre de capture et de muxer audio Capture->RenderStream(&PIN_CATEGORY_CAPTURE,&MEDIATYPE_Audio, Stream,NULL,WavDest); // Création du filewriter pour l'audio CoCreateInstance(CLSID_FileWriter, NULL, CLSCTX_INPROC, IID_IBaseFilter, (void **) &FileWriter); Graph->AddFilter(FileWriter,L"FileWriter"); FileWriter->QueryInterface(IID_IFileSinkFilter, (void**)&Sink); Sink->SetFileName(L"test.wav",NULL); // Connexion du muxer audio et du filewriter IPin *Pout,*Pin; Pout = GetPin(WavDest,PINDIR_OUTPUT); Pin = GetPin(FileWriter,PINDIR_INPUT); Graph->Connect(Pout,Pin); SAFE_RELEASE(Pin); SAFE_RELEASE(Pout); Page 36/71 Université de Reims Champagne-Ardennes Programmation Multimédia Master d'Informatique 2004-2005 b. Configuration d'une entrée audio Un filtre d'entrée associé à un périphérique matériel qui permet une capture audio expose: • une borne d'entrée nommée généralement "Microphone", "Line In", … On ne peut pas connecter de filtre à cette borne. Elle représente l'entrée physique sur le périphérique. C'est cette borne qui est configurable avec l'interface IAMAudioInputMixer. • une borne de sortie "Capture". C'est sur cette borne que l'on récupère le flux en provenance du dispositif de capture audio. Le choix et la configuration des entrées audio s’effectuent avec l'interface IAMAudioInputMixer. Elle permet de fixer les propriétés suivantes d'une borne d'entrée audio. • • • • • • • Enable : activation/désactivation. Mono : mode mono ou multicanal. Mixlevel : niveau de d'enregistrement pour cette borne (ou gain automatique). Pan : balance (dans le cas d'une entrée multicanal). Treble : aiguë Bass : basse Loudness : boost des basses Attention: toutes ces propriétés ne peuvent pas nécessairement être réglées pour le périphérique en question. Les méthodes peuvent alors retourner E_NOTIMPL pour indiquer que la fonction n'est pas implémentée, E_FAIL si elle n'est pas disponible, … Page 37/71 Université de Reims Champagne-Ardennes Programmation Multimédia Master d'Informatique 2004-2005 Exemple : active la troisième entrée IPin *Pin = NULL; h = Capture->FindPin(Stream,PINDIR_INPUT,NULL,&MEDIATYPE_AnalogAudio, TRUE,2,&Pin); if (h == S_OK) { IAMAudioInputMixer *InputMixer = NULL; Pin->QueryInterface(IID_IAMAudioInputMixer,(void**)&InputMixer); InputMixer->put_Enable(TRUE); InputMixer->put_Mono(TRUE); InputMixer->put_MixLevel(1.0); SAFE_RELEASE(InputMixer); SAFE_RELEASE(Pin); } c. Configuration du format de la sortie IAMStreamConfig permet de connaître les formats de capture disponibles ainsi que de configurer le périphérique. Cela s'effectue en plusieurs étapes: 1. Récupérer la borne de sortie audio du dispositif de capture. Utiliser ICaptureGraphBuilder2::FindPin 2. Récupérer l'interface IAMStreamConfig de la borne (avant de la connecter). 3. Choisir l'un des modes disponibles GetNumberOfCapabilities pour récupérer le nombre de mode disponible, GetStreamCaps pour lire le ième mode. 4. Fixer le mode choisi avec SetFormat. Notons que de manière plus générique, IAMStreamConfig peut être exposé par toutes les bornes de sortie d'un graphe, permettant ainsi de changer le format en cours de traitement. Exemple de code lisant les modes d'enregistrement disponibles: IAMStreamConfig *Config = NULL; h = Capture->FindPin(Stream,PINDIR_OUTPUT,NULL,&MEDIATYPE_Audio, TRUE,0,&Pin); h = Pin->QueryInterface(IID_IAMStreamConfig,(void**)&Config); if (h != S_OK) return E_FAIL; int ncaps = 0, capsz = 0; Config->GetNumberOfCapabilities(&ncaps,&capsz); printf("%d availables modes\n",ncaps); // Comme il s'agit d'audio: capsz = sizeof(AUDIO_STREAM_CONFIG_CAPS) for(int i=0;i<ncaps;i++) { AM_MEDIA_TYPE *am; AUDIO_STREAM_CONFIG_CAPS cf; Config->GetStreamCaps(i,&am,(BYTE*)&cf); if (i==0) ViewSoundFormat(cf); ViewMediaType(*am); DeleteMediaType(am); } SAFE_RELEASE(Config); Page 38/71 Université de Reims Champagne-Ardennes Programmation Multimédia Master d'Informatique 2004-2005 Les fonctions ViewSoundFormat(…) et ViewMediaType(…) sont écrites par l'utilisateur et permettent respectivement d'afficher le contenu de: • la structure AUDIO_STREAM_CONFIG_CAPS qui contient les plages de variation: o du nombre de canaux disponibles o du nombre de bits par échantillon o de la fréquence d'échantillonnage • la structure AM_MEDIA_TYPE qui contient une description du format utilisé (déjà vu), et qui dans le cas des médias de type son, contient une structure WAVEFORMATEX. Exemple de sortie avec ce code: Audio: (AUDIO_STREAM_CONFIG_CAPS) Channels = 1:1:2 BitsPerSample = 8:8:16 SampleFrequency= 11025:11025:44100 Mode FixSz Comp Sz Format (AM_MEDIA_TYPE + WAVEFORMATEX) PCM audio true false 4 2 x 16 bits @ 44100 Hz (Format=PCM) PCM audio true false 2 1 x 16 bits @ 44100 Hz (Format=PCM) PCM audio true false 4 2 x 16 bits @ 32000 Hz (Format=PCM) PCM audio true false 2 1 x 16 bits @ 32000 Hz (Format=PCM) PCM audio true false 4 2 x 16 bits @ 22050 Hz (Format=PCM) PCM audio true false 2 1 x 16 bits @ 22050 Hz (Format=PCM) PCM audio true false 4 2 x 16 bits @ 11025 Hz (Format=PCM) PCM audio true false 2 1 x 16 bits @ 11025 Hz (Format=PCM) PCM audio true false 4 2 x 16 bits @ 8000 Hz (Format=PCM) PCM audio true false 2 1 x 16 bits @ 8000 Hz (Format=PCM) PCM audio true false 2 2 x 8 bits @ 44100 Hz (Format=PCM) PCM audio true false 1 1 x 8 bits @ 44100 Hz (Format=PCM) PCM audio true false 2 2 x 8 bits @ 32000 Hz (Format=PCM) PCM audio true false 1 1 x 8 bits @ 32000 Hz (Format=PCM) PCM audio true false 2 2 x 8 bits @ 22050 Hz (Format=PCM) PCM audio true false 1 1 x 8 bits @ 22050 Hz (Format=PCM) PCM audio true false 2 2 x 8 bits @ 11025 Hz (Format=PCM) PCM audio true false 1 1 x 8 bits @ 11025 Hz (Format=PCM) PCM audio true false 2 2 x 8 bits @ 8000 Hz (Format=PCM) PCM audio true false 1 1 x 8 bits @ 8000 Hz (Format=PCM) PCM audio true false 4 2 x 16 bits @ 48000 Hz (Format=PCM) PCM audio true false 2 1 x 16 bits @ 48000 Hz (Format=PCM) PCM audio true false 4 2 x 16 bits @ 96000 Hz (Format=PCM) PCM audio true false 2 1 x 16 bits @ 96000 Hz (Format=PCM) On remarque que l'énumération complète fournit plus de modes (indiqués en bleu) que ceux prévus par AUDIO_STREAM_CONFIG_CAPS. Voir la documentation pour plus d'information. 3. Capture vidéo A noter qu'un filtre de capture vidéo peut avoir une borne de capture et une borne de preview. Afin d'éviter de perdre des frames lors de la capture, la perte de frame sur la borne de preview est autorisée si elle est nécessaire afin de garantir une bonne qualité sur la borne de capture. Il est donc conseillé de l'utiliser dans le cas d'une preview. Page 39/71 Université de Reims Champagne-Ardennes Programmation Multimédia Master d'Informatique 2004-2005 a. Configuration d'un dispositif de capture vidéo IAMVideoProcAmp permet de régler les caractéristiques de l'image capturée à savoir Brightness (luminosité), Contrast (contraste), Hue (teinte), Saturation (saturation), Sharpness (finesse), Gamma (gamma), ColorEnable (couleur), WhiteBalance (balance des blancs), BacklightCompensation (compensation du contre-jour), Gain. En 3 étapes: 1. Récupérer l'interface IAMVideoProcAmp sur le filtre de capture. Si l'interface n'est pas disponible, aucun réglage n'est possible. 2. Utiliser la méthode IAMVideoProcAmp::GetRange pour récupérer les plages de variations, le pas, … pour la propriétés souhaitées (en premier paramètre). Cette méthode renvoie E_PROP_ID_UNSUPPORTED si la propriété ne peut pas être réglé sur le périphérique considéré. 3. Utiliser IAMVideoProcAmp::Set/Get pour fixer ou lire le paramètre souhaité (toujours en premier paramètre). Exemple: affiche les propriétés disponibles et leurs échelles de variation const int nProp = 10; IAMVideoProcAmp *ProcAmp = NULL; VideoProcAmpProperty Prop[nProp]={ VideoProcAmp_Brightness, VideoProcAmp_Contrast, VideoProcAmp_Hue, VideoProcAmp_Saturation, VideoProcAmp_Sharpness, VideoProcAmp_Gamma, VideoProcAmp_ColorEnable, VideoProcAmp_WhiteBalance, VideoProcAmp_BacklightCompensation, VideoProcAmp_Gain }; const char StrProcAmp[nProp][30] = { "Brightness","Contrast","Hue","Saturation","Sharpness","Gamma", "ColorEnable","WhiteBalance","BacklightCompensation","Gain" }; h = Pin->QueryInterface(IID_IAMVideoProcAmp, (void **)&Stream); if (h==S_OK) { for(int i=0;i<nProp;i++) { long min,max,delta,defaut,flag; h = ProcAmp->GetRange(Prop[i],&min,&max,&delta,&defaut,&flag); if (h!=S_OK) continue; printf("%s : %d:%d:%d def=%d %s%s%s\n", StrProcAmp[i],min,delta,max,defaut, (VideoProcAmp_Flags_Auto & flag ? "auto" : ""), (VideoProcAmp_Flags_Manual & flag ? "manual" : "")); } SAFE_RELEASE(ProcAmp); b. Configuration du format de la sortie Pareil que pour l'audio: utiliser l'interface de IAMStreamConfig (permet aussi de lire les modes disponibles et de fixer les modes de sortie). Page 40/71 Université de Reims Champagne-Ardennes Programmation Multimédia Master d'Informatique 2004-2005 A noter l'interface IAMVfwCaptureDialogs pour les périphériques à la norme VfW qui permet de choisir à travers une interface: la source de la vidéo, la format de la vidéo, et l'affichage de la vidéo (son apparence). c. Autre dispositif de configuration Les filtres de capture CLSID_VfwCapture exposent l'interface IAMVfwCaptureDialogs qui permettent d'accéder à l'interface utilisateur ShowDialog (3 boîtes de dialogue éventuellement possibles si elles sont implémentées: Source, Format, Display). 5. Autres dispositifs de capture Voir les annexes pour voir comment traiter: • • Page 41/71 un caméscope. un tuner TV. Université de Reims Champagne-Ardennes Programmation Multimédia Master d'Informatique 2004-2005 Contrôle du rendu • NULL Renderer Rendu rapide: pour faire en sorte que le flux traverse le graphe le plus rapidement possible. • Horloge du graphe Lorsque vous construisez un graphe, le manager choisi automatiquement une horloge de référence. Tous les filtres du graphe sont synchronisés sur celle-ci. En particulier, les filtres de rendus l’utilisent pour connaître le temps d’affichage d’un sample. Il n’y a généralement aucune raison pour modifier l’horloge choisie par le manager. Cependant, vous pouvez le faire avec la méthode SetSyncSource de l’interface IMediaFilter, lorsque le graphe est arrêté. Exemple : IGraphBuilder *pGraph = 0; IReferenceClock *pClock = 0; CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&pGraph); // Build the graph. pGraph->RenderFile(L"C:\\Example.avi", 0); // Create your clock. hr = CreateMyPrivateClock(&pClock); if (SUCCEEDED(hr)) { // Set the graph clock. IMediaFilter *pMediaFilter = 0; pGraph->QueryInterface(IID_IMediaFilter, (void**)&pMediaFilter); pMediaFilter->SetSyncSource(pClock); pClock->Release(); pMediaFilter->Release(); } Cet exemple suppose que la fonction CreateMyPrivateClock crée une horloge et renvoie un pointeur sur IReferenceClock. Vous pouvez également la supprimer en mettant la valeur NULL à SetSyncSource. Ceci permet de traiter les données aussi vite qu’elles arrivent. Page 42/71 Université de Reims Champagne-Ardennes Programmation Multimédia Master d'Informatique 2004-2005 Debug de DirectShow Utilisation d’un fichier de trace La méthode IGraphBuilder::SetLogFile permet de spécifier un fichier qui contiendra les traces relatives à la construction et à l'utilisation du graphe spécifié. // Initialisation du fichier de trace LPCTSTR LogFile = TEXT("trace.log"); HANDLE hRenderLog=INVALID_HANDLE_VALUE; hRenderLog = CreateFile(LogFile, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, 0, NULL); SetFilePointer(hRenderLog, 0, NULL, FILE_END); if (hRenderLog != INVALID_HANDLE_VALUE) pGRAPH->SetLogFile((DWORD_PTR) hRenderLog); // Ici les opérations sur lesquelles ont souhaite des traces ... // Fin des traces pGRAPH-> SetLogFile(NULL); CloseHandle(hRenderLog); hRenderLog = INVALID_HANDLE_VALUE; Attention: le fichier résultat contient les traces au format Unicode. Page 43/71 Université de Reims Champagne-Ardennes Programmation Multimédia Master d'Informatique 2004-2005 Annexe A: Montage Vidéo 1) Introduction DirectShow Editing Services (DES) est une API (Application Programming Interface) qui simplifie grandement les tâches nécessaires à l’édition vidéo. DES est construite sur le cœur de l’architecture DirectShow, et fournit un ensemble d’interfaces conçues spécifiquement pour développer des projets d’édition vidéo. Voici quelques caractéristiques de DES : Un ordonnancement temporel (modèle de la Timeline) qui organise les pistes audio et vidéo en couches La possibilité de voir le résultat du montage en temps réel L’enregistrement et le chargement de projets sous forme de fichiers XML La gestion d’effets audio et vidéo, ainsi que de transitions entre clips vidéo Plus de 100 transitions standard disponibles, définis par la SMPTE (Society of Motion Picture and Television Engineers) La conversion automatique du nombre d’images par seconde, et de l’échantillonnage audio, cela permet d’utiliser des sources hétérogènes Le redimensionnement ou le recadrage de la vidéo Voici l’architecture de DirectShow Editing Services : - Page 44/71 Timeline : Organise le montage vidéo sous formes de pistes audio et vidéo où sont insérés des extraits (ayant comme origine un fichier), des transitions, des effets. XML Parser : Génère un fichier à partir d’une Timeline, ou bien construit une Timeline à partir d’un fichier. Render Engine : Moteur de rendu : produit un graphe des filtres complet à partir d’une Timeline. Pour visionner le résultat du montage, il n’y a plus qu’à lancer le graphe. Université de Reims Champagne-Ardennes Programmation Multimédia - Master d'Informatique 2004-2005 Media Locator : Gère une mémoire cache des répertoires où se trouvent les éléments média insérés. Quand une tentative de lecture d’un élément échoue, DES utilise le cache pour trouver l’élément, basé sur un historique des tentatives réussies. La Timeline est une description abstraite d’un projet de montage vidéo. Elle permet de spécifier les extrait vidéo ou audio utilisés dans le projet, les instants de début et de fin, les effets et les transitions, et bien d’autres choses. La Timeline n’effectue pas de rendu des flux audio et vidéo. A la place, le moteur de rendu (Render Engine) construit un graphe des filtres à partir d’une Timeline, pour le rendu ou l’enregistrement du résultat dans un fichier. Une application de montage vidéo manipule une Timeline plutôt que directement le graphe des filtres, ce qui serait lourd et source d’erreurs. Voici les principales tâches que l’on aurait envie de faire avec DES, ainsi que les interfaces qui nous permettent d’y arriver : Construire ou modifier une Timeline : IAMTimeline et toutes les interfaces de la forme IAMTimelineXXXX Charger ou sauvegarder des projets : IXml2Dex Voir le résultat d’un projet ou le sauvegarder : IRenderEngine, ISmartRenderEngine Connaître les information d’un fichier média : IMediaDet Définir les propriétés d’un effet ou d’une transition : IPropertySetter Nous allons maintenant entrer dans le vif du sujet en nous intéressant au modèle de la Timeline. 2) Architecture d’une composition vidéo : modèle de la Timeline Une Timeline est l’objet de base pour un projet de montage vidéo. Elle est destinée à contenir tous les objets utilisés dans le montage (échantillons vidéo, sonores, effets, transitions), et définit une échelle de temps, ou chronologie, pour le placement de tous ces objets. DES utilise une structure en arbre pour la construction d’une Timeline : Les échantillons audio et vidéo forment les feuilles (extrémités de l’arbre). On les appelle les objets sources. Un ensemble de sources d’un même type forme une piste (track). Un ensemble de pistes forme une composition. Un groupe contient une composition mère qui peut contenir plusieurs compositions filles. Il y a un groupe par types de média. Un ensemble de plusieurs groupes forme une Timeline. Généralement, une Timeline contient deux groupes : l’un pour le son, l’autre pour la vidéo. Page 45/71 Université de Reims Champagne-Ardennes Programmation Multimédia Master d'Informatique 2004-2005 Une Timeline contient au moins un groupe. Chaque groupe constitue un flux à part entière dans la composition finale. Voici une illustration de la structure d’une Timeline afin de bien comprendre le principe : La figure suivante montre qu’une Timeline a aussi le rôle d’ordonner les éléments par rapport à l’axe du temps : L’intérêt de disposer de plusieurs pistes (tracks) est visible ici : chacune a une priorité différente des autres. Ici, la piste 1 a une priorité plus grande que la piste 0. A chaque niveau de priorité, l’échantillon source dans une piste masque les échantillons dans les pistes de priorités moindres, sauf dans le cas particulier des transitions. Ainsi, dans cet exemple, pour ce qui est du groupe audio, DES va sélectionner le début de la source D, puis la source E, puis la fin de la source D. Lorsqu’il n’y a pas d’éléments sur la piste de priorité la plus élevée, elle ne masquera pas la piste de priorité moindre et ainsi de suite. 3) Gestion du temps Page 46/71 Université de Reims Champagne-Ardennes Programmation Multimédia Master d'Informatique 2004-2005 Dans DES, on doit à de nombreuses reprises travailler avec des informations temporelles. Mais leur sens n’est pas toujours le même. Il faut à chaque fois réfléchir au référentiel dans lequel on travaille. Les trois référentiels différents sont : - - La Timeline : Le temps est exprimé par rapport au début de la Timeline (qui est l’instant t = 0). Ce référentiel est utilisé lorsque l’on insère un objet dans la Timeline, pour définir à quel instant de la Timeline on l’insère. L’échantillon source : Le temps est exprimé par rapport au début du fichier. Par exemple t = 5s correspond à la moitié d’une vidéo d’une durée de 10 secondes. On l’utilise pour définir quelle portion du média, contenue dans un fichier, on veut insérer dans la Timeline (par exemple les 5 premières secondes). L’objet parent : Le temps est exprimé pour une source par rapport à une autre source. Par exemple, si un objet démarre à t = 8s sur la Timeline et contient un autre objet qui démarre à t = 10s sur la Timeline, l’objet fils démarre à t = 2s dans le référentiel de l’objet parent. Lorsque l’on veut changer le nombre d’images par seconde d’une vidéo (« framerate ») c’est-à-dire augmenter la vitesse de lecture ou la diminuer, il faut choisir de spécifier des instants appropriés. Par exemple, pour jouer une vidéo de 10 secondes en seulement 5 secondes entre les instants t1 = 20 et t2 = 25 de la Timeline, il suffit de prendre la totalité de la vidéo (de t = 0 à t = 10 dans le référentiel de la source) puis de l’insérer entre les instants t = 20 et t = 25 de la Timeline. La conversion de « framerate » se fera automatiquement. 4) Application d’effets et de transitions Un effet s’applique sur une seule source, tandis qu’une transition s’effectue entre deux sources, donc entre deux pistes différentes. Pour appliquer un effet, il suffit d’ajouter un objet de type effet à une piste en spécifiant à quel moment débute l’effet et à quel moment il se termine. Si aucune source n’est placée dans cet intervalle, l’effet n’aura aucun résultat visible. Voici un exemple de composition qui montre comment on doit placer une transition : Page 47/71 Université de Reims Champagne-Ardennes Programmation Multimédia Master d'Informatique 2004-2005 Le premier cadre bleu montre comment ont été insérés les éléments sur la Timeline, et le deuxième montre le résultat que l’on obtiendra. Puisque deux sources ne peuvent se chevaucher sur une même piste, deux pistes sont nécessaires. La transition, pour s’appliquer, doit chevaucher la fin de la source A et le début de la source C. La source C doit chevaucher une partie de la source A et inversement. Le placement des sources sur les pistes associées est très important puisque la piste 1 a une priorité plus grande que la piste 0. De même, le sens de la transition est important. Le comportement par défaut est le passage de la piste de priorité moins importante à la plus importante (de la piste 0 à la piste 1). Par exemple, si l’on avait voulu placer une transition pour passer progressivement de la source C à la source B, il aurait fallu modifier une propriété de l’objet transition pour changer le sens de transition (de la piste 1 à la piste 0). 5) Architectures des interfaces de DES Les diverses interfaces qui permettent de construire une Timeline et d’y ajouter des éléments sont liées entre elles à la manière du système de hiérarchie de classes en C++. Les interfaces mères présentent des méthodes assez générales, tandis que les filles fournissent des méthodes appropriées dans le cas d’objets précis. Voici la hiérarchie de ces interfaces : Page 48/71 Université de Reims Champagne-Ardennes Programmation Multimédia Master d'Informatique 2004-2005 IUnknown IAMTimelineObj IAMTimelineGroup IAMTimelineComp IAMTimelineTrack IAMTimelineTransable IAMTimelineEffectable IAMTimelineSrc IAMTimelineTrans IAMTimelineEffect 6) Ordre dans la création d’un projet Lorsque l’on crée une Timeline, il faut respecter un certain ordre. Ainsi on crée d’abord un objet Timeline, puis un objet Groupe, puis un objet Composition, puis un objet Piste, et enfin un objet Source, un objet Transition, ou un objet Effet. Cela se comprend aisément au vu de l’architecture de la Timeline vu plus haut. De plus, il est préférable, pour une question de lisibilité du code de créer et de manipuler une seule piste à la fois (il serait bien sûr possible d’en manipuler plusieurs, en créant plusieurs instances de l’interface IAMTimelineTrack). 7) Comment s’utilise chaque élément Je ne décrirai pas ici chaque interface car elles ont chacune de nombreuses fonctions et toutes ne sont pas utiles pour la majorité de ce que l’on veut faire. Nous verrons les fonctions incontournables et leur intérêt. 1. Timeline Page 49/71 Université de Reims Champagne-Ardennes Programmation Multimédia Master d'Informatique 2004-2005 Pour créer une Timeline, on affecte l’interface IAMTimeline grâce à CoCreateInstance() comme nous l’avons vu pour les interfaces de base du rendu vidéo. D’une manière générale, les interfaces d’objets « de base » s’affectent de cette manière, pour les interfaces plus précises, c’est en effectuant un QueryInterface() sur l’interface « mère ». 2. Objets d’une Timeline Pour chaque objet d’une Timeline (groupe, composition, piste, source, transition, effet), il faut utiliser l’interface IAMTimelineObj. On l’affecte grâce à la fonction CreateEmptyNode() de l’interface IAMTimeline définie précédemment. On fournit en paramètre de cette fonction, outre le pointeur sur l’interface IAMTimelineObj à affecter, le type d’objet (groupe, piste, …) que l’on veut créer. 3. Groupe Après avoir créé un objet avec l’interface générique IAMTimelineObj, on affecte l’interface particulière pour l’objet créé. Pour un objet groupe, il s’agit de l’interface IAMTimelineGroup. On l’affecte en appelant QueryInterface() sur l’interface IAMTimelineObj. IAMTimelineGroup contient des méthodes spécialement utiles pour les groupes. On utilise SetMediaType() afin de définir un type de média pour le groupe. Généralement, on ne remplit que le champ majortype de la structure AM_MEDIA_TYPE passé en paramètre. Ce champ indique seulement si le groupe contiendra des flux audio ou vidéo. En modifiant les autres champs, il est possible de définir un format très précis pour le groupe. Si l’on cherche par la suite à insérer une source de type différent, cela produira une erreur. Une fois que l’on a défini tout ce que l’on voulait sur l’objet groupe, on l’insère dans la Timeline en appelant IAMTimeline::AddGroup(). 4. Composition L’interface pour les compositions, IAMTimelineComp, s’affecte en effectuant un QueryInterface() sur l’interface IAMTimelineGroup (voire plus haut dans la partie architecture des interfaces de DES). 5. Piste Une fois l’objet générique de type piste (IAMTimelineObj) créé, on l’insère dans la composition grâce à la fonction IAMTimelineComp::VTrackInsBefore() en lui spécifiant l’ordre de priorité de cette piste par rapport aux autres. Après cela, on affecte l’interface particulière IAMTimelineTrack avec la fonction QueryInterface() de l’interface IAMTimelineObj. 6. Sources L’interface IAMTimelineSrc est affectée avec IAMTimelineObj::QueryInterface(). Cette interface va particulièrement nous servir à Page 50/71 Université de Reims Champagne-Ardennes Programmation Multimédia Master d'Informatique 2004-2005 définir le fichier source que l’on insère (chemin) avec la fonction IAMTimelineSrc::SetMediaName(). Ensuite, on définit la portion de média que l’on insère : IAMTimelineSrc::SetMediaTimes(), en passant en paramètre l’instant de début et l’instant de fin par rapport au fichier. Puis, on définit à quel endroit de la Timeline on insère le clip : IAMTimelineObj::SetStartStop(). Les instants début et fin passés en paramètres sont exprimés par rapport à la Timeline. Finalement, on insère la source dans la piste : IAMTimelineTrack::SrcAdd(). 7. Transitions et effets Après la création de l’objet générique, on appelle la fonction SetSubObjectGUID() où l’on spécifie le GUID de la transition choisie. Le GUID du lot de transitions standard est CLSID_DxtJpeg. Ensuite, on définit à quel endroit de la Timeline on insère la transition : IAMTimelineObj::SetStartStop(). Pour insérer la transition dans la piste, on a besoin de l’interface IAMTimelineTransable. On l’obtient grâce à IAMTimelineTrack::QueryInterface(). On appelle ensuite la fonction IAMTimelineTransable::TransAdd(). Si l’on veut modifier le sens par défaut de la transition (piste n à piste n-1), il faut appeler l’interface IAMTimelineTrans et sa fonction SetSwapInputs(). Les effets fonctionnent à peu de choses près de la même manière que les transitions, nous n’allons donc pas en parler ici. Pour plus de détails, vous pouvez aller voir le code source de l’exemple qui utilise les effets : DESCompo3. 8) Rendu du projet Comme nous l’avons vu précédemment, l’interface IRenderEngine est dédiée à la construction d’un graphe à partir d’un projet de montage vidéo. Pour ce faire, on commence par indiquer à l’interface quelle Timeline on utilise : SetTimelineObject(). Puis on lui demande de construire le graphe avec les deux fonctions : ConnectFrontEnd() et RenderOutputPins(). La première insère tous les filtres sauf les filtres de rendu. Cela permet, si on le souhaite, d’insérer d’autres filtres de rendu que ceux qui sont utilisés par défaut, cela permet aussi d’insérer un filtre d’enregistrement dans un fichier… RenderOutputPins() insère les filtres de rendu et les connecte au reste du graphe. Le graphe étant complètement construit, on lui affecte une interface avec GetFilterGraph(). Ensuite il n’y a plus qu’à lancer le graphe avec l’interface IMediaControl comme déjà vu dans la partie sur le rendu vidéo. Je vous invite à examiner les programmes qui ont été fait avec DES : DESCompo1, 2 et 3. DES se révèle vraiment être un environnement simple et agréable pour le montage vidéo, une fois que l’on a assimilé les concepts. Ceux-ci sont relativement bien expliqués dans la documentation de DirectShow. Page 51/71 Université de Reims Champagne-Ardennes Programmation Multimédia Master d'Informatique 2004-2005 Annexe B: Contrôle d'un caméscope 1) Vidéo numérique et fichiers AVI Jusqu’à présent, nous n’avions pas besoin de nous préoccuper du type du fichier AVI que nous créions lors de la capture avec une webcam. Et de toute façon, je ne connaissait pas moi-même l’existence de plusieurs types de fichier. Or, je me suis aperçu, grâce à la recherche effectuée sur les flux qui transitent à travers un caméscope numérique, qu’il existe deux types de fichier. Dans les sections précédentes qui traitaient de la webcam, nous utilisions, sans le savoir, le type 2 (voir plus loin). A partir de maintenant, il est important de distinguer les deux types. En effet, il est obligatoire d’utiliser le type 1 (voir plus loin) lorsque l’on veut travailler avec un caméscope numérique. La vidéo numérique (type 1), « Digital video » (DV) en anglais, peut provenir de plusieurs types. Elle peut être capturée à partir d’un caméscope numérique, stockée dans un fichier sur le disque dur, ou stockée sur une cassette en utilisant un caméscope numérique. A partir de là, plusieurs types d’opérations peuvent s’effectuer sur un flux numérique, à savoir: • • • • • • • Capturer la vidéo à partir d’une caméra. Transmettre le contenu d’une cassette dans un fichier sur l’ordinateur. Transmettre un fichier de l’ordinateur sur une cassette. Lire des données numériques à partir d’un fichier. Ecrire des données numériques dans un fichier. Visionner et écouter les flux vidéo et audio d’un flux numérique. Convertir un fichier d’un type vers l’autre. DirectShow fourni ces quelques filtres qui nous permettent de réaliser l’ensemble de ses tâches: • • • • • Le filtre « MSDV Driver ». Ce filtre contrôle un périphérique numérique, comme un caméscope. En général, le caméscope comporte deux parties ; la caméra et la cassette. Ce filtre permet de contrôler les deux. Le filtre « DV Splitter ». Un flux numérique contient à la fois un (ou deux) flux audio et un flux vidéo. Ce filtre permet de séparer les flux. Le filtre « DV Muxer ». Il est le contraire du filtre « DV Splitter ». Le filtre « DV Video Decoder ». Il permet de convertir un flux numérique en un flux vidéo non compressé. Le filtre « DV Video Encoder ». Il est le filtre contraire du « DV Video Decoder ». Les filtres « DV Splitter » et « DV Video Decoder » fonctionnent ensemble. Page 52/71 Université de Reims Champagne-Ardennes Programmation Multimédia Master d'Informatique 2004-2005 Bien entendu, pour le processus inverse, il faut utiliser les filtres « DV Video Encoder » et « DV Muxer ». 2) Les types de fichiers AVI Les caméscopes numériques produisent des flux numériques entrelacés. Si vous voulez enregistrer un tel flux sur le disque, vous avez le choix: • • Stocker les données telles quelles avec un seul flux. Ceci est le type 1. Stocker les données dans deux flux audio et vidéo séparés. Ceci est le type 2. Pour la capture vidéo, où la rapidité est importante, il est préférable d’utiliser le type de fichier 1. En effet, les fichiers de type 2 comportent un flux audio redondant. (Le flux vidéo contient toujours les données audio mais elles sont simplement cachées en nommant le flux vidéo.) De plus, écrire un fichier de type 2 requière du temps processeur supplémentaire pour séparer les flux. D’un autre côté, les fichiers de type 1 sont moins adaptés aux applications effectuant de l’édition en temps réel. L’application doit d’abord extraire le flux audio, effectuer les opérations d’édition puis ré-entrelacer les flux. De plus, le format type 1 n’est pas compatible avec le modèle VfW. Un fichier de type 2 peut être convertit un type 1 grâce au filtre « DV Muxer ». A l’inverse, le filtre « DV Splitter » convertit un fichier de type 1 en type 2. (Voir les codes « Sources\2 - Caméscope Numérique\AVI1_to_AVI2 » et « Sources\2 - Caméscope Numérique\ AVI2_to_AVI1 ».) Page 53/71 Université de Reims Champagne-Ardennes Programmation Multimédia Master d'Informatique 2004-2005 2.a) Capturer du caméscope à un fichier AVI Maintenant, nous voulons effectuer la même chose qu’avec une webcam mais en utilisant un caméscope numérique. Cette section décrit comment faire pour capturer une vidéo numérique à partir d’un caméscope ou d’une casette (insérée dans le caméscope.) Voici les étapes à suivre : 1. Créer une instance du filtre « MSDV Driver ». (Voir section « Sélectionner un périphérique de capture ».) 2. Initialiser le constructeur de graphe de capture. (Voir section « A propos du constructeur de graphe de capture ».) 3. Construire le graphe de capture dépendant du type de fichier voulu: • Capturer un fichier de type 1. • Capturer un fichier de type 2. 4. Lancer le graphe. • Capturer un fichier de type 1 Un fichier type 1 ne contient qu’un seul flux entrelacé. Pour capturer un fichier de type 1 et le prévisualiser en même temps, voici le graphe à construire : Les filtres contenus dans se graphe sont : Page 54/71 Université de Reims Champagne-Ardennes Programmation Multimédia • • • • Master d'Informatique 2004-2005 Le filtre « Smart Tee » divise le flux en deux flux pour la capture et la prévisualisation. Les deux flux contiennent le même flux entrelacé. Les filtres « AVI Mux » et « File Writer » écrivent le flux entrelacé sur le disque dur. Le filtre « DV Splitter » sépare le flux entrelacé en deux flux vidéo et audio. Les deux servent à la prévisualisation. Le filtre « DV Video Decoder » décode le flux numérique pour la prévisualisation. Voir le code « Sources\2 - Caméscope Numérique\camera_to_AVI1 ». • Capturer un fichier de type 2 Un fichier type 2 comporte deux flux, un qui contient la vidéo numérique et l’autre qui contient l’audio. Pour capturer un fichier de type 2 et le prévisualiser en même temps, voici le graphe à construire: Ce graphe est sensiblement identique au précédent pour capturer un fichier de type 1. La seule différence, c’est que le flux de capture passe à travers le filtre « DV Splitter » avant de passer dans le filtre « AVI Mux ». De ce fait, le filtre « AVI Mux » reçoit deux flux : un audio et un vidéo encodé. Voir le code « Sources\2 - Caméscope Numérique\camera_to_AVI2 ». • Capturer à partir d’une cassette Ce qui précède dans cette section explique comment capturer un flux à partir d’un caméscope numérique. (On l’utilisait donc comme un webcam.) Maintenant, nous allons nous intéresser à créer un fichier AVI à partir d’un film qui se trouve sur une cassette. Avant de commencer, il est important de spécifier que le caméscope doit être en mode cassette et non pas en mode caméra. De toute façon, pendant l’initialisation de Page 55/71 Université de Reims Champagne-Ardennes Programmation Multimédia Master d'Informatique 2004-2005 l’application, il existe un moyen de faire cette vérification et d’informer l’utilisateur si besoin est. Cette vérification ce fait avec la fonction « IAMExtDevice::GetCapability » avec a valeur « ED_DEVCAP_DEVICE_TYPE. Si la fonction renvoi la valeur « ED_DEVTYPE_VCR », le périphérique est dans le bon mode et toutes les fonctions spécifiques au contrôle de la cassette sont disponible (play, stop, pause, …). Sinon, il est toujours possible d’utiliser le mode caméra uniquement. Capturer un film à partir d’une cassette fonctionne de la même manière que capturer à partir du caméscope. Donc, les graphes à construirent sont exactement identiques suivant le type de fichier désiré. La seule différence réside dans le fait, qu’il faut mettre la cassette en lecture. (Voir la section « Contrôler un caméscope numérique ».) Afin d’éviter de perdre quelques secondes au début ou/et à la fin du film, l’ordre des étapes est important : Il faut d’abord lancer le graphe puis jouer la casette. Après la transmission complète, il faut d’abord arrêter la casette puis le graphe. Voir les codes « Sources\2 - Caméscope Numérique\K7_to_AVI1 » et « Sources\2 - Caméscope Numérique\K7_to_AVI2 ». 2.b) Transmettre un fichier AVI sur une cassette Après avoir transformé un film d’un cassette en un fichier AVI, il est intéressant de pouvoir faire le contraire: transmettre un fichier AVI sur une cassette. Ceci ne peut se faire sans rencontrer une petite difficulté, en effet le fichier AVI en question peut être soit de type 1, soit de type 2… Voici les étapes à suivre: 1. Créer une instance du filtre « MSDV Driver ». 2. Initialiser le constructeur de graphe de capture. 3. Créer le graphe dépendant du type de fichier: • Transmettre à partir d’un fichier type 1. • Transmettre à partir d’un fichier type 2. 4. Mettre le caméscope en mode Enregistrement-Pause. (Voir section « Contrôler un caméscope numérique ».) 5. Mettre en pause le graphe. Dans ce mode, il graphe envoi en continu la première image du film. 6. Pour commencer à transmettre, mettre le caméscope en mode Enregistrement puis lancer le graphe. Le caméscope a besoin d’un certain temps pour ce être disposé à enregistrer, donc, il est préférable d’attendre deux ou trois secondes avant de lancer le graphe. Ceci peut aboutir à une duplication de quelques images au début du film mais assure qu’il n’en manquera pas. Page 56/71 Université de Reims Champagne-Ardennes Programmation Multimédia • Master d'Informatique 2004-2005 Transmettre à partir d’un fichier type 1 Pour transmettre un fichier de type 1 sur une casette en prévisualisant le film, il faut utiliser le graphe montré ci-dessous: Les filtres qui composent ce graphe sont: • • • Le filtre « AVI Splitter ». Pour un fichier de type 1, la sortie délivre un flux entrelacé. Le filtre « Infinite Pin Tee » divise le flux en deux flux pour la capture et la prévisualisation. Les deux flux sont entrelacés. (Ce graphe utilise le filtre « Infinite Pin Tee » à la place du filtre « Smart Tee », parce qu’il n’y a pas de danger de supprimer des images lorsque la source est un fichier, contrairement à une capture en live.) Le filtre « DV Splitter » sépare le flux entrelacé en un flux audio et un flux vidéo décodé par le filtre « DV Video Decoder ». Voir le code « Sources\2 - Caméscope Numérique\AVI1_to_K7 ». • Transmettre à partir d’un fichier type 2 Pour transmettre un fichier de type 1 sur une casette en prévisualisant le film, il faut utiliser le graphe montré ci-dessous: Page 57/71 Université de Reims Champagne-Ardennes Programmation Multimédia Master d'Informatique 2004-2005 Un fichier type 2 à deux flux, d’où l’utilité d’utiliser le filtre « DV Mux » pour le convertir un fichier de type 1. On peut remarquer que dans tous les cas, le caméscope ne peut recevoir et envoyer que des flux entrelacé, alors que pour la prévisualisation, il faut re-séparer les flux. Voir le code « Sources\2 - Caméscope Numérique\AVI2_to_K7 ». 3) Contrôler un caméscope numérique On a vu qu’il était possible d’utiliser le caméscope numérique comme une webcam “de luxe”. On a également vu qu’il était possible de lire ou d’enregistrer un film sur une cassette. Mais à proprement parler des paramètres du caméscope, nous n’avons encore rien vu. Le filtre de capture vidéo WDM propose cinq interfaces pour contrôler en globalité le caméscope numérique: • • • • • IAMExtDevice : une basique interface qui gère quelques fonctions. IAMCameraControl : permet de régler les paramètres du caméscope (zoom, focus, …) IAMExtTransport : cette interface contrôle le mode cassette (lecture, stop, …). IAMTimecodeReader : permet de savoir à quel endroit nous sommes sur la cassette. IAMTimecodeDisplay : permet de modifier l’affichage du caméscope. Afin de pouvoir utiliser l’ensemble des fonctionnalités de ces interfaces (si toutefois elles sont disponible sur la caméscope), il ne faut pas oublier d’inclure le fichier « XPrtDefs.h » dans le projet sous peine d’avoir des erreur de compilation. Après avoir sélectionner le filtre de capture, il faut utiliser la fonction « QueryInterface » pour récupérer un pointeur sur l’une de ces interfaces. 3.a) IAMExtDevice Page 58/71 Université de Reims Champagne-Ardennes Programmation Multimédia Master d'Informatique 2004-2005 Cette interface gère des fonctions basiques du caméscope et n’est pas très utile. Elle permet de connaître le port sur lequel le périphérique est connecté (en général sur le port IEEE de la carte FireWire), et de pouvoir allumer et éteindre le caméscope. 3.b) IAMCameraControl Cette interface est utile si l’on veut paramétrer à distance les fonctions comme le zoom, le degré d’exposition, … du caméscope. Comme pour régler la luminosité d’une webcam, cette interface dispose de trois fonctions, une pour récupérer la plage de valeur possible et la valeur par défaut, une autre pour récupérer la valeur courante et enfin une dernière pour modifier cette valeur. Cette interface requière tout de même un matériel très perfectionné, en effet, le caméscope numérique mis à ma disposition ne supportait pas cette fonctionnalité. (Voir le code « Sources\2 Caméscope Numérique\IAMCameraControl ».) 3.c) IAMExtTransport Lorsque que l’on regarde la documentation de cette interface, on peut avoir peur ; elle est très complexe… mais lorsque que l’on lit les dernières lignes de chaque fonction, on s’aperçoit que la plupart des fonctions ne sont pas encore implémenter dans cette version de DirectShow. Pour l’instant, le seul moyen de pouvoir les utiliser est de créer soi-même sont propre filtre de capture. De ce fait, cette interface, nettoyée de tout ce qui est inutile, se résume à trois fonctionnalités : • • • Détecter le format du support d’enregistrement (cassette). Modifier des paramètres basiques comme le format de l’heure, … Contrôler la cassette du caméscope (lecture, stop, retour rapide, …) Les modes disponibles sont assez nombreux. Pour les utiliser, il suffit d’employer la méthode « put_Mode ». En voici la liste : Valeur Description ED_MODE_PLAY Lecture ED_MODE_STOP Stop ED_MODE_FREEZE Pause ED_MODE_THAW Reprendre ED_MODE_FF Avance rapide ED_MODE_REW Rembobiner ED_MODE_RECORD Enregistrer Page 59/71 Université de Reims Champagne-Ardennes Programmation Multimédia Master d'Informatique 2004-2005 ED_MODE_RECORD_FREEZE Enregistrer-Pause ED_MODE_RECORD_STROBE Enregistrer une seule image ED_MODE_STEP_FWD Avance d’une seule étape ED_MODE_STEP_REV Recule d’une seule étape ED_MODE_SHUTTLE Avance rapide mais la vidéo reste visible ED_MODE_EDIT_CUE Positionner la d’évènement ED_MODE_LINK_ON Utilise le même mode que le graphe ED_MODE_LINK_OFF Mode indépendant du graphe cassette à un point Voir le code « Sources\2 - Caméscope Numérique\IAMExtTransport ». 3.d) IAMTimecodeReader Cette interface sert à connaître l’endroit où nous en sommes sur la cassette ainsi que le numéro de la piste. Elle peut être utile pour savoir s’il faut ou non changer de cassette afin d’avertir l’utilisateur. 3.e) IAMTimecodeDisplay Elle gèrent les paramètres d’affichage du caméscope, comme la couleur, la taille des caractères, le centrage, la transparence… Voir le code « Sources\2 - Caméscope Numérique\IAMTimecodeDisplay ». Page 60/71 Université de Reims Champagne-Ardennes Programmation Multimédia Master d'Informatique 2004-2005 Annexe C: Contrôle d'une carte Tuner TV Nous présentons dans cette partie un autre exemple de capture de flux vidéo analogique: la carte Tuner-Télévision. Elle diffère des autres scénarios de captures vidéo en plusieurs points. Tout d’abord, la carte tuner se cale sur un signal analogique qui sera ensuite numérisé. Ensuite, la partie audio est véhiculée par le signal analogique et la façon dont elle peut atteindre la carte son peut varier d’un matériel à un autre (généralement cette liaison externe est réalisée par un câble joignant la carte tuner à la carte son). Et enfin le signal peut contenir des données supplémentaires dans le "Vertical Blanking Interval" (VBI, partie contenant un signal non visible), telles que les "Closed Captions" (CC), le "World Standard Teletext" (WST) et les services de données étendues (XDS) ; tous ces termes seront repris et développés par la suite. Sur la figure ci-dessous nous pouvons retrouver la représentation d’un graphe de prévisualisation de la télévision. Elle servira de base aux explications des filtres utilisés ainsi qu’à la compréhension du modèle. Représentation d’un graphe de prévisualisation de la télévision Voici donc les filtres nécessaires. Tout d’abord le premier filtre à insérer est le filtre de capture vidéo WDM. C’est le filtre qui pourra délivrer le flux vidéo numérisé mais pour cela d’autres filtres lui sont nécessaires à savoir: • le filtre Tuner TV : qui contrôle le tuning pour les tuners TV analogiques. • le filtre Audio TV : qui contrôle les réglages audio pour les tuners TV analogiques. • le filtre "Analog Video Crossbar" : qui se charge de router les signaux vidéo et audio à travers le composant matériel. Par exemple, un périphérique peut avoir plusieurs entrées (telles que l’entrée S-Vidéo et l’entrée composite). Le filtre crossbar permet à l’application de sélectionner l’entrée. Bien qu’ils soient des filtres séparés dans DirectShow, ils représentent pourtant le même composant matériel. Chaque filtre contrôle une fonction différente du composant. Les filtres sont connectés par l’intermédiaire des bornes, mais aucune donnée média ne circule dans les connexions entre les bornes. Par conséquent, les bornes de ces filtres ne négocient pas de type de média avant de se connecter. Mais à la place, ils utilisent des valeurs GUID appelées mediums. Un medium étant une structure qui identifie un chemin matériel de données entre deux périphériques sur une machine. Par exemple, le filtre Tuner TV et le filtre de capture vidéo pour une même carte TV supportent le même Page 61/71 Université de Reims Champagne-Ardennes Programmation Multimédia Master d'Informatique 2004-2005 medium, qui permet à l’application de construire le graphe correctement. En pratique, l’utilisation de ICaptureGraphBuilder2 pour la construction d’un graphe de capture à pour avantage que ces filtres soient ajoutés automatiquement au graphe. Sachant quel est le rôle "primaire" que joue chacun des filtres présents dans la graphe de capture. Nous pouvons maintenant aborder les fonctionnalités que nous offrent chacun de ces filtres. Dans le cadre ou nous sommes placés (capture de télévision), le filtre Tuner TV est énormément important puisque c’est par lui que la sélection d’un canal pourra être effectuée. De façon interne, le filtre Tuner TV conserve une liste de tables de fréquences. Chaque table de fréquences correspond aux fréquences de diffusion ou du câble pour un pays ou une région donné(e). Il existe aussi une table de fréquence "Unicable" générique qui est utilisée lorsqu’un pays ou une région ne s’est pas vu assigner de fréquences. Chaque table de fréquences contient une liste de fréquences de tuning. Pour un certain nombre de pays ou de régions, les indices dans la table correspondent directement aux numéros de canaux. Mais pour d’autres pays ou régions, cela n’est pas le cas. Alors, dans cette situation, l’application doit conserver une table de correspondance entre le numéro des canaux (sélectionner par l’utilisateur) et les entrées dans la table des fréquences. Grâce à l’interface IAMTVTuner (qui hérite de l’interface IAMTuner) exposée par ce filtre, nous pouvons obtenir son contrôle sur la sélection de canaux, des fréquences et récupérer des informations sur les différents standards vidéo analogiques que le Tuner TV ou encore de spécifier si le signal provient d’une antenne ou du câble. Ayant vu avant qu’il existe une liste de tables de fréquences, il existe une méthode prenant en paramètre un entier qui permet de sélectionner la table associée à un pays ou une région ; l’entier utilisé afin de correspondre avec un pays ou une région est le même que l’indicatif téléphonique d‘entrée dans ce même pays (par exemple 33 pour la France, 44 pour le Royaume-Uni ou encore 351 pour le Portugal). La méthode put_Channel nous permet de sélectionner un canal, mais l’entier qu’elle prend en paramètre correspond à l’indice de la table de fréquence en cours d’utilisation. Une autre méthode, ChannelMinMax nous permet de récupérer les canaux minimaux et maximaux utilisables dans la table de fréquence utilisée, ce qui peut être utile pour tester la validité d’un indice en vue de l’utiliser pour la méthode précédente par exemple. Il est possible que des entrées dans la table de fréquences puissent être incorrectes ou obsolètes. Par conséquent, un mécanisme est fourni pour remplacer chaque entrée par le biais de clés dans la base de registre. Chaque clé définie un espace de tuning une ou plusieurs sous-clés, et chaque sous-clé remplace une entrée dans la table des fréquences. La méthode put_TuningSpace permet de fixer l’espace de tuning courant. C’est donc à l’application de maintenir une correspondance entre ceux-ci et les pays ou régions. La meilleure approche est d’utiliser l’identifiant de région ou de pays comme nom pour l’espace de tuning. Bien que les fréquences sur le câble soient généralement supposées exactes, les fréquences de diffusion peuvent avoir été réajustées de quelques kHz par la station de diffusion afin de réduire les interférences potentielles avec des canaux voisins. Lorsque le filtre Tuner TV se positionne sur un canal, il scanne plus précisément le signal. Le filtre Tuner TV possède un mécanisme pour sauvegarder les fréquences ajustées dans la base de registres. La technique consiste à récupérer les canaux minimaux et maximaux, de parcourir les canaux compris entre ces bornes en le sélectionnant à chaque fois, et lorsque cela est terminé, de faire appel à StoreAutoTune qui se chargera d’écrire ces nouvelles valeurs Page 62/71 Université de Reims Champagne-Ardennes Programmation Multimédia Master d'Informatique 2004-2005 dans l’entrée de l’espace de tuning courant dans la base de registres. Une autre méthode permet de récupérer les différents types de standards de télévision vidéo analogique supportés par la carte. Ces différents standards sont des versions déclinées des 3 grands standards que sont : • NTSC (pour National Television Standards Committee) : qui est le standard le plus utilise aux Etats-Unis et au Japon. Il délivre 30 images entrelacées par seconde avec une résolution de 525 lignes. • PAL (pour Phase Alternating Line) : plus largement utilise en Europe et en Chine. Il délivre 25 images entrelacées par seconde avec une résolution de 625 lignes. • SECAM (pour Sequentielle Couleur Avec Mémoire) : le plus utilisé en France (où il a été développé), en Afrique et en Europe de l’Est. Tout comme PAL, il délivre 25 images entrelacées par seconde avec une résolution de 625 lignes. Le filtre TV Audio, par l’intermédiaire de l’interface IAMTVAudio permet à l’application de récupérer les modes Tv Audio supportés par le matériel physique, de récupérer le mode courant ou d’en spécifier un. Ces types étant contenus dans un énumérateur de type enum TVAudioMode, les valeurs pouvant être prises sont : AMTVAUDIO_MODE_MONO, AMTVAUDIO_MODE_STEREO, AMTVAUDIO_MODE_LANG_A, AMTVAUDIO_MODE_LANG_B ou AMTVAUDIO_MODE_LANG_C. Concernant les deux premières possibilités, comme on peut facilement l’imaginer, ils indiquent si l’audio est en mono ou en stéréo. Mais concernant les 3 autres, cela parait moins trivial. En effet, ils indiquent si l’audio est un langage additionnel. Ainsi lorsqu’un audio TV bilingue est utilisé dans des régions spécifiques, leurs représentations sont les suivantes : • AMTVAUDIO_MODE_LANG_A : l’audio multilingue principal. • AMTVAUDIO_MODE_LANG_B : l’audio multilingue secondaire. • AMTVAUDIO_MODE_LANG_C : l’audio multilingue tertiaire s’il y a, sinon le principal plus le second. Par exemple, ceci peut-être utilisé pour avoir de l’anglais dans l’enceinte gauche et du japonais dans l’enceinte droite. Le filtre Crossbar Video Analogique représente un crossbar vidéo sur un périphérique de capture vidéo qui supporte le modèle WDM. Chaque borne en entrée représente un chemin physique pour l’obtention d’un signal vidéo analogique. Une de ces bornes d’entrée provient du Tuner TV, les autres supportent des flux vidéo ou audio. Ce filtre ne peut pas être directement créé par CoCreateInstance. Mais sachant qu’il est inséré dans un graphe de capture en amont d’un filtre de capture dès qu’il est nécessaire, nous pouvons alors nous contenter de chercher une interface de type IAMCrossbar (exposée par le filtre) dans le graphe, ou d’utiliser ICaptureGraphBuilder2 qui (comme indiqué précédemment) ajoutera alors automatiquement ce filtre au graphe. Sa présence se justifie par le fait que c’est par lui que la sélection de l’entrée vidéo analogique s’effectuera. La borne de sortie vidéo devra alors être routée en interne vers la borne d’entrée sélectionnée. Nous pouvons retrouver sur le tableau les différents types physiques reconnus à une broche d’un crossbar. Les deux types en rouge correspondent aux broches de sorties. Attention, ce sont les types gérés par DirectShow, mais le crossbar qui reflète le matériel physique ne devrait pas disposer de tout cela. Page 63/71 Université de Reims Champagne-Ardennes Programmation Multimédia Master d'Informatique 2004-2005 Types physiques d’une borne du crossbar Vidéo audio PhysConn_Video_Tuner PhysConn_Video_Composite PhysConn_Video_SVideo PhysConn_Video_RGB PhysConn_Video_YRYBY PhysConn_Video_SerialDigital PhysConn_Video_ParallelDigital PhysConn_Video_SCSI PhysConn_Video_AUX PhysConn_Video_1394 PhysConn_Video_USB PhysConn_Video_VideoDecoder PhysConn_Video_VideoEncoder PhysConn_Video_SCART PhysConn_Audio_Tuner PhysConn_Audio_Line PhysConn_Audio_Mic PhysConn_Audio_AESDigital PhysConn_Audio_SPDIFDigital PhysConn_Audio_SCSI PhysConn_Audio_AUX PhysConn_Audio_1394 PhysConn_Audio_USB PhysConn_Audio_AudioDecoder Types physiques des bornes du crossbar Dans notre cas la borne de sortie correspondant au type "PhysConn_Video_VideoDecoder" devra être routée sur la borne en entrée correspondant au type "PhysConn_Video_Tuner". Concernant la partie audio, s’il est décidé de ne seulement avoir qu’un aperçu, il suffit de réaliser l’opération identique à la précédente mais sur les bornes de types audio, c’est-à-dire que la borne dont le type est "PhysConn_Audio_AudioDecoder" devra être routée (cela toujours de façon interne) sur la borne en entrée correspondant au type "PhysConn_Audio_Tuner", comme le montre la figure. Aucun filtre de capture audio, ni même de rendu audio ne seront nécessaires puisqu’il y aura une connexion physique entre la carte tuner et la carte son. Symbolisation du routage sur la partie audio du crossbar pour un aperçu audio. En revanche, s’il est décidé de rediriger la partie audio dans un fichier, le filtre de capture sera alors nécessaire. Alors la démarche évoquée dans la partie précédente sera à renouveler. Et le filtre de capture audio ne verra toujours pas ses bornes en entrée connecter à d’autres filtres. Il faudra alors sélectionner la broche qui participe à l’enregistrement et qui physiquement connectée à la carte tuner. Page 64/71 Université de Reims Champagne-Ardennes Programmation Multimédia Master d'Informatique 2004-2005 En ce qui concerne la sortie du crossbar, sa borne dédiée à la vidéo doit être reliée au filtre de capture vidéo. Ce dernier contrôlant le périphérique de capture qui utilise des pilotes basés sur WDM, le filtre est un plug-in KsProxy en mode noyau. Une application peut le considérer comme un simple filtre. Il est nécessaire de passer par l’énumérateur de périphériques systèmes afin de l’insérer au graphe. Le filtre expose différentes interfaces qui permettent (entre autre) : de retrouver le format TV utilisé, de déterminer si la synchronisation horizontale est verrouillée (s’il reçoit bien un signal), de retrouver le nombre de lignes scannées dans le signal, de récupérer le nombre de trames qui ont été délivrées par le filtre depuis le lancement du graphe, etc... Nous allons maintenant nous pencher sur les données véhiculées dans le signal analogique TV mais qui ne sont pas visibles. Mais tout d’abord, rappelons le fonctionnement d'un écran. Une image est affichée sur un moniteur pixels par pixels. Les faisceaux d'électrons balaient l'écran cathodique horizontalement, ligne par ligne. Lorsqu'une ligne est finie, ils descendent d'un cran et font la ligne suivante. Lorsqu'ils atteignent le bas de l'écran, ils reviennent à la première ligne et recommencent leur balayage. Le temps mis par les faisceaux pour aller du bas droite de l'écran au coin haut gauche est appelé intervalle vide vertical (soit le Vertical Blank Interval). Le VBI est exprimé en nombre de lignes horizontales scannée. Le signal VBI se doit d’être faible afin de ne pas affecter défavorablement le faisceau d’électrons qui transporte le signal de l’image principale. En fait, les signaux analogiques TV doivent indiquer une intensité nulle pour le faisceau durant le VBI afin de s’assurer que l’image ne sera pas affectée. Mais grâce à d’autres circuits internes aux téléviseurs, il est possible de détecter et d’interpréter ce faible signal. Les signaux transmis pendant le VBI sont habituellement numériques, mais on peut se rappeler que si la télévision n’intègre pas de circuit (matériel) permettant de les décoder, cela n’a aucun effet sur la diffusion, et ne sont pas vu par le téléspectateur. A titre d’exemple, sur les 525 lignes horizontales à balayer spécifiées dans le format NTSC, seulement 486 sont visibles et donc qui fait une quarantaine de lignes pour le VBI. Le VBI peut contenir des données concernant le "Closed Captioning" et le Teletext. Les Closed Captions (CC) sont des versions textuelles des "parties parlées" d’une émission, d’un film ou d’une présentation sur ordinateur. Leurs utilisations ont été conçues afin d’aider les personnes malentendantes. Ceci peut être utile à toute personne lorsque l’environnement est trop bruyant ou, au contraire lorsque le silence est requis (comme dans un hôpital par exemple). Ils peuvent être considérés comme des sous-titres plus précis, puisque cela ne se limite pas qu’aux dialogues. Par exemple, pourront être perçus la sonnerie de téléphone ou le fait que quelqu’un frappe à la porte. "Caption" pourrait être traduit par sous-titre ou légende et le "Closed" se justifie par le fait que ces informations sont encodées dans la ligne 21 du VBI (et donc cachées) d’un signal NTSC. Le texte ne devient visible qu’avec l’utilisation d’un décodeur, qu’il soit intégré à la télévision ou sous forme d’un boîtier venant se placer entre la source et la télévision. La plupart des programmes télévisuels se voient insérer en avance de telles données avant la diffusion, mais pour d’autre, comme la diffusion d’émissions en direct, cela nécessite d’être effectué en temps réel. Auquel cas, un sténographe écoute la diffusion et saisie en sténo ce qu’il perçoit dans un programme, celui-ci se chargeant de les convertir en "soustitres" et de les insérés dans le signal vidéo. Page 65/71 Université de Reims Champagne-Ardennes Programmation Multimédia Master d'Informatique 2004-2005 Le teletext est un système de transmission (à sens unique) de texte et de graphiques le plus utilisé en Europe (mais aussi disponible dans différentes régions aux Etats-Unis) qui utilise des lignes du VBI des diffusions de signaux vidéo PAL et SECAM. Un décodeur (tout comme le CC) est nécessaire quant à l’extraction de ces données. C’est une boucle cachée de pages d’informations qui sont transmises les unes après les autres. L’utilisateur peut sélectionner les pages qu’il souhaite visualiser. Lorsque qu’un numéro de page est entré, après un certain délai, celle-ci est affichée sur l’écran. Bien que teletext puisse paraître interactif, il ne l’est pas. Lorsqu’une page est demandée, le décodeur attend simplement que la page soit diffusée, la capture et l’affiche sur le poste. La variation du délai peut dépendre du nombre de "trames" dans la boucle teletext ou du poste, mais cela est généralement compris entre 5 et 30 secondes. XDS (auparavant connu sous le nom EDS) pour Extended Data Services. C’est un concept qui n’a pas encore été complètement implémenté. L’idée est d’utiliser un des champs auparavant réservés pour les captions pour transporter des informations concernant le programme diffusé mais pas sous forme de captions. Les informations XDS devront être sous forme de paquets, contenant des informations comme le moment de la journée, le réseau ou le programme actuel. Cela signifie que les télévisions et les magnétoscopes pourraient être capables de régler automatiquement leur horloge interne et qu’un utilisateur pourra rechercher après un programme par son nom ou son réseau mais plus par son numéro de canal. Dans le cas où nous souhaiterions visualiser ces informations cachées, nous pouvons voir sur les figures suivantes, les graphes qui seront à construire. On peut constater que dans les deux cas, le filtre de capture vidéo est à la base du graphe. Pour supporter les CC en télévision analogique, le filtre expose une borne qui délivre les données VBI ou CC. Cette borne doit appartenir à l’une des catégories suivantes : • PIN_CATEGORY_VBI : délivre un flux d’échantillons VBI. Ils seront passés à un filtre décodeur qui extraira les données CC. • PIN_CATEGORY_CC : délivre des paires d’octets de CC, extraites à partir de la ligne 21. • PINNAME_VIDEO_CC_CAPTURE Représentation du graphe de prévisualisation des "Closed Captions" Page 66/71 Université de Reims Champagne-Ardennes Programmation Multimédia Master d'Informatique 2004-2005 Représentation du graphe de prévisualisation du Teletext Dans le cas des CC, l’utilisation d’une méthode (appartenant à ICaptureGraphBuilder2) de demande de rendu sur cette borne du filtre de capture, procure l’avantage que les filtres suivants seront automatiquement insérés : • le filtre "Tee/Sink-to-Sink Converter" : qui accepte les informations VBI du filtre de capture et les scinde en flux séparés chacun des services présents dans le signal. Microsoft fournit des codecs VBI pour CC, NABTS et World Standard Teletext. • le filtre "CC Decoder" : qui décode les données CC d’un échantillon VBI fourni par le filtre de capture. • le filtre "Line 21 Decoder" : qui traduit les paires d’octets CC et dessine le texte sur les images. Dans le cas du Teletext, les filtres insérés entre le "Tee/Sink-to-Sink Converter" et l’"Overlay Mixer" sont : le filtre "WST Codec" qui décode les données teletext à partir des échantillons VBI et le filtre "WST Decoder" qui traduit les données teletext et dessine le texte sur les images. Il est à noter que dans ce cas, ces filtres ne pourront pas être insérés automatiquement. Page 67/71 Université de Reims Champagne-Ardennes Programmation Multimédia Master d'Informatique 2004-2005 Annexe D: Contrôle d'un DVD En général, les applications DVD sont très complexes. Cela dépend des fonctionnalités attendues par l’utilisateur. S’il souhaite simplement regarder un film ou paramétrer chaque angles de vues d’une scène, … DirectShow nous propose, pour nous aider dans cette tâche, un filtre source appelé « DVD Navigator ». Ce navigateur de DVD contient absolument toutes les fonctionnalités que vous pourrez trouver dans un lecteur de DVD de salon, et à cela s’ajoute des fonctionnalités spécifiques pour la lecture de DVD sur un ordinateur personnel. Ainsi, il est possible de développer des lecteurs de DVD sans se référer aux spécifications du DVD. Le navigateur, en coordination avec le décodeur, gère les problèmes de région du DVD et de sa protection contre le piratage. Le navigateur fonctionne sur un DVD entier qui comporte tous ses fichiers .vob dans un répertoire nommé « VIDEO_TS ». Contrairement aux autres filtres sources de DirectShow qui ne gèrent qu’un flux ou fichier à la fois, le navigateur utilise la structure en titres et chapitres du DVD. Avant de pouvoir visionner un film avec DirectShow, il est primordial d’installer préalablement un décodeur MPEG-2 non fournie avec le SDK de DirectX. L’ensemble des fonctionnalités du navigateur est divisé en deux catégories. Chaque catégorie est représentée par une interface spécifique qui permet de les contrôler. La première est l’interface « IDvdControl2 ». Elle regroupe toutes les méthodes « set ». La seconde est l’interface « IDvdInfo2 ». Elle rassemble toutes les fonctions « get ». 1) Ecrire une application DVD De la même façon que pour créer un graphe de capture, il existe un objet spécifique pour concevoir un graphe destiné à lire un DVD. L’interface qui lui ait attribuée est « IDvdGraphBuilder ». Elle dispose de trois fonctions : • GetFilterGraph : permet de spécifier le graphe utiliser. • GetDvdInterface : permet de récupérer un pointeur sur l’une des interfaces « IDvdControl2 » ou « IDvdInfo2 ». • RenderDvdVideoVolume : Cette fonction crée le graphe du début à la fin. Il y a eu quelques changements lors de l’évolution de Windows et du passage à la version 9 de DirectX. Dans les précédentes versions de DirectX, seul le filtre « Overlay Mixer » était disponible. Dans Windows XP, le filtre « Video Mixing Rendere 7 » fut introduit. Puis, avec DirectX 9, le filtre « Video Mixing Renderer 9 » vient s’ajouter. Donc, maintenant, il y a trois filtres de rendu disponibles. Le choix de l’un d’entre eux dépendra du système d’exploitation, du type du décodeur MPEG-2 et du matériel vidéo présent dans le système de l’utilisateur. Le schéma suivant montre un graphe de lecture de DVD qui fonctionne sous Windows 98SE, Windows 2000, ou Windows Me. Ici, un décodeur MPEG-2 est installé. Page 68/71 Université de Reims Champagne-Ardennes Programmation Multimédia Master d'Informatique 2004-2005 Sur Windows XP, les filtres « Overlay Mixer » et « Video Renderer » sont remplacés par le filtre « Video Mixing Renderer 7 ». Et le filtre « Line 21 Decoder » est remplacé par le filtre « Line 21 Decoder 2 », comme le montre le schéma suivant. Ici également, un décodeur MPEG-2 est installé. Lorsqu’un décodeur matériel est présent, il est directement connecté à la carte vidéo. Ceci permet de passez directement à la carte graphique sans passer par la mémoire centrale. Pour réaliser cette connexion sur les anciennes versions de Windows, DirectShow utilise « DirectDraw Video Port Extensions » (VPE) à travers une interface sur le filtre « Overlay Mixer ». Le diagramme suivant illustre ce cas. Le diagramme suivant montre le même cas mais sous Windows XP. Page 69/71 Université de Reims Champagne-Ardennes Programmation Multimédia Master d'Informatique 2004-2005 Dans l’ensemble de ces graphes, le navigateur de DVD est le filtre source; il réalise différentes tâches: • Lire la navigation et la vidéo sur le disque. • Sépare les flux vidéo, audio et sous-titres. • Envoie les flux dans les différentes broches. • Informe l’application des évènements du DVD. 2) Recevoir des évènements du DVD Le navigateur de DVD prévient l’application lorsqu’il reçoit un évènement provenant du DVD. Le genre d’évènement que l’on peut recevoir est : le DVD change de domaine, le niveau de contrôle parental change pour une certaine scène, ou il y a plusieurs angles de vues disponible pour la même scène. Les paramètres des évènements peuvent varier en fonction du type de l’évènement. Les messages d’erreurs sont également transmis de cette manière. L’application informe la fenêtre de l’évènement en utilisant un pointeur sur l’interface « IMediaEventEx » puis appelle la fonction « SetNotifyWindow ». L’évènement lui-même est récupérer par l’application grâce à un appelle de la méthode « IMediaEvent::GetEvent ». Du fait que plus d’un évènement peut survenir à n’importe quel moment, l’application doit effectuer un appel à « GetEvent » dans une boucle jusqu’à ce que tous les évènements soient traités. Voir les codes « Sources\3 - DVD\lire_DVD » et « Sources\3 - DVD\lire_film ». 3) Le filtre MPEG-2 Demultiplexeur Comme vous l’aurez remarqué, pour l’instant, nous n’avons vu que le navigateur de DVD qui permet uniquement de lire un DVD. J’ai essayé de l’utiliser afin d’enregistrer le film dans un fichier AVI compressé en DivX par exemple. Malheureusement, ce n’est pas possible de cette façon. De plus, aucune documentation n’est disponible dans le SDK de DirectX ;-). Après de multiples recherches, j’ai finalement trouvé un filtre : le « MPEG-2 Demultiplexeur » qui permet de séparer les flux audio, vidéos et sous-titre d’un fichier .vob. Il y a également le filtre « I-Media Multiple MPEG2 Source » qui permet de mettre en source non pas un fichier mais une liste de fichiers .vob. (Malheureusement, ce filtre ne fonctionne pas correctement.) Mais cela n’est qu’un détail, il suffit de réitérer le Page 70/71 Université de Reims Champagne-Ardennes Programmation Multimédia Master d'Informatique 2004-2005 processus sur tous les fichiers .vob contenu dans le DVD puis de regrouper les bouts de film et le tour est joué. Etant conscient du caractère interdit de cette application, je ne l’ai développé qu’à titre d’exemple et d’apprentissage, et en aucun cas, j’en aurais recours pour un usage illégal. La première chose à faire pour espérer réussir convertir un DVD en DivX, il faut copier tous les fichiers .vob du DVD sur le disque dur. Voici déjà la première difficulté : la plupart des DVD sont protégés contre la copie directe. Si c’est la cas pour votre DVD, il va falloir avoir recourt à un programme externe qui se chargera de supprimer cette protection (uniquement pour tester). Une fois l’intégralité du film sur le disque (cela prend 5 ou 6 Gigas, voir plus en fonction du film), on peut commencer à créer le graphe de cette manière : Dans cet exemple, seul le flux vidéo est compressé. Pour compresser également le flux audio, il suffit de rajouter un filtre de compression MP3 (par exemple) entre les filtres « AC3Filter » et « AVI Mux ». Pour un exemple de cette application et un exemple avec le filtre de multiples sources, voir les codes « Sources\3 - DVD\VOB_to_DivX » et « Sources\3 DVD\DVD_to_DivX ». Page 71/71 Université de Reims Champagne-Ardennes