BETA
Aby się zalogować, najpiew wybierz portal.
Aby się zarejestrować, najpiew wybierz portal.
Podaj słowa kluczowe
Słowa kluczowe muszą mieć co najmniej 3 sąsiadujące znaki alfanumeryczne
Pole zawiera niedozwolone znaki

Baza wiedzy











Odtwarzacz DirectShow MediaPlayer

31-08-2005 15:48 | User 131786
W tym artykule postaram się wyjaśnić, co to jest DirectShow, do czego można go wykorzystać i przede wszystkim jak to zrobić. Zbudujemy swój własny odtwarzacz wykorzystując Visual C# i biblioteki umożliwiające korzystanie z DirectShow.
  1. Wprowadzenie

 

1.1.    Treść artykułu

1.2.    Krótki opis programu, jego możliwości i zastosowań

     

  1. Niezbędna Teoria

 

2.1.  Wprowadzenie do DirectShow

2.2.  Wprowadzenie do programowania z wykorzystaniem DirectShow

2.3.   Jak zacząć pisanie aplikacji wykorzystującej DirectShow?

      

  1. Pisanie odtwarzacza wykorzystującego DirectShow

 

3.1.    Ustawienie niezbędnych referencji

3.2.    Budowa interfejsu odtwarzacza

3.3.    Powołanie obiektu Filter Graph Manager oraz interfejsów

3.4.    Obsługa wyjątków generowanych przez graf filtrów

3.5.    Uruchamianie odtwarzacza

3.6.    Aktualizacja przycisków i pasków

3.6.1.      UpdateStatusBar

3.6.2.      UpdateToolBar

3.6.3.      UpdateMediaProgress

3.6.4.      UpdateMainMenu

3.7.    Oprogramowanie przycisków odtwarzacza oraz menu

3.7.1.      Otwórz plik

3.7.2.      Zamknij plik

3.7.3.      Wyjście

3.7.4.      Pauza/Odtwarzaj

3.7.5.      Stop

3.7.6.      Przewiń do przodu

3.7.7.      Przewiń do tyłu

3.7.8.      Regulacja głośności

3.7.9.      Regulacja prędkości odtwarzania

3.7.10.  Odtwarzanie w trybie pełnego ekranu

3.7.11.  Obsługa paska narzędzi

3.7.12.  Skróty klawiszowe

    

  1. Podsumowanie

 

 

1.  Wprowadzenie

 

1.1.  Treść artykułu

 

   W tym artykule postaram się wyjaśnić, co to jest DirectShow, do czego można go wykorzystać i przede wszystkim jak to zrobić. Zbudujemy swój własny odtwarzacz wykorzystując Visual C# i biblioteki umożliwiające korzystanie z DirectShow.  Na końcu każdego z działów będę umieszczał linki do stron, z których korzystałem w celu lepszego zrozumienia tematu

 

1.2. Opis odtwarzacza, jego możliwości i zastosowań

 

     DirectShow daje nam ogromne możliwości, a w tym artykule poruszymy zaledwie drobną część tego, co udostępnia nam ten produkt. Skupimy się na budowie odtwarzacza filmów, a co za tym idzie tylko na tych funkcjach DS, które będą nam do tego potrzebne. Celem podstawowym jest możliwość uruchomienia dowolnego akceptowanego przez DirectShow formatu multimedialnego. Żeby zapewnić funkcjonalność odtwarzacza dodamy następujące możliwość sterowania strumieniem: odtwarzaj, pauza, stop, przewiń do tyłu, przewiń do przodu, przyśpiesz animację i zwolnij animację. Dla naszej wygody dodamy suwak umożliwiający przeskok w dowolna chwilę animacji, rozwijane menu oraz skróty klawiszowe. Dodatkowo odtwarzacz będzie mógł pracować w trybie pełnego ekranu, a w przypadku klipów zawierających strumień audio będzie istniała możliwość sterowania nim.

 

2. Niezbędna teoria

 

2.1. Wprowadzenie do DirectShow

 

DirectShow jest warstwą zintegrowaną z technologią DirectX i jest używany do obsługi danych zawierających multimedia. Produkt ten bazuje na technologii COM (Component Object Model). W odróżnieniu od DirectSound czy DirectDraw, DirectShow jest bardziej złożony i do odpowiedniej kontroli strumienia danych potrzebnych jest więcej interfejsów ( czyt. poniżej ). Technologia ta umożliwia odtwarzanie i przechwytywanie strumieni multimedialnych.. Wspiera wiele formatów jak np. Advanced Systems Formats (ASF), Motion Picture Experts Group (MPEG), Audio-Video Interleaved (AVI), MPEG Audio Layer-3 (MP3) oraz  WAV. Aplikacje, które mogą wykorzystywać DirectShow to między innymi różnego rodzaju odtwarzacze ( TV, DVD), programy do edycji video, programy do konwersji plików oraz wiele innych.

 

Linki:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directshow/htm/introductiontodirectshow.asp

 

2.2.    Wprowadzenie do programowania z wykorzystaniem DirectShow

 

   DirectShow jest zbiorem bloków połączonych ze sobą w funkcjonalną całość. Każdy z poszczególnych bloków pełni odpowiednią funkcję. Na jego wejście (bloku) podawany jest strumień danych, a na wyjście strumień przetworzony w odpowiedni sposób. Liczba bloków oraz sposób ich połączenia jest określona i zależy od strumienia wejściowego ( np. ułożenie bloków będzie inne w przypadku avi a mp3). Przyjęto nazywać poszczególne bloki jako filtry, a całość tworzy graf filtrów (filter graph). Każdy filtr reprezentuje etap w przetwarzaniu danych np. czytanie z pliku źródłowego, dekodowanie audio, dekodowanie video lub renderowanie. I tak w przypadku otworzenia pliku avi strumień danych będzie przepływał w dany sposób przez łańcuch filtrów:

 

 

 

Jak jest to widoczne na rysunku powyżej do poprawnego odtworzenia pliku avi (zawierającego strumień audio) niezbędnych jest 5 etapów. Dzieje się to w sposób następujący:

Filtr File Source czyta plik avi z dysku twardego. Filtr AVI Spliter rozdziela plik na dwa strumienie, skompresowany strumień obrazu i strumień dźwięku.. Filtr AVI Decompressor dekoduje skompresowany strumień obrazu a następnie filtr Video Renderer wyświetla poszczególne klatki na wyświetlaczu przy użyciu DirectDraw lub GDI. Filtr Default DirectSound Device odtwarza strumień audio przy użyciu DirectSound.

 

DirectShow daje nam możliwość sterowania strumieniem danych. Co to oznacza? Oznacza to, iż w dowolnym momencie animacji możemy np. ją zastopować. Jeśli chcemy zmienić stan w jakim znajduje się graf (np. odtwarzaj/pauza) musimy wykorzystać do tego odpowiednie interfejsy udostępnione wraz z DirectShow. Jednak należy sobie uświadomić, iż to nie one bezpośrednio sterują tym strumieniem, gdyż odwołują się one do obiektu Filter Graph Manager. Obiekt ten jest obiektem typu COM i to on bezpośrednio steruje strumieniem przepływającym przez graf filtrów. Odpowiada on także za odbieranie różnego rodzaju wyjątków (wiadomości wysyłane przez graf filtrów np. koniec strumienia zawierającego dane multimedialne).

 

Linki:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directshow/htm/introductiontodirectshowapplicationprogramming.asp

 

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directshow/htm/aboutthefiltergraphmanager.asp

 

http://msdn.microsoft.com/library/en-us/directshow/htm/dshowcoreinterfaces.asp

 

2.3   Jak zacząć pisanie aplikacji wykorzystującej DirectShow?

 

   Musimy wykonać trzy niezbędne kroki:

  1. Utworzenie obiektu Filter Graph Manager.
  2. Aplikacja wykorzystuje prędzej stworzony Filter Graph Manager do budowy grafu filtrów (filter graph).
  3. Aplikacja steruje przepływem strumienia przez graf filtrów (filter graph) przy wykorzystaniu Filter Graph Manager. Aplikacja odpowiada także na wyjątki wysyłane przez Filter Graph Manager.

Niżej przedstawiony jest rysunek przedstawiający trzy niezbędne kroki.

 

 

Wyjaśnienia może wymagać 3 rysunek. Widzimy, że aplikacja wysyła do obiektu Filter Graph Manager ”Method Calls”,a odbiera ”Events”. ”Method Calls” to zbiór metod udostępnionych poprzez interfejsy (funkcje API). ”Events” to wyjątki (wiadomości) przekazywane od obiektu FGM do aplikacji i tu także wykorzystujemy do tego interfejsy.

 

Linki:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directshow/htm/introductiontodirectshowapplicationprogramming.asp

 

3. Pisanie odtwarzacza wykorzystującego DirectShow

 

3.1. Ustawienie niezbędnych referencji

 

Tworzymy nowy projekt  File->New->Project , a następnie Visual C# Project i Windows Application.. Jak wspomniałem wyżej do kontroli przepływu strumienia używać będziemy Filter Graph Manager,a że jest on składnikiem typu COM musimy dodać referencję do biblioteki zawierającej ten składnik. W tym celu wykonujemy następujące kroki:

Project ->Add Reference następnie z dostępnych zakładek wybieramy COM, odszukujemy i dodajemy komponent  „ActiveMovie control type library”. Poniżej przedstawiony jest rysunek na, którym zaznaczona jest biblioteka do dodania.

 

 

Jeśli wszystko poszło dobrze w naszych referencjach powinno pojawić się nowe dowiązanie do biblioteki ”interop.quartztypelib.dll” która została utworzona w katalogu naszego projektu 

 

 

Alternatywną metodą wyłuskania niezbędnych funkcji z biblioteki quartz.dll jest metoda ręczna z wiersza poleceń.  W tym celu należy otworzyć konsole Visual Studio .NET 2003 Command Prompt i wpisać następujące polecenie

 

tlbimp %windir%\system32\quartz.dll /out:QuartzTypeLib.dll

 

Type Library Importer  (tlbimp.exe)  konwertuje zdefiniowane funkcje zawarte w bibliotece typu COM do odpowiedniej biblioteki zdefiniowanej w ” common language runtime assembly”. I tak w naszym przypadku z biblioteki quartz.dll powstanie biblioteka QuartzTypeLib.dll, która będzie zrozumiałą dla naszego środowiska.

 

Po wyborze jednej z metod ostatecznie należy dodać jedna linię kodu do naszego odtwarzacza

[Kod C#]

using QuartzTypeLib;

 

3.2. Budowa interfejsu odtwarzacza

 

  Rozplanowanie interfejsu zależy od indywidualnych upodobań, ja będę się trzymał dość standardowego rozmieszczenia klawiszy, menu oraz pasków.

 

Na początku dodajmy ”MainMenu” i wypełnijmy odpowiednimi polami. Aby to zrobić z zakładki ”ToolBox” należy przeciągnąć obiekt ”MainMenu” na obszar okna. A następnie pierwsza kolumnę (której nadajemy nazwę Plik) wypełnić w następujący sposób.

 

  

 

Między ”Zamknij plik”, a ”Wyjście” dodany jest separator. Do każdej z opcji dodane zostały skróty klawiszowe (”Otwórz plik...” odpowiada skrót CTRL + O), które wybiera się w zakładce ”Properites”. Także w tej zakładce należy ustawić dostępność poszczególnych pozycji menu ”Plik”. I tak ”Otwórz plik...” jak i ”Wyjście” maja być Enabled = true natomiast ”Zamknij plik” ma mieć ustawioną opcje Enabled = false. Opcja ta została wprowadzona w celu uniknięcia niepożądanych akcji jak np. zamknięcie pliku,który nie został jeszcze otwarty.

Tworzymy następna kolumnę tym razem o nazwie ”Odtwarzanie” i wypełniamy ja w sposób pokazany na rysunku poniżej.

 

Jak widać tym razem elementy ”Odtwarzaj/Pauza”, ”Stop”, ”Przewiń do przodu” oraz ”Przewiń do tyłu” mają ustawioną opcję Enabled = false. Należy zwrócić uwagę, że przy każdym z wyżej wymienionych elementów stoi znak (np. przy ”Stop” ”X”, nie są to skróty klawiszowe takie jak wybieraliśmy powyżej w zakładce ”Properites”, chociaż będą działać w ten sam sposób). Dwa ostatnie elementy rozwijają się w sposób jak jest to widoczne na rysunkach poniżej.

Przy ”0” należy zaznaczyć opcję ”Checked”. ”0” uznałem domyślnie za normalną prędkość odtwarzania.

 

 

”Głośność” zawiera trzy elementy widoczne na rysunku powyżej.

Ostatnią kolumną jaką należy wypełnić jest ”Okno” zawiera ona tylko jeden element, a jego nazwa to ”Pełny ekran”

 

 

Teraz podam jaką akcję będzie podejmowała nasza aplikacja po wybraniu poszczególnego elementu menu.

 

”Plik->Otwórz plik” – Pojawia się okno dialogowe z możliwością wybrania pliku do odtwarzania.

”Plik->Zamknij plik...” – Następuje zamknięcie otwartego pliku.

”Plik->Wyjście” – Aplikacja kończy swoje działanie i zamyka okno.

”Odtwarzanie->Odtwarzaj/Pauza” – W zależności od stanu w jakim znajduje się graf następuje zatrzymanie odtwarzania lub wznowienie.

”Odtwarzanie->Stop” – Animacja zostaje zatrzymana, a wskaźnik postępu ( wskaźnik postępu określa odległość od początku filmu w sekundach) przesunięty na pozycję 0.

”Odtwarzanie->Przewiń do przodu” – Wskaźnik postępu zostaje przesunięty do przodu o określoną liczbę sekund.

”Odtwarzanie->Przewiń do tyłu” – Wskaźnik postępu zostaje przesunięty do tyłu o określoną liczbę sekund.

”Odtwarzanie->Prędkość->[-5 - +5]” – Zmiana prędkości odtwarzania, przy czym –5 to najmniejsza, a +5 to największa szybkość.

”Odtwarzanie->Głośność->Podgłoś” – Zmiana natężenia dźwięku o określoną liczbę decybeli.

”Odtwarzanie->Głośność->Przycisz” – Zmiana natężenia dźwięku o określoną liczbę decybeli.

”Odtwarzanie->Głośność-> Wycisz” – Zmiana natężenia dźwięku na maksymalną lub minimalną w zależności od stanu grafu

”Okno->Pełny ekran” – Przełączenie odtwarzania w tryb pełnego ekranu.

 

Przejdźmy teraz do stworzenia dolnego panelu, który składa się z następujących elementów: StatusBar, ToolBar oraz TrackBar.

 

 

Na samym dole mamy StatusBar należy go przeciągnąć z zakładki ToolBox, a następnie ustawić Anchor: Bottom, Left, Right. W ”Properties” wybieramy ”Panels” i dodajemy trzy elementy. Pierwszy dodany nazywamy ”StatusBarStan” i ustawiamy następujące własności: Aligment Center, AutoSize None, BorderStyle None, Icon (none), Style Text, Text Zamknięte, Width 95, MinWidth 60, (name) StatusBarStan. Odpowiada on za wyświetlanie informacji o stanie odtwarzacza (wartość początkowa to ”Zamknięte”).

Drugi dodany nazywamy ”StatusBarTytul” i ustawiamy następujące własności: Aligment Center, AutoSize Spring, BorderStyle None, Icon (none), Style Text, Text, Width 79, MinWidth 10, (name) StatusBarTytul. Odpowiada on za wyświetlanie nazwy aktualnie otwartego pliku.

Trzeci dodany nazywamy ”StatusBarCzas” i ustawiamy następujące własności: Aligment Center, AutoSize Contents, BorderStyle Sunken, Icon (none), Style Text, Text 00:00:00 / 00:00:00, Width 130, MinWidth 130, (name) StatusBarCzas. Odpowiada on za wyświetlanie ”czas, jaki upłynął” / ”czas całkowity filmu”.

 

Teraz do naszego odtwarzacza dodajemy nowy element o nazwie ToolBar,który znajduje się w zakładce ToolBox. Po dodaniu ustawiamy Anchor: Bottom, Left, Right, Dock None,a ButtonSize zmniejszamy do 15; 15. Ustawiamy go tak jak jest to pokazane na rysunku powyżej. Przyciski najpierw dodajemy do ”Image list” znajdującej się w zakładce ToolBox następnie ustawiamy TransparetnColor na blue (opcja w Image list). Należy zwrócić uwagę,że tło w dołączonych przyciskach także jest niebieskie, a zatem będzie ono niewidoczne, gdy dodamy przyciski do paska ToolBar. Teraz dodajemy 3 przyciski do ToolBar ( ustawić opcję Enabled = false) oraz dwa separatory po ich bokach. Przyciski jak i separatory są dołączone do tego artykułu.

 

Ostatnim elementem,który będziemy dodawać jest TrackBar. Przeciągamy go z zakładki ToolBox i zmieniamy Anchor: Bottom, Left, Right, Maximum = 50, Enabled = false, AutoSize = false, TickSyle = None, Size 208;25. Po tych zmianach ustawiamy nasz TrackBar jak jest to pokazane na rysunku powyżej. Będzie on nam umożliwiał przeskok do dowolnego momentu w odtwarzanym filmie.

 

Po dodaniu tych wszystkich elementów musimy zadbać o miejsce, w którym będzie wyświetlana nasz animacja. Przeciągamy obiekt ”Panel” z ToolBox na okno naszego odtwarzacza,a następnie zmieniamy kilka opcji. Ustawiamy Anchor: Top , Bottom, Left , Right, a BackColor na Black. Rozciągamy nasz panel od lewej do prawej krawędzi oraz od dolnej krawędzi górnego menu do górnej krawędzi ToolBar. Możemy dodać jeszcze obrazek, który będzie wyświetlany, gdy odtwarzacz będzie znajdował się wstanie ”Zamknięte” (obrazek jest dołączony do tego artykułu). Po tych wszystkich operacjach nasz odtwarzacz powinien wyglądać tak jak na rysunku poniżej.

 

 

Linki:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemwindowsformsstatusbarclasstopic.asp

 

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemwindowsformstoolbarclasstopic.asp

 

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemwindowsformstrackbarclasstopic.asp

 

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemwindowsformsmainmenuclasstopic.asp

 

3.3. Powołanie obiektu Filter Graph Manager oraz interfejsów

 

   W standardowej aplikacji wykorzystującej DirectShow istnieje potrzeba wykorzystania 3 lub więcej interfejsów w celu kontroli grafu filtrów. Oto lista najczęściej wykorzystywanych interfejsów:

IMediaControl interfejs dostarcza metody kontrolujące przepływ strumienia danych przez graf filtrów. Zawiera metody dla uruchamiania, pauzowania i stopowania strumienia.

IVideoWindow ustawia opcje dla okna video. Aplikacja może wykorzystać ten interfejs do ustawienia właściciela okna, pozycji, rozmiarów oraz innych właściwości.

IMediaPosition interfejs zawiera metody do przesuwania odtwarzania do odpowiedniego miejsca w strumieniu danych.

IBasicAudio interfejs umożliwia aplikacji sterowanie głośnością i balansem strumienia audio.

IMediaEventEx  interfejs zawiera metody do przechwytywania wyjątków i wysyłania ich do odpowiedniego okna.

 

Wszystkie te interfejsy tworzymy w sposób następujący:

 

[Kod C#]

private IBasicAudio o_BasicAudio = null;

private IVideoWindow o_VideoWindow = null;

private IMediaEventEx o_MediaEventEx = null;

private IMediaPosition o_MediaPosition = null;

private IMediaControl o_MediaControl = null;

Interfejsy musimy powiązać z obiektem Filter Graph Manager w celu umożliwienie sterowania grafem filtrów. Należy go (obiekt FGM) jednak najpierw powołać. Poniżej zamieszczam kod funkcji, która wiąże interfejsy z obiektem FGM oraz go powołuje.

 

[Kod C#]

private FilgraphManager o_FilterGraph = null;

 

private void GetInterfaces()

{

      o_FilterGraph = new FilgraphManager();

      o_FilterGraph.RenderFile(MediaFile); //MediaFile–ścieżka dostępu do pliku

 

      o_BasicAudio = o_FilterGraph as IBasicAudio;

              

      try

      {                      

            o_VideoWindow = o_FilterGraph as IVideoWindow;

            o_VideoWindow.Owner = (int) panel1.Handle;

            o_VideoWindow.WindowStyle = WS_CHILD | WS_CLIPCHILDREN;

 

o_VideoWindow.SetWindowPosition(

panel1.ClientRectangle.Left,

                              panel1.ClientRectangle.Top,

                              panel1.ClientRectangle.Width,

                              panel1.ClientRectangle.Height);

      }

      catch (Exception)

      {

            o_VideoWindow = null;

      }

           

      o_MediaEventEx = o_FilterGraph as IMediaEventEx;

o_MediaEventEx.SetNotifyWindow((int)  this.Handle,WM_GRAPHNOTIFY, 0);

                 

 

      o_MediaPosition = (IMediaPosition) o_FilterGraph ;

      o_MediaControl = o_FilterGraph as IMediaControl;

       

}

 

Widzimy, że metoda ”RenderFile” (RenderFile – metoda buduje graf filtrów, który renderuje dany plik), wykorzystuje nie znany dla nas argument ”MediaFile”. ”MediaFile” to ścieżka dostępu do pliku, który będziemy odtwarzać. Nie musimy obecnie wiedzieć, w jaki sposób tej zmiennej przypisywana jest dana wartość ( w dziale 3.7.1 zostanie omówione to zagadnienie).

 

Należy zwrócić uwagę, iż przy kilku interfejsach podawane są dodatkowe opcje. Przy IVideoWindow podajemy okno, w którym będzie wyświetlana nasza animacja (metoda ”Owner”), styl okna ( metoda ”WindowStyle”) oraz pozycja (metoda ”SetWindowPosition”). Natomiast przy IMediaEventEx należy podać okno, do którego mają być wysyłane wyjątki generowane przez graf filtrów (metoda ”SetNotifyWindow”).

 

Linki:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directshow/htm/imediaeventexsetnotifywindow.asp

 

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directshow/htm/ivideowindowinterface.asp

 

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directshow/htm/imediaeventexinterface.asp

 

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directshow/htm/imediapositioninterface.asp

 

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directshow/htm/imediacontrolinterface.asp

 

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directshow/htm/aboutthefiltergraphmanager.asp

 

3.4. Obsługa wyjątków generowanych przez graf filtrów

 

   Po tym jak ustanowiliśmy interfejsy w poprzednim rozdziale moglibyśmy uruchomić naszą animację. Jednak dobrym pomysłem jest wprowadzenie obsługi wyjątków wysyłanych przez graf filtrów. Takie podejście okazuje się przydatne, gdy np. po zakończeniu filmu chcemy wykonać jakąś akcję. Nas interesować będzie wyjątek, który powie nam o końcu strumienia. Będziemy sprawdzać wszystkie, a jeśli dany wyjątek okaże się tym na, który czekamy wykonamy określoną akcję. Poniżej zamieszczona jest funkcja realizująca powyższe założenia.

 

[Kod C#]

protected override void WndProc( ref Message m )

{

      if (m.Msg == WM_GRAPHNOTIFY)

      {

            int EventCode;

            int Param1, Param2;

                       

            while (true)

            {

                  try

                  {

                        o_MediaEventEx.GetEvent(out EventCode,

out Param1,

out Param2, 0);

                                   

o_MediaEventEx.FreeEventParams(EventCode,

        Param1,

  Param2);

 

                        if (EventCode == EC_COMPLETE)

                        {    

                              o_MediaControl.Stop();

                              o_MediaPosition.CurrentPosition = 0;

                              Media_Status = MediaStatus.Stopped;

                        }

                  }

                  catch (Exception)

                  {

                        break;

                  }

            }

                       

      }

      base.WndProc(ref m);

}

 

Widzimy, że oczekiwanym wyjątkiem jest EC_COMPLETE, a akcja, którą podejmujemy zawarta jest wewnątrz wyrażenia warunkowego. Te trzy linijki zawarte wewnątrz tego wyrażenia zatrzymują naszą animację ( metoda ”Stop” interfejsu IMediaControl) oraz przesuwają wskaźnik pozycji na ”0” ( metoda ”CurrentPosition”  interfejsu IMediaPosition).

 

Linki:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemwindowsformscontrolclasswndproctopic.asp

 

3.5. Uruchamianie odtwarzacza

 

Obecnie jesteśmy w stanie odtwarzać dowolny akceptowany format. Jednak nie będziemy mogli podjąć żadnej akcji związanej ze sterowaniem gdyż przyciski nie są oprogramowane.  Wiemy już jak ustanawiać niezbędne interfejsy ( dział 3.3), a więc możemy przystąpić do uruchomienia animacji, a wykorzystamy do tego metodę ”Run”, którą udostępnia nam interfejs IMediaControl.

 

[Kod C#]

private void PlayMediaFile()

{

            CloseInterfaces();

GetInterfaces() ; //funkcja opisana w rozdziale 3.3

o_MediaControl.Run();

}    

 

Widzimy,że wywoływana jest dodatkowo funkcja, której jeszcze nie znamy "CloseInterfaces()". Odpowiada ona za zamknięcie wszystkich otwartych interfejsów. Dobrym pomysłem jest jej wywołanie przed jak i po zakończeniu animacji. Kod umieszczony został poniżej.

 

[Kod C#]

private void CloseInterfaces()

{

      if (o_MediaControl != null)

            o_MediaControl.Stop();

 

      Media_Status = MediaStatus.Stopped;

 

 

      if (o_VideoWindow != null)

      {

            o_VideoWindow.Visible = 0;

            o_VideoWindow.Owner = 0;

      }

 

      if (o_MediaControl != null) o_MediaControl = null;

      if (o_MediaPosition != null) o_MediaPosition = null;

      if (o_MediaEventEx != null) o_MediaEventEx = null;

      if (o_VideoWindow != null) o_VideoWindow = null;

      if (o_BasicAudio != null) o_BasicAudio = null;

      if (o_FilterGraph != null) o_FilterGraph = null;              

}

 

Jak widzimy wszystkie interfejsy, które wcześniej wskazywały obiekt FGM teraz zostają ustawione na null. Zagwarantuje to nam uniemożliwienie próby sterowania obiektem FGM. Funkcja ta musi zostać wywołana po zamknięciu pliku lub przed ustanowieniem interfejsów.

 

3.6. Aktualizacja przycisków i pasków

 

   Dobrym pomysłem jest informowanie użytkownika, w jakim stanie znajduje się obecnie graf filtrów. My będziemy to robić na kilka sposobów. Gdy budowaliśmy interfejs umieściliśmy pasek statusu, w którym będziemy informować użytkownika o obecnym stanie odtwarzacza (stan odtwarzacza jest bezpośrednio związany ze stanem grafu np. stan ”Odtwarzenie...” będzie informował nas, że przez graf filtrów przepływa strumień danych). Będziemy także ograniczać wykonywanie pewnych akcji poprzez blokowanie odpowiednich przycisków jak np. gdy mamy wciśniętą pauzę nie będziemy mogli wcisnąć jej jeszcze raz. Poniżej opisane są funkcje, które będą dbały o poprawność wyżej wymienionych założeń.

    

3.6.1. UpdateStatusBar

 

      Pasek StatusBar odpowiada za informowanie nas o stanie odtwarzacza (”Zamknięte” – plik multimedialny nie został otworzony, ”Wstrzymanie” – animacja została wstrzymana (pauza), ”Odtwarzanie ...” – animacja jest odtwarzana oraz ”Gotowy” – plik jest wczytany jednak animacja została zastopowana). A zatem musimy zadbać o zmianę opisu (dolny lewy róg odtwarzacza), a jest to zrealizowane w instrukcji ”switch (Media_Status)” (funkcja poniżej). Musimy zagwarantować także wyświetlanie aktualnego postępu w następującym formacie xx:xx:xx (godziny:minuty:sekundy), aby zapewnić zmianę co 1s musimy dodać do naszego odtwarzacza zegar ( znajduje się w zakładce ToolBox interval ustawić na wartość 100 = 1s).

 

[Kod C#]

private void licznk_czasu_Tick(object sender, System.EventArgs e)

{

      if (Media_Status == MediaStatus.Running)

      {

            UpdateStatusBar();

            UpdateMediaProgress();       

      }

}

 

 Funkcja powyżej obsługuje nasz zegar. Ustawienie interwału na 1s zagwarantuje nam wywołanie UpdateStatusBar dokładnie co 1s. Natomiast funkcja poniżej to już sama funkcja aktualizująca StatusBar.

 

[Kod C#]

private void UpdateStatusBar()

{          

            switch (Media_Status)

            {

                  case MediaStatus.None         :      statusBarStan.Text = "Zamknięte";

                                                       statusBarTytul.Text= "";

                                                       statusBarCzas.Text = "00:00:00 / 00:00:00";

                                                       break;

                  case MediaStatus.Paused       :      statusBarStan.Text = "Wstrzymanie"; break;

                  case MediaStatus.Running      :      statusBarStan.Text = "Odtwarzanie..."; break;

                  case MediaStatus.Stopped      :      statusBarStan.Text = "Gotowy"; break;

            }

           

            if (o_MediaPosition != null)

            {

                  int s = (int) o_MediaPosition.Duration;

                  int h = s / 3600;

                  int m = (s  - (h * 3600)) / 60;

                  s = s - (h * 3600 + m * 60);

               

                  int s1 = (int) o_MediaPosition.CurrentPosition;

                  int h1 = s1 / 3600;

                  int m1 = (s1  - (h1 * 3600)) / 60;

                  s1 = s1 - (h1 * 3600 + m1 * 60);

               

                  statusBarCzas.Text = String.Format("{0:D2}:{1:D2}:{2:D2} / {3:D2}:{4:D2}:{5:D2}",h1,m1,s1,h,m,s);               

            }

}

 

3.6.2. UpdateToolBar

 

   Funkcja UpdateToolBar odpowiada za aktualizowanie dostępności wszystkich przycisków na paskaku ToolBar oraz paska postępu (TrackBar). W zależności od stanu w jakim znajduje się odtwarzacz wyłączane lub włączane są odpowiednie przyciski. Poniżej zamieszczona jest funkcja realizująca to zadanie.

 

[Kod C#]

private void UpdateToolBar()

{

      switch (Media_Status)

      {

            case MediaStatus.Running      :     play_button.Enabled = true;

                                                play_button.Pushed = true;

                                                stop_button.Enabled = true;

                                                pause_button.Enabled = true;

                                                pause_button.Pushed = false;

                                                trackBar1.Enabled = true;

                                                pictureBox1.Enabled = false;

                                                break;

            case MediaStatus.Stopped      :      play_button.Enabled = true;

                                                play_button.Pushed = false;

                                                stop_button.Enabled = true;

                                                pause_button.Enabled = true;

                                                pause_button.Pushed = false;

                                                break;

            case MediaStatus.None        :      play_button.Enabled = false;

                                                play_button.Pushed = false;

                                                stop_button.Enabled = false;

                                                pause_button.Enabled =false;

                                                pause_button.Pushed = false;

                                                trackBar1.Enabled = false;

                                                pictureBox1.Enabled = true;

                                                break;

            case MediaStatus.Paused      :      play_button.Enabled = true;

                                                play_button.Pushed = false;

                                                stop_button.Enabled = true;

                                                pause_button.Enabled = true;

                                                pause_button.Pushed = true;

                                                break;

}

}

 

3.6.3. UpdateMediaProgress

 

      Funkcja ta odpowiada za aktualizację paska postępu. Jeśli pozycja wskaźnika postępu jest różna od null sprawdzana jest odległość od początku animacji, a następnie ustawiany jest wskaźnik paska postępu na odpowiednią pozycję (tracBar1.Value).

 

[Kod C#]

private void UpdateMediaProgress()

{

      if(o_MediaPosition != null)

            trackBar1.Value = (int) o_MediaPosition.CurrentPosition;

      else

            trackBar1.Value = 0;

}

 

3.6.4. UpdateMainMenu

 

      Funkcja UpdateMainMenu odpowiada za aktualizowanie dostępności wszystkich przycisków znajdujących się w menu. W zależności od stanu w jakim znajduje się odtwarzacz wyłączane lub włączane są odpowiednie przyciski. Poniżej zamieszczona jest funkcja realizująca to zadanie

 

[Kod C#]

private void UpdateMainMenu()

{          

      switch(Media_Status)

      {

            case MediaStatus.Running      :     Stop.Enabled = true;

                                                Play_Pause.Enabled = true;

                                                zamknij_plik.Enabled = true;

                                                przewin_do_przodu.Enabled = true;

                                                przewin_do_tylu.Enabled = true;

                                                pelny_ekran.Enabled = true;

                                                break;

            case MediaStatus.None        :      Stop.Enabled = false;

                                                Play_Pause.Enabled = false;

                                                zamknij_plik.Enabled = false;

                                                przewin_do_przodu.Enabled = false;

                                                przewin_do_tylu.Enabled = false;

                                                pelny_ekran.Enabled = false;       

                                                            break;

            case MediaStatus.Stopped      :     Stop.Enabled = false;

                                                Play_Pause.Enabled = true;

                                                zamknij_plik.Enabled = true;

                                                przewin_do_przodu.Enabled = false;

                                                przewin_do_tylu.Enabled = false;

                                                pelny_ekran.Enabled = true;

                                                break;

      }

}

 

3.7. Oprogramowanie przycisków odtwarzacza oraz menu

 

   Poniżej zawarty jest opis funkcji obsługujących nasze przyciski oraz menu, które dodawaliśmy przy budowaniu interfejsu.

 

3.7.1. Otwórz plik

 

  Do otwierania plików posłużymy się klasą OpenFileDialog. Daje ona możliwość wyboru pliku o określonych parametrach. Nas interesują pliki o dozwolonych rozszerzeniach (formaty plików akceptowane przez DirectShow). Do odpowiedniej filtracji dozwolonych formatów wykorzystujemy metodę OpenMediaFile.Filter.  Stała clipFileFilters zawiera rozszerzenia plików rozpoznawanych przez DirectShow. Poniżej zamieszczony jest kod funkcji jak również definicja stałej clipFileFilters.

 

[Kod C#]

private const string clipFileFilters =

"Pliki video (avi qt mov mpg mpeg m1v)|*.avi;*.qt;*.mov;*.mpg;*.mpeg;*.m1v |" +

"Wszystkie pliki (*.*) | *.*";

 

private void otworz_plik_Click(object sender, System.EventArgs e)

{

      OpenFileDialog OpenMediaFile = new OpenFileDialog();

      OpenMediaFile.Title = "Otwórz plik..."; 

      OpenMediaFile.Filter = clipFileFilters;                   

      if( OpenMediaFile.ShowDialog() != DialogResult.OK )

            return;

      MediaFile = OpenMediaFile.FileName;

}

 

 

Linki:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemwindowsformsopenfiledialogclasstopic.asp

 

3.7.2. Zamknij plik

 

      Po naciśnięciu tej opcji menu, następuje zerowanie zmiennej przechowującej nazwę pliku obecnie otwartego. Aktualizowane są wszystkie paski, menu oraz przyciski poprzez wywołanie wszystkich wyżej omówionych funkcji ”update”.

 

[Kod C#]

private void zamknij_plik_Click(object sender, System.EventArgs e)

{

      MediaFile = null;

      CloseInterfaces();

      Media_Status = MediaStatus.None;

               

      UpdateMediaProgress();

      UpdateStatusBar();

      UpdateMainMenu();

      UpdateToolBar();           

}

 

3.7.3. Wyjście

 

     Oprogramowanie tego przycisku jest chyba najłatwiejszą rzeczą w całym odtwarzaczu. Ponieważ jest to tylko jedna linia kodu wykonująca zamkniecie naszej aplikacji.

 

[Kod C#]

private void wyjscie_Click(object sender, System.EventArgs e)

{

      this.Close();

}

    3.7.4. Pauza/Odtwarzaj

    Tu w zależności od stanu, w jakim znajduje się odtwarzacz (graf filtrów) podejmowane są różne działania. Jeśli odtwarzanie w chwili naciśnięcia przycisku ”Pauza/Odtwarzaj” jest wstrzymane następuje wznowienie animacji oraz aktualizacja StatusBar i ToolBar (taka sama akcja podejmowana jest gdy animacja jest zastopowana). Natomiast gdy animacja jest odtwarzana następuje zatrzymanie oraz aktualizacja StatusBar i ToolBar. Do wznawiania i zatrzymywania animacji wykorzystujemy ten sam interfejs IMediaControl natomiast dwie różne metody ”Pause” oraz ”Run”.

 

[Kod C#]

private void Play_Pause_Click(object sender, System.EventArgs e)

{                

      if( o_MediaControl == null )

            return;

                 

      if(Media_Status == MediaStatus.Running)

      {

            o_MediaControl.Pause();

            Media_Status = MediaStatus.Paused;   

      }

      else if(Media_Status == MediaStatus.Paused)

      {

            o_MediaControl.Run();

            Media_Status = MediaStatus.Running;

      }

      else if(Media_Status == MediaStatus.Stopped)

      {

          o_MediaControl.Run();

            Media_Status = MediaStatus.Running;

            UpdateMainMenu();

      }

      UpdateStatusBar();

      UpdateToolBar();

}

 

3.7.5. Stop

 

   Jak sama nazwa mówi animacja zostaje zastopowana. Wiąże się z tym aktualizacja pasków, menu oraz przesunięcie wskaźnika pozycji na 0. Tak jak powyżej wykorzystujemy dwie metody interfejsu IMediaControl, ale tym razem są to ”Stop” i ”Pause”. Do zmiany wskaźnika pozycji wykorzystujemy metodę ”CurrentPosition” interfejsu IMediaPosition.

 

[Kod C#]

private void Stop_Click(object sender, System.EventArgs e)

{

      if( (Media_Status != MediaStatus.Paused) && (Media_Status != MediaStatus.Running) )

            return;

 

      if ( (o_MediaControl == null) || (o_MediaPosition == null) )

            return;

 

      o_MediaControl.Stop();

      Media_Status = MediaStatus.Stopped;

 

      o_MediaPosition.CurrentPosition = 0;

      o_MediaControl.Pause();

      UpdateStatusBar();

      UpdateMainMenu();

      UpdateToolBar();

      UpdateMediaProgress();

}

 

3.7.6. Przewiń do przodu

 

Przewijanie do przodu zwiększa położenia wskaźnika postępu (wskaźnik postępu określa odległość od początku filmu w sekundach) o 5s. jeśli jest to możliwe (do końca filmu pozostało więcej niż 5s.).

 

[Kod C#]

private void przewin_do_przodu_Click(object sender, System.EventArgs e)

{

      if ( o_MediaPosition == null)

            return;

 

      double pozycja,czas_trwania,delta;

                 

      pozycja = o_MediaPosition.CurrentPosition;

      czas_trwania = o_MediaPosition.Duration;

      delta = czas_trwania - pozycja;

 

      if( delta < 5 )

            o_MediaPosition.CurrentPosition = czas_trwania;

      else

            o_MediaPosition.CurrentPosition = pozycja + 5;

}

 

3.7.7. Przewiń do tyłu

 

Przewijanie do tyłu zmniejsza położenia wskaźnika o 5s. jeśli jest to możliwe (od początku filmu musi upłynąć więcej niż 5s.).

 

[Kod C#]

private void przewin_do_tylu_Click(object sender, System.EventArgs e)

{

      if ( o_MediaPosition == null )

            return;

 

      double pozycja;

                 

      pozycja = o_MediaPosition.CurrentPosition;

                 

      if( pozycja < 5 )

            o_MediaPosition.CurrentPosition = 0;

      else

            o_MediaPosition.CurrentPosition = pozycja - 5;

}

    3.7.8. Regulacja głośności

   Tu zmniejszane lub zwiększane jest natężenie dźwięku. W naszym przypadku zmiana następuje o 5dB ( należy pamiętać, że jedna jednostka to 0.01 dB, a zatem wartość 500 odpowiada 5 dB). Możliwość sterowania dźwiękiem udostępnia nam interfejs IBasicAudio metoda ”Volume”.  Poniżej zamieszczona jest funkcja podgłaszająca.

 

[Kod C#]

private void podglos_Click(object sender, System.EventArgs e)

{

      if( o_BasicAudio == null )

            return;

 

      if(o_BasicAudio.Volume > -500 )

            o_BasicAudio.Volume =0;

      else

            o_BasicAudio.Volume = o_BasicAudio.Volume + 500;

           

}

 

3.7.9. Regulacja prędkości odtwarzania

 

   Po wybraniu z menu opcji zmiany prędkości następuje zwiększenie lub zmniejszenie szybkości przepływu strumienia przez graf filtrów. ”Rate” (”Rate” jest to metoda interfejsu IMediaPosition wykorzystywana do przyśpieszania lub zwalniania animacji) może przyjmować wartości od (0,2> przy czym 2 oznacza najszybsze odtwarzanie, a 1 to prędkość normalna. Poniżej zamieszczona jest funkcja zmieniająca prędkość odtwarzania do prędkości normalnej.

 

[Kod C#]

private void play0_Click(object sender, System.EventArgs e)

{

      if( o_MediaPosition == null )

            return;

                 

      o_MediaPosition.Rate = 1.0;

      Zaznacz(play0);

}

 

3.7.10. Odtwarzanie w trybie pełnego ekranu

 

      Wybranie opcji ”Pełny ekran” zmienia tryb odtwarzania na tryb pełnego ekranu, jeśli obecnie animacja odtwarzana była w trybie okienkowym. Natomiast w przypadku gdy animacja odtwarzana była w trybie pełnego ekranu następuje zmiana odtwarzania na tryb okienkowy. Realizuje to funkcja zamieszczona poniżej. Jeśli chcemy by w trybie pełnego ekranu obsługiwane były wiadomości wysyłane przez klawiaturę i myszkę (wiadomości te chcemy obsługiwać gdyż do sterowania odtwarzaczem używamy także klawiatury) musimy użyć metody ”MessageDrain” i wskazać okno, które otrzymuj te wiadomości w trybie okienkowym. 

 

[Kod C#]

private void pelny_ekran_Click(object sender, System.EventArgs e)

{

      if( o_VideoWindow == null )

            return;

                             

      int mode;

      mode = o_VideoWindow.FullScreenMode;

      if( mode == OAFALSE )

      {

            o_VideoWindow.MessageDrain = (int) panel1.Handle  ;

            mode = OATRUE;

            o_VideoWindow.FullScreenMode = mode;

            FullScreen = true;

      }

      else

      {

            mode = OAFALSE;

            o_VideoWindow.FullScreenMode = mode ;

            FullScreen = false;

      }

}

 

3.7.11. Obsługa paska narzędzi

 

      Nasz pasek narzędzi składa się z dwóch separatorów oraz trzech przycisków. Jeśli chcemy sprawdzić jaki przycisk został wciśnięty sprawdzamy wartość ”e.Button”. U nas ”1” odpowiada ”Odtwarzaj”, ”2”  odpowiada ”Stop”, a ”3” to ”Pauza”. Po sprawdzeniu podejmujemy odpowiednie działanie, a następnie aktualizujemy StatusBar oraz ToolBar.

 

 

 

[Kod C#]

private void toolBar1_ButtonClick(object sender, System.Windows.Forms.ToolBarButtonClickEventArgs e)

{

      switch(toolBar1.Buttons.IndexOf(e.Button))

      {

            case 1      :     o_MediaControl.Run();

                              Media_Status = MediaStatus.Running;

                              break;

            case 2      :     Stop_Click(null,null);

                              break;

            case 3      :     o_MediaControl.Pause();

                              Media_Status = MediaStatus.Paused;

                              break;     

      }

      UpdateStatusBar();

      UpdateToolBar();

}

 

3.7.12. Skróty klawiszowe

 

   Skróty klawiszowe wprowadziliśmy by ułatwić nam używanie naszego odtwarzacza. Musimy teraz napisać funkcję, która będzie  sprawdzać jaki klawisz został wciśnięty na klawiaturze. Funkcja, która realizuje te zadanie zamieszczona jest poniżej.

 

[Kod C#]

this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.mediaplayer_KeyDown);

 

private void mediaplayer_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)

{

      switch(e.KeyCode)

      {

            case Keys.P            :      Play_Pause_Click(null,null);

                                          break;

            case Keys.X            :      Stop_Click(null,null);

                                          break;

            case Keys.F            :      pelny_ekran_Click(null,null);

                                          break;

            case Keys.Escape       :      if( FullScreen == true )

                                          pelny_ekran_Click(null,null);

                                          break;

            case Keys.M            :      wycisz_Click(null,null);

                                          break;

            case Keys.Add          :      podglos_Click(null,null);

                                          break;

            case Keys.Subtract     :      przycisz_Click(null,null);

                                          break;

            case Keys.Oemplus      :      podglos_Click(null,null);

                                    break;

            case Keys.OemMinus     :      przycisz_Click(null,null);

                                          break;

            case Keys.Oemcomma     :      przewin_do_tylu_Click(null,null);

                                          break;

            case Keys.OemPeriod    :      przewin_do_przodu_Click(null,null);

                                          break;

      }

}

 

Jak widzimy powyżej sprawdzany jest kod naciśniętego klawisza, a następnie podejmowana jest odpowiednia akcja (wywoływane są funkcje, które zostały omówione w rozdziałach poprzedzających).

4.  Podsumowanie

 

W ten oto sposób można stworzyć dość prosto nieskomplikowany odtwarzacz. Możliwości jakie tkwią w DirectShow są znacznie większe. Istnieje jeszcze wiele interfejsów udostępniających ciekawe metody. Przy niewielkiej modyfikacji naszego odtwarzacza możliwe jest stworzenie tunera TV lub odtwarzacza DVD. W przypadku jakichkolwiek niejasność odsyłam do kodu dołączonego do tego artykułu. Zawarte tam są opisy funkcji, zmiennych oraz stałych, które z pewnością ułatwią zrozumienie materiału.

Załączniki:

Podobne artykuły

Komentarze 5

User 115665
User 115665
0 pkt.
Nowicjusz
21-01-2010
oceń pozytywnie 0
Ogólnie nie lubie artykułów w stylu - "pokarze jak napisać program". Niemniej jednak jest to bardzo dobry wstęp do multimediów zilustrowany przejrzystym przykładem. Siedem...
User 82969
User 82969
35 pkt.
Poczatkujacy
21-01-2010
oceń pozytywnie 0
Tresc mi sie podobala, choc juz o tym troche wiem:) Niestety forma dla mnie odrazajaca bo to ma byc artykul a nie praca magisterska czy cokolwiek w tym guscie. Szczegolnie ten spis tresci na poczatku mnie "zamurowal"
User 82969
User 82969
35 pkt.
Poczatkujacy
21-01-2010
oceń pozytywnie 0
To chyba drugi artykul w tym miesiacu na ktorym w niektorych przegladarkach siada oprawa graficzna, ale z tym to chyba do admina
SeSo
SeSo
0 pkt.
Nowicjusz
21-01-2010
oceń pozytywnie 0
    Artykuł bardzo dobry osobiście sprawdziłem czy to działa i jest super :) Jest to idealny przykład dla osób które zaczynają się bawić w C# i DirectShow co uczy ich kombinować :) SIEDEM :)
User 131786
User 131786
1 pkt.
Nowicjusz
21-01-2010
oceń pozytywnie 0
Nie zauważyłem działu artykuły lecz publikacje :). To wydaje mi sie, że daje mi możliwość wyboru formy. Ja zdecydowałem się na połączenie artykułu i dokumentacji, a spis treść dodałem tylko dlatego, aby ułatwić nawigację bo "artykuł" jest dość długi. Pozdrawiam kaszub
pkt.

Zaloguj się lub Zarejestruj się aby wykonać tę czynność.