Вы находитесь на странице: 1из 11

Java Media Framework

Introduccin:

Acerca de Java Media Framework


Java Media Framework proporciona a los applets y aplicaciones Java la capacidad de reproducir,
capturar y transmitir/recibir en tiempo real audio video y otros contenidos multimedia. Provee de
una serie de codificadores y decodificadores para los formatos multimedia ms relevantes siendo
capaz adems, de realizar transcodificacin entre dichos formatos.
Acerca de este tutorial
Para visualizar correctamente los applets que forman parte de este tutorial se recomienda tener
instalados:

Plug-in de Java correctamente configurado para su navegador. Se recomienda la versin


1.4 o posteriores.

Java Media Framework, versin 2.1.1e.

Todos los permisos de la mquina virtual de java habilitados


Conceptos bsicos:

Aplicaciones multimedia
Una aplicacin multimedia es aquella que produce, reproduce, procesa o maneja uno o varios
contenidos multimedia. A su vez un contenido multimedia es aquel que est compuesto de
diversos medios, como pueden ser audio, video, texto, etc. Decimos que un contenido
multimedia est basado en el tiempo en tanto que cada uno de sus medios cambia
significativamente con l. Esta caracterstica hace que un contenido multimedia requiera ser
proporcionado y procesado en unas condiciones temporales estrictas. Por ejemplo cuando se
reproduce un video, si los datos multimedia no pueden ser proporcionados lo suficientemente
rpido pueden producirse pausas y retardos en la reproduccin; por otro lado si los datos no
pueden ser recibidos y procesados lo suficientemente rpido el video se reproduce a saltos en
tanto que se desechan cuadros como medio para mantener la tasa de reproduccin.

Cada uno de los medios de los que se compone un contenido multimedia se denominapista . Por
ejemplo un contenido multimedia correspondiente a una videoconferencia puede contener una
pista de audio y otra de video. Se dice que las pistas que componen un contenido multimedia
estn multiplexadas, al proceso de extraccin de las distintas pistas que componen un contenido
multimedia se le denomina demultiplexacin. Existen distintos tipos de pistas en funcin del tipo
de datos que contienen, como audio y/o video; a su vez cada pista posee un formato que define
como estn estructurados los datos que forman parte de ella. Los distintos formatos se distinguen
en funcin de:

La calidad que proporcionan

Su exigencia de recursos de CPU para ser procesados

La cantidad de ancho de banda requerida para su transmisin


Tabla 1 - Formatos multimedia soportados por JMF y sus caractersticas
Formato Calidad Uso CPU Ancho de banda
Cinepak Media Bajo Alto
MPEG 1 Alta Alto Alto
H.261 Baja Medio Medio
H.263 Media Medio Bajo
JPEG Alta Alto Alto
Indeo Media Medio Medio
PCM Alta Bajo Alto
Mu-Law Baja Bajo Alto
ADPCM (DVI, Media Medio Medio
IMA)
MPEG 1 Alta Alto Alto
MPEG 1 Layer 3 Alta Alto Medio
GSM Baja Bajo Bajo
G.723.1 Media Medio Bajo

Cada formato est destinado a diferentes tipos de aplicaciones y servicios. Formatos como MPEG
1 de gran calidad pero altos requerimientos de ancho de banda estn destinados usualmente a
aplicaciones que trabajan con almacenamiento local o en dispositivos pticos como CD-ROM o
DVD donde el ancho de banda y la capacidad de almacenamiento no son limitantes. En cambio
otros formatos como H.261 y H.263 se usan para aplicaciones de videoconferencia donde el ancho
de banda es un bien muy escaso; de la misma forma G.723 se usa para producir voz codificada
con tasa de bits reducida para aplicaciones de telefona IP por ejemplo.

Fuentes de datos multimedia


En Java Media Framework los datos multimedia pueden proceder de diversas fuentes, como
archivos locales o remotos y video y audio en tiempo real o bajo demanda.

Una fuente de datos multimedia se modela mediante un objeto DataSource. Podemos crear una
DataSource directamente a travs de una URL (Universal Resource Locator) o bien mediante un
objeto de tipo MediaLocator.
Reproduccin de contenidos multimedia

En esta pagina

Abordaremos la reproduccin de contenidos multimedia de diversos formatos y procedencia


haciendo uso de las fuentes de datos que pone a nuestra disposicin Java Media Framework.
Creando un reproductor (player)
En Java Media Framework un reproductor ser el encargado de reproducir un determinado
contenido multimedia a travs del hardware existente en nuestro equipo.

Para reproducir un flujo de datos multimedia, se ha de construir una instancia de la clase de Java
Media Framework Player cuya entrada sea dicho flujo de datos.
Grafico 1 - Esquema de funcionamiento de un Player

Podemos construir un objeto Player indirectamente a travs del mtodo createPlayer() de la clase
de Java Media Framework Manager. El flujo multimedia de entrada al Player constituye un
parmetro del mtodo createPlayer() admitiendose una DataSource, un MediaLocator o una URL.
Tabla 1 - Creacin de un Player. Mtodos createPlayer() de la clase Manager

Player createPlayer (DataSource dataSource)

Player createPlayer (MediaLocator sourceLocator)

Player createPlayer (java.net.URL sourceURL)

Listado 1 - Ejemplo de creacin de un Player


public void abrirContenidoMM(String cadenaContenidoMM) {
//Se crea URL para la cadena
URL url = null;
url = new URL(cadenaContenidoMM);
//Se crea el reproductor
player = Manager.createPlayer(url);
...

(Se omiten captura de excepciones!)


Codigo fuente completo de ReproduccionJMF.java

El Player creado a travs de createPlayer se encuentra en estado Unrealized, en este estado el


Player no est capacitado para reproducir su flujo de datos multimedia de entrada. En el apartado
siguiente "Estados de un player", se profundizar acerca de los diferentes estados en los que se
puede encontrar un Player a lo largo de su vida.

La mayora de los mtodos que pueden ser llamados en un Player requieren que ste est en el
estado Realized. Como se ver, se puede promocionar a este estado llamando al mtodo realize()
del Player. Java Media Framework tambin permite la creacin de un Player directamente en
estado Realized mediante el mtodo createRealizedPlayer() de la clase Manager. Ntese que este
mtodo bloquea hasta que el Player es realizado[PTE: Peligro]

Un Player ha de pasar al estado Realized antes de que se pueda iniciar y controlar la reproduccin
propiamente dicha del contenido multimedia.

Estados de un Player y mtodos disponibles


Un Player puede encontrarse a lo largo de su vida en 4 estados fundamentales:
"Unrealized": El estado en el que se encuentra un player cuando es creado por primera vez
y no tiene ningn conocimiento acerca de la fuente de datos de entrada.
"Realized": Al pasar a este estado el player conoce el tipo de fuente de datos de entrada
que habr de reproducir, conoce tambin los recursos que va a necesitar.
"Prefetched": En este estado el player est preparado para reproducir los datos multimedia
de su fuente de entrada.
"Started": Llamando al mtodo start del player se pasa a este estado en el que se est
reproduciendo el contenido multimedia.

Grafico 2 - Estados de un player a lo largo de su vida

La siguiente tabla recoge los mtodos fundamentales que pueden ser llamados en un Player para
intervenir sobre la reproduccin, junto a informacin acerca de el/los estado/s en los que se
encuentran disponibles:
Tabla 2 - Mtodos fundamentales proporcionados por un Player en funcin del estado
Mtodo Descripcin Disponible en

Inicia la reproduccin, progresando el


Player a estado Started desde
start() Todos los estados
cualquier estado en que se
encontrara

Detiene la reproduccion,
stop() Estado Started
descendiendo a estado Prefetched

Hace al Player progresar al estado


realize() Estado Unrealized
Realized

Hace al Player progresar al estado


prefetch() Estado Realized
Prefetched

Aborta la actividad del y libera los Todos los estados


deallocate()
recursos consumidos por el Player excepto Started

Establece la velocidad de A partir del estado


setRate(float rate)
reproduccin del contenido MM Realized

Indica a partir de donde A partir del estado


setMediaTime(Time time)
continuar/iniciar la reproduccin Realized
Devuelve el componente visual de la A partir del estado
getVisualComponent()
reproduccin Realized

Devuelve el componente de control A partir del estado


getControlPanelComponent()
de la reproduccin Realized

Creando la interfaz del Player

Un player tiene una serie de componentes visuales que se pueden aadir a la aplicacin o applet
para actuar de interfaz con la reproduccin. Los ms importantes son el componente visual y el
componente de control.

El componente visual es el que permite reproducir la componente visual (pista de video)


del contenido multimedia, si la hubiere. Es donde el player renderiza la representacin
visual correspondiente a su reproduccin. Para obtenerlo llamamos al mtodo del Player
getVisualComponent(), el componente visual devuelto ha de ser aadido a continuacin a
nuestro interfaz grfico.
El componente de control es el que permite al usuario controlar la reproduccin del
contenido multimedia. Permite actuar sobre el Player iniciando o deteniendo la
reproduccin, o bien intervenir sobre el volumen del audio y obtener infomacin acrca del
estado de la reproduccin. Para obtenerlo llamamos al mtodo del Player
getControlPanelComponent(), aadiendo a continuacin a nuestra interfaz el componente
de control devuelto.

Listado 2 - Ejemplo de creacin de una interfaz bsica para controlar un Player


...
Component componenteControl = player.getControlPanelComponent();
Component componenteVisual = player.getVisualComponent();
//Se aade el componente de visualizacin y el de control a la UI
if (componenteVisual != null){
UI.addComponenteVisual(componenteVisual, this);
}
if (componenteControl != null) {
UI.addComponenteControl(componenteControl, this);
}
...
Codigo fuente completo de ReproduccionJMF.java

Los eventos de la reproduccin: como atenderlos


Durante la reproduccin se pueden producir diversas circunstancias previstas o imprevistas que
requieran de nuestro conocimiento y atencin. Se nos informa de ellas a travs de los eventos.

Los eventos que se generan en el proceso de reproduccin de un contenido multimedia son de


tipo asncrono, lo que significa que pueden producirse en cualquier momento (no respetan un
sincronismo). As pues, han de atenderse cuando se produzcan. Para atender a los eventos de la
reproduccin debemos:
1. Implementar el interfaz ControllerListener en toda aquella clase que queramos que sea
notificada de los eventos. Cada una de las clases que implementen este interfaz debern
contener el mtodo controllerUpdate()
2. Registrar cada una de las instancias de las clases anteriores para ser notificada de los
eventos de la reproduccin. A tal efecto se llamar al mtodo del Player
addControllerListener() tantas veces como instancias queramos registrar para ser
notificadas de los eventos, indicando en cada llamada cada una de las instancias.
Listado 3 - Ejemplo de registro de diversos listener para ser notificados de eventos
...
player = Manager.createPlayer(url);
player.addControllerListener(listener1);
player.addControllerListener(listener2);
...
Codigo fuente completo de ReproduccionJMF.java

De esta forma cada vez que se genera un evento, se llama al mtodo controllerUpdate de cada
una de las instancias registradas. La implementacion del mtodo controllerUpdate consiste en una
serie de sentencias if-else, que pretenden proporcionar una atencin especfica a cada tipo de
evento.
Listado 4 - Ejemplo de creacin de una interfaz bsica para controlar un Player
public synchronized void controllerUpdate(ControllerEvent event) {
if (event instanceof TipoDeEvento){
...
} else if (event instanceof OtroTipoDeEvento){
...
}
...
Codigo fuente completo de ReproduccionJMF.java

Se recogen a continuacin los eventos ms importantes que pueden producirse en la


reproduccin:
Procesamiento de contenidos multimedia:

En esta pgina

Se presentar el procesador como medio para realizar transformaciones a los contenidos


multimedia, enviarlos en una sesin rtp a travs de internet, capturarlos de una webcam o un
micrfono y muchas ms.
Qu diferencia a un procesador de un reproductor?

Un procesador no es ms que un tipo especializado de reproductor (player) que permite controlar


el procesamiento que se hace sobre la fuente de datos que recibe a su entrada. Un procesador
tambien proporciona a su salida la fuente de datos procesada.

As un Processor recibe a su entrada un flujo de datos multimedia, que representamos como una
DataSource de entrada, y produce un nuevo flujo de datos multimedia correspondiente a la
entrada procesada y que representamos como una DataSource de salida.
Grafico 1 - Esquema de funcionamiento de un Processor

El flujo de datos de entrada al procesador puede proceder de:

1. Una URL, que puede localizar: archivos multimedia locales o archivos multimedia alojados
en servidores remotos.
2. Una sesin RTP.
3. Una captura de audio y/o video

A su vez el flujo de datos procesados puede ser:

1. Almacenado en un archivo
2. Transmitido den tiempo real a travs de Internet mediante RTP.
3. Reproducido.
Construyendo un procesador
El mtodo createManager() de la clase Manager devuelve un Processor. El flujo Multimedia de
entrada al Processor es un argumento de createProcessor(), puede consistir en una DataSource,
un MediaLocator o una URL.
Tabla 1 - Creacin de un Processor. Mtodos createProcessor() de la clase Manager

Processor createProcessor (DataSource dataSource)

Procesor createProcessor (MediaLocator sourceLocator)

Processor createProcessor (java.net.URL sourceURL)

Java Media Framework tambin permite la creacin de un Processor, directamente en estado


Realized, mediante el mtodo createRealizedProcessor de la clase Manager.
Tabla 2 - Creacin de un Processor. Mtodo createRealizedProcessor, clase Manager

Processor createRealizeProcessor (ProcessorModel modelo)

Este mtodo recibe como argumento un objeto ProcessorModel en el que se detalla el


procesamiento que va a efectuar el Processor. De esta forma establecemos las opciones de
procesamiento directamente al crear el Processor, en el siguiente apartado profundizaremos
acerca de la creacin de los ProcessorModels. Ntese adems que se crea un Processor
directamente en estado realizado.
Especificando las opciones de procesamiento
Un flujo de datos MultiMedia pude contener una o ms pistas (Tracks) multiplexadas. Por ejemplo,
dicho flujo MM, puede ser demultiplexado en dos pistas diferentes, una de audio y otra de video.
Grafico 2 - Demultiplexacin/Multiplexacin de pistas por parte de un Processor

Los estados de un Processsor son muy similares a los de un Player (Estados de un Player).
Cuando un Processor se encuentra en estado Realized, podemos llamar al mtodo
getTrackControls() para obtener sendos objetos TrackControl para cada una de las pistas
contenidas en el flujo de datos MM. Estos objetos permiten especificar el procesamiento que se va
a efectuar sobre cada una de las pistas.
Listado 1 - Ejemplo de obtencin de los TrackControls de las pistas de un Processor
...
controlPista = processor.getTrackControls();
//Obtencion de los formatos de salida soportados para cada pista
for (int i = 0; i < controlPista.length; i++) {
Format[] formatosPista = controlPista[i].getSupportedFormats();
if (controlPista[i].getFormat() instanceof AudioFormat){
formatosAudio = formatosPista;
formatoAudioActual = controlPista[i].getFormat();
} else if (controlPista[i].getFormat() instanceof VideoFormat){
formatosVideo = formatosPista;
formatoVideoActual = controlPista[i].getFormat();
}
}
...
(Continua en listado 3)
Codigo fuente completo de ProcesamientoJMF.java

Existen dos formas fundamentales de especificar el procesamiento que se va a llevar a cabo en un


Processor:

Usar un ProcessorModel al construir el Processor. Un objeto ProcessorModel contiene


informacin acerca de:

El flujo MultiMedia de entrada


El formato de salida de cada una de las pistas
El descriptor de contenido de la salida (ContentDescriptor), que indica el formato
global de la salida del Processor (por ejemplo: archivo quicktime, datos RAW, datos
RTP ...)
Listado 2 - Ejemplo de uso de un Processor Model para especificar opciones de
procesamiento
...
//Descriptor de contenido de la salida
descContenido = new ContentDescriptor(ContentDescriptor.RAW);
...
//Formatos de salida de cada una de las pistas
formatos[0] = new AudioFormat(formatoAudio);
formatos[1] = new VideoFormat(formatoVideo);
...
//Creacion del Processor en estado realizado mediante
//un ProcessorModel

try {
procesador = Manager.createRealizedProcessor(new
ProcessorModel(
dataSourceOrigen, formatos,descContenido));
}
catch (Exception ex) {
System.err.println(ex);
}
...
Codigo fuente completo de ProcesamientoJMF.java

Una vez obtenidos los TrackControls correspondientes a cada pista. Llamar al mtodo
setFormat() en cada TrackControl para especificar el formato de salida de cada pista (en la
prctica formato de salida del video y del audio). Se debe establecer tambin el descriptor
de contenido de la salida del Processor llamando al mtodo setOutputContentDescriptor del
Processor.
Listado 3 - Ejemplo de uso de TrackControls para establecer opciones de
procesamiento
(Contina al listado 1)
...
public boolean setFormatoVideo(VideoFormat formato) {
controlPista[0].setFormat(formato);
controlPista[0].setEnabled(true);
}
return exito;
}
...
Codigo fuente completo de ProcesamientoJMF.java

Destino para los datos procesados


Los destinos posibles para los datos multimedia de salida de un procesador son:

Reproduccin: Recordemos que un Processor no es ms que un tipo especializado de


Player. Por lo tanto podemos obtener el componente visual correspondiente al contenido
reproducido as como el componente de control y de esta forma reproducir el contenido
multimedia en nuestro equipo como si de un Player se tratase.
Almacenamiento en un archivo: Podemos almacenar la salida de un procesador en un
archivo utilizando el siguiente procedimiento:

1. Obtener la DataSource de salida del procesador llamando al mtodo getDataOutput() de ste

2. Construir un DataSink cuyo cometido es escribir la salida del procesador en un archivo de


nuestro sistema. Para ello llamamos al mtodo Manager.createDataSink al que pasamos como
parmetro la DataSource de (1) y un MediaLocator que especifique el nombre y localizacin del
archivo, devuelve un objeto tipo DataSink
3. Llamar a open() del objeto DataSink, devuelto en (2)

4. Llamar a start() del objeto DataSink

5. Iniciar el procesamiento de los datos multimedia llamando al mtodo start() del Processor

Una vez se produzca un evento EndOfMediaEvent u otro que indique el final del procesamiento:

6. Llamar al mtodo stop() del Processor para finalizar el procesamiento

7. Llamar al mtodo close() del Processor

8. Llamar al mtodo close() en el DataSink


Listado 4 - Ejemplo de almacenamiento en un archivo de la salida de un Processor
...
public void guardarContenidoMM(DataSource fuente, String destino){
System.out.println(destino);
try {
mlrDest = new MediaLocator(new URL(destino));
}
catch (Exception ex) {
System.out.println(ex);
}
try {
filewriter = Manager.createDataSink(fuente, mlrDest);
System.out.println(filewriter);
filewriter.addDataSinkListener(this);
}
catch (NoDataSinkException ex) {
System.out.println(ex);
}
System.out.println(filewriter);
try {
filewriter.open();
}
catch (SecurityException ex1) {
}
catch (IOException ex1) {
}
try {
filewriter.start();
}
catch (IOException ex2) {
}
}
...
Codigo fuente completo de ProcesamientoJMF.java

Por ltimo la salida de un Processor tambin puede servir de entrada a otro Processor o
Player