Dokumentation

Werbung
Java Media Framework API
Theoretischer Hintergrund und Anwendungen
LVA: Java3D (Seminar)
Thema: Java Media Framework API
Autor: Daniel Birk
Email: [email protected]
Java3D (Seminar), Java Media Framework API
Inhaltsverzeichnis:
1. Einleitung
2. Java Media Framework (JMF) API
3. High-Level Architektur und Erweiterungen
3.1 High-Level Architektur
3.1.1
Wiedergabe (engl. presentation) zeitbasierter Medien
3.1.2
Bearbeiten (engl. processing) zeitbasierter Medien
3.1.3
Aufnahme (engl. capturing) zeitbasierter Medien
3.2 Erweiterungen
4. Echtzeiterweiterung: JMF Real-Time Transport Protocol
(RTP) API
4.1 Streaming-Media
4.2 Real-Time Transport Protocol
4.3 Architektur des JMF RTP API
4.3.1
Senden von Streaming-Media
4.3.2
Empfangen von Streaming-Media
5. Literaturstellen
6. Anhang
Seite 2
Java3D (Seminar), Java Media Framework API
1. Einleitung
Grundlage dieses Tutorials ist der Java Media Framework (JMF) API Guide v. 2.0 [1].
Zusätzliche Informationen und Hintergrundwissen stammen aus dem Entwicklerbereich
der IBM Website [3]. Das Java Media Framework API erweitert die Funktionalität des Java
SDK um weitreichende Multimediaeigenschaften. Es enthält Bibliotheken zum Einbinden
zeitabhängiger Medien, wie Audio und Video.
Das JMF API besteht seit Version 2.0 aus einer Kombination des Vorgängers, nämlich der
Java Media Player API 1.0, und einer Echtzeiterweiterung, die früher unter dem Namen
RTP Session Manager API verbreitet wurde.
Inzwischen wurde die Version 2.1.1.b veröffentlicht. Diese Version bietet neben dem
einfachen Abspielen auch das Aufnehmen und Bearbeiten verschiedener Medienformate.
Aufgrund eines Lizenzstreits wurde, mit Ausnahme der Windowsplattformen, in der
aktuellen Version die MP3-Funktionalität entfernt.
Der zweite große Bestandteil des JMF API ist die Echtzeitfunktionalität. Mit ihr lassen sich
zeitkritische Anwendungen, wie beispielsweise Audio- oder Videostreaming, in JavaApplikationen und Applets realisieren.
2. Java Media Framework (JMF) API
Das JMF API ist eine komfortable Lösung im Umgang mit verschiedensten Mediendaten
für die Programmiersprache Java. Dabei werden die Daten zunächst importiert,
anschließend verarbeitet und wieder exportiert. Die importierten Daten können aus
unterschiedlichen Quellen, wie z.B. Lesen einer Datei oder Empfang aus einem Netzwerk,
stammen und werden deshalb allgemein als Input bezeichnet. In der Verarbeitungsphase
können die importierten Daten komprimiert, konvertiert oder mit verschiedenen Filtern
belegt werden. Der Output der Applikationen und Applets kann je nach Wunsch und
Einsatzgebiet vom einfachen Darstellen auf einem Bildschirm bis hin zur Übertragung
über ein Netz differieren. Abbildung 1 illustriert noch einmal den eben beschriebenen
Verarbeitungsprozess.
Seite 3
Java3D (Seminar), Java Media Framework API
Abbildung 1 aus [1]
Eine erste Unterscheidung ist die nach der dem Initiator. Je nachdem wie die
Mediendaten zur Verfügung gestellt werden, unterscheidet man zwischen Push- und PullTransfer. Beim Push-Transfer dient in der Regel ein Server als Initiator, der die Daten
sozusagen zum Client schiebt. Das RealTime Transport Protokoll (RTP) beispielsweise ist
ein Push-Protokoll, das beim Streaming-Verfahren von Audio und Video eingesetzt wird.
Ein weiteres Beispiel für Push-Transfer ist Video-On-Demand (VOD), das mit Hilfe des
SGI MediaBase Protokoll realisiert wird.
Im Gegensatz dazu ist beim Pull-Transfer in der Regel ein Client der Initiator, der die
Mediendaten anfordert und auch kontrolliert. Beispiele hierfür sind das FILE- oder das
HTTP-Protokoll.
3. High-Level Architektur und Erweiterungen
3.1 High-Level Architektur
Die High-Level Architektur des JMF API bildet Komponenten ab, wie sie auch bei
herkömmlichen analogen Verfahren verwendet werden. So speichert beispielsweise eine
Videokamera die aufgenommen Daten auf einem Videoband, dass in einem
Videorekorder über ein Fernsehgerät wiedergegeben werden kann. Die Videokamera ist
in diesem Fall ein Aufnahmegerät (engl. capture device), das Videoband die Datenquelle
(engl. data source) und der Videorekorder ist das Abspielgerät (engl. player). Die
folgende Abbildung verdeutlicht diesen Sachverhalt.
Seite 4
Java3D (Seminar), Java Media Framework API
Abbildung 2 aus [1]
Das JMF API ist stark an diesem Modell orientiert, so dass sich viele Begriffe in den
Klassen- und Interfacebezeichnungen wieder finden. Daneben gibt es ein Zeitmodel, ein
Eventmodel, ein Datenmodel und drei sog. Manager.
Das Zeitmodel besteht aus einem Time Objekt und einem Clock Interface, dass alle
Methoden zur Ermittlung der Zeit und zur Synchronisation definiert. Das Clock Interface
bekommt seine Informationen wiederum von einer TimeBase, die meist auf der
Systemzeit basiert.
Das Eventmodel folgt den Regeln der JavaBeans. Ein Controller hat einen
ControllerListener, der an ein Objekt gehängt werden kann. Tritt ein Event an diesem
Objekt auf, so kann dies in der Methode ControllerUpdate behandelt werden. Alle
Events des JMF API sind Unterklassen von MediaEvent.
Das Datenmodell wird durch das DataSource Objekt repräsentiert. Dieses Objekt zeigt
einerseits den Speicherort der Datenquelle an und andererseits das Protokoll und die
Software, die nötig sind die Quelle abzuspielen. Weiterhin hat jede Datenquelle ein
bestimmtes Format. Dadurch werden alle spezifischen Eigenheiten der einzelnen Formate
vom JMF API verdeckt und man braucht sich als Entwickler nicht darum zu kümmern.
Die drei Managerklassen sind Manager, CaptureDeviceManager und PlugInManager. Der
Manager ist für Erstellung der Player, Processor und DataSource bzw. DataSink
Objekte verantwortlich. Der CaptureDeviceManager verwaltet die verfügbaren
Aufnahmegeräte, während der PlugInManager die installierten und verfügbaren PlugIns
verwaltet.
Seite 5
Java3D (Seminar), Java Media Framework API
Dies sind die Hauptkomponenten der High-Level Architektur die nötig sind, um
verschieden Medien zu präsentieren, zu bearbeiten oder aufzunehmen. Diese drei
Bereiche werden im Folgenden näher vorgestellt.
3.1.1 Wiedergabe zeitbasierter Medien
Das Abspielen zeitbasierter Medien geschieht mit Hilfe des Player Objekts. Der Player
wird, wie oben erwähnt vom Manager erzeugt. Dies kann auf unterschiedliche Weise
passieren. Zunächst ist wichtig zu verstehen, dass das Player Objekt verschiedene
Phasen durchläuft, ehe es bereit ist die Quelle abzuspielen. Folgende Abbildung gibt den
zeitlichen Verlauf dieser Phasen wieder.
realize
unrealized
prefetch
realizing
realized
prefetching
RCE
deallocate
Stopped
Started
prefetched
PFCE
started
SE
deallocate,
setMediaTime
stop
Events:
RCE: RealizeCompleteEvent
PFCE: PrefetchCompleteEvent
SE: StopEvent
Abbildung 3 aus [2]
Zwei dieser Phasen haben besondere Bedeutung. Denn einige Methoden des Players
können erst aufgerufen werden, wenn er sich im Zustand realized, andere wenn er sich
im Zustand prefetched befindet. Eine komplette Übersicht darüber, wann welche
Methoden aufgerufen werden können befindet sich im Anhang. Um nun ein Player
Objekt zu erzeugen ruft man die Methode
Player player = Manager.createPlayer(Parameter p);
Seite 6
Java3D (Seminar), Java Media Framework API
auf. Diese Methode stößt die Erzeugung aber lediglich an, überwacht jedoch nicht die
einzelnen Phasen. Dafür muss man das ControllerListener Interface implementieren,
dass in diesen Phasen die dazu passenden Events auslöst.
Der Grund für diese Zerlegung des Erzeugungsprozesses ist, dass dieser von mehreren
asynchron arbeitenden Threads übernommen wird, um nicht den Hauptthread für die
Dauer der Erzeugung zu blockieren. Genau dies passiert beim Aufruf der Methode
Player realizedplayer = Manager.createRealizedPlayer(Parameter p);
was zu unerwünschten Ergebnissen führen kann. Dieser Ansatz hat aber den Vorteil, dass
sich der Entwickler nicht um die Überwachung der Zustände kümmern muss.
Folgende Abbildung zeigt einen Ausschnitt der Events, die ein Player Objekt erzeugt.
Abbildung 4 aus [2]
Die start() Methode des Players kann z.B. erst aufgerufen werden, wenn das
RealizeCompleteEvent erzeugt wurde. Wenn der Datenstrom vor dem Abspielen
gepuffert werden soll, wartet man damit bis das PrefetchCompleteEvent ausgelöst
wurde. Weiterhin zeigt die Abbildung verschiedene Events, die auch durch den Benutzer
erzeugt werden können. Zu nennen sind hierbei das StartEvent oder das
StopByRequestEvent, die ausgelöst werden, wenn die Start- bzw. Pausetaste des
Players gedrückt werden.
Auch die Start- und Pausetasten müssen erst erzeugt werden. Sie gehören zu den
Kontrollkomponenten eines Players. Um zu erfahren welche Komponenten ein Player
Objekt unterstützt, ruft man die Methode
Control[] controls = Player.getControls();
Seite 7
Java3D (Seminar), Java Media Framework API
auf und erhält als Rückgabewert ein entsprechendes Array. Folgende Auflistung
beschreibt die wichtigsten Komponenten, die die meisten Player unterstützen.
Steuerkomponente mit Start- und Pausetaste:
Component controlcomponenet = Player.getControlPanelComponent();
Anzeigebereich beim Abspielen von Videos:
Component visualcomponent = Player.getVisualComponent();
Lautstärkeregler, bei Implementierung des GainControl Interfaces:
Component gaincomponent = Manager.getGainControl().getControlComponent();
Der Rückgabewert ist jeweils eine AWT-Komponente, die man anschließend in einem
Applet oder einer Applikation aufnehmen und darstellen kann.
Der Parameter p, den die beiden Methoden zur Erzeugung der Player Objekte
benötigen, kann entweder ein DataSource, ein MediaLocator oder ein URL Objekt sein,
je nach Einsatzgebiet und Format. Letztendlich werden alle drei Objekte jedoch mit einer
Pfadangabe erzeugt.
3.1.2 Bearbeiten zeitbasierter Medien
Zum Bearbeiten von Mediendaten stellt das JMF API den Processor zur Verfügung. Seine
Klasse ist von der Klasse Player abgeleitet, d.h. dass jeder Processor gleichzeitig auch
ein Player ist. Genau wie das Player Objekt, durchläuft auch der Processor bei seiner
Entstehung verschiedene Phasen. Bevor der Processor in die realizing Phase eintreten
kann, muss er im Zustand configured sein. In dieser Phase wird für jede Spur einer
Mediadatei ein sog. TrackControl Objekt generiert, mit dem verschiedene Parameter,
wie z.B. das Outputformat, eingestellt werden. Ist diese Phase abgeschlossen wird ein
ConfiguredCompleteEvent ausgelöst. Alle weiteren Schritte sind analog zum Player
Objekt. Eine Abbildung aller Konfigurationsschritte des Processor ist im Anhang zu
finden.
Seite 8
Java3D (Seminar), Java Media Framework API
Die genauen Konfigurationsschritte sind davon abhängig, was man mit dem Processor
machen möchte. Nachstehende Auflistung gibt Aufschluss über die verschiedenen
Möglichkeiten:
a) Erzeugung des Processors mit Hilfe eines ProcessorModels
b) Verwendung eines Plug-Ins (Codec und/oder Renderer)
c) Ausgabeformat festlegen
zu a) Erzeugung des Processors mit Hilfe eines ProcessorModels
Bei der Erzeugung mit Hilfe eines ProcessorModels wird die schon von Player bekannte
Methode aufgerufen, die einen „fertigen“ Processor erzeugt.
Processor p = Manager.createRealizedProcessor(ProcessorModel pm);
Um ein ProcessorModel zu erzeugen, braucht man eine Datenquelle, ein Array, das die
für diese Quelle verfügbaren Formate enthält und einen ContentDescriptor, der den
Typ der Zieldatei beschreibt.
zu b) Verwendung eines Plug-Ins
Jede Spur des Eingangsdatenstroms kann mit Hilfe eines installierten Plug-Ins
entsprechend manipuliert werden. Dafür lässt man sich vom PlugInManager eine Liste
aller installierten Plug-Ins generieren und ruft anschließend eine der Methoden
setCodecChain(Condec[] c) oder
setRenderer(Renderer r)
für die jeweilige Spur, bzw. das jeweilige TrackControl Objekt auf. Auf diese Weise lässt
sich z.B. das Audiosignal eines Videos separat vom eigentlichen Bildsignal in einem
Arbeitsschritt bearbeiten.
zu c) Ausgabeformat festlegen
Um das Ausgabeformat einer Spur festzulegen ruft man
trackcontrol.setFormat(Format f)
am gewünschten TrackControl Objekt auf. Die Methode
Format[] formats = trackcontrol.getSupportedFormats();
Seite 9
Java3D (Seminar), Java Media Framework API
liefert ein Array aller verfügbaren Formate zurück. Außerdem kann man neben dem
Format auch den Typ der Datei festlegen. Dies erreicht man mit den Methoden
ContentDescriptor[] cd = processor.getSupportedContentDescriptors() und
Processor.setContentDescriptor(ContentDescriptor cd),
die am Processor Objekt aufgerufen werden. Hierbei muss beachtet werden, dass die
Formate der einzelnen Spuren mit dem Typ der Datei, also dem ContentDescriptor
kompatibel sind.
3.1.3 Aufnahme zeitbasierter Medien
Das JMF API hat neben dem Abspielen und Bearbeiten von Mediendaten auch die
Möglichkeit solche Daten von einem analogen Gerät, wie z.B. einem Mikrophon oder einer
Videokamera, aufzunehmen. Dazu benötigt man die dritte Managerklasse, den
CaptureDeviceManager. Dieser generiert ein CaptureDeviceInfo Objekt von der
angegebenen Aufnahmequelle. Wenn der genaue Name der Quelle nicht bekannt ist,
kann der CaptureDeviceManager eine Liste aller verfügbaren Quellen erstellen. Dabei
muss lediglich das Format angegeben wie der Eingabestrom digitalisiert werden soll.
Anschließend erzeugt man mit Hilfe des CaptureDeviceInfo Objektes ein
MediaLoacator Objekt und mit diesem ein Player oder Processor Objekt. Folgende
Prorammzeilen fassen diese Schritte noch einmal zusammen.
CaptureDeviceInfo ci = CaptureDeviceManager.getDevice(„deviceName“);
Alternativ:
Vector v =
CaptureDeviceManager.getDeviceList(new AudioFormat("linear", 44100, 16, 2));
CaptureDeviceInfo ci = (CaptureDeviceInfo)v.elementAt(1);
Player/Processor p = Manager.createPlayer/Processor(ci.getLoacator());
Mit dem Player kann man den digitalisierten Eingabestrom natürlich nur wiedergeben.
Will man die Daten jedoch weiterverarbeiten, wie z.B. komprimieren oder in eine Datei
speichern, benötigt man immer das Processor Objekt. Nachdem der Processor erzeugt
wurde lassen sich alle Manipulationen durchführen, die unter 3.1.2 Bearbeiten
zeitbasierter Medien, angesprochen wurden. Um eine Datei zu schreiben, generiert der
Processor vom Eingabegabestrom eine Datenquelle, die nötig ist, um später eine
Seite 10
Java3D (Seminar), Java Media Framework API
korrespondierende Datensenke zu erzeugen. Weiterhin muss ein ContentDescriptor
gesetzt werden, der das Speicherformat beschreibt. Zum Schluss wird ein MediaLoactor
Objekt erzeugt, das den Speicherort und den Dateinamen festlegt. Danach kann mit dem
Schreiben kann begonnen werden. Die eben beschriebenen Schritte sind im Folgenden
noch einmal, in zeitlich korrekter Abfolge der Anweisungen zusammengefasst.
p.setContentDescriptor(FileTypeDescriptor ftd);
DataSource source = p.getDataOutput();
MediaLocator dest = new MediaLocator(„protocol://file.ext“);
DataSink filewriter = Manager.createDataSink(source, dest);
filewriter.open();
Um die Größe der zu schreibenden Datei kontrollieren zu können, implementiert man das
StreamWriterControl Interface und überschreibt die Methoden
getControlComponent();
setStreamSizeLimit(long bytes);
getStreamSize();.
3.2 Erweiterungen
Unter Erweiterungen sind hier selbst implementierte Erweiterungen des JMF API gemeint.
Hierdurch können eigene Formate und benutzerdefinierte Methoden zu deren Be- und
Verarbeitung definiert werden. Dazu implementiert man je Zweck bestimmte Interfaces
und überschreibt deren Methoden. Anschließend muss das neu geschriebene Plug-In
noch registriert werden, damit es über den PlugInManager erreichbar wird.
4. Echtzeiterweiterung: JMF Real-Time Transport
Protocol (RTP) API
Die Echtzeiterweiterung des JMF API besteht aus den Packeten
javax.media.rtp
javax.media.rtp.event und
javax.media.rtp.rtcp.
Seite 11
Java3D (Seminar), Java Media Framework API
Auch die Echtzeitfunktionalität kann durch selbst geschriebene Plug-Ins über den in 3.2
beschriebenen Mechanismus erweitert werden.
4.1 Streaming-Media
Die Erweiterung des JMF API bezieht sich auf den Umgang mit Streaming-Media. Damit
ist eine Technik gemeint, bei der Mediendaten, wie Audio oder Video, über ein Netzwerk
übertragen werden und bei einem Client in Echtzeit wiedergegeben werden. Der Begriff
schließt sowohl den Client, bei dem der Datenstrom empfangen und wiedergegeben wird,
als auch den Server, der die Daten sendet, mit ein. Zwischen dem Server und den Clients
bestehen dabei Ende-zu-Ende-Verbindungen, d.h. es gibt keine tatsächliche oder virtuelle
Verbindung auf dem Übertragungsweg. Das besondere an dieser Technik ist, dass eine
Datei bereits wiedergegeben werden kann, ohne vollständig übertragen worden zu sein.
Außerdem kommt es nicht darauf, die Daten um jeden Preis fehlerfrei zu übertragen,
sondern auf die Echtzeitfähigkeit des Systems. Protokolle wie HTTP oder FTP legen im
Gegensatz dazu den größten Wert auf eine fehlerfreie Übertragung. Hierfür setzt es auf
dem zuverlässigen TCP Protokoll auf. Das von der JMF API verwendete Protokoll ist das
Real-Time Transport Protocol (RTP).
4.2 Real-Time Transport Protocol (RTP)
Das Real-Time Transport Protocol (RTP) überträgt Daten mit Hilfe von Ende-zu-Ende
Verbindungen in Echtzeit. Mit Echtzeit ist gemeint, sicherzustellen, dass ein konstanter
Datendurchsatz erreicht wird und dabei bestimmte Zeitgrenzen eingehalten werden. RTP
ist von der Architektur des Netzwerks und den eingesetzten Protokollen unabhängig,
setzt jedoch meist auf dem „unzuverlässigen“ User Datagram Protocol (UDP) auf.
Folgende Abbildung verdeutlicht die Architektur und Einordnung des RTP.
Seite 12
Java3D (Seminar), Java Media Framework API
Real-Time Media Framework and Applications
Real-Time Control Protocol (RTCP)
Real-Time Transport Protocol (RTP)
Other Network Transport
Protocols
(TCP, ATM, ST-II, etc)
UDP
Internet Protocol (IP)
Abbildung 5 aus [2]
RTP kann für unicast und multicast Anwendungen eingesetzt werden. Beim unicast
Verfahren werden einzelne Kopien der Originaldatei an die Teilnehmer versendet und ist
daher nur für eine begrenzte Anzahl von Benutzern praktikabel. Im Gegensatz dazu
übernimmt bei der multicast Übertragung der oder die Router die Dublizierung der
Pakete, sodass eine sehr große Anzahl von Teilnehmern gleichzeitig bedient werden
können. Aus der Abbildung wird ebenfalls ersichtlich, dass sich RTP einem zweiten
Protokoll bedient, nämlich dem Real-Time Control Protocol (RTCP). Dieses Protokoll bietet
dem Entwickler die Möglichkeit die Qualität der Datenströme zu identifizieren und zu
überwachen. Dadurch wird eine Quality of Service Funktionalität erreicht.
Die Übertragung der Mediendaten geschieht mit Hilfe von Sitzungen. Eine Sitzung ist
durch eine Adresse und zwei Portnummer charakterisiert. Dabei wird ein Port für die
eigentliche Mediendaten verwendet und ein zweiter für die Übertragung der
Kontrollpakete des RTCP.
4.3 Architecktur des JMF RTP API
Mit dem JMF RTP API kann die gesamte Funktionalität der JMF API bezogen auf
Streaming-Media verwendet werden. So gliedert sich die Echtzeiterweiterung nahtlos in
die High-Level Architektur des JMF API ein. Folgende Abbildung verdeutlicht die
Einsatzmöglichkeiten des JMF RTP API.
Seite 13
Java3D (Seminar), Java Media Framework API
File
Sender
Processor
Session
Manager
Capture
Device
Empfänger
Netzwerk
Session
Manager
DataSource
DataSink
Player
Processor
DataSink
Abbildung 6 aus [2]
Im Grunde sind es die gleichen wie auch beim JMF API mit der Einschränkung, dass die
verwendeten Mediendaten mit Hilfe des RTP über ein Netzwerk übertragen werden. Diese
Daten können auf Senderseite von einer Datei oder einem Aufnahmengerät kommen. Auf
der Seite des Empfängers können die Daten entweder abgespielt oder in einer Datei
gespeichert werden. Der unterste Zweig der Abbildung beim Empfänger zeigt einen
Anwendungsfall, bei dem die empfangenen Daten zunächst als Input durch einen
Processor laufen und anschließend in einer Datei gespeichert werden. Der Processor
könnte die eingehenden Daten z.B. wiedergeben oder vor dem Speichern in ein anderes
Format überführen.
Bei der Übertragung mit Hilfe einer Sitzung, kann pro Sitzung nur ein Stream gesendet
und empfangen werden. Deswegen ist ein sog. SessionManager nötig, sobald mehr als
nur Stream übertragen werden soll. Der SessionManager des Senders startet für jeden
Stream, der übertragen werden soll eine separate Sitzung. Auf Seite des Empfängers
generiert der SessionManager für jeden erkannten Eingangsstream einen neuen Player
oder Processor.
4.3.1 Übertragen von RTP Streaming-Media
Um eine streamingfähige Datei vom Sender zum Empfänger zu übertragen sind eine
Datenquelle (DataSource), ein MediaLocator und eine Datensenke (DataSink)
notwendig. Der MediaLocator spezifiziert den Empfänger und den Typ der übertragenen
Seite 14
Java3D (Seminar), Java Media Framework API
Datei. Das Objekt wird mit einer URL erzeugt, die diese Angaben enthält. Sie könnte wie
folgt aussehen:
MediaLocator medialocator =
new MediaLocator(„rtp://192.168.0.1:49150/audio“);
Der IP-Adrsse des Empfängers geht dem Protokollname voraus, gefolgt von Portnummer
und Medientyp.
Die Datenquelle enthält Angaben zur Datei, die übertragenden werden soll. Der
Processor wird mit Hilfe eines ProcessorModels, das auch die Datenquelle beinhaltet,
erzeugt. Das ProcessorModel legt das Streamingfomat und den ContentDescriptor
fest. Streamingformat und ContentDescriptor müssen zur Datenquelle kompatibel sein.
Die JMF RTP API bietet eine Reihe vordefinierter Standardformate, die für die geläufigen
Medientypen wie Audio und Video ausreichend sind.
Die Datensenke wird am Ende vom Manager mit Hilfe des MediaLocators und dem
Output des Processors erzeugt. Diese Datensenke ist als Repräsentation des
Empfängers zu sehen. Nachdem die Operation
DataSink ds = Manager.createDataSink(processoroutput, medialocator);
ausgeführt wurde, kann der Processor gestartet, die Datenquelle geöffnet und gestartet
und mit der Übertragung begonnen werden.
Der eben beschriebene Weg ist nur praktikabel, wenn lediglich ein Stream übertragen
werden soll. Eine Mediendatei kann jedoch mehrere Formate und damit mehrere Streams
enthalten. So besteht z.B. eine Videodatei neben den Bildinformationen auch meistens
aus einer Audiospur. Mit dem oben angesprochen Weg kann immer nur der erste
erkannte Stream übertragen werden. Sind dagegen mehrere Streams gleichzeitig zu
übertragen, benötigt man den oben angesprochenen SessionManager. Weiterhin
bekommt man alle in einer Datei enthaltenen Streams über den Processor mit der
Methode
TrackControl[] trackControls = Processor.getTrackControls();
Alle in diesem Array enthaltenen TrackControl Objekte können anschließend aktiviert
oder deaktiviert, sowie individuelle Einstellungen getroffen werden. Jedes TrackControl
Objekt repräsentiert später einen Stream. Folgender Programmausschnitt beschreibt die
Erzeugung des SessionManagers und der bzw. des Streams.
Seite 15
Java3D (Seminar), Java Media Framework API
SessionManager sm = new com.sun.media.rtp.RTPSessionMgr();
sm.createSendStream(processoroutput, 0);
sm.initSession();
sm.startSession();
Der SesionManager ist ab diesem Zeitpunkt für die Übertragung verantwortlich. Mit Hilfe
des zweiten Parameters der Funktion createSendStream, kann eingestellt werden,
welcher Stream bzw. welches TrackControl Objekt übertragen werden soll. Steht dort
eine eins, so bedeutet dies, dass der erste aktivierte Stream im Array trackControls
übertragen werden soll. Steht, wie in diesem Fall eine null an dieser Stelle, so ist der
tatsächlich übertragene Stream eine Mischung aller aktivierten TrackControl Objekte.
Die Einzelstreams werden dabei mit Hilfe eines Multiplexers zu einem entsprechend
kodierten Signal vereinigt und auf Seite des Empfängers wieder getrennt, sodass
tatsächlich nur ein Stream übertragen wird, dieser jedoch aus Einzelstreams oder Spuren
zusammengesetzt ist. Auf diese Weise können scheinbar mehrere Streams gleichzeitig
übertragen und beim Empfänger synchronisiert abgespielt werden.
4.3.2 Empfangen von RTP Streaming-Media
Das Empfangen von RTP Streaming-Media ist noch einfacher als das Senden. Dennoch
muss man auch hier unterscheiden, zwischen einem einzigen Stream, der empfangen
und wiedergegeben werden soll und mehreren parallelen Streams. Im ersten Fall
benötigt man lediglich eine MediaLocator Objekt, das analog zum MediaLocator Objekt
des Senders erstellt wird. Danach wird der Player mit Hilfe des Managers und des
gerade erzeugten MediaLocators kreiert. Sobald der Player den ersten Stream entdeckt
hat, löst er ein RealizeCompleteEvent aus und ist damit bereit die Quelle abzuspielen.
Folgende Anweisungen fassen die eben beschriebenen Schritte zusammen:
MediaLocator medialoc = new MediaLocator(„rtp://192.168.0.1:49150/audio“);
Player player = Manager.createPlayer(medialoc);
player.addControllerListener(ControllerListener);
player.realize();
Seite 16
Java3D (Seminar), Java Media Framework API
Sollen mehrere Streams einer Sitzung empfangen und wiedergegeben werden, braucht
man auch hier den SessionManager. Diesem muss ein ReceiveStreamListener engehängt
werden, damit neue eingehende Streams erkannt werden können. Jedes Mal, wenn nun
ein neuer Stream erkannt wird, löst der Manager ein NewReceiveStreamEvent aus.
Anhand des Streams kann ein DataSource Objekt gewonnen werden, dass an die
Mananger Methode createPlayer übergeben wird. Auf diese Weise wird jedes Mal ein
neuer Player erzeugt, wenn ein neuer Stream erkannt wird. Die folgenden Anweisungen
verdeutlichen noch einmal, wie bei einem neu eintreffenden Stream einer Sitzung zu
Verfahren ist.
ReceiveStream stream = ((NewReceiveStreamEvent)event).getReceiveStream();
DataSource datasource = stream.getDataSource();
Player player = Manager.createPlayer(datasource);
Dies waren die Grundlagen, um einen oder mehrere Streams einer Sitzung empfangen
und abspielen zu können. Daneben gibt es eine Reihe weiterer Maßnahmen, die
einerseits zu statistischen Zwecken gebraucht werden und andererseits die Anwendung
robuster machen. So gibt es z.B. die Möglichkeit auf Veränderungen im Format zu
reagieren. Dabei wird entweder ein FormatChangeEvent oder ein
RemotePayloadChangeEvent ausgelöst. Im ersten Fall, ist zu prüfen, ob ein neuer Player
erzeugt wurde. Ist dies der Fall, müssen die Referenzen seiner visuellen und
Kontrollkomponenten auf das Player Objekt gesetzt werden. Im Falle der
RemotePayloadChangeEvent, muss der alte Player freigegeben, alle Listener entfernt
und ein neuer Player mit der gleichen Datenquelle erzeugt werden.
5. Literaturstellen
[1]: Java Media Framework API Guide v. 2.0
[2]: vom Autor erstellte Bilder dessen Vorlage aus [1] stammt
[3]: https://www6.software.ibm.com/developerworks/education/j-jmf/index.html
Seite 17
Herunterladen