DirectShow bevezető

Igazából ezzel kellett volna kezdenem, nem rögtön a falnak nekirohanni, hogy jobban megértsük ennek az egésznek a működését, de akkor most megteszem utólag. A DirectShow mint önálló Microsoft technológia a DirectX részét képezi, de részét képezi a DirectSound, DirectMusic, Direct3D, s a már elavultnak számító DirectDraw is. Ezek közül most a DirectShow-val fogunk foglalkozni. Mivel ez a technológia a DirectX részét képezi, ezért erősen kötődik annak kiadásaihoz is azaz pl. a Video Mixing Renderer 9, mint ahogy neve is mutatja DirectX 9 alól érhető el, továbbá a sima Video Mixing Renderer pedig csak Windows XP operációs rendszerektől fogva elérhető. Maga a DirectShow alkalmas multimédia tartalmak lejátszására, multimédia adatok manipulálására, mindezt egy ún. szűrő rendszer segítségével. A Windows Media Player megértéséhez, vagy bármely más komoly multimédiás lejátszó/felvétel készítő, vagy vágó/szerkesztő, formátum konvertáló program megértéséhez is ez az első, amit keresnünk kell. Szerintem ez egy nagyon izgalmas részét képezi a multimédiás fejlesztésnek és nem utolsó sorban olyan információkhoz enged hozzáférni a multimédiás tartalommal kapcsolatban, amelyekhez más API-val nem is tudnánk Windows alatt hozzáférni. Tehát mint mondtam, ún. szűrő rendszer alapján épül fel egy kijátszási folyamat is. Ezek a filterek különböző műveleteket hajtanak végre, mint például elemzés, dekódolás, renderelés, stb. Továbbá ezek a szűrők dinamikusan kapcsolódnak egymáshoz, ily módon lehetőségünk nyílik akár saját filtereket is írni és telepíteni azokat, s beépíteni a saját gráfunkba. A DirectShow felfogható úgy is, mint egy közvetítő. Támogatja a kodekeket, melyekkel dinamikusan bővíteni lehet az operációs rendszer által támogatott médiaformátumokat. Alapértelmezésben a DirectShow is támogat jópár formátumot, úgy mint Advanced Streaming Format (ASF), Motion Picture Experts Group (MPEG), Audio-Video Interleaved (AVI), MPEG Audio Layer-3 (MP3), Waveform Audio (WAV), Windows Media Audio and Video (WMA and WMV). További szépsége a dolognak, hogy mivel a DirectShow a DirectX része, így nyilván az átjárhatóság megvan az egyes DirectX technológiák között, mint pl. Direct3D. Az egész műveletet egy Filter Graph Manager (FGM) vezérli, ami egy COM objektum. Egyenlőre sajnos még nincs betervezve a teljes DirectShow átvitele .NET alá, a Microsoft elérhetővé tett a managelt DirectX-ben egy AudioVideoPlayback névteret, amiben taláható egy Audio és egy Video osztály is, amelyek egy DirectShow lejátszó gráfot képesek felépíteni, de továbbra is a Microsoft managelt Audio és Video osztálya is a COM interopot használja. Ettől függetlenül a DirectShow API is némi fejlődésen ment át az utóbbi időkben. Továbbá láttam a neten, hogy próbálják páran a DirectShow-ra épülő lejátszóikat, stb. hosztolni WPF alá több-kevesebb sikerrel, ez még a jövő kérdése lesz, hogy mennyire fogják ezeket a szolgáltatásokat a .NET-be integrálni. Lehetőségünk van továbbá hozzáférni saját alkalmazásainkból Windows Driver Modell (WDM) alapú hardver-eszközökhöz, DV kamerákhoz, TV tunerekhez, USB webkamerákhoz és egyéb külső eszközökhöz is. S nem utolsó sorban egy fontos jellemzője még a szoros integráció a Windows Media Format SDK-val. A legutolsó DirectX-et innen letölthetjük. A DirectShow stream alapú megközelítést használ, a DirectX SDK-ban találunk egy GraphEdit.exe programot, amellyel betölthetünk egy média fájlt és máris láthatjuk, hogyan is néz ki egy ilyen gráf. Remélem elég jól láthatóan sikerült szemléltetnem, hogyan is épül ez fel:

 

Először is minden fájl betöltéséhez kell egy file source (fájl forrás) szűrő, ami kiolvassa az adatokat a fájlból, de lehet ez egy URL is akár. Ez direktbe az IFileSourceFilter felület kinyerésével érhető el. Ezután következnek az ún. transzformációs szűrők, ezek ún. köztes szűrők, amelyek kezelik a különböző formátumokat, mint MPEG-1 video, AVI video, WAV audio és egyéb más formátumokat (ezek különböző transzformációkat végeznek el az adatokon), majd végül a legvégén találhatók a renderelő szűrők, amelyek az átalakított adatfolyamot kijátszák a kimeneti eszközre, vagy egy fájlba. Minden szűrő rendelkezik ún. pinekkel, de legalábbis minimum egyel, amelyek által összeköthetők a különböző szűrők. A pinek típusuknál fogva lehetnek input, illetve output pinek. Két szűrő között csak abban az esetben jöhet létre kapcsolat, ha mindkét oldal megfelelő pinjei támogatják az adott médiatípust, tehát eszementen ne próbáljunk összekötögetni mindent mindennel. Amikor mi az IGraphBuilder RenderFile tagfüggvényét meghívjuk egy fájlnevet átadva, akkor az automatikusan felépíti a gráfot a file source filter elemzése után. Fontos, nem a fájl kiterjesztése határozza meg a médiatípusát! Meg is próbálhatunk átnevezni egy AVI-t pl. MPG-re például, meglátjuk mi fog történni. Ugyan az a gráf fog felépülni, persze ez azt jelenti, hogy teljesen mindegy mire kereszteljük a fájlt, akkor is letudjuk játszani. De vajon ha több azonos szűrőnk van egy adott médiatípushoz, akkor vajon mi fogja eldönteni, hogy melyiket használja a rendszer? Erre kitaláltak egy ún. merit tulajdonságot. Ez egy betöltési sorrendet állít fel, minél magasabb a merit értéke, annál kitüntetőbb szerepet kap az a filter. Ettől függetlenül persze lehetőségünk van magunknak kézzel felépíteni a gráfot az általunk jónak vélt szűrőkkel, bár ezt minden médiatípusra levezetni elég időigényes feladat lenne. De lehetőségünk van pl. egy szűrőt kivenni és egy újat betenni a helyére, majd újra összekapcsolni az egészet. Forrás szűrőt a gráfhoz az IGraphBuilder AddSourceFilter() tagfüggvényével tudunk megadni, aminek át kell adnunk a betöltendő fájl nevét, az általunk választott szűrőnevet, s a tényleges szűrő objektumot. Általánosságban igaz, hogy minden szűrőtípust a DirectShow-ban az IBaseFilter felület ír le, még a File Source Filtert is, attól függetlenül, hogy speciálisan van hozzá egy IFileSourceFilter felület.

Mivel még a DirectShow a COM-ra épül, ezért nem dob kivételt, a HRESULT visszatérési értékeket kell lekezelni. A DirectShowLib COM interop assemblyben van egy DsError osztály, amellyel ki lehet dobni egy kivételt, ami a szokásos AMGetErrorText függvény segítségével kinyeri az utolsó DirectShow hiba szövegét az adott operációs rendszer nyelvének megfelelően és azt jeleníti meg. De ha nem szeretnénk kivételt dobni, akkor az eredményt egyszerűbben a DsResults osztályt felhasználva is ellenőrizhetjük, amely tartalmazza az összes konstans értéket nevesítve. Ha csak annyit szeretnénk ellenőrizni, hogy biztosan sikerült e lefuttatni az adott tagfüggvényt, akkor elég a 0-val történő egyezőség vizsgálata, vagy hiba esetén: < 0. Általában nem célszerű minden esetben kivételt dobni médialejátszó alkalmazások esetében pl. azért sem mert nem sikerült az aktuális stream pozíciót lekérdezni, különösen ha ez még egy timeren belül fut. Bár ezt is ki lehet védeni és megközelítés kérdése, de akkor sem ajánlott minden esetben, általánosságban ilyenkor az a megközelítés él, hogy nem sikerült és kész. A mediaplayer sem fog nekünk kivételt dobni ebben az esetben.

A DirectShow ezen felül szolgáltat debuggolási lehetőséggel is, az IGraphBuilder SetLogFile() tagfüggvényével például lehetőség van a gráfépítés folyamatának naplózására is. A fájl létrehozása és lezárása a mi a dolgunk.

Továbbá rendelkezik egy intelligens kapcsolatépítési mechanizmussal. Azaz a Microsoft által készített algoritmussal kiválasztja a megfelelő szűrőket, majd hozzá adja azokat a Filter Graph-hoz. Mindig ez történik amikor a RenderFile() tagfüggvénnyel lerendereljük a fájlt. Persze saját szűrők írása esetében néhány dologra oda kell figyelni, például a merit konfigurálására is. Az intelligens kapcsolódási mechanizmus részeként szerepet játszik a következő is: ugye mint mondtam a merit értéke dönti el automatikus gráfépítés esetén, hogy melyik szűrő lesz beépítve. Ez úgy történik, hogy amikor felépíti a GraphBuilder a gráfot szépen felsorolja az összes regisztrált szűrőt (ami egyébként általában egy DLL fájl, amit a RegSvr32 programmal lehet be/ki regisztrálni, vagy manuálisan meghívni a DLL ismeretében az ennek megfelelő tagfüggvényeket, mivel ezek COM könyvtárak), majd rendezi a merit értéke alapján ezeket és a magassabb merit értékű filtert fogja beszúrni először hozzá. A merit értékek:  MERIT_PREFERRED, MERIT_NORMAL, MERIT_UNLIKELY, MERIT_DO_NOT_USE, MERIT_SW_COMPRESSOR, MERIT_HW_COMPRESSOR.

Az IBaseFilter az elsődleges interfész a DirectShow szűrőkhöz. Ez az interfész rendelkezik néhány tagfüggvénnyel amellyel a képen is látható dolgok reprezentálhatók, mint pl. a szűrők pinjeinek lekérdezése az EnumPins() tagfüggvénnyel történhet. Továbbá mivel minden szűrő származhat más és más gyártótól, ezzel kapcsolatos információ lekérdezésére is van lehetőség. Továbbá igaz még, hogy bizonyos szűrők rendelkeznek úgynevezett tulajdonságlappal. Ez egy sima futásidőben megjeleníthető form, ahol esetenként be is lehet avatkozni az adatfeldolgozásba.

Nézzük gyakorlatban hogyan építhetünk fel egy egyszerű gráfot:
A FilterGraph egy COM objektum, amit példányosítanunk kell és melyből ki kell nyernünk az IGraphBuilder felületet. Ha ezzel megvagyunk az IGraphBuilder RenderFile() tagfüggvényével a DirectShow az intelligens kapcsolatépítési mechanizmussal felépít egy általa optimálisnak vélt gráfot a médiatartalom kijátszásához:

IGraphBuilder Graph = new FilterGraph() as IGraphBuilder;
Graph.RenderFile(@"C:\Windows\Clock.avi", null);

Ez így idáig szép, lerendereltük a fájlt. A gráf már felépült, de le is kell azt játszanunk. Minden egyes feladatkörhöz tartozik egy saját felület a DirectShow-ban. Így pl. a vezérléshez az IMediaControl interfész. Tehát indítsuk el a lejátszást, ezt a Run() tagfüggvénnyel tudjuk megtenni:

(Graph as IMediaControl).Run();

A pozícionáláshoz használható az IMediaPosition (ez már elavultnak számít), van egy újabb IMediaSeeking interfész, amelynek be lehet állítani az időformátumot is (frames léptetés, médiaidő, stb.). Az IBasicAudio felülettel pl. lehetőségünk van a hangtulajdonságokon változtatni (Balance, Volume), illetve a IBasicVideo interfészel a forrásvideóról is, mint pl. eredeti képméret is nyerhetünk ki többek között információkat. Az IVideoWindow interfészel kezelhetjük le a videóablakot, mivel így az most egy különálló keretes ablak alapértelmezésben. Viszont megjegyzendő, hogy a Video Mixing Renderer esetében, ami már támogatja többek közt az overlay technológiát is, más megközelítést kell használnunk. Az IMediaEventEx interfészel saját eseménykezelőt rendelhetünk a DirectShow események lekezelése végett, továbbá pl. az IVideoFrameStep interfésszel igazi valódi frames léptetést is meglehet valósítani, csak azért hangsúlyozom, hogy valódi, mert az IMediaSeeking időformátuma is beállítható frames léptékre, s akkor az is framenként léptet, de ez utóbbi az audio streamet is vele együtt tolja, csak az utóbbi a visszafele léptetést nem támogatja. Továbbá mint mondtam beépíthetünk saját magunk is szűrőket, így pl. a Sample Grabber filtert, amivel grabbelhetünk. A Media Detector külön grabelési mechanizmust nyújt, viszont ha már mi felépítjük a gráfot, akár automatikusan (RenderFile), akár manuálisan (AddSourceFilter…), be kell építenünk a SampleGrabber filtert, s feleslegesen ilyenkor a média detektor használata, mint ahogy azt én még eddig tettem, de majd át fogom írni, ez még csak alpha tesztelési verzió. A Video Mixing Renderer lehetőséget ad továbbá 3D alapokra helyezni a megjelenített képet, pl. akár egy hengerre rácsavarhatjuk a lejátszott videót a Direct3D használatával.

Na kb. ennyit bevezetőnek, remélem ezzel sikerült rávilágítanom néhány dologra ezzel a technológiával kapcsolatban, aki nem tudta volna elképzelni, hogy az előző írásaimban mi a jó fenéket írtam eddig :). Ez alapján már őszintén remélem, hogy könnyebben elindul mindenki magától. Windows alatt a DirectShow API az alapja az összes médiával kapcsolatos dolognak. Ennél alacsonyabb szintre nem is lehetne nyúlni ezen a téren. Remélem így most már világossá vált mindenki számára, miért is szeretem ezt annyira . Engem ez a terület mindig is nagyon érdekelt.

Hozzászólás