Progression des API JMF et Java Media

Mon premier article sur JavaWorld était sur le Java Media Framework (JMF). Au fur et à mesure que les différentes API médias ont mûri, j'ai le sentiment que la boucle est bouclée. Par conséquent, je dédierai ma dernière colonne de programmation multimédia à une revisite de JMF et de l'état général de toutes les API Java Media.

Il y a eu des changements notables dans le JMF et d'autres technologies Java Media, les entreprises qui en développent leurs implémentations et leur disponibilité pour les développeurs. Cet article met à jour le matériel des articles précédents le cas échéant.

Un rappel important: Java Media Framework est une API spécifique pour la synchronisation des flux multimédias (fichiers, flux réseau, etc.). Il s'agit de l'une des nombreuses API Java Media, qui incluent également Java 2D, Java 3D, Java Speech, etc. Je me réfère au Java Media Framework comme au JMF, en réservant le terme Java Media à l'ensemble de la collection d'API multimédia.

Histoire et bases de JMF

De la JMF 1.0, alias Java Media Player API, j'ai écrit ce qui suit en avril 1997 (voir Ressources):

L'API Java Media Player, une partie de Java Media Framework (JMF), permet aux programmeurs Java d'intégrer facilement de l'audio et de la vidéo dans des applets et des applications. Le multimédia statique et le streaming sont pris en charge à partir de toute URL valide. Les lecteurs JMF peuvent être contrôlés par d'autres lecteurs, permettant la lecture synchrone de plusieurs échantillons audio et vidéo.

Cette information est toujours vraie avec les mises à jour et les ajouts des deux dernières années. Cependant, JMF a fait évoluer de nouvelles fonctionnalités et s'est élargi, en particulier avec la prochaine version de l'API 2.0 (prévue pour la seconde moitié de 1999).

Acteurs de l'industrie JMF

Tout d'abord, jetons un coup d'œil aux acteurs de l'industrie. Sun, Silicon Graphics (SGI) et Intel ont conçu et spécifié le JMF 1.0 original à la mi-1998. Dans l'intervalle, depuis la version initiale de l'API, SGI et Intel se sont retirés du processus de spécification JMF. Pendant un certain temps, la communauté des utilisateurs JMF s'est inquiétée du fait que Sun était le seul fournisseur prenant en charge JMF. Cette situation n'était pas souhaitable.

Heureusement, à la fin de 1998, IBM est intervenu avec intérêt pour le JMF. Peu de temps après qu'IBM a rejoint Sun, une implémentation entièrement Java de l'API 1.0 a été publiée (décembre 1998). Cette implémentation, connue sous le nom de JMF 1.1 pour les plates-formes Java, prend en charge un sous-ensemble limité mais significatif des types de contenu et de protocole pris en charge par les implémentations JMF 1.1 natives de Win32 et Solaris (appelées packs de performances). La disponibilité d'un JMF 1.1 entièrement Java a été une étape importante pour JMF, dans la mesure où la technologie est devenue disponible pour tout environnement d'exécution compatible Java 1.1 ou Java 2. En fait, l'implémentation Java JMF 1.1 est même disponible dans une version orientée Web avec des outils qui permettent aux développeurs d'inclure uniquement les classes JMF pertinentes dans un fichier JAR à télécharger avec leurs applets JMF. Cela permet de déployer des applets JMF sur un serveur Web pour une utilisation par n'importe quel navigateur compatible Java 1.1. Netscape et Microsoft prennent en charge Java 1.1 - et donc JMF 1.1 pour Java - dans leurs dernières versions de navigateur de Navigator et Internet Explorer, respectivement.

IBM aide Sun à coder l'API JMF 2.0, qui comprendra une spécification et fournira une implémentation de référence de la prochaine API JMF: Java Media Capture. Espérons qu'IBM trouvera comment intégrer par la suite la fonctionnalité JMF dans certains de ses produits logiciels basés sur Java orientés métier - ce qui est potentiellement une bonne chose pour la longévité de la technologie JMF.

Quoi de neuf dans JMF 2.0 par rapport à 1.0?

L'API JMF 1.0 spécifie les composants nécessaires pour gérer la lecture audio et vidéo synchronisée. Veuillez vous référer à mon précédent article JMF (voir Ressources) pour un examen des capacités de JMF 1.0.

JMF 2.0 apporte plusieurs ajouts clés à la spécification:

  • Capture audio et vidéo
  • Streaming audio et vidéo, et donc possibilité de construire des serveurs de streaming entièrement Java en plus des clients
  • Prise en charge du codec enfichable dans les lecteurs

Pour plus d'informations sur JMF 2.0 et ses nouvelles fonctionnalités, veuillez vous référer au Guide du programmeur Java Media Framework (voir Ressources), actuellement disponible en accès anticipé version 0.5.

Installation des outils de développement et du runtime JMF

Silicon Graphics et Intel ont supprimé les versions précédentes de JMF de leurs sites Web respectifs. Vous pouvez toutefois télécharger les dernières implémentations de référence (notées JMF 1.1, conformes à la spécification API 1.0) pour les plates-formes Win32, Solaris et Java à partir du site Sun (voir Ressources).

Notez que la documentation de la version entièrement Java mentionne spécifiquement AIX, indiquant qu'IBM a testé ce logiciel sur son environnement d'exécution Java AIX. Je m'attends à ce que les futures versions de JMF (2.0 et au-delà) prennent spécifiquement en charge les environnements d'exploitation IBM, que ce soit via une implémentation Java pure ou des implémentations natives spécifiques au système d'exploitation.

Exemples JMF mis à jour

J'ai mis à jour l'exemple de compatibilité bêta JMF 1.0 de mon précédent article JMF pour qu'il s'exécute dans des environnements compatibles API JMF 1.0. Vous pouvez télécharger l'exemple de code et l'essayer sous les implémentations JMF 1.1 en utilisant vos propres fichiers multimédias. L'applet doit également s'exécuter sur les environnements d'exécution JMF 2.0 lorsqu'ils sont disponibles. (Pour télécharger tous les fichiers associés à cet article au format zip, voir Ressources.)

001 // Commentez l'instruction de package suivante pour la compiler séparément. 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 met à jour la JMFApplet à partir de l'article d'avril 1997 012 * JavaWorld pour la conformité de l'API JMF 1.1. Veuillez 013 * consulter l'article sur:

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

016 * De plus, JMF11Applet a été retravaillé pour devenir 017 * utiliser le modèle d'événement Java 1.1 (et au-delà). Cette version 018 * a été développée et testée sur Java 2 019 * et l'implémentation JMF 1.1 tout-Java, mai 1999. 020 *

021 * Cette applet peut être déployée sur des serveurs Web publics 022 * à l'aide du fichier jmf-server.jar fourni dans le téléchargement JMF 1.1 023 * pour les serveurs Web. Cette archive JAR contient 024 * les classes d'exécution JMF entièrement Java nécessaires. JMF11Applet 025 * a été déployé de cette manière pour la colonne 026 * de juin 1999:

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 ** / 038039 classe publique JMF11Applet étend L'applet implémente ControllerListener {040 URL privée myURL = null; 041 joueur privé myPlayer = null; 042 Composant privé myVisual = null; 043 Composant privé myControls = null; 044 panneau privé visualPanel = null; 045 046 / ** 047 * Initialisez l'applet JMF11. Nous mettons en place l'interface et 048 * créons notre lecteur dans init (). 049 ** / 050 public void init () {051 super.init (); 052 053 // Spécifiez AWT Layout Manager. 054 setLayout (nouveau BorderLayout ());055 056 // Charger l'URL à partir de la page Web JMF11Applet est incorporé dans. 057 String asset = getParameter ("ASSET"); 058 059 // Vérifiez l'URL et créez un objet URL pour la contenir. 060 if (asset.equals ("")) {061 // nous n'avons pas saisi d'actif dans l'applet. 062} else {063 essayez {064 myURL = new URL (getDocumentBase (), asset); 065} catch (MalformedURLException e) {066 // Nous avons saisi un élément incomplet ou créé une URL incorrecte. 067 // Une applet plus robuste devrait gérer cela avec élégance. 068} 069} 070 essayez {071 // Voici un peu intéressant. Manager est utilisé pour 072 // créer le lecteur réel pour cette URL. Nous 073 // ajoutons ensuite JMF11Applet en tant que ControllerListener pour myPlayer. 074 // Cela nous permet de répondre à RealizeCompleteEvents. 075 myPlayer = Manager.createPlayer (myURL); 076 myPlayer.addControllerListener (ceci);077} catch (IOException e) {078 // Rencontré un problème avec les E / S; sortie. 079 System.out.println ("Problème d'E / S lors de la tentative de création du lecteur ... sortie"); 080 System.exit (1); 081} catch (NoPlayerException e) {082 // Impossible de renvoyer un lecteur utilisable; sortie. 083 System.out.println ("Aucun lecteur utilisable renvoyé ... sortie"); 084 System.exit (1); 085} 086} 087 088 / ** 089 * Remplacez la méthode de démarrage par défaut de l'applet pour appeler le 090 * réalise () du joueur. Cela fera d'abord la réalisation, qui à son tour 091 * déclenche les derniers bits de la construction de l'interface graphique dans la méthode controllerUpdate () 092 *. Nous ne démarrons pas automatiquement la lecture: l'utilisateur a besoin de 093 * pour cliquer sur le bouton «play» dans notre applet pour commencer à lire l'échantillon multimédia 094 *. 095 ** / 096 public void start () {097 myPlayer.realize ();098} 099 100 101 / ** 102 * Remplacez la méthode d'arrêt par défaut de l'applet pour appeler myPlayer.stop () 103 * et myPlayer.deallocate () afin que nous libérons correctement les ressources 104 * si quelqu'un quitte cette page dans son navigateur. 105 ** / 106 public void stop () {107 myPlayer.stop (); 108 monPlayer.deallocate (); 109} 110 111 / ** 112 * Puisque nous devons savoir quand la réalisation est terminée, nous utilisons 113 * controllerUpdate () pour gérer RealizeCompleteEvents. 114 * Lorsque nous recevons le RealizeCompleteEvent, nous mettons en page 115 * et affichons le composant vidéo et les commandes dans notre 116 * applet GUI. 117 ** / 118 public void controllerUpdate (événement ControllerEvent) {119 if (instance d'événement de RealizeCompleteEvent) {120 //System.out.println("Received RCE ... "); 121 // Maintenant que nous avons un joueur Réalisé,nous pouvons obtenir les 122 // VisualComponent et ControlPanelComponent et les emballer 123 // dans notre applet. 124 myVisual = monPlayer.getVisualComponent (); 125 if (myVisual! = Null) {126 // Afin de m'assurer que le VisualComponent 127 // n'est pas redimensionné par BorderLayout, je l'emboîte 128 // dans visualPanel en utilisant FlowLayout. 129 visualPanel = nouveau panneau (); 130 visualPanel.setLayout (nouveau FlowLayout ()); 131 visualPanel.add (myVisual); 132 add (visualPanel, BorderLayout.CENTER); 133 //System.out.println("Ajout de VisualComponent ... "); 134} 135 myControls = myPlayer.getControlPanelComponent (); 136 if (myControls! = Null) {137 add (myControls, BorderLayout.SOUTH); 138 //System.out.println("Contrôles ajoutés ... "); 139} 140 // invalider (); 141 valider (); 142} 143 // Sinon, nous consommons simplement l'événement. 144} 145}124 myVisual = monPlayer.getVisualComponent (); 125 if (myVisual! = Null) {126 // Afin de m'assurer que le VisualComponent 127 // n'est pas redimensionné par BorderLayout, je l'emboîte 128 // dans visualPanel en utilisant FlowLayout. 129 visualPanel = nouveau panneau (); 130 visualPanel.setLayout (nouveau FlowLayout ()); 131 visualPanel.add (myVisual); 132 add (visualPanel, BorderLayout.CENTER); 133 //System.out.println("Ajout de VisualComponent ... "); 134} 135 myControls = myPlayer.getControlPanelComponent (); 136 if (myControls! = Null) {137 add (myControls, BorderLayout.SOUTH); 138 //System.out.println("Contrôles ajoutés ... "); 139} 140 // invalider (); 141 valider (); 142} 143 // Sinon, nous consommons simplement l'événement. 144} 145}124 myVisual = monPlayer.getVisualComponent (); 125 if (myVisual! = Null) {126 // Afin de m'assurer que le VisualComponent 127 // n'est pas redimensionné par BorderLayout, je l'emboîte 128 // dans visualPanel en utilisant FlowLayout. 129 visualPanel = nouveau panneau (); 130 visualPanel.setLayout (nouveau FlowLayout ()); 131 visualPanel.add (myVisual); 132 add (visualPanel, BorderLayout.CENTER); 133 //System.out.println("Ajout de VisualComponent ... "); 134} 135 myControls = myPlayer.getControlPanelComponent (); 136 if (myControls! = Null) {137 add (myControls, BorderLayout.SOUTH); 138 //System.out.println("Contrôles ajoutés ... "); 139} 140 // invalider (); 141 valider (); 142} 143 // Sinon, nous consommons simplement l'événement. 144} 145}= null) {126 // Afin de m'assurer que le VisualComponent 127 // n'est pas redimensionné par BorderLayout, je l'emboîte 128 // dans visualPanel en utilisant FlowLayout. 129 visualPanel = nouveau panneau (); 130 visualPanel.setLayout (nouveau FlowLayout ()); 131 visualPanel.add (myVisual); 132 add (visualPanel, BorderLayout.CENTER); 133 //System.out.println("Ajout de VisualComponent ... "); 134} 135 myControls = myPlayer.getControlPanelComponent (); 136 if (myControls! = Null) {137 add (myControls, BorderLayout.SOUTH); 138 //System.out.println("Contrôles ajoutés ... "); 139} 140 // invalider (); 141 valider (); 142} 143 // Sinon, nous consommons simplement l'événement. 144} 145}= null) {126 // Afin de m'assurer que le VisualComponent 127 // n'est pas redimensionné par BorderLayout, je l'emboîte 128 // dans visualPanel en utilisant FlowLayout. 129 visualPanel = nouveau panneau (); 130 visualPanel.setLayout (nouveau FlowLayout ()); 131 visualPanel.add (myVisual); 132 add (visualPanel, BorderLayout.CENTER); 133 //System.out.println("Ajout de VisualComponent ... "); 134} 135 myControls = myPlayer.getControlPanelComponent (); 136 if (myControls! = Null) {137 add (myControls, BorderLayout.SOUTH); 138 //System.out.println("Contrôles ajoutés ... "); 139} 140 // invalider (); 141 valider (); 142} 143 // Sinon, nous consommons simplement l'événement. 144} 145}133 //System.out.println("Ajout de VisualComponent ... "); 134} 135 myControls = myPlayer.getControlPanelComponent (); 136 if (myControls! = Null) {137 add (myControls, BorderLayout.SOUTH); 138 //System.out.println("Contrôles ajoutés ... "); 139} 140 // invalider (); 141 valider (); 142} 143 // Sinon, nous consommons simplement l'événement. 144} 145}133 //System.out.println("Ajout de VisualComponent ... "); 134} 135 myControls = myPlayer.getControlPanelComponent (); 136 if (myControls! = Null) {137 add (myControls, BorderLayout.SOUTH); 138 //System.out.println("Contrôles ajoutés ... "); 139} 140 // invalider (); 141 valider (); 142} 143 // Sinon, nous consommons simplement l'événement. 144} 145}

J'ai inclus un simple exemple de document HTML, example.html (que vous pouvez essayer dans votre navigateur dès maintenant en cliquant ici), pour vous montrer comment intégrer l'applet dans vos propres pages Web. Changez simplement le fichier multimédia dans la ASSETbalise et c'est parti!

Pour cet exemple, j'ai utilisé le téléchargement JMF 1.1 pour serveurs Web (documenté sur le site Web JMF) pour permettre JMF11Appletle téléchargement automatique d' jmf-server.jarune archive de code contenant les classes d'exécution JMF nécessaires. Cela permet à l'applet de s'exécuter dans n'importe quel navigateur compatible Java 1.1, sans logiciel à installer par l'utilisateur final. (Notez que la version JMF pour serveurs Web comprend également un outil de personnalisation,, JMFCustomizerqui vous permettra potentiellement de supprimer encore plus de classes inutiles du fichier JAR JMF. Cet outil ne fonctionne pas actuellement sous Java 2, car il utilise un nom du package pour Swing.)

Dans l'exemple particulier intégré dans example.html , nous chargeons un fichier WAV (welcome.wav), vérifions les composants de contrôle appropriés à mettre à disposition (pas de composant vidéo, puisqu'il s'agit d'un fichier multimédia uniquement sonore), et lisons le multimédia fichier. Notez que le fichier WAV (600 Ko) et les classes JMF (570 Ko) peuvent nécessiter plusieurs minutes pour se télécharger sur votre machine en fonction de votre vitesse de connexion.

Après avoir analysé la page d'exemple, les navigateurs compatibles Java 1.1 doivent charger l'applet et les classes JMF de prise en charge automatiquement à partir du serveur Web JavaWorld . Une fois l'applet chargée et en cours d'exécution, vous pouvez appuyer sur le bouton Lecture pour commencer la lecture du fichier son WAV. Essayez de repositionner la lecture à l'aide de la barre de défilement et de mettre en pause et redémarrer la lecture à l'aide du bouton Pause / Lecture.

L'implémentation de la plate-forme Java JMF 1.1 utilise des widgets entièrement Java pour ses contrôles, de sorte que les contrôles ont la même apparence d'un navigateur à l'autre et d'une plate-forme à l'autre. Remarquez à quoi ressemble l'applet s'exécutant dans la JVM de Netscape Communicator sur Solaris 7 et la JVM de Microsoft dans Internet Explorer sur Win32.

Le bouton étiqueté i fournit des informations sur le fichier multimédia lu dans l'applet JMF. Cliquez sur ce lien d'information pour obtenir des détails sur le fichier WAV exécuté dans cette page Web.