Fortschritte bei den JMF- und Java Media-APIs

Mein erster JavaWorld- Artikel war das Java Media Framework (JMF). Als die verschiedenen Medien-APIs gereift sind, habe ich das Gefühl, dass sich der Kreis geschlossen hat. Daher werde ich meine letzte Spalte zur Medienprogrammierung einem erneuten Besuch von JMF und dem allgemeinen Status aller Java Media-APIs widmen .

Es gab einige bemerkenswerte Änderungen in der JMF und anderen Java Media-Technologien, den Unternehmen, die Implementierungen davon entwickeln, und ihrer Verfügbarkeit für Entwickler. Dieser Artikel aktualisiert das Material aus früheren Artikeln entsprechend.

Eine wichtige Erinnerung: Java Media Framework ist eine spezielle API zum Synchronisieren von Multimedia-Streams (Dateien, Netzwerk-Streams usw.). Es ist eine von mehreren Java Media-APIs, zu denen auch Java 2D, Java 3D, Java Speech usw. gehören. Ich bezeichne das Java Media Framework als JMF und reserviere den Begriff Java Media für die gesamte Sammlung von Multimedia-APIs.

JMF Geschichte und Grundlagen

Von der JMF 1.0, auch bekannt als Java Media Player API, habe ich im April 1997 Folgendes geschrieben (siehe Ressourcen):

Mit der Java Media Player-API, einem Teil des Java Media Framework (JMF), können Java-Programmierer Audio und Video problemlos in Applets und Anwendungen einbetten. Sowohl statische als auch Streaming-Multimedia-Inhalte werden von jeder gültigen URL unterstützt. JMF-Player können von anderen Playern gesteuert werden, wodurch mehrere Audio- und Videobeispiele synchron wiedergegeben werden können.

Diese Informationen gelten weiterhin für die Aktualisierungen und Ergänzungen der letzten zwei Jahre. JMF hat jedoch neue Funktionen entwickelt und an Umfang gewonnen, insbesondere mit der bevorstehenden Version 2.0 der API (voraussichtlich in der zweiten Hälfte des Jahres 1999).

Akteure der JMF-Branche

Schauen wir uns zunächst die Akteure der Branche an. Sun, Silicon Graphics (SGI) und Intel haben Mitte 1998 das Original JMF 1.0 entworfen und spezifiziert. In der Zwischenzeit seit der ersten Version der API haben sich sowohl SGI als auch Intel aus dem JMF-Spezifikationsprozess zurückgezogen. Für eine Weile gab es in der JMF-Benutzergemeinschaft erhebliche Bedenken, dass Sun der einzige Anbieter war, der JMF unterstützte. Diese Situation war unerwünscht.

Glücklicherweise trat IBM Ende 1998 mit Interesse an der JMF ein. Kurz nachdem IBM zu Sun gekommen war, wurde eine All-Java-Implementierung der 1.0-API veröffentlicht (Dezember 1998). Diese Implementierung, bekannt als JMF 1.1 für Java-Plattformen, unterstützt eine begrenzte, aber signifikante Teilmenge der Inhalte und Protokolltypen, die von den Win32- und Solaris-nativen JMF 1.1-Implementierungen (sogenannte Performance Packs) unterstützt werden). Die Verfügbarkeit eines All-Java-JMF 1.1 war ein wichtiger Meilenstein für JMF, da die Technologie für jede Java 1.1-kompatible oder Java 2-Laufzeit verfügbar wurde. Tatsächlich ist die Java-Implementierung von JMF 1.1 sogar in einer weborientierten Version mit Tools verfügbar, mit denen Entwickler nur die relevanten JMF-Klassen in eine JAR-Datei aufnehmen können, um sie mit ihren JMF-Applets herunterzuladen. Auf diese Weise können JMF-basierte Applets auf einem Webserver zur Verwendung durch einen Java 1.1-kompatiblen Browser bereitgestellt werden. Sowohl Netscape als auch Microsoft unterstützen Java 1.1 - und damit JMF 1.1 für Java - in ihren jüngsten Browserversionen von Navigator bzw. Internet Explorer.

IBM unterstützt Sun bei der Codefinition der JMF 2.0-API, die eine Spezifikation enthält und eine Referenzimplementierung der nächsten JMF-API bereitstellt: Java Media Capture. Hoffen wir, dass IBM herausfindet, wie die JMF-Funktionalität anschließend in einige seiner geschäftsorientierten Java-basierten Softwareprodukte integriert werden kann - eine potenziell gute Sache für die Langlebigkeit der JMF-Technologie.

Was ist neu in JMF 2.0 vs. 1.0?

Die JMF 1.0-API gibt die Komponenten an, die für die Wiedergabe von synchronisiertem Audio und Video erforderlich sind. In meinem vorherigen JMF-Artikel (siehe Ressourcen) finden Sie eine Übersicht über die Funktionen von JMF 1.0.

JMF 2.0 erweitert die Spezifikation um mehrere wichtige Elemente:

  • Audio- und Videoaufnahme
  • Streaming von Audio und Video und damit die Möglichkeit, neben Clients auch Java-Streaming-Server aufzubauen
  • Pluggable Codec-Unterstützung innerhalb der Spieler

Weitere Informationen zu JMF 2.0 und seinen neuen Funktionen finden Sie im Java Media Framework-Programmierhandbuch (siehe Ressourcen), das derzeit in Version 0.5 für den frühen Zugriff verfügbar ist.

Installation von JMF-Entwicklungstools und Laufzeit

Sowohl Silicon Graphics als auch Intel haben frühere Versionen von JMF von ihren jeweiligen Websites entfernt. Sie können jedoch die neuesten Referenzimplementierungen (mit JMF 1.1 bezeichnet, kompatibel mit der 1.0-API-Spezifikation) für Win32-, Solaris- und Java-Plattformen von der Sun-Site herunterladen (siehe Ressourcen).

Beachten Sie, dass in der Dokumentation für die All-Java-Version AIX ausdrücklich erwähnt wird, was darauf hinweist, dass IBM diese Software auf seiner AIX-Java-Laufzeit getestet hat. Ich erwarte, dass zukünftige Versionen von JMF (2.0 und höher) IBM Betriebsumgebungen speziell unterstützen, sei es durch eine reine Java-Implementierung oder durch betriebssystemspezifische native Implementierungen.

Aktualisierte JMF-Beispiele

Ich habe das JMF 1.0-Beta-kompatible Beispiel aus meinem vorherigen JMF-Artikel so aktualisiert, dass es in JMF 1.0-API-kompatiblen Umgebungen ausgeführt werden kann. Sie können den Beispielcode herunterladen und unter JMF 1.1-Implementierungen mit Ihren eigenen Mediendateien ausprobieren. Das Applet sollte auch auf JMF 2.0-Laufzeiten ausgeführt werden, sobald diese verfügbar sind. (Informationen zum Herunterladen aller mit diesem Artikel verknüpften Dateien im Zip-Format finden Sie unter Ressourcen.)

001 // Kommentieren Sie die folgende Paketanweisung aus, um sie separat zu kompilieren. 002 // package com.javaworld.media.jmf; 003 004 import java.applet. *; 005 import java.awt. *; 006 import java.net. *; 007 import java.io. *; 008 import javax.media. *; 009 010 / ** 011 * JMF11Applet aktualisiert das JMFApplet aus dem April 1997 012 * JavaWorld-Artikel für JMF 1.1-API-Konformität. Bitte 013 * siehe Artikel unter:

014 * //www.javaworld.com/jw-04-1997/jw-04-jmf.html 015 *

016 * Zusätzlich wurde JMF11Applet auf 017 * überarbeitet, wobei das Java 1.1-Ereignismodell (und darüber hinaus) verwendet wurde. Diese 018 * -Version wurde auf Java 2 019 * und der JMF 1.1-All-Java-Implementierung im Mai 1999 entwickelt und getestet. 020 *

021 * Dieses Applet kann auf öffentlichen Webservern bereitgestellt werden. 022 * Verwenden Sie die Datei jmf-server.jar, die in JMF 1.1 023 * zum Herunterladen von Webservern enthalten ist. Dieses JAR-Archiv enthält 024 * die erforderlichen JMF-All-Java-Laufzeitklassen. JMF11Applet 025 * wurde auf diese Weise für die Spalte Juni 1999 026 * bereitgestellt:

027 * //www.javaworld.com/jw-06-1999/jw-06-media.html 028 * 029 * @author Bill Day 030 * @version 1.1 031 * @see javax.media.ControllerEvent 032 * @see javax .media.ControllerListener 033 * @see javax.media.Manager 034 * @see javax.media.NoPlayerException 035 * @see javax.media.Player 036 * @see javax.media.RealizeCompleteEvent 037 ** / 038 039 public class JMF11Applet erweitert Applet implementiert ControllerListener {040 private URL myURL = null; 041 privater Spieler myPlayer = null; 042 private Komponente myVisual = null; 043 private Komponente myControls = null; 044 privates Panel visualPanel = null; 045 046 / ** 047 * JMF11Applet initialisieren. Wir legen die Oberfläche an und erstellen 048 * unseren Player in init (). 049 ** / 050 public void init () {051 super.init (); 052 053 // AWT Layout Manager angeben. 054 setLayout (neues BorderLayout ());055 056 // URL von der Webseite laden JMF11Applet ist eingebettet in. 057 String asset = getParameter ("ASSET"); 058 059 // Überprüfen Sie die URL und erstellen Sie ein URL-Objekt, um sie zu speichern. 060 if (asset.equals ("")) {061 // Wir haben kein Asset in das Applet eingegeben. 062} else {063 try {064 myURL = neue URL (getDocumentBase (), Asset); 065} catch (MalformedURLException e) {066 // Wir haben ein unvollständiges Asset eingegeben oder eine falsche URL erstellt. 067 // Ein robusteres Applet sollte dies ordnungsgemäß handhaben. 068} 069} 070 try {071 // Hier ist ein interessantes Stück. Der Manager wird verwendet, um den tatsächlichen Player für diese URL zu erstellen. Wir fügen dann JMF11Applet als ControllerListener für myPlayer hinzu. 074 // Damit können wir auf RealizeCompleteEvents antworten. 075 myPlayer = Manager.createPlayer (myURL); 076 myPlayer.addControllerListener (this);077} catch (IOException e) {078 // Es ist ein Problem mit der E / A aufgetreten. Ausfahrt. 079 System.out.println ("E / A-Problem beim Versuch, einen Player zu erstellen ... wird beendet"); 080 System.exit (1); 081} catch (NoPlayerException e) {082 // Ein verwendbarer Player kann nicht zurückgegeben werden. Ausfahrt. 083 System.out.println ("Kein verwendbarer Player zurückgegeben ... beendet"); 084 System.exit (1); 085} 086} 087 088 / ** 089 * Überschreiben Sie die Standard-Applet-Startmethode, um die 090 * realize () des Players aufzurufen. Dies führt zuerst die Realisierung durch, die wiederum 091 * die letzten Bits der GUI-Erstellung in der controllerUpdate () 092 * -Methode auslöst. Die Wiedergabe wird nicht automatisch gestartet: Der Benutzer benötigt 093 *, um auf die Schaltfläche "Wiedergabe" in unserem Applet zu klicken, um die Wiedergabe des 094 * -Medienbeispiels zu starten. 095 ** / 096 public void start () {097 myPlayer.realize ();098} 099 100 101 / ** 102 * Überschreiben Sie die Standard-Applet-Stoppmethode, um myPlayer.stop () 103 * und myPlayer.deallocate () aufzurufen, damit wir die Ressourcen 104 * ordnungsgemäß freigeben, wenn jemand diese Seite in seinem Browser beendet. 105 ** / 106 public void stop () {107 myPlayer.stop (); 108 myPlayer.deallocate (); 109} 110 111 / ** 112 * Da wir wissen müssen, wann die Realisierung abgeschlossen ist, verwenden wir 113 * controllerUpdate (), um RealizeCompleteEvents zu verarbeiten. 114 * Wenn wir das RealizeCompleteEvent erhalten, legen wir 115 * an und zeigen die Videokomponente und Steuerelemente in unserer 116 * Applet-GUI an. 117 ** / 118 public void controllerUpdate (ControllerEvent-Ereignis) {119 if (Ereignisinstanz von RealizeCompleteEvent) {120 //System.out.println("Received RCE ... "); 121 // Jetzt, wo wir einen realisierten Spieler haben,Wir können die 122 // VisualComponent und ControlPanelComponent abrufen und 123 // in unser Applet packen. 124 myVisual = myPlayer.getVisualComponent (); 125 if (myVisual! = Null) {126 // Um ​​sicherzustellen, dass die Größe der VisualComponent 127 // nicht von BorderLayout geändert wird, verschachtele ich sie 128 // in VisualPanel mit FlowLayout. 129 visualPanel = neues Panel (); 130 visualPanel.setLayout (neues FlowLayout ()); 131 visualPanel.add (myVisual); 132 add (visualPanel, BorderLayout.CENTER); 133 //System.out.println("Added VisualComponent ... "); 134} 135 myControls = myPlayer.getControlPanelComponent (); 136 if (myControls! = Null) {137 add (myControls, BorderLayout.SOUTH); 138 //System.out.println(" Steuerelemente hinzugefügt ... "); 139} 140 // invalidate (); 141 validate (); 142} 143 // Sonst konsumieren wir einfach das Ereignis. 144} 145}124 myVisual = myPlayer.getVisualComponent (); 125 if (myVisual! = Null) {126 // Um ​​sicherzustellen, dass die Größe der VisualComponent 127 // nicht von BorderLayout geändert wird, verschachtele ich sie 128 // in VisualPanel mit FlowLayout. 129 visualPanel = neues Panel (); 130 visualPanel.setLayout (neues FlowLayout ()); 131 visualPanel.add (myVisual); 132 add (visualPanel, BorderLayout.CENTER); 133 //System.out.println("Added VisualComponent ... "); 134} 135 myControls = myPlayer.getControlPanelComponent (); 136 if (myControls! = Null) {137 add (myControls, BorderLayout.SOUTH); 138 //System.out.println(" Steuerelemente hinzugefügt ... "); 139} 140 // invalidate (); 141 validate (); 142} 143 // Sonst konsumieren wir einfach das Ereignis. 144} 145}124 myVisual = myPlayer.getVisualComponent (); 125 if (myVisual! = Null) {126 // Um ​​sicherzustellen, dass die Größe der VisualComponent 127 // nicht durch BorderLayout geändert wird, verschachtele ich sie 128 // in VisualPanel mit FlowLayout. 129 visualPanel = neues Panel (); 130 visualPanel.setLayout (neues FlowLayout ()); 131 visualPanel.add (myVisual); 132 add (visualPanel, BorderLayout.CENTER); 133 //System.out.println("Added VisualComponent ... "); 134} 135 myControls = myPlayer.getControlPanelComponent (); 136 if (myControls! = Null) {137 add (myControls, BorderLayout.SOUTH); 138 //System.out.println(" Steuerelemente hinzugefügt ... "); 139} 140 // invalidate (); 141 validate (); 142} 143 // Sonst konsumieren wir einfach das Ereignis. 144} 145}= null) {126 // Um ​​sicherzustellen, dass die Größe der VisualComponent 127 // nicht durch BorderLayout geändert wird, verschachtele ich sie 128 // in VisualPanel mit FlowLayout. 129 visualPanel = neues Panel (); 130 visualPanel.setLayout (neues FlowLayout ()); 131 visualPanel.add (myVisual); 132 add (visualPanel, BorderLayout.CENTER); 133 //System.out.println("Added VisualComponent ... "); 134} 135 myControls = myPlayer.getControlPanelComponent (); 136 if (myControls! = Null) {137 add (myControls, BorderLayout.SOUTH); 138 //System.out.println(" Steuerelemente hinzugefügt ... "); 139} 140 // invalidate (); 141 validate (); 142} 143 // Sonst konsumieren wir einfach das Ereignis. 144} 145}= null) {126 // Um ​​sicherzustellen, dass die Größe der VisualComponent 127 // nicht von BorderLayout geändert wird, verschachtele ich sie 128 // in VisualPanel mit FlowLayout. 129 visualPanel = neues Panel (); 130 visualPanel.setLayout (neues FlowLayout ()); 131 visualPanel.add (myVisual); 132 add (visualPanel, BorderLayout.CENTER); 133 //System.out.println("Added VisualComponent ... "); 134} 135 myControls = myPlayer.getControlPanelComponent (); 136 if (myControls! = Null) {137 add (myControls, BorderLayout.SOUTH); 138 //System.out.println(" Steuerelemente hinzugefügt ... "); 139} 140 // invalidate (); 141 validate (); 142} 143 // Sonst konsumieren wir einfach das Ereignis. 144} 145}133 //System.out.println("Added VisualComponent ... "); 134} 135 myControls = myPlayer.getControlPanelComponent (); 136 if (myControls! = Null) {137 add (myControls, BorderLayout.SOUTH); 138 //System.out.println(" Steuerelemente hinzugefügt ... "); 139} 140 // invalidate (); 141 validate (); 142} 143 // Sonst konsumieren wir einfach das Ereignis. 144} 145}133 //System.out.println("Added VisualComponent ... "); 134} 135 myControls = myPlayer.getControlPanelComponent (); 136 if (myControls! = Null) {137 add (myControls, BorderLayout.SOUTH); 138 //System.out.println(" Steuerelemente hinzugefügt ... "); 139} 140 // invalidate (); 141 validate (); 142} 143 // Sonst konsumieren wir einfach das Ereignis. 144} 145}

Ich habe ein einfaches Beispiel-HTML-Dokument, example.html, hinzugefügt (das Sie jetzt in Ihrem Browser ausprobieren können, indem Sie hier klicken), um Ihnen zu zeigen, wie Sie das Applet in Ihre eigenen Webseiten einbetten können. Ändern Sie einfach die Mediendatei im ASSETTag und los geht's!

In diesem Beispiel habe ich den Download von JMF 1.1 für Webserver (auf der JMF-Website dokumentiert) verwendet, um JMF11Appletdas automatische Herunterladen jmf-server.jareines Codearchivs mit den erforderlichen JMF-Laufzeitklassen zu ermöglichen. Auf diese Weise kann das Applet in jedem Java 1.1-kompatiblen Browser ausgeführt werden, ohne dass der Endbenutzer Software installieren muss. (Beachten Sie, dass die Version von JMF für Webserver auch ein Anpassungstool enthält, JMFCustomizermit dem Sie möglicherweise noch mehr nicht benötigte Klassen aus der JMF-JAR-Datei entfernen können. Dieses Tool funktioniert derzeit jedoch nicht unter Java 2, da es ein veraltetes Tool verwendet Paketname für Swing.)

In dem speziellen Beispiel, das in example.html eingebettet ist , laden wir eine WAV-Datei (welcome.wav), ermitteln die entsprechenden Steuerungskomponenten, die zur Verfügung gestellt werden sollen (keine Videokomponente, da es sich um eine Nur-Ton-Mediendatei handelt) und geben die Multimedia-Inhalte wieder Datei. Beachten Sie, dass das Herunterladen der WAV-Datei (600 KB) und der JMF-Klassen (570 KB) je nach Verbindungsgeschwindigkeit einige Minuten dauern kann.

Nach dem Parsen der Beispielseite sollten Java 1.1-kompatible Browser das Applet und die unterstützenden JMF-Klassen automatisch vom JavaWorld- Webserver laden . Sobald das Applet geladen ist und ausgeführt wird, können Sie die Wiedergabetaste drücken, um die Wiedergabe der WAV-Sounddatei zu starten. Versuchen Sie, die Wiedergabe mithilfe der Bildlaufleiste neu zu positionieren und die Wiedergabe mit der Schaltfläche Pause / Wiedergabe anzuhalten und neu zu starten.

Die Implementierung der Java-Plattform JMF 1.1 verwendet für ihre Steuerelemente ausschließlich Java-Widgets, sodass die Steuerelemente von Browser zu Browser und von Plattform zu Plattform gleich aussehen. Beachten Sie, wie das Applet in der JVM von Netscape Communicator unter Solaris 7 und in der JVM von Microsoft in Internet Explorer unter Win32 ausgeführt wird.

Die Schaltfläche mit der Bezeichnung i enthält Informationen zur Mediendatei, die im JMF-Applet abgespielt wird. Klicken Sie auf diesen Informationslink, um Details zur WAV-Datei zu erhalten, die auf dieser Webseite ausgeführt wird.