Dr. Eric Jeltsch F. Programación en Java2 Cap12: Animación y más Capitulo 12 Animación, imagen y sonido. Una de las características más interesantes que se puede añadir a un applet o aplicación es la capacidad de reproducir archivos multimedia, como audio o video, aunque esto último no he logrado realizarlo en la práctica, sin embargo espero que este semestre si podamos realizarlo. JavaSoft desarrollo una API multimedia JMF que consiste en una API que reproduce y recibe archivos multimedia en una gama de formatos de audio y video. La clase Applet contiene 23 métodos que se utilizan para mostrar imagenes, reproducir archivos de audio, responder a eventos y obtener la información acerca del entorno(o contexto) de ejecución del applet. Los métodos getImage(), getAudioClip() se utilizan para recuperar un objeto Image o AudioClip que se identifica por un URL. Los métodos play() se utilizan para reproducir archivos de audio en los URL especificados. El JDK1.2 introduce el nuevo método newAudioClip(), que es un método estático que permite crear objetos AudioClip sin un contexto de applet, en versiones anteriores solo fué factible utilizar archivos .au(formato de archivo de audio para Sun), sin embargo, ahora es factible desde la versión 1.2 formatos, WAVE(Microsoft), AIFF(SiliconGraphics), AU(Sun), RMF, MIDI. Imagen Por otra parte, si bien la acción de incluir secuencias de animaciones en los programas Java puede parecer a simple vista un tanto complicado, pero de hecho es bastante sencillo. Las animaciones no son más que la visualización rápida de imagenes. Ahora para crear una animación, deberá producir la secuencia de los objetos que van a aparecer. La clase Applet proporciona un método llamado getImage() para cargar una imagen dentro de un objeto Image. Hay 2 formas sencillas de usarlo: como argumento sencillo(tipo URL)recuperando la imagen desde este URL, cuya forma sería URL u = new URL("http://papaya.cl/linda/vera.gif") y la otra forma es más flexible la cual tiene 2 argumentos, el URL base y una cadena que representa la trayectoria relativa o el nombre de archivo de la imagen real. Por ejemplo, Image img = getImage(getDocumentBase(), "vera.gif"); Image img = getImage(getDocumentBase(), "images/vera.gif"); donde una variante es getCodeBase(). La animación más sencilla se visualiza así: import javax.swing.*; // Una simple animacion con applet public class AnimacionApplet extends JApplet { public void init() { ImageIcon icon = new ImageIcon("imagen/rodar.gif"); // se incorpora gif animado. getContentPane().add(new JLabel(icon)); } } _________________________________________________________________________ Area de Computación, Universidad de La Serena 1 Dr. Eric Jeltsch F. Programación en Java2 Cap12: Animación y más Veamos un ejemplo, el cual muestra una foto, pero redimensiona su tamaño. import java.awt.Graphics; import java.awt.Image; import java.applet.*; public class Erico extends Applet { Image foto; public void init() { foto = getImage(getCodeBase(),"Eric.gif"); } public void paint(Graphics g) { int iWidth = foto.getWidth(this); int iHeight = foto.getHeight(this); int xPos = 10; // 25% g.drawImage(foto, xPos, 10, iWidth / 4, iHeight / 4, this); // 100% xPos += (iWidth / 4) + 10; g.drawImage(foto, xPos, 10, this); } } _________________________________________________________________________ Area de Computación, Universidad de La Serena 2 Dr. Eric Jeltsch F. Programación en Java2 Cap12: Animación y más como una aplicación de lo anterior, el siguiente applet despliega la imagen en su tamaño original y luego superpone el doble de la original. import java.applet.Applet; import java.awt.*; import javax.swing.*; public class EricoImagen extends JApplet { private Image logo1; //Image de java.awt private ImageIcon logo2; //ImageIcon de javax.swing // invita la imagen para cuando el applet es cargado public void init() { logo1 = getImage( getDocumentBase(), "eric.gif" ); logo2 = new ImageIcon( "eric.gif" ); } // display la imagen public void paint( Graphics g ) { /* draw la imagen original, con 4 parametros, el primero es la imagen, el 2 y 3 parametro son las x e y coordenadas en donde la imagen será desplegada en el applet(la 0,0 corresponde izq superior izq), this para indicar o referirnos al applet*/ g.drawImage( logo1, 0, 0, this ); /* draw la imagen agrandandola, según las medidas del applet, el 4 y 5 argumento especifica el ancho y la altura de la imagen que se propone despegar*/ _________________________________________________________________________ Area de Computación, Universidad de La Serena 3 Dr. Eric Jeltsch F. Programación en Java2 Cap12: Animación y más g.drawImage( logo1, 0, 120, getWidth(), getHeight() - 120, this ); /* despliega la imagen usando el método paintIcon , el que necesita 4 parametros, una referencia a la Component sobre la cual la imagen será desplegada, una referencia al objeto Graphics, y las coordenadas x e y.*/ logo2.paintIcon( this, g, 180, 0 ); } } En general, respecto a la inclusión de una secuencia de animaciones en los programas de Java puede parecer a simple vista complicado, sin embargo no es tal. Las animaciones en lo conceptual no son nada más que la visualización rápida de imágenes, de manera que basta con generar una secuencia de los objetos que van a aparecer para luego escribir un programa en Java, el que mostrará esa secuencia en un nivel de visualización determinado. Para entender mejor los fundamentos de las animaciones, se puede desarrollar una animación sencilla pero basada en caracteres. La animación es un proceso que requiere los siguientes pasos: Dibujar “algo” mediante texto, objeto o archivos de imagen, e indicar al sistema de manejo de ventanas que despliege lo que Ud. ha dibujado. Para ver como trabajan las animaciones se invocan una serie de clases y métodos, muchos de ellos ya conocidos, como por ejemplo, paint(), repaint(), start(), stop(), sin embargo la novedad radica en los procesos que intervienen. En particular un subproceso es parte de un programa que se configura para ejecutarlo en sus propias condiciones mientras el resto del programa hace otra cosa. A esto también se le llama multitarea debido a que el programa puede manejar más de una tarea simultáneamente. En éste caso en las animaciones los subprocesos son los más recurrentes, pues aparte de tomar mucho tiempo de procesamiento estos deben estar corriendo continuamente. La ventaja de estos subprocesos es que mientras ellos se ejecutan, Ud deja libre al resto del programa para manejar otras cosas. Esta acción son las llamadas Hilos y Procesos, las que están descritas en java.lang que admiten multihilos, también abordan la clase Process, que se usa para _________________________________________________________________________ Area de Computación, Universidad de La Serena 4 Dr. Eric Jeltsch F. Programación en Java2 Cap12: Animación y más manejar procesos que se ejecutan por medio de los métodos System.exec(). Subprocesos en Applet son factibles de realizar al menos de 5 formas: Modificar la declaración de clase agregando el texto implements Runnable. Crear un objeto Thread que contenga al subproceso. Sobreponer el método start() del applet para crear el subproceso e iniciar su ejecución. Sobreponer el método stop() para asignar null al proceso en ejecución. Crear un método run() que contenga las instrucciones que hagan que el applet corra continuamente. Runnable es un tipo especial de clase llamada interfaz, recordar que esto significa que ella es una forma de heredar métodos que de otra manera no podrían ser heredados de sus superclases. Runnable proporciona una definición para el método run(), el cual es llamado para iniciar un subproceso. La interfaz Runnable la implementa la clase Thread y otras que admiten ejecución de hilos. La clase Thread es parte del paquete estandar java.lang, y se usa para construir y acceder a hilos individuales de ejecución que se ejecutan como parte de un programa multihilo, en general no necesita la palabra import. Iniciar la creación de un Thread es por ejemplo la declaración Thread correr; este objeto puede ser creado en el método del applet start(), en donde la variable correr tendrá el valor null hasta que el objeto sea creado realmente. Un lugar ideal es por ejemplo, public void start() { If (correr == null) { correr = new Thread (this); correr.start();//ejecución subproceso } } Este método es el corazón del applet con subprocesos public void run() { //lo que hace realmente el applet } que se utilizan para conducir una secuencia animada, configurándolo con todo lo necesario para los dibujos y cambiar cosas entre cada cuadro. La forma de detener los subprocesos es establecer su objeto a null, ahora esto no detendrá al subproceso, pero Ud. puede diseñar el método run() de tal modo que se mantenga en ejecución solo mientras su objeto Thread no sea igual a null. En resumen los ingredientes para tener un applet con subprocesos es agregar implements Runnable, crear un objeto Thread asociado con el applet y usar los métodos start(), stop() y run(). Por ejemplo, import java.awt.Graphics; import java.awt.Font; import java.util.Date; _________________________________________________________________________ Area de Computación, Universidad de La Serena 5 Dr. Eric Jeltsch F. Programación en Java2 Cap12: Animación y más public class RelojDigital extends java.applet.Applet implements Runnable { Font miFont = new Font("TimesRoman",Font.BOLD,24); Date miFecha; Thread correr; //inician un proceso public void start() { if (correr == null) { correr = new Thread(this); correr.start(); } } //detienen un proceso public void stop() { if (correr != null) { correr = null; } } /*la mayor parte del trabajo del applet esta en run(), dentro de este método es donde realmente se lleva a cabo la animación.*/ public void run() { Thread miHilo = Thread.currentThread(); while (correr == miHilo) { /* devolvera un valor de verdad true, hasta que el objeto correr se configure null(lo que ocurrira en el método stop() del applet),así se ha construído una animación sencilla. Una de las primeras acciones dentro del ciclo while es la instrucción repaint()*/ repaint(); /*hacen una pausa de 1000 milisegundos(1 segundo), en donde el método sleep de la clase Thread hace que el applet realice la pausa, de manera que sleep controla la ocurrencia exacta de la animación, try es para manejar eventuales errores que puedan ocurrir*/ try { Thread.sleep(1000); } catch (InterruptedException e) { } } } public void paint(Graphics g) { miFecha = new Date(); g.setFont(miFont); g.drawString("" + miFecha.toString(), 10, 50); } } _________________________________________________________________________ Area de Computación, Universidad de La Serena 6 Dr. Eric Jeltsch F. Programación en Java2 Cap12: Animación y más como se han dado cuenta, ya tenemos una primera animación, sencilla pero animación. Muchas animaciones mustran su secuencia de imágenes en un modo de ciclo. El parametro principal de una animación es, junto al tipo y calidad de las imágenes que aparecen, la cantidad de unidades de imagen por segundo que muestra, cuanto más imágenes por segundo aparezcan, más nítida parecerá la animación. Para entender mejor los fundamentos veamos el siguiente ejemplo, que genera una cadena de arteriscos para dar una apariencia de movimiento. Este programa contiene los elementos básicos que debe tener una animación más general, con más ingredientes, tomando en consideración que Ud. ya han visto archivos y menus al final del curso anterior, o visto los capítulos 6 y 7 del tutorial en Java2. Se declara Thread anima; int frameDelay = 100; y el array de frames, frames[], que se utiliza para implementar la visualización de la animación, así como las declaraciones de variables int numFrames = frames.length; int actualFrame = 0; long ultimoDisplay = 0;//la duración de una unidad de imagen. La configuración de este programa es bastante estandar, en donde run() implementa el bucle de la animación, comprobando la hora en curso del sistema y la hora de visualización de la última imagen para ver si es el momento de mostrar una nueva unidad de imagen, utilizando para ello el método currentTimeMillis() de la clase System. Para cuando sea hora de mostrar otra imagen run() invoca a repaint() y se pone a “dormir” con frameDelay, actualiza actualFrame %= numFrames; con una aritmética modular y cambia la hora de ultimoDisplay. import java.awt.*; import java.awt.event.*; public class Anima_Simple extends Frame implements Runnable { Thread anima; int frameDelay = 100; String frames[]= {"*","**","***","****","*****","****","***","**","*"}; int numFrames = frames.length; int actualFrame = 0; long ultimoDisplay = 0; int winWidth = 300; int winHeight = 300; public static void main(String args[]) { _________________________________________________________________________ Area de Computación, Universidad de La Serena 7 Dr. Eric Jeltsch F. Programación en Java2 Cap12: Animación y más Anima_Simple app = new Anima_Simple(); } public Anima_Simple() { super("Animacion Simple"); setup(); setSize(winWidth,winHeight); addWindowListener(new WindowEventTrato()); show(); anima = new Thread(this); anima.start(); } void setup() { setupMenuBar(); setFont(new Font("default",Font.BOLD,18)); } void setupMenuBar() { MenuBar menuBar = new MenuBar(); Menu fileMenu = new Menu("File"); MenuItem fileExit = new MenuItem("Exit"); fileExit.addActionListener(new MenuItemTrato()); fileMenu.add(fileExit); menuBar.add(fileMenu); setMenuBar(menuBar); } public void paint(Graphics g) { g.drawString(frames[actualFrame],60,60); } public void run() { do { long tiempo = System.currentTimeMillis(); if(tiempo - ultimoDisplay > frameDelay) { repaint(); try { Thread.sleep(frameDelay); }catch(InterruptedException ex){ } ++actualFrame; actualFrame %= numFrames; ultimoDisplay = tiempo; } } while (true); } class MenuItemTrato implements ActionListener, ItemListener { public void actionPerformed(ActionEvent ev){ String s=ev.getActionCommand(); if(s=="Exit"){ System.exit(0); } } public void itemStateChanged(ItemEvent e){ } _________________________________________________________________________ Area de Computación, Universidad de La Serena 8 Dr. Eric Jeltsch F. Programación en Java2 Cap12: Animación y más } class WindowEventTrato extends WindowAdapter { public void windowClosing(WindowEvent e){ System.exit(0); } } } Como otras aplicaciones de animaciones vea los códigos de los directorios anima01, anima02 y anima03. Ahora, si Ud. se ha dado cuenta la animación gráfica es cuestión de incorporar en el programa anterior las figuras que se necesiten para animarlas. En esta ocasión he considerado una gráfica muy elemental, pero para los fines es apropiada, las diferencias sustanciales que Ud. notará están relacionadas con: El array frames[], que se ha cambiado de un array de String a uno de objetos Image, y el método setup() que se ha actualizado para crear un objeto Toolkit y usarlo para cargar las imágenes stickman. Esto es todo para lograr una animación de gráficos. Vea el archivo Anima_Graf. para comprobarlo. Bueno después de la primera experiencia no todo es una maravilla, si Ud. notó durante la ejecución del applet Anima_Graf.java se generaba un parpadeo, esto esta asociada a la velocidad del procesador, en todo caso es factible de atenuar este problema. Vea el archivo Anima_Graf1.java, en donde se ha incluido la clase MediaTracker que ofrece la posibilidad de manipular la carga de archivos de imagen, el método addImage() que se usa para añadir una imagen a la lista de imágenes que se están controlando. Otro problema que surge respecto de la visualización de la animación es que se redibuja toda la pantalla con cada nueva unidad de imagen, lo que genera mucho parpadeo, este problema puede ser mitigado limitando el área de la vantana que se actualiza con cada imagen nueva, de manera que los métodos repaint() y update() de la clase Component ofrecen esta opción. Otra opción a considerar es cambiar el retardo de imagen, disminuyendo la cantidad de unidades de imagen por segundo, para así bajar el nivel de parpadeo. Para cuando Ud. ejecute el applet de Anima_Graf1.java, este le mostrará una cadena animada de arteriscos mientras las imágenes se estan cargando, después mostrará inmediatamente la animación de la imagen, esto reduce el parpadeo que se produce cuando se muestra una imagen a la vez que se esta cargando. También podrá observar que las imágenes se han tornado un tanto más lenta, esto es debido a que el nivel de retardo de imagen se ha incrementado de 100 a 200 microsegundos, disminuyendo 2 veces el nivel de retardo de la imagen. Los cambios que ha experimentado este último programa respecto al anterior son: boolean llenoDisplay , usada para asegurarse de que se ha conseguido una visualización completa de las imágenes antes de intentar una viasualización limitada por medio del método repaint(), MediaTracker tracker; para remitirse a un objeto MediaTracker. El método setup() se actualiza para crear el objeto MediaTracker y para agregar las imágenes que se están cargando a este objeto. _________________________________________________________________________ Area de Computación, Universidad de La Serena 9 Dr. Eric Jeltsch F. Programación en Java2 Cap12: Animación y más El método paint() se ha actualizado para dibujar las imágenes una vez que se han cargado y para dibujar cadenas de arteriscos antes de haber cargado las imágenes. El método todoInvitado() utiliza el método statusId() de la clase MediaTracker para determinar si se han cargado completamente todas las imágenes. Finalmente run() se ha modificado para usar el método todoInvitado() y la variable llenoDisplay a fin de determinar si ésta debe redibujar toda la pantalla o sólo una pequeña porción de la misma. Un último ejemplo es el archivo Neko.java, el gato regalón del proyecto PALOV(aunque aquí solo corria y dormía, pero puede tener otras gracias, veamos). Cada una de las gracias de Neko están contenidas en sus propios métodos. import java.awt.Graphics; import java.awt.Image; import java.awt.Color; public class Neko extends java.applet.Applet implements Runnable { Image nekoFotos[] = new Image[9]; Image actualImg; Thread correr; int x; int y = 50; /* el método init() se usa para cargar las imágenes dentro del array nekoGifes, Ud. podría hacer las llamadas a cada una de ellas, pero una forma más óptima es usar array String que contenga las fotos*/ public void init() { String nekoGifes[] = { "derecha1.gif", "derecha2.gif", "parar.gif", "bostezar.gif", "rascar1.gif", "rascar2.gif","duerme1.gif", "duerme2.gif", "despertar.gif" }; for (int i=0; i < nekoFotos.length; i++) { nekoFotos[i] = getImage(getCodeBase(), "images_Neko/" + nekoGifes[i]); } } public void start() { if (correr == null) { correr = new Thread(this); correr.start(); } } public void stop() { correr = null; } _________________________________________________________________________ Area de Computación, Universidad de La Serena 10 Dr. Eric Jeltsch F. Programación en Java2 Cap12: Animación y más public void run() { setBackground(Color.white); // run desde un lado de la pantalla hasta la mitad nekoCorre(0, getSize().width / 2); // stop y pause actualImg = nekoFotos[2]; repaint(); pause(1000); // parar actualImg = nekoFotos[3]; repaint(); pause(1000); // rascarse nekoRasca(4); // duerme nekoDuerme(5); // despierta y corre actualImg = nekoFotos[8]; repaint(); pause(500); nekoCorre(x, getSize().width + 10); } void nekoCorre(int start, int end) { for (int i = start; i < end; i += 10) { x = i; // swap images if (actualImg == nekoFotos[0]) actualImg = nekoFotos[1]; else actualImg = nekoFotos[0]; repaint(); pause(150); } } void nekoRasca(int numTimes) { for (int i = numTimes; i > 0; i--) { actualImg = nekoFotos[4]; repaint(); pause(150); actualImg = nekoFotos[5]; repaint(); pause(150); } } void nekoDuerme(int numTimes) { for (int i = numTimes; i > 0; i--) { actualImg = nekoFotos[6]; repaint(); pause(250); _________________________________________________________________________ Area de Computación, Universidad de La Serena 11 Dr. Eric Jeltsch F. Programación en Java2 Cap12: Animación y más actualImg = nekoFotos[7]; repaint(); pause(250); } } /* como cada método de Neko necesita una pausa, se agrega este método al applet que se puede reutilizar.*/ void pause(int time) { try { Thread.sleep(time); } catch (InterruptedException e) { } } public void paint(Graphics g) { if (actualImg != null) g.drawImage(actualImg, x, y, this); } } Sonido y Video Los métodos play() se utilizan para reproducir archivos de audio en los URL especificados. El Java2 introduce el nuevo método newAudioClip(), que es un método estático que permite crear objetos AudioClip sin un contexto de applet, en versiones anteriores solo fué factible utilizar archivos .au(formato de archivo de audio para Sun). Ahora es factible desde la versión 1.2 formatos, WAVE(Microsoft), AIFF(SiliconGraphics), AU(Sun), RMF, MIDI. La estructura multimedial para Java es una API que sirve para utilizar audio y vídeo en las aplicaciones y applets de Java. Esta API admite la reproducción de una amplia gama de tipos de multimedios. La herramienta JMF está disponible en el sitio Web de JavaSoft en http://www.javasoft.com/products/java-media/jmf/index.html., por si desea incursionar en este tipo de aplicaciones. Aplicación (AudioPlayer) Este archivo nos muestra un espacio astral en donde es posible de escuchar un segmento de la 5ta. Sinfonía de Beethoven. import import import import java.applet.*; java.awt.*; java.awt.event.*; java.net.*; public class AudioPlayer extends Applet { AudioClip musica; Image background; public void init() { URL codeBase = getCodeBase(); musica = getAudioClip(codeBase,"beethove.au"); _________________________________________________________________________ Area de Computación, Universidad de La Serena 12 Dr. Eric Jeltsch F. Programación en Java2 Cap12: Animación y más background = getImage(codeBase,"espacio.gif"); setLayout(new BorderLayout()); Panel boton = new Panel(); Button playButton = new Button("Play"); Button stopButton = new Button("Stop"); Button loopButton = new Button("Loop"); playButton.addActionListener(new BotonTrato()); stopButton.addActionListener(new BotonTrato()); loopButton.addActionListener(new BotonTrato()); boton.add(playButton); boton.add(stopButton); boton.add(loopButton); add("South",boton); } public void stop() { musica.stop(); } public void paint(Graphics g) { g.drawImage(background,0,0,this); } class BotonTrato implements ActionListener { public void actionPerformed(ActionEvent e){ String s = e.getActionCommand(); if("Play".equals(s)) musica.play(); else if("Stop".equals(s)) musica.stop(); else if("Loop".equals(s)) musica.loop(); } } } A propo de música y aplicación Web, una pildorita de esto es cuando queremos que una página tenga una reacción musical para cuando ella es cargada por el Browser, para tal efecto debe considerar el código del método play() La clase java.applet.Applet contiene 2 métodos los cuales almacenen los archivos de sonidos desde una dirección URL particular y ejecutarlos. public void play(URL soundfile) public void play(URL directorio, String nombre_archivo) Normalmente son usados algunos códigos alternativos asociados al código base. Alternativamente, los URLs pueden ser especificados en uno de los applet's PARAM tags. Por ejemplo, la música que Ud. escucha es generada por el siguiente applet: import java.applet.*; public class SoundApplet extends Applet { public void init() { String soundfile = this.getParameter("soundfile"); if (soundfile != null) this.play(this.getDocumentBase(), soundfile); } _________________________________________________________________________ Area de Computación, Universidad de La Serena 13 Dr. Eric Jeltsch F. Programación en Java2 Cap12: Animación y más } Los programas en Java pueden manipular y hacer posible la contrucción de audio clips. Tal como mencionabamos al comienzo de este Capítulo, la posibilidad de incorporar a los applet la capacidad de reproducir archivos multimediales es hoy día una realidad, antes ya lo era con las antiguas versiones , sin embargo hoy en día es posible incorporar otros formatos de audio, como WAVE(.wav de la MicroSoft), AIFF, AU(de Sun MicroSystems), RMF, MIDI. Aplicación (audio1) Este archivo nos muestra un combobox con la incorporación de archivos .wav import import import import java.applet.*; java.awt.*; java.awt.event.*; javax.swing.*; public class audio1 extends JApplet { private AudioClip sonido1, sonido2, actualSonido; private JButton playSonido, loopSonido, stopSonido; private JComboBox escogerSonido; // invita la imagen para cuando ejecución public void init() { Container c = getContentPane(); c.setLayout( new FlowLayout() ); el applet comienza su String escoger[] = { "Welcome", "Hi" }; escogerSonido = new JComboBox( escoger ); escogerSonido.addItemListener( new ItemListener() { public void itemStateChanged( ItemEvent e ) { actualSonido.stop(); actualSonido = escogerSonido.getSelectedIndex() == 0 ? sonido1 : sonido2; } } ); c.add( escogerSonido ); BotonTrato trato = new BotonTrato(); playSonido = new JButton( "Play" ); playSonido.addActionListener( trato ); c.add( playSonido ); loopSonido = new JButton( "Loop" ); _________________________________________________________________________ Area de Computación, Universidad de La Serena 14 Dr. Eric Jeltsch F. Programación en Java2 Cap12: Animación y más loopSonido.addActionListener( trato ); c.add( loopSonido ); stopSonido = new JButton( "Stop" ); stopSonido.addActionListener( trato ); c.add( stopSonido ); sonido1 = getAudioClip( getDocumentBase(), "welcome.wav" ); sonido2 = getAudioClip( getDocumentBase(), "hi.au" ); actualSonido = sonido1; } // stop el sonido cuando el usuario se cambia de página Web public void stop() { actualSonido.stop(); } private class BotonTrato implements ActionListener { public void actionPerformed( ActionEvent e ) { if ( e.getSource() == playSonido ) actualSonido.play(); else if ( e.getSource() == loopSonido ) actualSonido.loop(); else if ( e.getSource() == stopSonido ) actualSonido.stop(); } } } Observación: Entre los formatos de video destacan, MPEG, MOV, VIV, AVI, ActiveMovie, de los citados MPEG produce el vídeo de más alta calidad utilizando el tamaño de archivos más reducido. Actividades 1) Customizing Applets via el parametro HTML Tag 2) Usar el API de Java Media Player para generar sus programas en los cuales les incorpora video. (http://java.sun.com/products/java-media/jmf/1.1). 3) Analizar Java Plug-in 1.2 HTML Converter.(http://java.sun.com/products/plugin/, una vez que lo haya cargado puede ejecutarlo tipeando java HTMLConverter en el directorio donde Ud. instalo el convertidor. _________________________________________________________________________ Area de Computación, Universidad de La Serena 15