Java Media Framework
Kamil Płaczko
JMF (Java Media Framework) – technologia
umożliwiająca wstawianie multimediów do
aplikacji napisanych w
, oraz transmisję
audio/video za pomocą protokołu RTP
.
…..o Javie
Java jest
stworzonym przez grupę roboczą pod kierunkiem
z firmy
. Java
jest językiem tworzenia
do
, czyli postaci
wykonywanej przez
. Język
cechuje się
. Jego
podstawowe koncepcje zostały przejęte z języka
(maszyna wirtualna,
) oraz z języka
(duża część składni i słów
kluczowych).
Autorzy języka Java określili kilkanaście kluczowych
koncepcji swojego języka. Najważniejsze z nich to:
Obiektowość - W przeciwieństwie do
-
języka C++, Java jest silnie
ukierunkowana na
. Wszelkie dane i
akcje na nich podejmowane są pogrupowane w klasy
obiektów. O obiekcie można myśleć jako o
samoistnej części programu, która może przyjmować
określone stany i posiada określone zachowania,
które mogą zmieniać te stany bądź przesyłać dane
do innych obiektów. Wyjątkiem od całkowitej
obiektowości
(jak np. w Smalltalku) są typy proste (int, float itp.).
// oznacza komentarz
// w tej postaci to obiekt reprezentujący kolorowy punkt
public class Figura {
// właściwości (atrybuty/pola)
private float środekX;
private float środekY;
private int kolor; //tak naprawdę do
przechowywania(tworzenia)
//koloru używa się zazwyczaj obiektu
java.awt.Color
// operacje (metody)
public float obliczPole()
{ return 0; }
public float obliczObwód()
{ return 0; }
public void wyświetl(){...} ... }
W Javie wszystkie obiekty są pochodną obiektu nadrzędnego
(jego klasa nazywa się po prostu Object), z którego
podstawowe zachowania i właściwości, dzięki czemu
wszystkie posiadają wspólny podzbiór podstawowych
możliwości, takich jak ich: identyfikacja, porównywanie,
kopiowanie, niszczenie czy wsparcie dla
.
Sieciowość i obsługa
programowania rozproszonego
Dzięki wykorzystaniu reguł obiektowości, Java nie
widzi różnicy między danymi płynącymi z
lokalnego a danymi z pliku dostępnego przez
.
Biblioteki Javy udostępniają wyspecjalizowane funkcje
umożliwiające programowanie rozproszone - zarówno
między aplikacjami Javy (
) jak i między aplikacją
Javy a aplikacjami napisanymi w innych językach (
, usługi
service). Inne biblioteki
udostępniają możliwość pisania aplikacji
uruchamianych w
(
) oraz aplikacji działających ciągle po stronie
(
).
Niezawodność i bezpieczeństwo
W zamierzeniu Java miała zastąpić
- obiektowego
następcę języka
. Jej projektanci zaczęli od rozpoznania cech
języka C++, które są przyczyną największej liczby błędów
programistycznych, by stworzyć język prosty w użyciu,
bezpieczny i niezawodny.
O ile po pięciu odsłonach Javy jej prostota jest dyskusyjna, o
tyle język faktycznie robi dużo, by utrudnić programiście
popełnienie błędu. Przede wszystkim Java posiada system
czyli sytuacji, gdy kod programu natrafia na nie
przewidywane trudności, takie jak np.:
----operacje na elemencie poza zadeklarowaną granicą
lub elemencie pustym
----czytanie z niedostępnego pliku lub nieprawidłowego adresu
URL
-----podanie nieprawidłowych danych przez użytkownika
W innych językach programowania programista oczywiście
może wprowadzić wewnętrzne testy sprawdzające poprawność
danych, pozycję indeksu tablicy, inicjalizację zmiennych itd.,
ale jest to jego dobra wola i nie jest to jakoś szczególnie
wspierane przez dany język. W Javie jest inaczej - obsługa
wyjątków jest obowiązkowa, bez tego program się nie
skompiluje. Przy tym obiekty wchodzące w skład pakietu
standardowego Javy (i gros obiektów z pakietów pochodzących
od poważnych programistów niezależnych) implementują
wyjątki w każdym miejscu kodu, którego wykonanie jest
niepewne ze względu na okoliczności zewnętrzne.
Sama obsługa wyjątków polega na napisaniu kodu, który
wykona się w odpowiedzi na taką sytuację nadzwyczajną. Może
to być np. podstawienie wartości domyślnej przy natrafieniu na
nieprawidłową wartość parametru, zaniechanie danej akcji i
powrót do stanu stabilnego czy choćby zapisanie pracy przed
wyjściem. W sytuacji wyjątkowej program przerywa normalne
wykonanie i tworzy specjalny obiekt wyjątku odpowiedniej
klasy, który "wyrzuca" z normalnego biegu programu.
Następnie zdefiniowany przez użytkownika kod "łapie" ten
obiekt wyjątku i podejmuje odpowiednie działanie.
Działanie może być dwojakiego typu: wspomniane wyżej środki
zaradcze lub odrzucenie takiego „błedu " dalej, do bloku
programu, który nakazał wykonanie wadliwej operacji. Takie
podawanie sobie wyjątku może być wieloetapowe i jeśli
skończy się w bloku głównym programu powoduje jego
przerwanie i ogłoszenie błędu krytycznego.
Oprócz systemu wyjątków Java od wersji 1.4 posiada dwa inne
systemy wspomagające pisanie niezawodnych programów:
logowanie i asercje.
Pierwsze pozwalają na zapisanie w plikach dziennika przebiegu
działania programu, z dodatkową możliwością filtrowania
zawartości, określenia poziomu logowanych błędów itp. Drugie
rozwiązanie pozwala na upewnienie się, że pewne założenia co
do określonych wyrażeń (np. że liczba, z której wyciągamy
pierwiastek jest nieujemna) są prawdziwe.
Asercje są o tyle ciekawe, że działają tylko z odpowiednią opcją
wykonania programu, dzięki czemu programista może
sprawdzić działanie programu, a później bez wysiłku
spowodować pominięcie testowej części kodu po prostu przez
ominięcie tej opcji.
Krytyka i kontrowersje
Język Java pomimo swoich wielu zalet, posiada wiele
wad w tym takie, które wzbudzają liczne
kontrowersje:
Najczęściej wymienianą wadą języka Java jest to, że
programy pisane w Javie wykonują się wolniej niż
programy pisane w językach negatywnie
kompilowanych (np. C++). Zarzut ten odnosi się
szczególnie do starych wersji Javy, kiedy
zaawansowane mechanizmy takie jak JIT albo
współbieżny odśmiecacz nie były dostępne. Obecnie
zdania są mocno podzielone. Można podać
przykłady programów zarówno takich, które w Javie
będą wykonywały się wolniej niż w C++, jak i takich,
które będą wykonywały się szybciej.
Javie zarzuca się, że niezbyt dobrze nadaje się do
zastosowań czasu rzeczywistego. Głównym problemem
jest brak przewidywalności wydajności oraz
nieoczekiwane przestoje powodowane działaniem
odśmiecacza. W nowych wersjach Javy ten drugi problem
został radykalnie ograniczony, jednak nadal do
zastosowań czasu rzeczywistego lepiej stosować języki
natywnie kompilowane.
Często Javie zarzucane jest to, że posiada mniejszą
funkcjonalność niż np. C++, co ogranicza programistę.
Jako przykład przywołuje się czasami fakt, że aby
uruchomić niewielki program trzeba napisać dłuższy kod
programu. Niektórzy jednak zwracają uwagę, że również
język C++ nie posiada wielu elementów, które można
znaleźć w Javie jak np. klasy anonimowe, odśmiecacz,
system pakietów
, dynamiczne ładowanie klas czy
reflection API.
Co możemy odtwarzać?
Niestety nie wszystko. JMF nie korzysta
bowiem z kodeków, które mamy w systemie,
lecz z własnych dekoderów
Np. support dla mp3 został dodany DOPIERO
w listopadzie 2004!
Najważniejsze typy plików obsługiwane przez
JMF 2.1.1
AIFF, AVI (ale bez kompresji Div-X ;-) lub XviD!),
MIDI, MPEG-1 Video, MPEG Audio Layer II i Layer III,
QuickTime, Sun Audio, Wave
Przy transmisji przez protokół RTP (przez sieć), lista
ta zdecydowanie się zawęża
Dostępne formaty video
Dostępne formaty video
Format
Content Type
Quality
CPU
Requirements
Bandwidth
Requirements
Cinepak
AVI
QuickTime
Medium
Low
High
MPEG-1
MPEG
High
High
High
H.261
AVI
RTP
Low
Medium
Medium
H.263
QuickTime
AVI
RTP
Medium
Medium
Low
JPEG
QuickTime
AVI
RTP
High
High
High
Indeo
QuickTime AVI
Medium
Medium
Medium
Dostępne formaty audio
Dostępne formaty audio
Format
Content Type
Quality
CPU
Requirement
s
Bandwidth
Requirements
PCM
AVI
QuickTime
WAV
High
Low
High
Mu-Law
AVI
QuickTime
WAV
RTP
Low
Low
High
ADPCM
(DVI,
IMA4)
AVI
QuickTime
WAV
RTP
Medium
Medium
Medium
MPEG-1
MPEG
High
High
High
MPEG
Layer3
MPEG
High
High
Medium
GSM
WAV
RTP
Low
Low
Low
G.723.1
WAV
RTP
Medium
Medium
Low
Obiekt Player
Za odtwarzanie danych odpowiadają obiekty typu
Player – udostępniają funkcjonalność typowego
odtwarzacza – play, stop, przewijanie, głośność itp.
Tworzenie playera:
public SimpleAudioPlayer(URL url) throws IOException,
NoPlayerException, CannotRealizeException
{
audioPlayer = Manager.createRealizedPlayer(url);
}
public SimpleAudioPlayer(File file) throws IOException,
NoPlayerException, CannotRealizeException
{
this(file.toURL());
}
Player działa na stanach
Obiekt Playera jest maszyną opartą na stanach:
Unrealized – obiekt dopiero co stworzony
Realizing – Player zaczyna pobierać informacje o danych
Realized –
wiemy co będziemy odtwarzać, możemy zwrócić
komponenty GUI
Prefetching – zaczynamy przygotowanie do
odtwarzania
Prefetched – mamy już zbuforowane dane
Started – gra i buczy
Większość metod JMF jest nieblokująca
W naszym przypadku kazaliśmy Managerowi stworzyć
Player będący od razu w stanie Realized. Dopóki obiekt
nie został stworzony, główny wątek programu w którym
tworzyliśmy Player, został zablokowany.
Takie rzeczy zwykle robi się w oddzielnym wątku
Odtwarzanie: audioPlayer.play()
Zatrzymanie: audioPlayer.stop()
Usunięcie obiektu: audioPlayer.close()
Szybkość odtwarzania: audioPlayer.setRate()
0.0-1.0 – wolniej
1.0 – normalnie
>1.0 – szybciej (The Chipmunks)
Wartości ujemne – podobno od tyłu, ale ciężko mi na
słuch ocenić czy to naprawdę działa
Głośność:
GainControl gain = audioPlayer.getGainControl();
gain.setLevel(); // w zakresie od 0.0f do 1.0f
Przewijanie:
Time czas = audioPlayer.getDuration();
int czasSekundy = duration.getSeconds();
if (przewinDo >= 0 && przewinDo <= czasSekundy) {
/* mała uwaga – obiekt Time bez rzutowania na
double stworzy się nam dla czasu w
nanosekundach co nas raczej słabo urządza */
Time goto = new Time((double)przewinDo);
audioPlayer.setMediaTime(goto);
}
Tworzenie komponentów
odtwarzacza video
Component visual = player.getVisualComponent() –
zwraca komponent odpowiedzialny za wyświetlanie danych
video
Component ctrl = player.getControlPanelComponent()
– zwraca panel sterujący
Component
vol = player.getGainControl().getControlComponent()
– głośniej/ciszej. Obiekt GainControl może służyć do
regulowania głośności z poziomu programu (np. fajny fade
na końcu)
Warto by się upewnić, czy obiekty nie są przypadkiem null –
np. getVisualComponent() wywołany dla obiektu Playera
pliku audio „raczej” będzie miał wartość null. Jeżeli mimo to
będziemy chcieli dodać go do okna – Java wyrzuci wyjątek.
Dodajemy komponenty do
okna
Teraz wystarczy już tylko dodać to do JFrame.
W konstruktorze dodajemy:
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
panel.add(visual, BorderLayout.NORTH);
panel.add(ctrl, BorderLayout.CENTER);
panel.add(vol, BorderLayout.SOUTH);
this.add(panel);
this.pack();
To wszystko! Komponenty są już skojarzone z
odpowiednim obiektem Playera. Wystarczy kliknąć na
play i zacznie się odtwarzanie.