Documente Academic
Documente Profesional
Documente Cultură
Java Media FrameworkTM (pe scurt JMF) este un API care folosete
la interconectarea multimedia folosind mediul Java. Acest mediu de dezvoltare
face parte dintr-unul mult mai amplu, numit Java Media, care conine mai multe
API-uri. Acestea sunt urmtoarele:
Prima versiune de API JMF a fost versiunea 1.0, versiune care a fost
dezvoltat de ctre SUN Microsystems Inc, Silicon Graphics Inc i Intel
Corporation. Aceast versiune permitea programatorilor s scrie cod cu care s
poat manipula procese multimedia n timp real.
Urmtoarea versiune de API JMF a fost versiunea 2.0, dezvoltat de
ctre SUN Microsystems Inc n colaborare cu IBM Corporation. Fa de
versiunea anterioar, specialitii au introdus i suport pentru captur, prelucrare
n timp real i au extins lucrul cu codec-urile. Dar, poate cea mai revoluionar
modificare este introducerea suportului pentru protocolul RTP (Real-Time
Transfer Protocol).
1
8.2. Lucrul cu date dependente de timp (Time-Based
Media)
Orice date care i modific structura n timp pot fi considerate ca
dependente de timp (time based). Clip-urile audio, secvenele MIDI, filmele i
animaiile sunt forme comune ale datelor dependente de timp. Aceste date pot
proveni dintr-o varietate de surse, cum ar fi fiiere locale sau din reea, camere
video sau microfoane etc.
2
De obicei, stream-urile media conin canale multiple de date care se
numesc piste (tracks). Aceste stream-uri media care conin mai multe piste
poart n general denumirea de stream-uri media multiplexate sau complexe.
Demultiplexarea este procesul de extragere a unei piste individuale dintr-un
stream media complex.
Tipul pistei identific tipul de date pe care acesta l conine, de exemplu
video sau audio.
Un stream media poate fi identificat prin locaia n care se afl i
protocolul folosit la accesarea lui. Spre exemplu, un URL ar putea fi folosit
pentru a descrie locaia unui fiier de tipul QuickTime ntr-un sistem local sau
aflat la distan. Dac fiierul este local, poate fi accesat prin protocolul FILE. Pe
de alt parte, dac fiierul se afl pe un server WEB, poate fi accesat prin
protocolul HTTP. Un locator media (media locator) este o cale de a identifica
locaia unui stream media n cazul n care un URL nu poate fi folosit.
Stream-urile media pot fi clasificate n funcie de modul n care datele
sunt distribuite:
Lrgime de
Format Tip coninut Calitate Solicitare Procesor
band
AVI
Cinepak Medie Sczut Ridicat
QuickTime
MPEG-1 MPEG Ridicat Ridicat Ridicat
3
Lrgime de
Format Tip coninut Calitate Solicitare Procesor
band
AVI
H.261 Sczut Medie Medie
RTP
QuickTime
H.263 AVI Medie Medie Sczut
RTP
QuickTime
JPEG AVI Ridicat Ridicat Ridicat
RTP
QuickTime
Indeo Medie Medie Medie
AVI
Tabel 8.2. Formate video uzuale
Tip Lrgime de
Format Calitate Solicitare Procesor
coninut band
AVI
PCM QuickTime Ridicat Sczut Ridicat
WAV
AVI
QuickTime
Mu-Law Sczut Sczut Ridicat
WAV
RTP
ADPCM AVI
(DVI, QuickTime Medie Medie Medie
IMA4) WAV, RTP
MPEG-1 MPEG Ridicat Ridicat Ridicat
MPEG
MPEG Ridicat Ridicat Medie
Layer3
WAV
GSM Sczut Sczut Sczut
RTP
WAV
G.723.1 Medie Medie Sczut
RTP
Tabel 8.3. Formate audio uzuale
Unele dintre aceste formate au fost proiectate pentru anumite aplicaii i
necesiti. Formatele care necesit calitate i lime de band ridicate sunt n
4
general destinate aplicaiilor stocate local sau pe CD-uri. Formatele H.261 i
H.263 sunt folosite n general la aplicaii de tip video conferin (video
conferencing) i sunt optimizate pentru stream-uri video care nu implic mult
aciune. Similar, G.723 este folosit pentru a stoca/transmite cuvinte la o rat
mic pentru aplicaiile telefonice.
8.2.2. Prezentarea datelor de tip media
n majoritatea cazurilor datele media sunt de tip audio sau video i pot fi
prezentate prin intermediul dispozitivelor de ieire (output devices), cum ar fi
boxele (speakers) sau monitorul. Stream-urile media pot fi trimise i spre alte
destinaii, spre exemplu pot fi salvate ntr-un fiier sau transmise prin reea. n
general aceste destinaii poart numele de data sink.
8.2.2.1. Controlul prezentrii
n timpul prezentrii unui stream media, se folosesc controale de genul
celor folosite la VCR pentru a permite utilizatorului controlul rulrii. Spre
exemplu, un panou de comand pentru un film ar trebui s aib funcii care s
permit pornirea, oprirea, i derularea nainte/napoi a filmului.
8.2.2.2. Latena
n multe cazuri, de obicei cnd este necesar prezentarea unui stream
media care provine din reea, prezentarea stream-ului media nu poate ncepe
imediat. Timpul scurs pn la nceperea prezentrii poart numele de laten de
start (start latency). Pentru utilizatori aceast laten este sesizabil ca timpul
scurs ntre momentul n care s-a apsat pe butonul de start i momentul n care
ncepe rularea efectiv.
Prezentrile multimedia combin de obicei cteva tipuri de date
dependente de timp ntr-o prezentare sincronizat. De exemplu, n timpul unui
slide-show poate rula n fundal muzic, sau, n cadrul unui clip audio sau video,
se poate face sincronizarea cu un text animat. Cnd prezentarea unor stream-uri
media multiple este sincronizat, este esenial s se in cont de latena fiecrui
stream, n caz contrar rularea diferitelor stream-uri putnd ncepe la momente
diferite.
5
n general, cu ct este mai mare calitatea, cu att este mai mare fiierul
i sunt necesare o putere de calcul mai ridicat i o lrgime de band mai mare.
Lrgimea de band este n general reprezentat de numrul de bii care sunt
transmii ntr-o anumit perioad de timp (bit rate).
Pentru a realiza prezentri video de nalt calitate, numrul de cadre
(frames) afiat n fiecare perioad de timp (frame rate) trebuie s fie ct mai
mare posibil. n general, filme care au 30 de cadre pe secund sunt considerate
insesizabil diferite de distribuiile TV pe scar larg sau de casetele video (ca i
senzaie de continuitate, nu ca i calitate).
8.2.3. Procesarea datelor multimedia
n majoritatea cazurilor asupra datele din stream-ul media se efectueaz
diverse operaii de procesare nainte de a fi prezentate utilizatorului. n general,
acestea sunt:
8
Figura 8.2. Procesul de nregistrare, procesare i prezentare
JMF se bazeaz pe acest model fundamental. Sursa datelor folosit n
JMF ncapsuleaz stream-ul media ca i caseta video despre care vorbeam mai
devreme. Player-ul din JMF are aceleai funcii i mecanisme de control ca i un
VCR. Rularea i captura audio i video din JMF necesit dispozitive de intrare i
ieire similare, cum ar fi microfonul, camera, boxele i monitorul.
Sursele datelor i dispozitivele de rulare sunt parte integrant a
arhitecturii API de nalt nivel a JMF. Aceast arhitectur de nivel nalt se refer
la componentele standard din JMF. Arhitectura JMF de nivel jos se refer la
posibilitatea programatorului de a dezvolta sau extinde instrumente de lucru
proprii. Aceast arhitectur multistrat permite dezvoltatorilor de programe Java
s aib la dispoziie un API uor de utilizat i de integrat n aplicaii Java,
beneficiind n continuare de flexibilitatea i extensibilitatea necesar pentru
crearea unor aplicaii media avansate i uor upgrade-abile.
8.3.1.1. Modelul Time (Timp)
JMF controleaz timpul cu o precizie de nanosecunde. Un anumit punct
particular n timp este vzut n general ca un obiect Time, dei exist i cteva
clase care suport specificarea timpului n nanosecunde.
Clasele care suport modelul de timp JMF implementeaz interfaa
Clock pentru a ine cont de timpul necesar pentru o anumit operaie efectuat
asupra unui stream media. Interfaa Clock definete operaiile de baz de
cronometrare i sincronizare, care sunt necesare pentru a controla prezentarea
media.
9
Figura 8.3. Modelul Time la Java Media Framework
Un Clock folosete TimeBase pentru a contoriza trecerea timpului n
timp ce un stream media este prezentat. Singura informaie pe care TimeBase o
ofer este timpul curent, care poart numele de time-base time. Acest timp nu
poate fi oprit sau resetat. De obicei, timpul oferit de TimeBase se bazeaz pe
ceasul sistemului, ora exact fiind aflat de la BIOS-ul calculatorului.
Media time reprezint poziia curent n cadrul unui stream media
(nceputul stream-ului este media time zero, sfritul stream-ului fiind maximul
media time pentru acel stream). Durata stream-ului media este timpul scurs ntre
start i stop, adic lungimea de timp necesar pentru prezentarea stream-ului
media.
Pentru a cunoate timpul curent, Clock folosete:
10
MediaTime=MediaStartTime+Rate(TimeBaseTime-TimeBaseStartTime)
11
8.3.1.3. Modelul Event (Eveniment)
JMF utilizeaz un mecanism structurat de raportare a evenimentelor
pentru a informa programele despre starea curent a sistemului media i pentru a
le permite acestora s rspund erorilor aprute. Ori de cte ori un obiect JMF
trebuie s raporteze starea sa, el genereaz un MediaEvent. MediaEvent este
alctuit n aa fel nct s poat clasa toate tipurile particulare de evenimente.
Pentru fiecare tip de obiect care poate genera un MediaEvent, JMF
definete o interfa de ascultare (listener) corespunztoare.
Obiectele cu funcii de control, cum sunt Player-ele sau Procesoarele
genereaz evenimente media.
12
Figura 8.5. Modelul Data din JMF
Datele pot fi obinute dintr-o varietate de surse, cum ar fiiere locale sau
din reea sau din transmisii n direct. Sursele de date pot fi categorizate dup
modul n care transferul este iniiat:
13
JMF definete dou tipuri de surse de date speciale, surse de date
clonabile (cloneable) i surse de date combinate (merging).
O surs de date clonabil poate fi folosit pentru a crea diferite clone
pentru surse de date de tipul Pull sau Push. Pentru a realiza aceast operaie,
trebuie apelat metoda Manager createCloneableDataSource. n continuare
toate operaiile se refer doar la clon. Obiectul original DataSource nu mai este
folosit direct. Sursele de date clonabile implementeaz interfaa
SourceCloneable, care definete o metod, createClone. Prin apelarea acestei
metode se pot crea orict de multe clone ale DataSource.
Clonele nu trebuie s aib neaprat aceleai proprieti ca i sursa
original. Aceste proprieti pot fi modificate dup clonare. O surs
MergingDataSource poate fi folosit pentru a combina stream-urile din mai
multe surse ntr-o singur surs. Aceasta permite ca un set de surse de date s
poat fi administrat dintr-un singur punct de control cnd connect, disconnect,
start sau stop sunt apelate, apelrile se refer la sursele de date combinate.
Pentru a construi o surs de date combinate, trebuie apelat metoda
createMergingDataSource. Pentru a asigura reuita operaiunii, trebuie ca toate
datele s fie de acelai tip. Spre exemplu, nu se pot combina date de tip Pull cu
date de tip Push. Durata sursei combinate este egal cu durata maxim a
obiectelor combinate.
Formatul exact al unui obiect este reprezentat de un obiect de tip
Format. Formatul nsui nu conine informaii despre codare sau despre durat,
ci doar descrie numele codrii i tipul de date necesare formatului.
JMF extinde Format pentru a defini formate audio i video specifice,
dup cum se poate vedea n Figura 8.6.
14
Un AudioFormat descrie atributele specifice unui format audio, ca rata
(sample rate) sau numrul de canale. Un VideoFormat ncapsuleaz informaii
referitoare la datele video. Mai multe formate sunt derivate din VideoFormat
pentru a descrie atributele formatelor video uzuale, incluznd:
IndexedColorFormat
RGBFormat
YUVFormat
JPEGFormat
H261Format
H263Format
Pentru a primi informaii despre schimbrile de format de la un
Controller, trebuie implementat o interfa ControllerListener i urmrite
evenimentele FormatChangeEvents.
8.3.1.5. Interfaa Control
Interfaa JMF Control prevede un mecanism pentru setarea i
interogarea atributelor unui obiect. Un Control permite de obicei accesul la
componenta interfeei utilizator corespondent, ceea ce ajut utilizatorul s
controleze atributele obiectului.
Orice obiect JMF care vrea s permit acces la obiectele Control
corespunztoare lui trebuie s aib implementat interfaa Controls. Aceast
interfa definete metode pentru obinerea obiectelor Control asociate.
JMF definete interfeele Control standard din Figura 8.8. Interfaa
CachingControl permite afiarea i monitorizarea progresului ncrcrii. Dac
un Player sau un Processor poate raporta progresul ncrcrii, el implementeaz
aceast interfa pentru ca bara de progres (progress bar) s poat fi afiat
utilizatorului.
Interfaa GainControl permite ajustri ale volumului audio, cum ar fi
setarea nivelului sau reducerea lui la zero (mute) la ieirea unui Player sau
Processor.
17
vizual i la componenta panoului de control. Pentru a afla aceste componente
trebuie apelate metodele getVisualComponent i getControlPanelComponent.
Dac nu se dorete folosirea componentelor de control implicite, este
posibil dezvoltarea unor componente utilizator.
8.3.1.7. Extensibilitatea
Programatorii avansai i furnizorii de tehnologii pot extinde
funcionalitatea JMF n dou moduri:
8.3.2.1. Player-ele
Un Player proceseaz un stream de date i le red la un anumit timp. O
surs de date este folosit pentru a asigura acest stream Player-ului. Destinaia
unde se realizeaz redarea depinde de tipul datelor ce sunt prezentate.
19
Figura 8.10. Modelul Player n JMF
Un Player nu permite nici un fel de control al procesrii pe care o
execut i nici asupra modului n care se face redarea.
Player-ul suport controale utilizator standard i ignor cteva restricii
operaionale impuse de Clock i Controller.
20
Figura 8.12. Strile unui Player
21
ntr-un mod de operare normal, un Player trece prin toate strile pn
cnd ajunge n starea Started:
Un Player n starea Unrealized a fost iniializat, dar nc nu
tie nimic despre datele pe care urmeaz s le prelucreze. Cnd un
Player este creat pentru prima dat, este n starea Unrealized;
Cnd procedura Realize este apelat, un Player trece din
starea Unrealized n starea Realizing. Un Player n starea Realizing este
n procesul de determinare a cerinelor de resurse. Aceast determinare
este efectuat o singur dat. Resursele ar putea fi resursele de redare,
altele dect resursele folosite exclusiv (exclusive-use resources);
Cnd un Player trece de starea Realizing, ajunge n starea
Realized. Un Player Realized tie de ce resurse are nevoie i are
informaii despre tipul datelor ce urmeaz a fi prezentate. Din cauz c
un Player Realized tie cum s redea aceste date, el poate pune la
dispoziie utilizatorului componente vizuale i controale. Conexiunea
lui cu alte obiecte din sistem este existent, dar nu i nsusete alte
resurse care ar putea mpiedica alt Player s porneasc;
Cnd procedura Prefetch este apelat, un Player trece de la
starea Realized la starea Prefetching. n aceast stare Player-ul se
pregtete s prezinte datele media. La nceput, Player-ul ncarc datele
ce trebuie prezentate, obine acces exclusiv la resursele necesare, dup
care face tot ceea ce este necesar pentru a se pregti de rulare.
Procedura de Prefetch se apeleaz i n cazul n care are loc o
repoziionare (spre exemplu o derulare napoi/nainte) n prezentare sau
dac o schimbare n rata de transfer necesit folosirea unor buffere
suplimentare sau o procesare alternativ;
Cnd un Player termin toate operaiile din starea de
Prefetching, trece n faza urmtoare, i anume Prefetched. n aceast
stare, Player-ul este gata de a fi pornit;
Apelarea procedurii Start pune un Player n starea Started. n
aceast moment, se face o mapare a timpului de start i Clock-ul asociat
este pornit, dei Player-ul s-ar putea s atepte un anumit timp nainte
de a ncepe prezentarea.
23
Figura 8.13. Modelul Processor n JMF
n afar de trimiterea datelor spre dispozitivele de redare, un Processor
poate trimite datele spre o DataSource pentru a putea fi prezentate de alt Player
sau Processor sau salvate ntr-un fiier.
8.3.2.3. Controlul prezentrii
n afara controalelor standard definite de Controller, un Player sau
Processor permite i ajustarea volumului.
Tipuri adiionale de interfee Control utilizator pot fi adugate printr-o
implementare particular a unui Player sau Processor care s modifice
comportamentul controalelor i s expun componentele interfeei utilizator.
Aceste controale pot fi accesate prin metoda getControls.
Spre exemplu, interfaa CachingControl extinde interfaa Control pentru
a realiza un mecanism de afiare a unei bare de progres a unui download
(download progress bar). Dac un Player poate raporta progresul lui de
download, el implementeaz aceast interfa. Pentru a afla dac un Player
suport CachingControl, trebuie apelat metoda getControl(CachingControl) sau
trebuie folosit getControls pentru a obine o list a controalelor suportate.
Un Player sau un Processor ofer n general dou componente pentru
interfaa utilizator, una vizual i una pentru panoul de control. Acestea pot fi
accesate direct prin metodele getVisualComponent pentru componenta vizual i
getControlPanelComponent pentru panoul de control.
De asemenea, este posibil implementarea unor interfee utilizator. n
acest caz trebuie folosit un mecanism de ascultare a evenimentelor pentru a
determina cnd trebuie modificate componentele acestor interfee.
24
unei metode. Spre exemplu, un Player genereaz un eveniment
RateChangeEvent cnd rata sa se modific prin apelarea setRate.
Evenimentele de tranziie (TransitionEvents) permit
programului s rspund modificrilor strii unui Controller. Un Player
genereaz evenimente de tranziie ori de cte ori trece de la o stare la
alta.
Evenimentele de ncheiere, cum este ControllerClosedEvents
sunt generate de un Controller cnd acesta se oprete. Cnd un
Controller genereaz un eveniment ControllerClosedEvent, el nu mai
poate fi folosit. Un eveniment ControllerErrorEvent este un caz special
de ControllerClosedEvent. Este posibil ascultarea unui astfel de
eveniment pentru a rspunde defeciunilor unui Controller i a minimiza
impactul acestora asupra utilizatorului.
25
Figura 8.14. Evenimentele n JMF
8.3.3. Procesarea
Un Processor este un Player care primete o DataSource la intrare,
execut procese definite de utilizator asupra datelor media, dup care trimite mai
departe datele media procesate. Figura 8.15 prezint procesarea n JMF.
26
Figura 8.15. Procesarea n JMF
Un Processor poate trimite datele de ieire spre un dispozitiv de
prezentare sau spre o DataSource. n cel de al doilea caz, DataSource poate fi
folosit ca intrare pentru un alt Player sau Processor, sau ca intrare ntr-un
DataSink.
n timp ce procesarea executat de un Player este predefinit de
echipament, un Processor permite programatorului s defineasc tipul de
procesare pe care l vrea aplicat datelor. Aceast procesare poate fi aplicarea de
efecte, mixarea i compunerea de piste n timp real.
28
Figura 8.17. Strile unui Processor
29
Metoda aplicat Starea Unrealized Starea Configuring Starea Configured Starea Realized
30
addController NotRealizedError NotRealizedError NotRealizedError legal
Deallocate legal legal legal Legal
getControlPanelComponent NotRealizedError NotRealizedError NotRealizedError legal
getControls legal legal legal legal
getDataOutput NotRealizedError NotRealizedError NotRealizedError legal
getGainControl NotRealizedError NotRealizedError NotRealizedError legal
getOutputContentDescriptor NotConfiguredError NotConfiguredError legal legal
getStartLatency NotRealizedError NotRealizedError NotRealizedError legal
getSupportedContent-Descr legal legal legal legal
getTimeBase NotRealizedError NotRealizedError NotRealizedError legal
getTrackControls NotRealizedError NotRealizedError legal FormatChangeException
rspunde cu o eroare sau cu o excepie.
8.3.4. Captura
Un dispozitiv de captur multimedia poate aciona ca o surs de
distribuie de date multimedia. Spre exemplu, un microfon poate captura
semnal audio brut sau o plac de captur video poate captura semnal video
digital de la o camer video. Aceste dispozitive de captur poart numele de
DataSources. Exist mai multe tipuri de DataSource care pot fi folosire pentru
31
realizarea capturii: PushDataSource, PushBufferDataSource, PullDataSource i
PullBufferDataSource.
Unele dispozitive captureaz stream-uri de date multiple. Spre
exemplu, o plac pentru audio/video conferin captureaz un stream audio i
unul video. DataSource-ul corespondent poate conine multiple SourceStream-
uri care se mapeaz peste stream-urile de date provenite de la dispozitiv.
8.3.5. Stocarea datelor i transmisia
Un DataSink este folosit pentru a citi datele de la o DataSource i de a
le trimite spre o anumit destinaie (n general spre o alt destinaie dect
dispozitivul de prezentare). Un anumit DataSink poate scrie date ntr-un fiier,
poate scrie date prin reea sau poate funciona ca i un Broadcaster RTP.
Ca i Player-ele, obiectele de tip DataSink sunt construite de Manager
folosind DataSource. Un DataSink poate folosi un StreamWriterControl pentru
a permite controlul asupra modului n care datele sunt scrise ntr-un fiier.
Un DataSink genereaz un eveniment DataSinkEvent pentru a raporta
starea sa. Un eveniment DataSinkEvent poate fi generat cu un cod care explic
motivul sau poate fi generat ca unul dintre urmtoarele subtipuri:
32
Implementarea interfeei Multiplexer permite specificarea
modului n care pistele individuale sunt combinate pentru a forma un
singur stream de ieire pentru un Processor;
Implementarea interfeei Render permite controlul asupra
modului n care datele sunt procesate i trimise spre dispozitivele de
ieire.
NOT: API-ul JMF pentru plug-in-uri este parte component a API-
ului JMF, dar Player-ele i Processoarele nu trebuie neaprat s suporte plug-
in-uri. Aceste plug-in-uri nu funcioneaz cu Player-ele i Processoarele JMF
1.0. Versiunea 2.0 a JMF dezvoltat de SUN Microsystems, Inc. i IBM
Corporation suport integral acest API .
33
Manager-ul folosete URL-ul sau MediaLocator-ul care trebuie
specificat pentru creearea Player-ului. Un URL poate fi construit cu succes
doar dac URLStreamHandler-ul corespondent este instalat. Asupra
MediaLocator nu se aplic aceast restricie.
Multe dintre metodele care pot fi apelate asupra unui Player necesit
ca acesta s fie n starea Realized. O metod care garanteaz c Player-ul este
n starea Realized cnd se apleleaz aceste metode este folosirea metodei
createRealizedPlayer la construirea Player-ului. Aceast metod este o cale
convenabil de creeare i trecere a unui Player n starea Realized ntr-un singur
pas. Cnd aceast metod este apelat, se blocheaz pn cnd Player-ul este
Realized. Manager-ul are o metod echivalent, i anume
createRealizeProcessor pentru construirea unui Processor n starea Realized.
NOT: Trebuie inut seama c blocarea unui Player sau Processor
pn ajunge n starea Realized poate produce rezultate nesatisfctoare. Spre
exemplu, dac metoda createRealizedPlayer este apelat ntr-un applet,
Applet.start i Applet.stop nu vor putea ntrerupe procesul de construcie al
Player-ului sau Processor-ului.
Un Processor poate fi creat i folosind ProcessorModel. Acesta
definete necesarul de resurse pentru intrare i ieire iar Manager-ul face tot
posibilul pentru a ndeplini cererea de resurse. Pentru a construi un Processor
folosind modelul ProcessorModel, trebuie apelat metoda
Manager.createRealizedProcessor.
Exemplul urmtor creaz un Processor n starea Realized care poate
produce piste audio stereo codate IMA4 cu o rat de 44.1 kHz, pe 16 bii.
34
O component vizual apare n cazul n care un Player prezint vizual
datele multimedia, dac are aceste date. Chiar i un Player audio poate avea
componente vizuale, cum ar fi afiarea formelor de und sau afiarea unor
caractere animate.
Pentru a afia o component vizual a unui Player trebuie urmai
urmtorii doi pai:
35
trebuie apelat getControlComponent asupra componentei
GainControl returnate de Player;
se adaug componenta rezultat n spaiul de prezentare al
aplicaiei sau n fereastra aplicaiei.
8.4.1.2.4. Afiarea unor componente de control utilizator
Multe Playere au alte proprieti care pot fi administrate de ctre
utilizator. Spre exemplu, un Player video ar putea permite utilizatorului s
ajusteze luminozitatea i contrastul, care nu sunt administrare de interfaa
Player. Pentru a afla ce controale utilizator suport un Player trebuie apelat
metoda getControls.
Spre exemplu, se poate apela getControls pentru a determina dac un
Player suport interfaa CachingControl.
36
De fiecare dat cnd se primete un CachingControlEvent,
trebuie verificat dac download-ul este terminat. Cnd
getContentProgress returneaz aceeai valoare ca i getContentLength,
bara de progres trebuie nlturat.
37
8.4.1.5. Pregtirea startului
Majoritatea Player-elor nu pot fi pornite instant. nainte de a putea
realiza pornirea unui Player, trebuie ndeplinite anumite condiii hardware i
software. Spre exemplu, dac un Player nu a mai fost pornit niciodat, este
necesar alocarea unor buffere n memorie pentru stocarea datelor. Sau, dac
datele se afl undeva n reea, Player-ul trebuie s stabileasc conexiunea n
reea nainte de a aduce datele. Chiar i dac Player-ul a mai fost pornit, buffer-
ele ar putea conine date care nu corespund cu datele corespondente poziiei
curente.
JMF mparte procesul de pregtire de pornire a unui Player n dou
faze, Realizing i Prefetching. Dac aceste faze se execut nainte de pornirea
Player-ului, se minimizeaz timpul necesar Player-ului pentru nceperea
prezentrii cnd metoda start este apelat. Implementarea interfeei
ControlListener permite controlul exact al timpului de execuie al acestor
operaii.
Cea de a treia faz de pregtire a startului este numit Configuring. n
timpul acestei faze, pot fi selectate anumite opiuni pentru a controla felul n
care Processor-ul manipuleaz datele.
Pentru a trece Player-ul n starea Realizing i pentru a ncepe procesul
de realizare se apeleaz metoda realize. Pentru a trece Player-ul n starea
Prefetching i pentru a iniia procesul de prefetching, se apeleaz metoda
prefetch. Aceste metode sunt asincrone i rezultatul este imediat. Cnd Player-
ul a completat o operaie cerut, el genereaz un evenimet
RealizeCompleteEvent sau PrefetchCompleteEvent.
Un Player n starea Prefetched este pregtit de start i latena sa de
pornire nu poate fi redus mai mult.
Foarte important este faptul c un Player n starea Prefetched ine
blocate unele dintre resursele sistemului. Deoarece unele dispozitive, cum sunt
plcile de sunet, pot fi utilizate de un singur program ntr-un moment dat, un
Player aflat n starea Prefetched poate mpiedica alte Playere s porneasc.
Pentru a determina ct de mult timp este necesar pentru a porni un
Player, trebuie apelat metoda getStartLatency. Pentru Player-ele care au o
laten de start variabil, apelarea metodei getStartLatency returneaz latena de
start maxim posibil. Pentru unele tipuri de date, getStartLatency poate returna
LATENCY_UNKNOWN.
Latena de pornire raportat prin apelarea metodei getStartLatency
poate diferi n funcie de starea curent a Player-ului. Spre exemplu, dup o
operaie de prefetch, valoarea returnat este de obicei mai mic.
8.4.1.6. Pornirea i oprirea prezentrii
Interfeele Clock i Player definesc metodele necesare pentru pornirea
i oprirea prezentrii.
38
Pentru pornirea prezentrii se apeleaz metoda start. Aceasta spune
Player-ului s pornesc prezentarea ct mai repede posibil. Dac este necesar,
pregtete Player-ul prin efectuarea operaiilor de realize i prefetch. Dac
metoda start este apelat asupra unui Player deja pornit, singurul rezultat este
faptul c este generat un eveniment StartEvent.
Pentru realizarea sincronizrii interfaa Clock definete metoda
syncStart.
Pentru a porni un Player dintr-un punct specific al stream-ului de date
trebuie urmai urmtorii doi pai:
39
ntotdeauna se poate apela metoda setStopTime asupra unui Player
oprit. Oricum, timpul de stop se poate seta doar asupra unui Player pornit. Dac
exist deja un timp de stop, metoda setStopTime arunc o eroare.
Pentru a afla timpul de stop setat, trebuie apelat metoda getStopTime.
Dac timpul de stop nu este programat, getStopTime returneaz Clock.RESET.
Pentru a retrage timpul de stop i a permite Player-ului s continue pn ce
ajunge la sfritul prezentrii, se folosete setStopTime(Clock.RESET).
8.4.1.7. Eliberarea resurselor ocupate de Player
Metoda deallocate informeaz Player-ul c trebuie s elibereze toate
resursele pe care le folosete n exclusivitate i s minimizeze accesul la
resursele neexclusive. Managementul memoriei i dimensiunea bufferelor
alocate unui Player nu sunt specificate, motiv pentru care majoritatea Player-
elor aloc buffere care sunt mari raportate la bufferele standard din JAVA. Un
Player bine implementat elibereaz maximum de memorie posibil cnd metoda
deallocate este apelat.
Metoda deallocate poate fi apelat doar asupra unui Player oprit.
Pentru a evita erorile ClockStartedErrors, trebuie apelat metoda stop nainte
de apelarea metodei deallocate. Dac se apeleaz deallocate asupra unui
Player aflat n starea Prefetching sau Prefetched, el revine n starea Realized.
Dac se apeleaz asupra unui Player aflat n starea Realizing, Player-ul
genereaz un eveniment DeallocateEvent i revine n starea Unrealized.
Cnd se dorete terminarea lucrului cu un Player, trebuie apelat
metoda close. Aceasta indic faptul c Controller-ul nu va mai fi folosit i se
poate nchide automat. Prin apelarea close se elibereaz toate resursele care au
fost folosite de Controller i ntrerupe toate activitile. Tot atunci se genereaz
un eveniment ControllerClosedEvent. Un Controller nu poate fi redeschis iar
apelarea unor metode asupra lui poate duce la generarea unor erori.
8.4.1.8. Interogarea unui Player
Un Player poate da informaii despre parametrii lui cureni, incluznd
aici rata de rulare, timpul corespondent i durata.
8.4.1.8.1. Obinerea ratei de rulare
Pentru a obine rata de rulare trebuie apelat metoda getRate.
Rezultatul este rata de rulare ca o valoare de tip float.
40
Trebuie notat faptul c corespondena ntre timpul corespondent unui
Player i cadre nu este unu la unu. Fiecare cadru este prezentat pentru o
anumit perioad de timp, iar timpul corespondent continu s avanseze n
timpul acelei perioade.
S lum exemplul n care un Player prezint fiecare cadru pentru 5
secunde, caz n care rata cadrelor frame rate) este de 0.2 cadre/secund. Figura
8.18 ilustreaz aceast situaie.
myCurrentTBTime = player1.getTimeBase().getTime();
41
implicit, i anume 1.0 cadre/secund. Durata unui stream este accesibil doar
prin intermediul unui Player.
Dac durata nu poate fi determinat cnd metoda getDuration este
apelat, este returnat DURATION_UNKNOWN. Aceast situaie poate aprea
cnd Player-ul nu a ajuns ntr-o stare care s permit accesul la durata stream-
ului. Mai trziu, durata poate fi disponibil i o apelare a aceleiai metode poate
returna valoarea dorit. Dac sursa de date nu are o durat definit, cum este n
cazul broadcast-ului n direct, metoda getDuration returneaz valoarea
DURATION_UNBOUNDED.
8.4.1.9. Tratarea evenimentelor
Interfaa ControllerListener este o interfa asincron pentru tratarea
evenimentelor generate de un obiect de tip Controller. Folosirea acestei
interfee permite utilizatorului s administreze timpul necesar unor operaii
poteniale consumatoare de timp (spre exemplu, la un Player, operaia de
prefetching).
8.4.1.9.1. Implementarea interfeei ControllerListener
Pentru a implementa o interfa ControllerListener, trebuie:
42
Cnd se primesc evenimente de la un Controller, sunt necesare o serie
de operaii pentru a fi sigur c Controller-ul este n starea corespunztoare
nainte de apelarea unei metode de control. Spre exemplu, nainte de apelarea
oricrei metode care sunt restricionate la Player-ele oprite, trebuie verificat
starea intei Player-ului prin apelarea metodei getTargerState. Dac start a fost
apelat, Player-ul consider c este n starea Started, deci este posibil s
genereze evenimente de tranziie n timp ce se pregtete s prezinte datele.
Unele tipuri de evenimente ControllerEvents conin informaii de stare
adiionale. Spre exemplu, clasele StartEvent i StopEvent definesc fiecare o
metod care permite utilizatorului s afle timpul exact cnd a aprut un
eveniment.
8.4.1.9.2. Folosirea clasei ControllerAdapter
ControllerAdapter este o clas cu unele avantaje care implementeaz
interfaa ControllerListener i care poate fi extins uor pentru a rspunde unor
evenimente particulare. Pentru a implementa interaa ControllerListener
folosind clasa ControllerAdapter, sunt necesare urmtoarele operaii:
43
Dac se nregistreaz un singur ControllerAdapter ca listener pentru
mai multe Playere, n implementarea metodelor evenimentelor trebuie
determinat care anume dintre Playere a generat evenimentul. Pentru aceasta se
apeleaz getSource pentru a determina unde a fost un eveniment
ControllerEvent generat.
8.4.1.10. Sincronizarea stream-urilor multiple
Pentru a sincroniza prezentarea mai multor stream-uri media, trebuie
sincronizate Player-ele. Ele trebuie asociate cu acelai TimeBase. Pentru
aceasta, se folosesc metodele getTimeBase i setTimeBase definite de interfaa
Clock. Spre exemplu, dac avem dou Playere, mai exact player1 i player2, le
putem sincroniza ntre ele setnd player1 s foloseasc baza de timp a lui
player2:
44
Player. Invers, la apelarea metodei removeController, Controller-ul specificat
este nlturat din lista Controller-elor administrate.
De obicei, cnd se dorete sincronizarea Player-elor sau altor
Controllere, trebuie utilizat acest mecanism addController. Este simplu, este
rapid i mai ferit de erori dect ncercarea de a administra Playere sincronizate
individual.
Cnd un Player ia controlul asupra unui Controller:
45
Spre exemplu, pentru a pregti toate Controller-ele administrate de
pornire, trebuie apelat metoda prefetch asupra Player-ului administrator.
Acesta se asigur c toate Controller-ele se afl n starea Prefetched, determin
latena de pornire maxim i apeleaz metoda syncStart pentru a le porni,
specificnd latena maxim de start care trebuie respectat.
Cnd se apeleaz o metod asupra Player-ului administrator, acesta o
propag spre Controller-ele aflate sub administrarea lui. nainte de aceasta, el
se asigur c Controller-ul se afl n faza potrivit. Urmtorul tabel descrie ce
se ntmpl unui Controller administrat cnd se apeleaz o metod asupra
Player-ului administrator.
46
Apeleaz metoda stop asupra
Stop Nu are efect. tuturor Controller-elor
administrate.
Apeleaz deallocate asupra
deallocate tuturor Controller-elor Genereaz o eroare.
administrate.
Apeleaz setStopTime asupra
Apeleaz setStopTime asupra
tuturor Controller-elor
tuturor Controller-elor
setStopTime administrate. (Poate fi apelat
administrate. (Player-ul
o singur dat asupra unui
trebuie s fie Realized).
Player pornit).
Apeleaz syncStart asupra
syncStart tuturor Controller-elor Genereaz o eroare.
administrate.
Apeleaz close asupra tuturor
Close Genereaz o eroare.
Controller-elor administrate..
Tabel 8.6. Metodele de control aplicabile asupra unui Player administrator
Pentru ndeprtarea unui Controller se folosete metoda
removeController. Exemplul 8.7 arat cum se face eliberarea lui player1 de sub
administrarea lui player2.
47
se folosete metoda setOutputDescriptor pentru a specifica
formatul datelor multiplexate la ieirea din Processor;
se folosete metoda TrackControl setCodecChain pentru
selecia codec-urilor sau a efectelor folosite de Processor;
se folosete metoda TrackControl setRenderer pentru a
selecta plug-in-ul Renderer folosit de Processor.
8.5.1. Configurarea unui Processor
n afara fazelor Realizing i Prefetching prin care orice Processor trece
cnd se pregtete de pornire, un Processor trece i prin faza de configurare,
numit Configuring. Metoda configure este apelat pentru a trece un Processor
din starea Unrealized n starea Configuring.
n timpul n care se afl n starea Configuring, un Processor culege
informaia de care are nevoie pentru a construi obiecte TrackControl pentru
fiecare pist. Cnd termin, trece n starea Configured i genereaz un
eveniment ConfigureCompleteEvent. Odat ce un Processor este Configured, se
pot seta formatul datelor la ieire i opiunile pentru TrackControl. Cnd se
termin setarea acestor opiuni, se apeleaz metoda realize pentru a trece
Processor-ul n starea Realizing.
Odat ce un Processor este n starea Realized, modificrile viitoare de
modificare a opiunilor de procesare nu sunt garantate c vor funciona. n
majoritatea cazurilor, se va primi o excepie FormatChangeException.
8.5.2. Selectarea opiunilor de procesare a pistelor
Pentru a selecta ce plug-in-uri sunt folosite la procesarea fiecrei piste
din stream-ul de date, trebuie:
48
lanul de procesare este determinat de formatul datelor de intrare i de ieire pe
care fiecare plug-in l suport.
Pentru a controla codarea efectuat asupra unei piste de ctre un
anumit Codec, se pot folosi controalele pentru codec asociate acelei piste.
Pentru a obine aceste controale, trebuie apelat metoda TrackControl
getControls. Aceasta returneaz toate controalele asociate cu aceai pist,
inclusiv controalele de codec-uri cum sunt: H263 Control, QualityControl i
MPEGAudioControl.
8.5.3. Conversia datelor dintr-un format n altul
Se poate selecta formatul unei anumite piste prin apelarea unei metode
TrackControl pentru acea pist:
49
apelat metoda getTrackControls asupra Processor-ului
pentru a obine un TrackControl pentru fiecare pist din stream-ul de
date. Processor-ul trebui s fie n starea Configured nainte de apelarea
metodei;
apelat metoda TrackControl setRenderer pentru a specifica
plug-in-ul.
8.5.7. Salvarea detelor ntr-un fiier
Pentru a salva datele ntr-un fiier trebuie folosit un DataSink pentru a
citi datele de la ieirea Processor-ului. Trebuie urmai urmtorii pai:
getControl("javax.media.datasink.StreamWriterControl")
50
asupra Processor-ului.
8.5.8. Conectarea unui Processor la un alt Player
Datele de la ieirea unui Processor pot fi folosite ca date de intrare la
alt Player. Pentru a obine datele de la ieirea unui Processor trebuie apelat
metoda getDataOutput, care returneaz un obiect de tipul DataSource. Acest
obiect poate fi folosit la construirea unui Player sau a unui Processor prin
intermediul unui Manager.
8.6. Captura datelor n Java Media Framework
ncepnd cu versiunea 2.0, JMF ofer programatorilor posibilitatea de
a achiziiona date de la un dispozitiv de captur, cum ar fi un microfon sau o
camer video. Aceast operaie poart numele de capturare. Datele capturate
pot fi capturate i afiate sau pot fi stocate pentru o utilizare ulterioar.
Pentru a captura date trebuie:
51
8.6.2. Captura efectiv a datelor
Pentru a captura date de la un anumit dispozitiv de captur, trebuie
obinut MediaLocator din obiectul CaptureDeviceInfo al acelui dispozitiv.
Exist posibilitatea de a folosi acest MediaLocator pentru a construi un Player
sau Processor direct sau de a-l folosi pentru a construi o DataSource care s fie
folosit ca intrare ntr-un Player sau Processor. Pentru a iniia procesul de
captur trebuie pornit Player-ul sau Processor-ul.
8.6.3. Controlul utilizatorului asupra procesului de captur
n general un dispozitiv de captur are implementat un set de atribute
specifice care pot fi folosite pentru a controla acel dispozitiv. Pentru a permite
controlul utilizatorului asupra acestor setri, n JMF se folosesc dou tipuri de
control: PortControl i MonitorControl. Accesarea acestor controale se
realizeaz prin apelarea metodei getControl asupra DataSource-ului avnd ca
parametru atributul care dorim s l modificm.
Un PortControl ofer posibilitatea selectrii portului de unde datele
vor fi capturate.
Un MonitorControl ofer posibilitatea monitorizrii procesului de
captur.
Ca i alte obiecte de tip Control, dac exit o component vizual care
corespunde lui PortControl sau MonitorControl, aceasta poate fi obinut prin
apelarea getControlComponent. Adugarea acestei componente ferestrei applet-
ului sau ferestrei aplicaiei ofer utilizatorului posibilitatea controlului capturii.
Este posibil afiarea panoului standard de control i a componentelor
vizuale asociate cu un Player sau cu un Processor. Exemplul 8.10 ilustreaz
cum se realizeaz afiarea componentelor GUI (Graphic User Interface) pentru
un Processor.
52
se citesc datele de la ieirea Processor-ului prin apelarea
getDataOutput;
se construiete un DataSink pentru scrierea n fiier prin
apelarea Manager.createDataSink. Parametrii sunt DataSource-ul de
ieire i un MediaLocator care specific locaia fiierului n care se
dorete salvarea;
se apeleaz metoda open asupra DataSink-ului pentru a
deschide fiierul;
se apeleaz metoda start asupra DataSink-ului;
se apeleaz metoda start asupra Processor-ului pentru a
ncepe captura datelor;
se ateapt pentru un eveniment EndOfMediaEvent, un
anumit timp sau intervenia utilizatorului;
se apeleaz metoda stop asupra Processor-ului pentru a
termina captura datelor;
se apeleaz metoda close asupra Processor-ului;
cnd Processor-ul este oprit i DataSink-ul posteaz un
eveniment EndOfStreamEvent trebuie apelat metoda close asupra
DataSink-ului.
53
unui Player, Processor-ul este conectat automat la dispozitivul de captur care
ndeplinete necesitile formatului (dac exist unul).
} catch (IOException e) {
System.exit(-1);
} catch (NoProcessorException e) {
System.exit(-1);
} catch (CannotRealizeException e) {
System.exit(-1);
}
// citete de la ieirea Processor-ului
DataSource source = p.getDataOutput();
try {
filewriter = Manager.createDataSink(source, dest);
filewriter.open();
} catch (NoDataSinkException e) {
System.exit(-1);
} catch (IOException e) {
54
System.exit(-1);
} catch (SecurityException e) {
System.exit(-1);
}
p.start();
//opreste si inchide Processor-ul cand se termina captura
// inchide DataSink-ul cand apare evenimentul EndOfStream
55
transmiterea i recepionarea datelor fr erori n reea. Cnd un pachet este
pierdut sau recepionat incorect acel pachet se retransmite.
Din aceast cauz la transmiterea datelor multimedia sunt folosite alte
protocoale dect TCP, cel mai frecvent utilizat fiind UDP (User Datagram
Protocol). UDP nu garanteaz recepia pachetelor la destinaie: nu este capabil
s compenseze datele pierdute i nici nu cere retransmisia.
Ca i TCP, UDP este un protocol al stratului transport, un protocol la
nivelul de jos al reelei, care st la baza dezvoltii multor aplicaii.
Standardul Internet folosit la transmiterea datelor audio i video este
RTP (Real-Time Transport Protocol).
8.7.1.3. Protocolul RTP
RTP ofer servicii punct-la-punct pentru transmiterea datelor n timp
real. RTP este un protocol independent de reea, dei este folosit des peste UDP.
56
O sesiune RTP este o asociere ntre un set de aplicaii care comunic
folosind protocolul RTP. O sesiune este identificat printr-o adres a reelei i o
pereche de porturi. Un port este folosit pentru datele media iar cellalt este
folosit pentru datele de control (RTCP).
Un participant este o main unic, gazd sau utilizator care particip
la o sesiune. Participarea ntr-o sesiune poate consta ntr-o recepie pasiv a
datelor (receptor), ntr-o transmisie activ a datelor (transmitor) sau ambele.
Fiecare tip de date este transmis ntr-o sesiune diferit. Spre exemplu,
dac ntr-o conferin se transmit att video ct i audio, o sesiune este folosit
la transmiterea datelor video i o sesiune separat este folosit la transmiterea
datelor audio. Aceasta permite participanilor la conferin s aleag care tip de
date media doresc s recepioneze spre exemplu, cineva care are o conexiune
la reea cu band redus ar putea dori s recepioneze doar partea audio a
conferinei.
Transmisia datelor media ntr-o sesiune RTP se face sub form de
pachete. O serie de pachete care provin din aceeai surs poart numele de
stream RTP. Fiecare pachet are un header (antet) i un payload (datele utile).
Figura urmtoare prezint header-ul unui pachet RTP.
Bit 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
V P X CC M PT Numrul secvenei
Timestamp
Sursa sincronizrii (SSRC)
Sursa coninutului (CSRC) (0-15)
57
Tipul payload-ului (PT): 7 bii. Este un index ntr-un tabel cu
profilele posibile care descrie formatul payload-ului. Maprile pentru
payload-urile audio i video sunt specificate n RFC 1890.
Numrul secvenei: 16 bii. Un numr unic care identific
poziia pachetului n secvena de pachete. Se incrementeaz automat
cu 1 pentru fiecare pachet trimis.
Timestamp: 32 bii. Mai multe pachete consecutive pot avea
acelai timestamp dac sunt generate logic n acelai timp spre
exemplu, dac toate fac parte acelai cadru video.
SSRC: 32 bii. Identific sursa sincronizrii. Dac CSRC este
zero, sursa payload-ului este sursa sincronizrii.
CSRC: 32 bii fiecare. Identific sursele care contribuie la
payload. Pot fi maxim 16 surse.
raportul sursei
raportul destinaiei
descrierea sursei
de tip Bye
specifice aplicaiei
Pachetele RTCP sunt stivuibile (stackable) i sunt trimise ca un pachet
combinat care conine cel puin dou pachete, un pachet de raport i un pachet
cu descrierea sursei.
Toi participanii ntr-o sesiune transmit pachete RTCP. Un participant
care a trimis de curnd date emite un raport de tipul raportul sursei. Acesta
conine att informaii despre numrul total de pachete i octei trimii, precum
i informaii care pot fi folosite la sincronizarea stream-urilor din sesiuni
diferite.
Participanii la sesiune transmit periodic pachete de tip raportul
destinaiei spre toate sursele de unde primesc pachete cu date. Acesta conine
informaii despre numrul de pachete pierdute, numrul maxim al secvenelor
primite i despre estimarea ntrzierilor ce apar la comunicarea ntre surs i
destinaie.
58
Primul pachet dintr-un pachet RTCP combinat trebuie s fie un pachet
de raport, chiar dac nu au fost transmise sau recepionate date (n acest caz un
raport gol este trimis).
Toate pachetele RTCP combinate trebuie s includ o descriere a
sursei (SDES), element care conine numele canonic (CNAME) care identific
sursa. Alte informaii pot fi incluse n descrierea sursei, cum ar fi numele sursei,
adresa de e-mail, numrul de telefon, locaia geografic sau numele aplicaiei.
Cnd o surs nu mai este activ, trimite un pachet RTCP Bye. Acesta
poate include i motivul pentru care sursa prsete sesiunea.
Pachetele RTCP APP prevd un mecanism care permite aplicaiilor s
defineasc i s transmit informaii utilizator prin portul de control RTP.
8.7.1.3.3. Aplicaiile RTP
Aplicaiile RTP sunt clasificate de obicei n cele care primesc date din
reea (clieni RTP) i cele care transmit date n reea (servere RTP). Unele
aplicaii pot ndeplini ambele funcii spre exemplu aplicaiile de
videoconferin captureaz i transmit date n timp ce recepioneaz date din
reea.
8.7.1.3.4. Recepia stream-urilor media din reea
Recepia streamurilor RTP este necesar n cazul ctorva tipuri de
aplicaii. Spre exemplu:
59
JMF permite rularea i transmisia stream-urilor RTP prin API-urile
definite n pachetele javax.media.rtp, javax.media.rtp.event i
javax.media.rtp.rtcp.
Stream-urile RTP pot fi rulate local, salvate ntr-un fiier sau ambele.
60
stream-uri media care au fost capturate de la un dispozitiv de captur local
(folosind o DataSource), sau care au fost stocate ntr-un fiier (folosind un
DataSink).
61
ReceptionStats: menine statistici despre recepie pentru un
anumit participant;
TransmissionStats: menine statistici despre un anumit stream
transmis n reea.
62
Figura 8.24. Evenimentele RTP
63
ReceiveStreamListener: primete notificri despre schimbrile
strii unui stream RTP care este primit;
RemoteListener: primete notificri despre evenimente sau
mesaje de control RTP primite de la un participant la sesiune.
64
un ReceiveStream neidentificat anterior este asociat cu un
Participan;.
este primit un pachet RTCP APP;
formatul datelor utile se modific.
65
el. Pentru ReceiveStreams, aceast DataSource este ntotdeauna
PushBufferDataSource.
Managerul de sesiune construiete automat noi stream-uri de recepie
n momentul n care detecteaz recepia unor stream-uri de la participanii la
sesiune. Noi stream-uri de transmisie se construiesc prin apelarea
createSendStream asupra managerului de sesiune.
API-urile JMF RTP sunt proiectate pentru a fi independente de
protocolul de transport folosit. Utilizatorul poate crea un handler de date RTP
pentru a permite ca comunicarea s se realizeze folosind un anumit protocol de
transport. Handler-ul de date este o DataSource care poate fi folosit ca intrare
pentru un Player.
Clasa abstract RTPPushDataSource definete elementele de baz ale
uni handler de date RTP. Acesta are att un stream de date de intrare
(PushSourceStream) ct i unul de ieire (OutputDataStream). Un handler de
date poate fi folosit att pentru canalul de date ct i pentru cel de control al
unei sesiuni RTP. Dac este folosit pentru canalul de date, handler-ul
implementeaz interfaa DataChannel.
Un RTPSocket este un RTPPushDataSource care are att canalul de
date ct i cel de control. Fiecare canal are un stream de intrare i unui de ieire
prin care emite/recepioneaz date n reea. Un RTPSocket poate exporta
RTPControls pentru a trimite dinamic managerului de sesiune informaii despre
datele utile.
Deoarece un RTPSocket creat de utilizator poate fi folosit la
construirea unui Player prin intermediul Manager-ului, JMF definete numele
i locaiile implementrilor RTPSocket:
<protocol package-prefix>.media.protocol.rtpraw.DataSource
66
public static final String JPEG_RTP = "jpeg/rtp";
public static final String H261_RTP = "h261/rtp";
public static final String H263_RTP = "h263/rtp";
rtp://address:port[:ssrc]/content-type/[ttl]
67
creat, iniializat i pornit un SessionManeger pentru acea
sesiune;
construit un Processor folosind DataSource-ul de captur
potrivit;
setat formatul de ieire a datelor din Processor ntr-un format
specific RTP. Un codec de mpachetare RTP trebuie s fie disponibil
pentru a formata datele ce urmeaz a fi transmise;
preluate datele de la DataSource-ul de la ieirea Processor-
ului;
apelat createSendStream asupra managerului de sesiune i
trimis DataSource-ul spre acesta.
68
Figura 8.25. Fluxul datelor spre recepia RTP
Un Player separat este folosit pentru fiecare stream recepionat de
managerul de sesiune. Pentru a construi un Player pentru un stream RTP se
folosete mecanismul standard Manager createPlayer. Exist dou posibiliti:
if (mrl == null) {
System.err.println("Nu se poate construi MRL-ul pentru RTP");
return false;
}
69
try {
player = Manager.createPlayer(mrl);
} catch (NoPlayerException e) {
System.err.println("Eroare:" + e);
return false;
} catch (MalformedURLException e) {
System.err.println("Eroare:" + e);
return false;
} catch (IOException e) {
System.err.println("Eroare:" + e);
return false;
}
if (player != null) {
if (this.player == null) {
this.player = player;
player.addControllerListener(this);
player.realize();
}
}
70
if (oldVisualComp != visualComp) {
if (oldVisualComp != null) {
oldVisualComp.remove(zoomMenu);
}
framePanel.remove(oldVisualComp);
vSize = visualComp.getPreferredSize();
vSize.width = (int)(vSize.width * defaultScale);
vSize.height = (int)(vSize.height * defaultScale);
framePanel.add(visualComp);
if (controlComp != null)
{
if (oldComp != controlComp)
{
framePanel.remove(oldComp);
framePanel.add(controlComp);
if (controlComp != null) {
int prefHeight = controlComp.getPreferredSize().height;
71
Pentru a rula toate ReceiveStream-urile dintr-o sesiune, trebuie creat
un Player separat pentru fiecare stream. Cnd un nou stream este creat,
managerul de sesiune posteaz un eveniment NewReceiveStreamEvent. n
general trebuie nregistrat ca i ReceiveStreamListener i trebuie construit cte
un Player pentru fiecare ReceiveStream. Pentru a construi un Player, trebuie
obinut DataSource-ul din ReceiveStream i transmis la
Manager.createPlayer.
Pentru a crea un Player pentru fiecare stream recepionat ntr-o sesiune
trebuie:
1. setat sesiune RTP:
creat un SessionManager;
apelat RTPSessionMgr addReceiveStreamListener pentru a se
nregistra ca i listener;
pornete sesiunea RTP prin apelarea RTPSessionMgr
startSession;
mgr.addFormat(new AudioFormat(AudioFormat.DVI_RTP,
44100, 4, 1), 18);
if (listener) mgr.addReceiveStreamListener(this);
if (sendlistener) new RTPSendStreamWindow(mgr);
try {
username = System.getProperty("user.name");
} catch (SecurityException e){
username = "jmf-user";
}
72
// creaza Session Address local
SessionAddress localaddr = new SessionAddress();
try{
InetAddress destaddr = InetAddress.getByName(address);
new SourceDescription(SourceDescription
.SOURCE_DESC_CNAME, cname, 1, alse),
new SourceDescription(SourceDescription
.SOURCE_DESC_TOOL, "JMF RTP Player v2.0",
1, false)
};
return mgr;
}
73
urile pentru decodare i despachetare a datelor formatate RTP trebuie
s fie disponibile.
try
{
stream =((NewReceiveStreamEvent)event)
.getReceiveStream();
74
playerWindow = new RTPPlayerWindow( newplayer, cname);
}
}
if (newplayer != null) {
// opreste player-ul si asteapta pentru evenimentul stop
newplayer.stop();
// retrage controllerlistener
newplayer.removeControllerListener(listener);
try {
// cand player-ul este inchis, datasource-ul lui a fost
75
// deconectat. Acum trebuie reconectata inainte de a
// crea player-ul
rtpsource.connect();
newplayer = Manager.createPlayer(rtpsource);
if (newplayer == null) {
System.err.println("Nu se poate crea player-ul");
return;
}
newplayer.addControllerListener(listener);
newplayer.realize();
} catch (Exception e) {
System.err.println("could not create player");
}
}
}
}
76
RTP este un protocol independent de protocolul de transport folosit.
Folosind RTPSocket, se pot recepiona stream-uri RTP din orice reea. Formatul
socket-ului RTP este proiectat s aib un canal pentru date i unul de control.
Fiecare canal are un stream de intrare i unul de ieire pentru a
transmite i a recepiona datele n/din reea.
SessionManager-ul se ateapt s primeasc pachete RTP individuale
de la RTPSocket. Utilizatorii sunt responsabili de trimiterea pachetelor
individuale spre RTPSocket.
Pentru a rula un stream RTP de la RTPSocket, trebuie transmis acest
socket la Manager.createPlayer pentru a construi Player-ul. Alternativ, se poate
construi un Player prin apelarea createPlayer(MediaLocator) i trecerea la
MediaLocator cu un nou protocol care este o variant a RTP, rtpraw. Spre
exemplu,
Manager.createPlayer(new MediaLocator("rtpraw://"));
Conform mecanismului de creere a unui Player JMF, Manger-ul va
ncerca s construiasc DataSource-ul:
<protocol package-prefix>.media.protocol.rtpraw.DataSource
Coninutul RTPSocket trebuie setat pe rtpraw. Manager-ul va incerca
s creeze un Player de tipul <content-prefix>.media.content.rptraw.Handler i
va seta RTPSocket-ul pe acesta.
Not: RTPSocket-ul creat la <protocol package-prefix>
.media.protocol.rtpraw.DataSource este implementarea proprie a acestuia.
Implementarea RTPSocket-ului este dependent de protocolul de transport
folosit. Clasa RTPSocket trebuie localizat la <protocol package-
prefix>.media.protocol.rtpraw.DataSource iar canalele de date i control
trebuie setate s arate ca i n Exemplul 8.18. Interfeele RTPControl pentru
RTPSocket pot fi utilizate pentru a aduga informaii dinamice manager-ului de
sesiune RTP.
Exemplul 8.18 implementeaz o sesiune RTP peste un Player UDP
care poate recepiona pachete RTP UDP i le poate transmite unui Player sau
unui manager de sesiune. Acest exemplu folosete interfeele definite n
javax.media.rtp.RTPSocket i clasele care aparin acesteia.
import javax.media.*;
import javax.media.format.*;
77
import javax.media.protocol.*;
import javax.media.rtp.*;
import javax.media.rtp.event.*;
import javax.media.rtp.rtcp.*;
// tipul datelor
String media = "audio";
Player player;
public RTPSocketPlayer() {
// creeaza RTPSocket
rtpsocket = new RTPSocket();
// seteaza tipul continutului :
// rtpraw/video pentru o sesiune video
// rtpraw/audio pentru o sesiune audio
String content = "rtpraw/" + media;
rtpsocket.setContentType(content);
78
rtpsocket.setOutputStream(rtp);
rtcpsource = rtpsocket.getControlChannel();
rtcpsource.setOutputStream(rtcp);
rtcpsource.setInputStream(rtcp);
if (player != null) {
player.addControllerListener(this);
// send this player to out playerwindow
// playerWindow = new PlayerWindow(player);
}
}
public synchronized void controllerUpdate(ControllerEvent ce) {
if ((ce instanceof DeallocateEvent) ||
(ce instanceof ControllerErrorEvent)) {
79
}
try {
addr = InetAddress.getByName(sockaddress);
if (addr.isMulticastAddress()) {
MulticastSocket msock;
msock.joinGroup(addr);
sock = (DatagramSocket)msock;
}
else {
sock = new DatagramSocket(sockport,addr);
}
return sock;
}
catch (SocketException e) {
e.printStackTrace();
return null;
}
catch (UnknownHostException e) {
e.printStackTrace();
return null;
}
catch (IOException e) {
e.printStackTrace();
return null;
}
}
80
PushSourceStream, OutputDataStream
{
DatagramSocket mysock;
DatagramPacket dp;
SourceTransferHandler outputHandler;
String myAddress;
int myport;
boolean closed = false;
while(true) {
if (closed) {
cleanup();
return;
}
try {
do {
dp = new DatagramPacket( new byte[maxsize],
maxsize);
mysock.receive(dp);
if (closed){
cleanup();
return;
}
81
len = dp.getLength();
if (len > (maxsize >> 1)) maxsize = len << 1;
}
while (len >= dp.getData().length);
}catch (Exception e){
cleanup();
return;
}
if (outputHandler != null) {
outputHandler.transferData(this);
}
}
}
82
public boolean endOfStream() {
return false;
}
return dp.getData().length;
}
try {
addr = InetAddress.getByName(myAddress);
} catch (UnknownHostException e) {
83
e.printStackTrace();
}
return dp.getLength();
}
}
84
monitorizarea statisticilor pentru o sesiune, trebuie folosit direct
SessionManager-ul.
Indiferent de modul de transmisie a stream-ului RTP, trebuie:
85
ntrzierea pachetului, cunoscut i sub numele de interval de
mpachetare, este timpul petrecut de fiecare pachet RTP de-a lungul transmisiei
lui prin reea. Intervalul de mpachetare determin ntrzierea minim pentru
transmisia de la un capt la altul (end-to-end delay). Pachetele mai mari
micoreaz header-ul dar mresc ntrzierile i fac pierderea de pachete mai
sesizabil.
Un receptor ar trebui s accepte pachete reprezentnd ntre 0 i 200 ms
de date audio. Aceast restricie permite o mrime rezonabil a buffer-ului
pentru receptor. Fiecare codec de mpachetare are un interval de mpachetare
implicit, potrivit pentru acel tip de codare.
Dac codec-ul permite modificarea acestui interval, el export un
PacketSizeControl. Intervalul de mpachetare poate fi modificat sau setat prin
metoda setPacketSize. Pentru stream-urile video, fiecare cadru este transmis n
pachete RTP multiple. Mrimea fiecrui pachet este limitat de MTU-ul
(Maximum Transmission Unit) reelei. Acest parametru se poate seta prin
metoda setPacketSize care aparine de PacketSizeControl.
8.9.2. Transmisia datelor RTP folosind DataSink
Cea mai simpl metod de a transmite date RTP este s construim un
DataSink RTP folosind metoda Manager.createDataSink. Parametrii sunt
DataSource-ul de la ieirea Processor-ului i un MediaLocator care descrie
sesiunea RTP. MediaLocator-ul conine addresa i portul sesiunii RTP.
Pentru a controla transmisia, trebuie apelate start i stop asupra
DataSink-ului. Doar primul stream din DataSource este transmis.
n Exemplul 8.19, se captureaz date audio, dup care sunt transmise
folosind un DataSink.
if (devices.size() > 0) {
di = (CaptureDeviceInfo) devices.elementAt( 0);
}
else {
// daca nu gaseste dispozitivul de captura - exit
86
System.exit(-1);
}
// configureaza Processorul
processor.configure();
processor.setContentDescriptor(
new ContentDescriptor( ContentDescriptor.RAW));
track[i].setEnabled(false);
}
else {
encodingOk = true;
}
} else {
// pista aceasta nu este format gsm, asa ca o invalidam
track[i].setEnabled(false);
}
}
87
if (encodingOk) {
processor.realize();
// se blocheaza pana la realized
// obtine datasource-ul de iesire al processorului
// daca da eroare - exit
DataSource ds = null;
try {
ds = processor.getDataOutput();
} catch (NotRealizedError e) {
System.exit(-1);
}
88
nainte ca managerul de sesiune s transmit date, trebuie s cunoasc
locaia datelor ce urmeaz a fi transmise. Cnd se construiete un nou
SendStream, acesta trebuie s cunoasc DataSource-ul. Din moment ce un
DataSink poate conine stream-uri multiple, trebuie specificat i indexul
stream-ului ce urmeaz a fi transmis n aceast sesiune. Se pot creea stream-uri
de transmisie multiple prin transmiterea unor DataSource diferite prin apelarea
createSendStream sau prin specificarea mai multor indeci de stream.
Managerul de sesiune interogheaz formatul SourceStream-ului pentru
a determina dac are un tip de date nregistrat pentru acest format. Dac datele
nu sunt un format RTP sau dac tipul datelor nu poate fi localizat n formatul
RTP, o excepie UnSupportedFormatException este aruncat.
Multe scenarii de folosire a protocolului RTP implic transmisia unui
stream n mai multe sesiuni RTP sau codarea unui stream n formate multiple i
transmisia lui n mai multe sesiuni RTP. Cnd un stream codat ntr-un singur
format trebuie transmis m sesiuni RTP multiple, trebuie clonat DataSource-ul
de la ieirea Processor-ului de unde se captureaz datele. Aceasta se realizeaz
prin creearea unei DataSource clonabile prin intermediul Manager-ului i prin
apelarea metodei gerClone asupra DataSource-ului clonat. Un nou Processor
poate fi creat pentru fiecare DataSource clonat, pistele pot fi codate n formatul
dorit i fiecare stream poate fi transmis ntr-o sesiune RTP.
Dac se dorete mixarea stream-urilor multiple de acelai tip (cum ar
fi audio) ntr-un singur stream, trebuie folosit un mixer RTP. Dac stream-urile
ce trebuie mixate provin de la DataSource-uri multiple, trebuie creat un
MergingDataSource din DataSource-ele separate i transmise spre
SessionManager, care creeaz stream-ul.
8.9.3.2. Controlul unui stream de transmisie
Pentru a controla SendStream-ul se folosesc metodele RTPStream
start i stop. La pornirea unui SendStream ncepe transmisia datelor n reea. La
oprirea acestuia transmisia este oprit. Pentru a ncepe o transmisie RTP, fiecare
SendStream trebuie pornit.
Dac DataSource-ul este pornit independent n timp ce SendStream-ul
este oprit, datele vor fi ignorate (PushBufferDataSource) sau nu vor fi cerute
(PullBufferDataSource) de managerul de sesiune. n acest timp, nu vor fi
transmise date n reea.
8.9.3.3. Transmisia datelor audio capturate ntr-o singur sesiune
Exemplul 8.20. arat cum se realizeaz captura i transmisia ntr-o
sesiune RTP a unui stream audio mono.
89
// Avem nevoie de DataSource pt. a captura audio
AudioFormat format = new AudioFormat(AudioFormat.ULAW,
8000, 8, 1);
processor.configure();
processor.setContentDescriptor(
new ContentDescriptor( ContentDescriptor.RAW));
if (((FormatControl)track[i]).
90
setFormat( new AudioFormat(AudioFormat.ULAW_RTP,
8000, 8, 1)) == null) {
track[i].setEnabled(false);
}
else {
encodingOk = true;
}
}
else {
// pista aceasta nu poate fi setata pe gsm, asa ca o invalidam
track[i].setEnabled(false);
}
}
processor.realize();
DataSource ds = null;
try {
ds = processor.getDataOutput();
} catch (NotRealizedError e){
System.exit(-1);
}
try {
rtpsm.createSendStream(ds, 0);
} catch (IOException e) {
e.printStackTrace();
} catch( UnsupportedFormatException e) {
e.printStackTrace();
91
}
8.9.3.4. Transmisia datelor audio capturate n sesiuni multiple
Exemplul 8.21. ilustreaz codarea datelor audio i transmiterea
acestora n sesiuni RTP multiple. Datele sunt codate n format gsm.
// configureaza processorul
processor.configure();
processor.setContentDescriptor(
new ContentDescriptor( ContentDescriptor.RAW));
92
TrackControl track[] = processor.getTrackControls();
boolean encodingOk = false;
if (((FormatControl)track[i]).
setFormat( new AudioFormat(AudioFormat.GSM_RTP,
8000, 8, 1)) == null) {
track[i].setEnabled(false);
}
else {
encodingOk = true;
}
}
else {
// pista nu poate prelucra gsm, asa ca o invalidam
track[i].setEnabled(false);
}
}
if (encodingOk) {
processor.realize();
93
// vrem sa transmitem acest stream in doua sesiuni RTP
cloneableDataSource
= Manager.createCloneableDataSource(origDataSource);
clonedDataSource
= ((SourceCloneable)cloneableDataSource).createClone();
// creerea SendStream-ului
SessionManager rtpsm1
= new com.sun.media.rtp.RTPSessionMgr();
} catch (IOException e) {
e.printStackTrace();
} catch( UnsupportedFormatException e) {
e.printStackTrace();
}
try {
cloneableDataSource.connect();
cloneableDataSource.start();
} catch (IOException e) {
e.printStackTrace();
}
94
// datasource-ului clonat
if (clonedDataSource != null) {
SessionManager rtpsm2
= new com.sun.media.rtp.RTPSessionMgr();
// rtpsm2.initSession(...);
// rtpsm2.startSession(...);
try {
rtpsm2.createSendStream(clonedDataSource,0);
} catch (IOException e) {
e.printStackTrace();
} catch( UnsupportedFormatException e) {
e.printStackTrace();
}
}
}
else {
// procedura de codare gsm a dat gres.
// dealocam si inchidem processorul
processor.deallocate();
processor.close();
}
8.9.4. Transmisia datelor RTP cu RTPSocket
Pentru a transmite date RTP se mai poate folosi RTPSocket. Pentru a
folosi RTPSocket pentru transmisie, trebuie creat un DataSink RTP folosind
createDataSink prin alocarea unui MediaLocator cu un nou protocol care este o
variant a RTP, Ratibor. Managerul ncearc s construiasc un DataSink
din:
<protocol package-prefix>.media.datasink.rtpraw.Handler
95
definete o implemetare implicit a RTPSocket. Implementarea RTPSocket este
dependent de protocolul din stratul transport pe care l folosim.
Clasa RTPSocket trebuie localizat la <protocol-prefix>.media.
protocol.rtpraw.DataSource. Utilizatorul este responsabil pentru transmiterea
de pachete RTP n reea.
Exemplul 8.22 ilustreaz modul n care RTPSocket este folosit pentru
a transmite datele audio capturate.
try {
processor = Manager.createProcessor(di.getLocator());
} catch (IOException e) {
System.exit(-1);
} catch (NoProcessorException e) {
System.exit(-1);
}
// configureaza processor-ul
processor.configure();
96
processor.setContentDescriptor(
new ContentDescriptor( ContentDescriptor.RAW));
if (((FormatControl)track[i]).
setFormat( new AudioFormat(AudioFormat.GSM_RTP,
8000, 8, 1)) == null) {
track[i].setEnabled(false);
}
else {
encodingOk = true;
}
}
else {
// aceasta pista nu poate fi setata pe gsm, asa ca
// trebuie invalidata
track[i].setEnabled(false);
}
}
97
try {
MediaLocator m = new MediaLocator("rtpraw://");
// managerul cauta pentru un datasink in
// <protocol.prefix>.media.protocol.rtpraw.DataSink
// datasink-ul va crea un RTPSocket la
// <protocol.prefix>.media.protocol.rtpraw.DataSource
DataSink d = Manager.createDataSink(ds, m);
d.open();
d.start();
} catch (Exception e) {
System.exit(-1);
}
}
8.10. Importul i exportul stream-urilor RTP
Multe aplicaii trebuie s permit scrierea i citirea stream-urilor RTP.
Spre exemplu, aplicaiile de conferint trebuie s poat nregistra conferina i
s o poat rula mai trziu. Sau, aplicaiile de telefonie trebuie s poat transmite
stream-uri audio stocate ca mesaje de ntmpinare.
Stream-urile RTP recepionate prin reea pot fi salvate ntr-un fiier
folosind un DataSink RTP. Similar, se pot citi fiiere salvate, dup care pot fi
prezentate local sau pot fi transmise n reea.
8.10.1. Citirea stream-urilor RTP dintr-un fiier
Pentru a citi date dintr-un fiier i a le prezenta sau a le transmite,
trebuie folosit un MediaLocator pentru a construi direct un Processor. Tipul
fiierelor care pot fi folosite la transmisia RTP depinde de plug-in-urile de
codare care sunt disponibile pentru a coda i mpacheta datele ntr-un format
specific RTP.
98
}
// configureaza processorul
processor.configure();
if (((FormatControl)track[i]).
setFormat( new AudioFormat(AudioFormat.ULAW_RTP,
8000, 8, 1)) == null) {
track[i].setEnabled(false);
}
else {
encodingOk = true;
}
}
else {
// nu se poate seta pista pe ulaw, asa ca o invalidam
track[i].setEnabled(false);
}
}
if (encodingOk) {
processor.realize();
try {
99
ds = processor.getDataOutput();
} catch (NotRealizedError e) {
System.exit(-1);
}
// transmite datasource-ul spre manager pentru a creea
// un datasink RTP
// datasink RTP va transmite audio multicast
try {
String url= "rtp://224.144.251.104:49150/audio/1";
MediaLocator m = new MediaLocator(url);
DataSink d = Manager.createDataSink(ds, m);
d.open();
d.start();
} catch (Exception e) {
System.exit(-1);
}
}
8.10.2. Exportul stream-urilor RTP
Stream-urile RTP recepionate din reea pot fi stocate sau pot fi
prezentate. Pentru a scrie datele ntr-un fiier, trebuie obinut DataSource-ul din
ReceiveStream. Acesta trebuie folosit la scrierea unui fiier cu un DataSink,
prin intermediul Manager-ului.
Dac se dorete decodarea datelor nainte de stocare, trebuie folosit
DataSource-ul obinut din ReceiveStream pentru a construi un Processor. Apoi:
100
Exemplul 8.24. Scrierea unui stream RTP ntr-un fiier
public void update(ReceiveStreamEvent event) {
// gaseste managerul de sesiune pentru acest eveniment
SessionManager source = (SessionManager)event.getSource();
try {
// obtine ReceiveStream
stream =((NewReceiveStreamEvent)event)
.getReceiveStream();
Manager.createDataSink(dsource, f);
} catch (Exception e) {
System.err.println("Exceptie newReceiveStreamEvent "
+ e.getMessage());
return;
}
}
}
8.11. Bibliografie
[1]. www.java.sun.com
[2]. www.billday.com
101
[3]. www.codesourceonline.com
[4]. www.tutorials.com
102