Progressi sulle API JMF e Java Media

Il mio primo articolo su JavaWorld era su Java Media Framework (JMF). Man mano che le varie API multimediali sono maturate, sento che le cose sono tornate al punto di partenza. Pertanto, dedicherò la mia ultima rubrica sulla programmazione multimediale a una rivisitazione di JMF e allo stato generale di tutte le API Java Media.

Ci sono stati alcuni cambiamenti notevoli nel JMF e in altre tecnologie Java Media, le aziende che ne sviluppano le implementazioni e la loro disponibilità per gli sviluppatori. Questo articolo aggiorna il materiale degli articoli precedenti come appropriato.

Un importante promemoria: Java Media Framework è un'API specifica per la sincronizzazione dei flussi multimediali (file, flussi di rete e così via). È una delle numerose API Java Media, che includono anche Java 2D, Java 3D, Java Speech e così via. Mi riferisco a Java Media Framework come JMF, riservando il termine Java Media per l'intera raccolta di API multimediali.

Storia e basi di JMF

Di JMF 1.0, alias Java Media Player API, ho scritto quanto segue nell'aprile del 1997 (vedi Risorse):

Java Media Player API, una parte di Java Media Framework (JMF), consente ai programmatori Java di incorporare facilmente audio e video all'interno di applet e applicazioni. Sia i contenuti multimediali statici che quelli in streaming sono supportati da qualsiasi URL valido. I lettori JMF possono essere controllati da altri lettori, fornendo la riproduzione sincrona di più campioni audio e video.

Queste informazioni sono ancora valide con gli aggiornamenti e le aggiunte degli ultimi due anni. JMF, tuttavia, ha sviluppato nuove funzionalità e ampliato la portata, soprattutto con la prossima versione dell'API 2.0 (prevista nella seconda metà del 1999).

Attori del settore JMF

Per prima cosa, diamo uno sguardo agli attori del settore. Sun, Silicon Graphics (SGI) e Intel hanno progettato e specificato l'originale JMF 1.0 a metà del 1998. Nel frattempo, dalla versione iniziale dell'API, sia SGI che Intel si sono ritirati dal processo di specifica JMF. Per un po ', nella comunità degli utenti di JMF c'è stata una preoccupazione significativa che Sun fosse l'unico fornitore a supportare JMF. Questa situazione era indesiderabile.

Fortunatamente, alla fine del 1998 IBM è intervenuta con interesse nel JMF. Poco dopo l'adesione di IBM a Sun, è stata rilasciata un'implementazione interamente Java dell'API 1.0 (dicembre 1998). Questa implementazione, nota come JMF 1.1 per piattaforme Java, supporta un sottoinsieme limitato ma significativo dei tipi di contenuto e protocollo supportati dalle implementazioni JMF 1.1 native di Win32 e Solaris (noti come pacchetti di prestazioni). La disponibilità di un JMF 1.1 interamente Java è stata una pietra miliare per JMF, in quanto la tecnologia è diventata disponibile per qualsiasi runtime compatibile con Java 1.1 o Java 2. In effetti, l'implementazione Java JMF 1.1 è disponibile anche in una versione orientata al Web con strumenti che consentono agli sviluppatori di includere solo le classi JMF pertinenti in un file JAR per il download con le loro applet JMF. Ciò consente di distribuire applet basate su JMF su un server Web per l'utilizzo da parte di qualsiasi browser conforme a Java 1.1. Sia Netscape che Microsoft supportano Java 1.1 - e quindi JMF 1.1 per Java - rispettivamente nelle ultime versioni del browser di Navigator e Internet Explorer.

IBM sta aiutando Sun a definire il codice dell'API JMF 2.0, che includerà una specifica e fornirà un'implementazione di riferimento della prossima API JMF: Java Media Capture. Speriamo che IBM riesca a capire come integrare successivamente la funzionalità JMF in alcuni dei suoi prodotti software basati su Java orientati al business, una cosa potenzialmente positiva per la longevità della tecnologia JMF.

Cosa c'è di nuovo in JMF 2.0 rispetto a 1.0?

L'API JMF 1.0 specifica i componenti necessari per gestire la riproduzione di audio e video sincronizzati. Fare riferimento al mio precedente articolo JMF (vedere Risorse) per una revisione delle capacità di JMF 1.0.

JMF 2.0 apporta diverse aggiunte chiave alle specifiche:

  • Acquisizione di audio e video
  • Streaming di audio e video, e quindi la possibilità di costruire server di streaming interamente Java oltre ai client
  • Supporto codec inseribile all'interno dei giocatori

Per ulteriori informazioni su JMF 2.0 e le sue nuove funzionalità, fare riferimento alla Guida per programmatori di Java Media Framework (vedi Risorse), attualmente disponibile nella versione 0.5 ad accesso anticipato.

Installazione di strumenti di sviluppo JMF e runtime

Sia Silicon Graphics che Intel hanno rimosso le versioni precedenti di JMF dai rispettivi siti Web. Tuttavia, è possibile scaricare le ultime implementazioni di riferimento (denominate JMF 1.1, conforme alle specifiche API 1.0) per le piattaforme Win32, Solaris e Java dal sito Sun (vedere Risorse).

Notare che la documentazione per la versione interamente Java menziona specificamente AIX, indicando che IBM ha testato questo software sul suo runtime Java AIX. Mi aspetto che le versioni future di JMF (2.0 e successive) supportino in modo specifico gli ambienti operativi IBM, sia tramite un'implementazione Java pura o implementazioni native specifiche del sistema operativo.

Esempi JMF aggiornati

Ho aggiornato l'esempio compatibile con JMF 1.0 beta dal mio precedente articolo JMF per l'esecuzione in ambienti compatibili con JMF 1.0 API. È possibile scaricare il codice di esempio e provarlo con le implementazioni JMF 1.1 utilizzando i propri file multimediali. L'applet dovrebbe anche essere eseguito sui runtime JMF 2.0 quando diventano disponibili. (Per scaricare tutti i file associati a questo articolo in formato zip, vedi Risorse.)

001 // Commenta la seguente dichiarazione del pacchetto da compilare separatamente. 002 // pacchetto com.javaworld.media.jmf; 003004 import java.applet. *; 005 import java.awt. *; 006 import java.net. *; 007 import java.io. *; 008 import javax.media. *; 009010 / ** 011 * JMF11Applet aggiorna JMFApplet dall'articolo di aprile 1997 012 * JavaWorld per la conformità API JMF 1.1. Si prega di 013 * fare riferimento all'articolo su:

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

016 * Inoltre, JMF11Applet è stato rielaborato per 017 * utilizzare il modello di eventi Java 1.1 (e oltre). Questa versione 018 * è stata sviluppata e testata su Java 2 019 * e l'implementazione completamente Java JMF 1.1, maggio 1999. 020 *

021 * Questa applet può essere distribuita ai server Web pubblici 022 * utilizzando jmf-server.jar fornito in JMF 1.1 023 * per il download dei server Web. Questo archivio JAR contiene 024 * le necessarie classi di runtime JMF tutto Java. JMF11Applet 025 * è stato distribuito in questo modo per la colonna giugno 1999 026 *:

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 extends L'applet implementa ControllerListener {040 URL privato myURL = null; 041 giocatore privato myPlayer = null; 042 componente privato myVisual = null; 043 componente privato myControls = null; 044 pannello privato visualPanel = null; 045046 / ** 047 * Inizializza JMF11Applet. Disegniamo l'interfaccia e 048 * creiamo il nostro player in init (). 049 ** / 050 public void init () {051 super.init (); 052 053 // Specifica AWT Layout Manager. 054 setLayout (new BorderLayout ());055 056 // Carica l'URL dalla pagina Web JMF11Applet è incorporato in. 057 String asset = getParameter ("ASSET"); 058 059 // Controlla l'URL e crea un oggetto URL per conservarlo. 060 if (asset.equals ("")) {061 // non abbiamo inserito una risorsa nell'applet. 062} else {063 try {064 myURL = new URL (getDocumentBase (), asset); 065} catch (MalformedURLException e) {066 // Abbiamo inserito un asset incompleto o creato un URL errato. 067 // Un'applet più robusta dovrebbe gestirla con grazia. 068} 069} 070 try {071 // Ecco una parte interessante. Manager viene utilizzato per 072 // creare il player effettivo per questo URL. Quindi 073 // aggiungiamo JMF11Applet come ControllerListener per myPlayer. 074 // Questo ci consente di rispondere a RealizeCompleteEvents. 075 myPlayer = Manager.createPlayer (myURL); 076 myPlayer.addControllerListener (questo);077} catch (IOException e) {078 // Si sono verificati dei problemi con l'I / O; Uscita. 079 System.out.println ("Problema di I / O durante il tentativo di creare il lettore ... uscita"); 080 System.exit (1); 081} catch (NoPlayerException e) {082 // Impossibile restituire un lettore utilizzabile; Uscita. 083 System.out.println ("Nessun lettore utilizzabile restituito ... in uscita"); 084 System.exit (1); 085} 086} 087 088 / ** 089 * Ignora il metodo predefinito di avvio dell'applet per chiamare il 090 * realizzo di Player. Questo farà prima la realizzazione, che a sua volta 091 * innesca i bit finali della costruzione della GUI nel metodo controllerUpdate () 092 *. La riproduzione non viene avviata automaticamente: l'utente ha bisogno di 093 * per fare clic sul pulsante "play" nella nostra applet per avviare la riproduzione del campione multimediale 094 *. 095 ** / 096 public void start () {097 myPlayer.realize ();098} 099 100 101 / ** 102 * Ignora il metodo di arresto dell'applet predefinito per chiamare myPlayer.stop () 103 * e myPlayer.deallocate () in modo da liberare correttamente le risorse 104 * se qualcuno esce da questa pagina nel proprio browser. 105 ** / 106 public void stop () {107 myPlayer.stop (); 108 myPlayer.deallocate (); 109} 110 111 / ** 112 * Dato che dobbiamo sapere quando la realizzazione viene completata, usiamo 113 * controllerUpdate () per gestire RealizeCompleteEvents. 114 * Quando riceviamo RealizeCompleteEvent, impaginiamo 115 * e visualizziamo il componente video ei controlli nella nostra GUI applet 116 *. 117 ** / 118 public void controllerUpdate (ControllerEvent event) {119 if (event instanceof RealizeCompleteEvent) {120 //System.out.println("Received RCE ... "); 121 // Ora che abbiamo un giocatore realizzato,possiamo ottenere 122 // VisualComponent e ControlPanelComponent e impacchettarli // nella nostra applet. 124 myVisual = myPlayer.getVisualComponent (); 125 if (myVisual! = Null) {126 // Per garantire che VisualComponent 127 // non venga ridimensionato da BorderLayout, lo annido 128 // all'interno di visualPanel utilizzando FlowLayout. 129 visualPanel = nuovo pannello (); 130 visualPanel.setLayout (new 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("Added controls ... "); 139} 140 // invalidate (); 141 validate (); 142} 143 // Altrimenti consumiamo semplicemente l'evento. 144} 145}124 myVisual = myPlayer.getVisualComponent (); 125 if (myVisual! = Null) {126 // Per garantire che VisualComponent 127 // non venga ridimensionato da BorderLayout, lo annido 128 // all'interno di visualPanel utilizzando FlowLayout. 129 visualPanel = nuovo pannello (); 130 visualPanel.setLayout (new 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("Added controls ... "); 139} 140 // invalidate (); 141 validate (); 142} 143 // Altrimenti consumiamo semplicemente l'evento. 144} 145}124 myVisual = myPlayer.getVisualComponent (); 125 if (myVisual! = Null) {126 // Per garantire che VisualComponent 127 // non venga ridimensionato da BorderLayout, lo annido 128 // all'interno di visualPanel utilizzando FlowLayout. 129 visualPanel = nuovo pannello (); 130 visualPanel.setLayout (new 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("Added controls ... "); 139} 140 // invalidate (); 141 validate (); 142} 143 // Altrimenti consumiamo semplicemente l'evento. 144} 145}= null) {126 // Per garantire che VisualComponent 127 // non venga ridimensionato da BorderLayout, lo annido 128 // all'interno di visualPanel utilizzando FlowLayout. 129 visualPanel = nuovo pannello (); 130 visualPanel.setLayout (new 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("Added controls ... "); 139} 140 // invalidate (); 141 validate (); 142} 143 // Altrimenti consumiamo semplicemente l'evento. 144} 145}= null) {126 // Per garantire che VisualComponent 127 // non venga ridimensionato da BorderLayout, lo annido 128 // all'interno di visualPanel utilizzando FlowLayout. 129 visualPanel = nuovo pannello (); 130 visualPanel.setLayout (new 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("Added controls ... "); 139} 140 // invalidate (); 141 validate (); 142} 143 // Altrimenti consumiamo semplicemente l'evento. 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("Added controls ... "); 139} 140 // invalidate (); 141 validate (); 142} 143 // Altrimenti consumiamo semplicemente l'evento. 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("Added controls ... "); 139} 140 // invalidate (); 141 validate (); 142} 143 // Altrimenti consumiamo semplicemente l'evento. 144} 145}

Ho incluso un semplice documento HTML di esempio, example.html (che puoi provare subito nel tuo browser facendo clic qui), per mostrarti come incorporare l'applet nelle tue pagine Web. Cambia semplicemente il file multimediale nel ASSETtag e il gioco è fatto!

Per questo esempio, ho utilizzato il download di JMF 1.1 per server Web (documentato sul sito Web JMF) per abilitare JMF11Appletil download automatico jmf-server.jar, un archivio di codice contenente le classi di runtime JMF necessarie. Ciò consente all'applet di essere eseguita all'interno di qualsiasi browser compatibile con Java 1.1, senza alcun software da installare da parte dell'utente finale. (Si noti che la versione JMF per server Web include anche uno strumento di personalizzazione JMFCustomizer, che potenzialmente consentirà di rimuovere ancora più classi non necessarie dal file JAR JMF. Questo strumento attualmente non funziona con Java 2, tuttavia, poiché utilizza un nome del pacchetto per Swing.)

Nel particolare esempio incorporato in example.html , carichiamo un file WAV (welcome.wav), accertiamo i componenti di controllo appropriati da rendere disponibili (nessun componente video, poiché si tratta di un file multimediale solo audio) e riproduciamo il multimediale file. Si noti che il file WAV (600 KB) e le classi JMF (570 KB) potrebbero richiedere diversi minuti per il download sulla macchina, a seconda della velocità di connessione.

Dopo aver analizzato la pagina di esempio, i browser compatibili con Java 1.1 dovrebbero caricare l'applet e supportare le classi JMF automaticamente dal server Web JavaWorld . Una volta caricata e in esecuzione l'applet, è possibile premere il pulsante Riproduci per avviare la riproduzione del file audio WAV. Prova a riposizionare la riproduzione utilizzando la barra di scorrimento e sospendere e riavviare la riproduzione utilizzando il pulsante Pausa / Riproduci.

L'implementazione della piattaforma Java JMF 1.1 utilizza widget interamente Java per i suoi controlli, quindi i controlli hanno lo stesso aspetto da browser a browser e da piattaforma a piattaforma. Notare come l'applet appare in esecuzione nella JVM di Netscape Communicator su Solaris 7 e nella JVM di Microsoft in Internet Explorer su Win32.

Il pulsante etichettato i fornisce informazioni sul file multimediale riprodotto nell'applet JMF. Fare clic su questo collegamento di informazioni per ottenere dettagli sul file WAV in esecuzione in questa pagina Web.