Progreso en las API de JMF y Java Media

Mi primer artículo de JavaWorld fue en Java Media Framework (JMF). A medida que las diversas API de medios han madurado, siento que las cosas han cerrado el círculo. Por lo tanto, dedicaré mi columna final de Programación de medios a una revisión de JMF y el estado general de todas las API de Java Media.

Ha habido algunos cambios notables en JMF y otras tecnologías Java Media, las empresas que desarrollan implementaciones de las mismas y su disponibilidad para los desarrolladores. Este artículo actualiza el material de artículos anteriores según corresponda.

Un recordatorio importante: Java Media Framework es una API específica para sincronizar transmisiones multimedia (archivos, transmisiones de red, etc.). Es una de las API de Java Media, que también incluyen Java 2D, Java 3D, Java Speech, etc. Me refiero a Java Media Framework como JMF, reservando el término Java Media para toda la colección de API multimedia.

Historia y conceptos básicos de JMF

De JMF 1.0, también conocido como Java Media Player API, escribí lo siguiente en abril de 1997 (ver Recursos):

La API de Java Media Player, una parte de Java Media Framework (JMF), permite a los programadores de Java incrustar fácilmente audio y video en applets y aplicaciones. Tanto la multimedia estática como la de transmisión son compatibles desde cualquier URL válida. Los reproductores JMF pueden ser controlados por otros reproductores, lo que permite la reproducción sincrónica de múltiples muestras de audio y video.

Esta información sigue siendo válida con las actualizaciones y adiciones de los últimos dos años. Sin embargo, JMF ha desarrollado nuevas capacidades y ha aumentado su alcance, especialmente con la próxima versión 2.0 de la API (prevista para la segunda mitad de 1999).

Jugadores de la industria de JMF

Primero, echemos un vistazo a los actores de la industria. Sun, Silicon Graphics (SGI) e Intel diseñaron y especificaron el JMF 1.0 original a mediados de 1998. Mientras tanto, desde la versión inicial de la API, tanto SGI como Intel se han retirado del proceso de especificación JMF. Durante un tiempo, hubo una gran preocupación en la comunidad de usuarios de JMF de que Sun fuera el único proveedor que respaldaba JMF. Esta situación era indeseable.

Afortunadamente, a finales de 1998 IBM intervino con interés en el JMF. Poco después de que IBM se uniera a Sun, se lanzó una implementación totalmente en Java de la API 1.0 (diciembre de 1998). Esta implementación, conocida como JMF 1.1 para plataformas Java, admite un subconjunto limitado pero significativo de los tipos de contenido y protocolo admitidos por las implementaciones de JMF 1.1 nativas de Win32 y Solaris (conocidas como paquetes de rendimiento). La disponibilidad de un JMF 1.1 totalmente Java fue un hito importante para JMF, ya que la tecnología estuvo disponible para cualquier tiempo de ejecución de Java 2 o compatible con Java 1.1. De hecho, la implementación de JMF 1.1 Java incluso está disponible en una versión orientada a la web con herramientas que permiten a los desarrolladores incluir solo las clases JMF relevantes en un archivo JAR para descargar con sus subprogramas JMF. Esto permite implementar subprogramas basados ​​en JMF en un servidor web para que los utilice cualquier navegador compatible con Java 1.1. Tanto Netscape como Microsoft admiten Java 1.1, y por lo tanto JMF 1.1 para Java, en sus versiones recientes de navegador de Navigator e Internet Explorer, respectivamente.

IBM está ayudando a Sun a codificar la API JMF 2.0, que incluirá una especificación y proporcionará una implementación de referencia de la próxima API JMF: Java Media Capture. Esperemos que IBM descubra cómo implementar posteriormente la funcionalidad JMF en algunos de sus productos de software basados ​​en Java orientados a los negocios, algo potencialmente bueno para la longevidad de la tecnología JMF.

¿Qué hay de nuevo en JMF 2.0 frente a 1.0?

La API JMF 1.0 especifica los componentes necesarios para manejar la reproducción de audio y video sincronizados. Consulte mi artículo anterior de JMF (ver Recursos) para obtener una revisión de las capacidades de JMF 1.0.

JMF 2.0 hace varias adiciones clave a la especificación:

  • Captura de audio y video
  • Transmisión de audio y video y, por lo tanto, la posibilidad de crear servidores de transmisión totalmente Java además de los clientes
  • Soporte de códec conectable dentro de los reproductores

Para obtener más información sobre JMF 2.0 y sus nuevas capacidades, consulte la Guía del programador de Java Media Framework (ver Recursos), actualmente disponible en la versión 0.5 de acceso anticipado.

Instalación de herramientas de desarrollo JMF y tiempo de ejecución

Tanto Silicon Graphics como Intel han eliminado versiones anteriores de JMF de sus respectivos sitios web. Sin embargo, puede descargar las últimas implementaciones de referencia (denominadas JMF 1.1, que cumplen con la especificación API 1.0) para las plataformas Win32, Solaris y Java desde el sitio de Sun (consulte Recursos).

Tenga en cuenta que la documentación de la versión totalmente Java menciona específicamente AIX, lo que indica que IBM ha estado probando este software en su tiempo de ejecución de AIX Java. Espero que las versiones futuras de JMF (2.0 y posteriores) admitan específicamente los entornos operativos de IBM, ya sea a través de una implementación de Java pura o implementaciones nativas específicas del sistema operativo.

Ejemplos de JMF actualizados

He actualizado el ejemplo compatible con JMF 1.0 beta de mi artículo anterior de JMF para ejecutarlo en entornos compatibles con JMF 1.0 API. Puede descargar el código de ejemplo y probarlo en implementaciones de JMF 1.1 utilizando sus propios archivos multimedia. El subprograma también debería ejecutarse en tiempos de ejecución JMF 2.0 cuando estén disponibles. (Para descargar todos los archivos asociados con este artículo en formato zip, consulte Recursos).

001 // Comente la siguiente declaración del paquete para compilar por separado. 002 // paquete com.javaworld.media.jmf; 003 004 importar java.applet. *; 005 importar java.awt. *; 006 importar java.net. *; 007 import java.io. *; 008 import javax.media. *; 009010 / ** 011 * JMF11Applet actualiza JMFApplet del artículo 012 * JavaWorld de abril de 1997 para el cumplimiento de la API de JMF 1.1. 013 * consulte el artículo en:

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

016 * Además, JMF11Applet se ha vuelto a trabajar para 017 * utilizar el modelo de eventos Java 1.1 (y posteriores). Esta versión 018 * ha sido desarrollada y probada en Java 2 019 * y la implementación JMF 1.1 totalmente Java, mayo de 1999. 020 *

021 * Este subprograma se puede implementar en servidores web públicos 022 * utilizando el archivo jmf-server.jar proporcionado en JMF 1.1 023 * para la descarga de servidores web. Este archivo JAR contiene 024 * las clases de tiempo de ejecución JMF totalmente Java necesarias. JMF11Applet 025 * se ha implementado de esta manera para la columna 026 * de junio de 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 clase pública JMF11Applet extiende Applet implementa ControllerListener {040 URL privada myURL = null; 041 jugador privado myPlayer = null; 042 componente privado myVisual = null; 043 componente privado myControls = null; 044 panel privado visualPanel = null; 045046 / ** 047 * Inicializar JMF11Applet. Diseñamos la interfaz y 048 * creamos nuestro reproductor en init (). 049 ** / 050 public void init () {051 super.init (); 052053 // Especifique AWT Layout Manager. 054 setLayout (nuevo BorderLayout ());055 056 // Cargar URL desde la página web en la que está incrustado JMF11Applet. 057 String asset = getParameter ("ASSET"); 058 059 // Verifique la URL y cree un objeto URL para contenerla. 060 if (asset.equals ("")) {061 // no hemos introducido un activo en el subprograma. 062} else {063 try {064 myURL = new URL (getDocumentBase (), asset); 065} catch (MalformedURLException e) {066 // Ingresamos un activo incompleto o creamos una URL incorrecta. 067 // Un applet más robusto debería manejar esto con elegancia. 068} 069} 070 try {071 // Aquí hay algo interesante. El administrador se utiliza para 072 // crear el reproductor real para esta URL. Luego 073 // agregamos JMF11Applet como ControllerListener para myPlayer. 074 // Esto nos permite responder a RealizeCompleteEvents. 075 myPlayer = Manager.createPlayer (myURL); 076 myPlayer.addControllerListener (esto);077} catch (IOException e) {078 // Encontré algún problema con E / S; salida. 079 System.out.println ("Problema de E / S al intentar crear un reproductor ... saliendo"); 080 System.exit (1); 081} catch (NoPlayerException e) {082 // No se puede devolver un reproductor utilizable; salida. 083 System.out.println ("No se devolvió ningún reproductor utilizable ... saliendo"); 084 System.exit (1); 085} 086} 087 088 / ** 089 * Anula el método de inicio del subprograma predeterminado para llamar al 090 * realizar () del jugador. Esto primero hará la realización, que a su vez 091 * activa los bits finales de la construcción de la GUI en el método controllerUpdate () 092 *. No iniciamos la reproducción automáticamente: el usuario necesita 093 * para hacer clic en el botón "reproducir" en nuestro subprograma para comenzar a reproducir la muestra multimedia 094 *. 095 ** / 096 public void start () {097 myPlayer.realize ();098} 099 100 101 / ** 102 * Anula el método de detención del subprograma predeterminado para llamar a myPlayer.stop () 103 * y myPlayer.deallocate () para que podamos liberar adecuadamente los recursos 104 * si alguien sale de esta página en su navegador. 105 ** / 106 public void stop () {107 myPlayer.stop (); 108 myPlayer.deallocate (); 109} 110 111 / ** 112 * Ya que debemos saber cuándo se completa la realización, usamos 113 * controllerUpdate () para manejar RealizeCompleteEvents. 114 * Cuando recibimos RealizeCompleteEvent, diseñamos 115 * y mostramos el componente de video y los controles en nuestra interfaz gráfica de usuario 116 *. 117 ** / 118 public void controllerUpdate (evento ControllerEvent) {119 if (instancia de evento de RealizeCompleteEvent) {120 //System.out.println("Received RCE ... "); 121 // Ahora que tenemos un jugador Realizado,podemos obtener 122 // VisualComponent y ControlPanelComponent y empaquetarlos 123 // en nuestro applet. 124 myVisual = myPlayer.getVisualComponent (); 125 if (myVisual! = Null) {126 // Para asegurar que el VisualComponent 127 // no sea redimensionado por BorderLayout, lo anido 128 // dentro de visualPanel usando FlowLayout. 129 visualPanel = nuevo Panel (); 130 visualPanel.setLayout (nuevo FlowLayout ()); 131 visualPanel.add (myVisual); 132 agregar (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("Controles añadidos ... "); 139} 140 // invalidar (); 141 validar (); 142} 143 // De lo contrario, simplemente consumimos el evento. 144} 145}124 myVisual = myPlayer.getVisualComponent (); 125 if (myVisual! = Null) {126 // Para asegurar que el VisualComponent 127 // no sea redimensionado por BorderLayout, lo anido 128 // dentro de visualPanel usando FlowLayout. 129 visualPanel = nuevo Panel (); 130 visualPanel.setLayout (nuevo FlowLayout ()); 131 visualPanel.add (myVisual); 132 agregar (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("Controles añadidos ... "); 139} 140 // invalidar (); 141 validar (); 142} 143 // De lo contrario, simplemente consumimos el evento. 144} 145}124 myVisual = myPlayer.getVisualComponent (); 125 if (myVisual! = Null) {126 // Para asegurar que el VisualComponent 127 // no sea redimensionado por BorderLayout, lo anido 128 // dentro de visualPanel usando FlowLayout. 129 visualPanel = nuevo Panel (); 130 visualPanel.setLayout (nuevo FlowLayout ()); 131 visualPanel.add (myVisual); 132 agregar (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("Controles añadidos ... "); 139} 140 // invalidar (); 141 validar (); 142} 143 // De lo contrario, simplemente consumimos el evento. 144} 145}= null) {126 // Para asegurar que el VisualComponent 127 // no cambie de tamaño por BorderLayout, lo anido 128 // dentro de visualPanel usando FlowLayout. 129 visualPanel = nuevo Panel (); 130 visualPanel.setLayout (nuevo FlowLayout ()); 131 visualPanel.add (myVisual); 132 agregar (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("Controles añadidos ... "); 139} 140 // invalidar (); 141 validar (); 142} 143 // De lo contrario, simplemente consumimos el evento. 144} 145}= null) {126 // Para asegurar que el VisualComponent 127 // no cambie de tamaño por BorderLayout, lo anido 128 // dentro de visualPanel usando FlowLayout. 129 visualPanel = nuevo Panel (); 130 visualPanel.setLayout (nuevo FlowLayout ()); 131 visualPanel.add (myVisual); 132 agregar (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("Controles añadidos ... "); 139} 140 // invalidar (); 141 validar (); 142} 143 // De lo contrario, simplemente consumimos el 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("Controles añadidos ... "); 139} 140 // invalidar (); 141 validar (); 142} 143 // De lo contrario, simplemente consumimos el 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("Controles añadidos ... "); 139} 140 // invalidar (); 141 validar (); 142} 143 // De lo contrario, simplemente consumimos el evento. 144} 145}

He incluido un documento HTML de ejemplo simple, example.html (que puede probar en su navegador ahora mismo haciendo clic aquí), para mostrarle cómo incrustar el subprograma en sus propias páginas web. ¡Simplemente cambie el archivo multimedia en la ASSETetiqueta y listo!

Para este ejemplo, utilicé la descarga de JMF 1.1 para servidores web (documentada en el sitio web de JMF) para permitir JMF11Appletla descarga automática de jmf-server.jarun archivo de código que contiene las clases de tiempo de ejecución de JMF necesarias. Esto permite que el subprograma se ejecute en cualquier navegador compatible con Java 1.1, sin software para que el usuario final lo instale. (Tenga en cuenta que la versión JMF para servidores web también incluye una herramienta de personalización JMFCustomizer, que potencialmente le permitirá eliminar aún más clases innecesarias del archivo JMF JAR. Sin embargo, esta herramienta no funciona actualmente en Java 2, ya que utiliza una nombre del paquete para Swing.)

En el ejemplo particular incrustado en example.html , cargamos un archivo WAV (welcome.wav), determinamos los componentes de control apropiados para que estén disponibles (ningún componente de video, ya que este es un archivo multimedia de solo sonido) y reproducimos el contenido multimedia archivo. Tenga en cuenta que el archivo WAV (600 KB) y las clases JMF (570 KB) pueden requerir varios minutos para descargarse en su máquina dependiendo de la velocidad de su conexión.

Después de analizar la página de ejemplo, los navegadores compatibles con Java 1.1 deben cargar el subprograma y las clases JMF compatibles automáticamente desde el servidor web JavaWorld . Una vez que el subprograma está cargado y en ejecución, puede presionar el botón Reproducir para comenzar la reproducción del archivo de sonido WAV. Intente reposicionar la reproducción usando la barra de desplazamiento y pausando y reiniciando la reproducción usando el botón Pausa / Reproducir.

La implementación de la plataforma Java JMF 1.1 utiliza widgets exclusivamente Java para sus controles, por lo que los controles tienen la misma apariencia de navegador a navegador y de plataforma a plataforma. Observe cómo se ve el subprograma ejecutándose dentro de la JVM de Netscape Communicator en Solaris 7 y la JVM de Microsoft en Internet Explorer en Win32.

El botón etiquetado i proporciona información sobre el archivo multimedia que se reproduce en el subprograma JMF. Haga clic en este enlace de información para obtener detalles sobre el archivo WAV que se ejecuta en esta página web.