martes, diciembre 05, 2006

Distribuir el JMF con nuestras aplicaciones

Programar con las librerías del JMF es un auténtico tormento, hacer que funcionen es más difícil todavía, y realizar el despliegue de estas aplicaciones a gran escala es casi imposible. Normalmente intento evitar usar el JMF, pero muchas veces no queda más remedio. En estos casos intento usar la versión multiplataforma de estas librerías, ya que simplemente es necesario incluir los jars en el CLASSPATH para que funcione.

El número de formatos soportados por la versión multiplataforma del JMF es patético, si bien es cierto que el soporte de las versiones para las Windows y Linux no es mucho mejor, al menos es "algo" mejor. Por esto a veces no queda más remedio que usar este tipo de versiones. Tan sólo queda esperar que el panorama mejore ahora con el cambio de licencia del software de Java.

Si usas el JMF en una aplicación la solución más evidente es indicar al usuario que tiene que instalar el JMF. En el caso de Linux la instalación del JMF en Linux no está al alcance al usuario medio. En el caso de Windows la instalación es mucho más sencilla, pero si el usuario tiene activadas las actualizaciones automáticas de java, cada vez que el usuario actualice su versión java, el JMF dejará de funcionar y tendrá que instalarlo de nuevo. Esta situación normalmente es inadmisible para cualquier persona/empresa que distribuya aplicaciones en Java.

Por último, si te gusta (como a mi) distribuir la aplicación con su propio JRE (para evitar tener que explicarle al usuario que es eso de JAVA), también es deseable integrar el JMF para que el usuario no tenga que instalar ningún paquete adicional.

Integrar la versión multiplataforma del JMF en nuestras aplicaciones no tiene ninguna historia, es una librería empaquetada en un jar como cualquier otra libería en java. El caso de las versiones específicas para cada una de las plataformas es distinto. A continuación voy a comentar mis experiencias a la hora de distribuir el JMF con mis aplicaciones.

Distribuir JMF 2.1.1e (Solaris/Linux Performance Pack) en Linux

Para poder distribuir el JMF con nuestras aplicaciones en Linux, primero tenemos que instalarlo en una máquina con Linux (una opción es usar VMware, si no tenemos ninguna máquina con Linux). Una vez instalado deberemos copiar todo el contenido del directorio lib y el fichero readme.html a un subdirectorio de nuestra aplicación que podemos denominar jmf_linux. El fichero readme.html hay que distribuirlo para cumplir con la licencia de distribución del JMF.

En el fichero de arranque de nuestra aplicación debemos establecer una serie de variables de entorno para que nuestra aplicación reconozca el JMF (todas estas sentencias deberían estar en el script de arranque de la aplicación).

export JMF_HOME="${INSTALL_PATH}/jmf_linux"
export CLASSPATH="${JMF_HOME}/jmf.jar:${JMF_HOME}/mediaplayer.jar:${CLASSPATH}"
export LD_LIBRARY_PATH="${JMF_HOME}:${LD_LIBRARY_PATH}"

Además de estas variables debería estar establecida previamente la variable de entorno $INSTALL_PATH, indicando el directorio de instalación. Posteriormente en el mismo script ejecutaremos nuestra aplicación indicando el classpath correcto, por ejemplo:

java -cp $CLASSPATH:lib/app.jar Aplicacion

Distribuir JMF 2.1.1e (Windows Performance Pack) en Windows
La distribución del JMF en Windows es bastante más complicada que en Linux, ya que en Windows no hay un método sencillo de indicar en donde se encuentran las librerías nativas (por defecto intenta buscarlas en C:\Windows\system32, que es donde las pone el instalador el JMF para Windows). En primer lugar debemos instalar el JMF en un ordenador con Windows, una vez instalado localizaremos el directorio de instalación (normalmente C:\Archivos de Programa\JMF2.1.1e) y copiaremos todos los contenidos del subdirectorio lib y el fichero readme.html en un subdirectorio de nuestra aplicación que llamaremos jmf_windows.

A partir de aquí empieza más complicado, ya que primero deberemos localizar las dlls necesarias para el JMF en el directorio de librerías del sistema (normalmente C:\Windows\system32) y copiar esas dll al directorio raiz de nuestra aplicación. Las dlls que necesitamos son las siguientes: jmacm.dll, jmam.dll, jmcvid.dll, jmdaud.dll, jmdaudc.dll, jmddraw.dll, jmfjawt.dll, jmg723.dll, jmgdi.dll, jmgsm.dll, jmh261.dll, jmh263enc.dll, jmjpeg.dll, jmmci.dll, jmmpa.dll, jmmpegv.dll, jmutil.dll, jmvcm.dll, jmvfw.dll, jmvh263.dll, jsound.dll

La razón por la que debemos copiarlas al directorio raíz de nuestra aplicación es que Windows por defecto también busca las librerías nativas en el directorio de ejecución del programa. Hay que tener cuidado con este detalle, ya que debemos asegurarnos que el directorio de ejecución es siempre ese, incluso cuando se ejecuta desde accesos directos y similares.

Una vez creado el directorio jmf_windows y copiadas las dlls al directorio raiz de nuestra aplicación podremos arrancar nuestra aplicación a través de un fichero .bat, por ejemplo:

java -cp .;lib\app.jar;jmf_windows\jmf.jar;jmf_windows\sound.jar Aplicacion

Crear un instalador multiplataforma

La mejor opción para crear un instalador multiplataforma para aplicaciones en Java es IzPack, este instalador proporciona muchas opciones que podemos consultar en su documentación, pero la que más nos interesa es la posibilidad de indicar paquetes diferentes para diferentes plataformas (en nuestro caso Windows y Linux). Podemos meter en un paquete el núcleo de nuestra aplicación, y en dos paquetes diferentes los dos JMFs, uno para Linux y otro para Windows.

Así en el fichero xml en el que definimos la generación del instalador indicaremos dos paquetes similares a los siguientes:

<pack name="Java Media Framework" required="yes">

<os family="unix" />

<description>Java Media Framework</description>


<fileset dir="jmf_linux" targetdir="$INSTALL_PATH/jmf_linux" />

<file src="aplicacion.sh" targetdir="$INSTALL_PATH" os="unix" />

<executable os="unix" keep="true" failure="warn" stage="never"

targetfile="$INSTALL_PATH/aplicacion.sh" />

</pack>


<pack name="Java Media Framework" required="yes">


<os family="windows" />


<description>Java Media Framework</description>


<fileset dir="jmf_windows" targetdir="$INSTALL_PATH/jmf_windows" />


<fileset dir="jmf_windows_dll" targetdir="$INSTALL_PATH" />


<file src="aplicacion.bat" targetdir="$INSTALL_PATH" os="windows" />


</pack>



De esta forma podremos estar seguros que en cada plataforma estará disponible el JMF apropiado.

Problemas comunes del JMF en Linux
Las aplicaciones el JMF no funcionan en las últimas distribuciones de Linux, ya que con el Toolkit por defecto de java (sun.awt.X11.XTookit) en Linux no funcionan las aplicaciones del JMF. Por esto al ejecutar las aplicaciones jmfregistry y jmfstudio es necesario editar los ficheros y añadir a la línea de ejecución de la aplicación el Toolkit adecuado, por ejemplo en la última línea del jmfregistry:

exec java -Dawt.toolkit=sun.awt.motif.MToolkit JMFRegistry

Para depurar la carga de librerías nativas en Linux disponemos de múltiples métodos, uno de ellos es localizar el pid de nuestra aplicación y revisar el fichero /proc/num_pid/maps para ver si se ha cargado la librería necesaria. Otra opción es establecer la variable de entorno LD_DEBUG y obtendremos información sobre la carga de librerías dinámicas en la salida estándar del programa:

export LD_DEBUG=xxx

Para ver los posibles valores que puede tomar LD_DEBUG podemos revisar la página del manual con "man ld.so". En la misma página del manual se puede ver que con la variable de entorno LD_DEBUG_OUTPUT podemos indicarle un fichero en el que volcar esta información.

También podemos obtener información muy valiosa del log del jmf. Para activar la generación de este fichero de log e indicar el directorio en el que queremos que lo escriba (cuidado con tener permiso de escritura en ese directorio), tenemos que ejecutar la aplicación jmfregistry.

Además de la carga de librerías nativas en Linux, hay otra serie de errores difíciles de depurar en Linux. A menudo tenemos aplicaciones que hacen uso intensivo de Threads y nos funcionan en Windows y en Linux nos encontramos con un desagradable deadlock. Java proporciona un sistema para poder depurar este tipo de errores, ya que si enviamos la señal nº 3 al proceso este mostrará en la salida estándar información sobre los threads y posibles deadlocks. Si nuestra aplicación tiene el pid nº 101 (podemos localizar el pid de la aplicación con el comando ps), podemos hacerlo así:

kill -3 101

Me imagino que muchos de vosotros habreis tenido problemas en la distribución de aplicaciones multiplataforma en Java, me gustaría escuchar vuestras experiencias al respecto a través de comentarios.

Edición: Hay que tener la precaución de poner el jmf.properties con los codecs que necesitamos en el directorio en el que se encuentre el jmf.jar.

Del.icio.us Meneame

12 Comments:

Anonymous Anónimo dijo...

Has probado el instalador multiplataforma BitRock ? Es gratis para FLOSS

abril 07, 2007 1:28 a. m.  
Blogger eumesmo dijo...

No conocía este producto, pero le eché un vistazo al manual y tiene buena pinta.

De todas formas creo que seguiré usando IzPack, ya que su licencia es mucho menos restrictiva y a pesar de no tener un entorno gráfico para crear los instaladores es un instalador realmente potente. Por ahora no he encontrado ninguna carencia importante en IzPack, y en los momentos que necesité alguna funcionalidad que no estaba disponible ... simplemente modifiqué el código fuente o añadí un panel hecho a medida.

Muchas gracias por el enlace al instalador, queda anotado en los bookmarks.

abril 09, 2007 9:31 a. m.  
Anonymous Anónimo dijo...

Interesante artículo, me ha gustado.
Estoy intentando hacer funcionar el JMF en Ubuntu 7.04, pero no me reproduce vídeos mpeg2, se ve una pantalla verde con cuadritos distorsionados y en consola me aparece 'mpx bad data'. Ni idea qué puede ocurrir, y así he llegado a tu página, buscando como loco cómo solucionar esto.
Un saludo.

octubre 04, 2007 10:02 a. m.  
Blogger eumesmo dijo...

Si te funciona el JFM con otros forrmatos, lo más probable es que el JMF no sea capaz de reproducirlo. Los codecs del JMF están plagados de bugs, te anconsejo que pruebes con FOBS que es un wrapper para ffmpeg que añade una serie de codecs al JMF que suelen ser bastante mejores que los que vienen con el JMF por defecto.

Otra opción es que pruebes el proyecto gstreamer-java que aunque está todabía en fase de pruebas ya funciona bastante bien.

Un saludo.

octubre 04, 2007 11:43 a. m.  
Anonymous Anónimo dijo...

Muchas gracias por responder :)
Me bajé el FOBS, pero se me queda bloqueando, no llega a reproducir nada.
En este foro detallo más el problema.
No se qué me puede faltar, porque según todos los documentos debo tenerlo todo para poder reproducir.

Gracias por tu tiempo. Un saludo.

octubre 04, 2007 2:59 p. m.  
Blogger eumesmo dijo...

No descartes que el problema sea simplemente que los codecs de sonido del JMF tienen un bug o que ese codec está mal soportado, por desgracia es algo bastante común. Lo que me parece raro es que con FOBS no se te solucione el problema . Antes de nada me aseguraría que está usando FOBS para la reproducción del audio, asegúrate de que lo tienes bien configurado.

En algunas Ubuntu he tenido problemas con la compatibilidad de ALSA con OSS. Asegúrate que tienes los módulos snd_mixer_oss y snd_pcm_oss cargados correctamente. Este fué un problema que tuve hace tiempo y he ayudaron en su momento a solucionarlo en el C.I.R.L., aquí tienes su respuesta.

octubre 04, 2007 6:39 p. m.  
Anonymous Anónimo dijo...

Lo tengo!!, ya funciona. Tenían bien las librerías, pero el jmf.properties tiene que estar en la misma ruta que la aplicación java, no en lib/ con el jmf.jar, ya que ahí no lo encontraba y por consiguiente no usaba el fobs4jmf.jar

Me di cuenta cuando llamaba a la aplicación con el parámetro -verbose:class, y vi que no aparecía fobs4jmf.jar por ningún lado.

Bueno, voy a probar lo del sonido que me comentaste, a ver si lo soluciono de una vez :)

Muchas gracias!!!
Un saludo.

octubre 10, 2007 10:55 a. m.  
Anonymous Anónimo dijo...

Hola estoy realizando una aplicacion que utiliza una camara web para tomar fotografias, con JMF, me funciona perfectamente en windows, pero cuando lo hago en ubunto no, me dice q no se puede inicializar la camara, porfa si tienen un codigo fuente o instrucciones de como se hace esto, se los agradeceria

mayo 27, 2009 4:54 p. m.  
Blogger Julian Osorio Amaya dijo...

Posible Solucion

Se debe crear el archivo .exe
se recomienda usar JSmooth o Jar2Wizard

al .jar de la aplicacion se deben agregar todas las clases de jmf

para mas informacion sobre este procedimiento pueden escribir un correo a mangelan03@gmail o julian.osorio@gmail

mayo 23, 2010 6:47 p. m.  
Anonymous Anónimo dijo...

pues tienes toda la razon, vaya multiplataforma el JMF.....

Yo al final tire por JavaSpimp3 (Javazoom) con Jlayer y tritonius, mucho mas sencillo y multiplataforma....con 3 jars funciona (al menos reproduccion basica de mp3).

supongo que JMF hara chino, pero vamos si tienes que instalar to la pesca.......

marzo 06, 2012 12:58 p. m.  
Blogger gggg dijo...

gran artículo muchacho :)

julio 09, 2012 2:40 p. m.  
Blogger gggg dijo...

Me gustaría añadir este artículo que te informa sobre los archivos necesarios para poder utilizar la cámara web desde Java. Únicamente con dos dll, un jar y un archivo properties es posible. JMF - Esquema de clases y archivos necesarios

julio 17, 2012 1:35 p. m.  

Publicar un comentario

<< Home