Java Media Framework.
Resumen.
Este Informe tiene como fin presentar
de una manera más entendible el concepto que hay debajo de JMF (Java Media
Framework), que gracias a las ventajas que otorga la plataforma Java, JMF
promete que sus aplicaciones se “Escriben una vez, corren en cualquier parte”.
Los temas que se tocaran en el presente informe son los siguientes:
à Introduccion a JMF y sus versiones.
à Una presentación de los “Medios Basados en
el Tiempo” (Time-Based Media).
à El funcionamiento de JMF para trabajar con
estos tipos de medios.
à Presentando medios basados en el tiempo con
JMF.
à Procesando
medios basados en el tiempo con JMF.
à
Capturando datos de medios con JMF.
Javaä Media Framework (JMF) es un API (Application
Programming Interface), para la incorporación de medios basados en el tiempo
(time-based medias) en aplicaciones Java y Applets. Los medios basados en el
tiempo son medios tales como el audio, video, MIDI y animaciones que cambian
con respecto al tiempo.
Inicialmente, el
JMF 1.0 API, habilitaba a los programadores para desarrollar software de tipo
Java que presentaban estos tipos de medios. Actualmente, el JMF 2.0 API,
extiende el área de trabajo, para proveer soporte para captura y almacenaje de
medios (basados en el tiempo), controlando el tipo de procesamiento que es
efectuado durante la reproducción y para la personalización del procesamiento
sobre flujos de medios.
Los objetivos
principales del diseño de JMF 2.0 API son:
·
Ser
más fácil para programar.
·
Soporte
para la captura de medios.
·
Habilita
el desarrollo de aplicaciones para flujos de medios (media streaming) y
conferencias en Java.
·
Habilitación
de tecnología y desarrollo avanzado que permita implementar soluciones
personalizadas basadas en APIs ya existentes
y nuevas características fácilmente integrables.
·
Proveer
el acceso a datos Raw Media.
·
Habilitar
el desarrollo de demultiplexores, codecs, procesadores de efectos,
multiplexores, y renderers personalizables y descargables (JMF plug-ins).
·
Mantener
la compatibilidad con JMF 1.0 API.
Toda
información que tenga cambios
significativos con respecto al tiempo puede ser catalogada como un medio basado
en el tiempo, como lo son los clips de audio, secuencias MIDI, clips de video,
etc. Estos medios pueden ser obtenidos de diversas fuentes, como archivos
locales o remotos, cámaras, micrófonos y difusiones en vivo.
A continuación
se presenta un modelo que describe las características de estos medios y la
manipulación que a estos se les debe aplicar.
Figura 1. Modelo de
Procesamiento de Medios.
Las características claves de los medios basados en el tiempo son las siguientes:
·
Flujo de Medios (Streaming Media).
La característica principal de este medio es que requiere de un tiempo de entrega y de procesamiento, y por esto se debe controlar, ya que una vez iniciado el flujo de datos, se deben satisfacer ciertos limites de tiempo.
·
Presentación de Medios (Output).
La mayoría de estos medios pueden ser presentados a través de dispositivos de salida tales como parlantes y monitores, u otras destinaciones (Ej.: a la red). Comúnmente a estos destinos de medios se le llaman DataSinks.
·
Procesamiento de Medios (Process).
En muchas instancias, la información contenida en un medio es manipulada antes de ser presentado al usuario, ya sea multiplexándola, filtrándola, comprimiéndola, o convirtiéndola en otro tipo de medio.
· Captura de Medios (Input).
Estos pueden ser capturados desde una fuente en vivo para procesarla y reproducirla o puede ser adquirida de un archivo de forma remota.
3. Entendiendo
a JMF.
JMF provee una arquitectura y un protocolo de mensajes unificado, para administrar la adquisición, procesamiento y entrega de medios basados en el tiempo. Para llevar a cabo su cometido, JMF cuenta con las siguientes características:
·
Arquitectura de alto nivel.
Una parte integral de JMF son las fuentes de datos y los reproductores para la administración de la captura, presentación y procesamiento de los medios, presentando la estructura de la figura 2.
Algunos de los principales elementos (clases e interfaces) de JMF se presentan a continuación:
¨ Time model.
¨ Managers.
¨ Event Model.
¨ Data Model.
¨ Controls.
Figura 2. Arquitectura de
Alto Nivel.
1) Time
Model.
JMF lleva el
tiempo con precisión de nanosegundos. Un punto determinado de tiempo es
representado típicamente por un objeto de la clase Time, aunque algunas clases también
utilizan la especificación del tiempo en nanosegundos.
Las clases que utilizan el modelo del tiempo de JMF, implementan la interfaz Clock para llevar el control del tiempo para una secuencia determinada de medios. La interfaz Clock define las operaciones básicas de sincronización que son necesarias para controlar la presentación de los medios.
Figura 3. JMF Time Model.
Para funcionar, Clock utiliza:
TimeBase: Esta interfaz es la encargada de dar los ticks, la fuente del compás
del tiempo. Da el tiempo actual time base).
Duration: La interfaz Duration proporciona una manera de determinar la
duración de los elementos de media que son reproducidos por un objeto de
Media. Los objetos de Media que exponen una duración implementan esta
interfaz.
Time: Clase
del paquete javax.media que lleva el tiempo con precisión de nanosegundos.
2)
Managers.
El JMF API
consiste principalmente en interfaces que definen el comportamiento e interacción
de los objetos usados para capturar, procesar y presentar los medios basados en
el tiempo. Las implementaciones de estas interfaces funcionan dentro de la
estructura del JMF. Usando los objetos intermedios llamados managers, JMF
hace fácil integrar nuevas implementaciones de interfaces claves que se pueden
utilizar junto con las clases existentes.
JMF utiliza
cuatro managers:
i) Manager à maneja la construcción de Players,
Processors, DataSources y DataSinks. Este nivel de indirección permite
que las nuevas implementaciones sean perfectamente integradas con JMF. De
la perspectiva del cliente, estos objetos siempre se crean la misma manera si
el objeto solicitado está construido de una implementación por default o de
encargo.
ii) PackageManager à mantiene un registro de paquetes que
contiene clases de JMF, tales como Players, Processors, DataSources y DataSinks.
iii)
CaptureDeviceManager à mantiene un registro de
dispositivos de captura disponibles.
iv) PlugInManager à mantiene un registro de componentes de
procesamiento de JMF plug-in disponibles, tales como Multiplexers,
Demultiplexers, Codecs, Effects y Renderers.
3)
Event Model.
JMF utiliza un
mecanismo de reporte de eventos estructurado para mantener los programas
de JMF informados sobre el estado actual del sistema de media y permitirles
responder a las condiciones de error. Siempre que un objeto de JMF
necesite reportar sobre las condiciones actuales, envía un MediaEvent.
MediaEvent tiene subclases para identificar muchos tipos determinados de
eventos. Estos objetos siguen los modelos establecidos de Java-Beans para
los eventos. Para cada tipo de objeto de JMF que pueda fijar MediaEvents, JMF
define el listener interface correspondiente.
Los objetos de
Controller (tales como Players y Processors) y ciertos objetos de Control tales
como GainControl fijan eventos de media.
Figura 4. JMF Event Model.
4) Data Model.
Los
reproductores de medios de JMF utilizan generalmente DataSources para manejar
la transferencia del contenido de medios. Un DataSource encapsula tanto
la localización de los medios y el protocolo y el software usado para
entregarlo. Una vez obtenido, el DataSource no se puede reutilizar para
entregar otros medios. Un DataSource es identificado por un JMF MediaLocator o
un URL.
Un DataSource
maneja un conjunto de objetos de SourceStream. Una fuente de datos estándar
utiliza un arreglo de bytes como unidad de la transferencia. Una fuente
de datos de buffer utiliza un objeto de clase Buffer como su unidad de la
transferencia.
Figura 5. JMF Data Model.
El formato
exacto de un objeto de media es representado por un objeto de la clase
Format. El formato en sí mismo no lleva ningún parámetro específico de
codificación o información de sincronización, describe el nombre de la
codificación del formato y el tipo de datos que el formato requiere.
JMF extiende
Format para definir formatos de audio y video específicos.
Figura 6. JMF Media
Formats.
5)
Controls.
El Control de
JMF proporciona un mecanismo para asignar y obtener los atributos de un
objeto. Un Control proporciona a menudo acceso a un componente
correspondiente de interfaz de usuario que habilita el control del usuario
sobre los atributos de un objeto. Muchos objetos de JMF exponen Controls,
incluyendo objetos de Controller, DataSource, DataSink y JMF plug-ins.
Cualquier objeto
de JMF que desee proporcionar acceso a sus objetos correspondientes de Control,
puede implementar la interfaz Controls. Controls define los métodos para
extraer objetos asociados de Control. DataSource y PlugIn utilizan
Controls para proporcionar al acceso a sus objetos de Control.
Figura 7. JMF Controls.
Entre estas
interfaces, destacan:
CachingControl: Permite que el progreso de la transferencia sea vigilado y
visualizado. Si un Player o Processor puede reportar el progreso de su
transferencia, implementa esta interfaz para que el usuario pueda visualizar
una barra de progreso.
GainControl: Permite ajustes del volumen del audio tales como fijar
el nivel y apagar la salida de un Player o Processor. También utiliza un
mecanismo de escucha para los cambios de volumen.
Figura 8. JMF Gain Control.
·
Presentación.
El proceso de presentación es modelado por la
interfaz controladora, que define el estado básico y el mecanismo de control
para el objeto presentado o capturado. En este caso se definen 2 tipos de
controladores: Reproductores y Procesadores.
·
Procesamiento.
El procesador es un reproductor que toma una
fuente de datos, realiza algunos procesos definidos por el usuario, y luego
entrega la información de medio procesada. Las etapas por las que el medio
atraviesa son la de demultiplexación, Transcoding, Multiplexación,
Renderización.
·
Captura.
Un dispositivo de captura multimedia puede actuar
como una fuente de entrega de medios basados en el tiempo. Algunos dispositivos
entregan múltiples flujos de datos que pueden ser separados mediante el
procesamiento.
·
Almacenamiento
y transmisión de medios.
Un DataSink es usado para
leer medios desde una fuente y renderizarlo a algún destino. Particularmente el
DataSink puede escribir datos a un archivo, escribir datos a través de
la red o funcionar como un RTP broadcaster.
Para presentar medios con JMF
se debe usar un reproductor, la reproducción puede ser programada o se puede
controlar desde el panel. Un Processor es un tipo especial de
reproductor que provee control de cómo se procesan los datos antes de ser
presentados. Un Processor puede ser
creado usando un ProcessorModel, llamando al metodo
Manager.createRealizedProcessor. El ProcessorModel define los requerimientos de entrada y salida para
el Processor.
El Media Player bean es un Java Bean que encapsula un JMF Player
para proveer una vía fácil para presentar flujos de medios desde un applet o
aplicación. El Media Player bean
automáticamente construye un nuevo reproductor cuando un flujo de medios
diferente es seleccionado, lo cual hace mas fácil reproducir una serie de clips
o permite que el usuario seleccione cual clip quiere reproducir.
Se puede crear indirectamente un
reproductor usando el media Manager.
Para mostrar el reproductor se deben agregar los componentes de objetos en su
espacio de presentación de la applet o en la ventana de aplicación. Cuando se
necesita crear un nuevo reproductor, este se pide al Manager llamando a createplayer o createprocessor.
Un reproductor generalmente tiene dos
tipos de componentes en la interfase, un componente visual y un panel de control,
en JMF esto se puede setear a elección, cada componente debe ser agregado a la
applet para que pueda ser usado, ya sea el control de volume, de progreso, etc.
También se puede setear la posición inicial, el contador de tiempo y otros
componentes típicos de los reproductores.
Un reproductor puede proveer información
sobre sus parámetros actuales, incluyendo velocidad de reproducción, tiempo
transcurrido y duración. Para obtener la velocidad se llama a getRate quien retorna la velocidad
como un número flotante, para obtener el tiempo se llama a getMediaTime la cual retorna un objeto Time, para obtener la duración
del clip se llama a getDuration.
Para responder a eventos
durante la reproducción se debe implementar una interface llamada ControllerListener, la cual debe ser
implementada en una clase y luego registrar esta clase llamando addControllerListener sobre el controlador del
cual se quiere recibir los eventos.
Para sincronizar la reproducción de múltiples
flujos estos se asocian con una misma base de tiempo, para esto se usa getTimeBase y setTimeBase, por ejemplo se puede setear player1 usando la base de tiempo de player2:
player1.setTimeBase(player2.getTimeBase());
Un Processor puede ser usado como un reproductor programable que sirva
para decodificar procesos, pero también puede ser usado para codificar y
multiplexar los datos de medios capturados. Se puede controlar lo capturado por
el Processor de diferentes maneras:
Configurando el Processor
Seleccionando las
opciones de procesamiento de las pistas:
Para
seleccionar que plug-ins es usado para cada pista en el flujo de medios se debe
hacer lo siguiente:
Cuando se usa setCodecChain para especificar el codec y
efecto plug-ins para un Processor, el
orden en que el plug-ins aparece realmente en la cadena de procesamiento está
determinado por los formatos de entrada y salida de cada plug-ins cargado.
Convirtiendo datos de medios de un formato a otro
Se puede seleccionar el formato para una pista en particular a través
del TrackControl para cada pista:
1.
Llamar
getTrackControls sobre el Processor para hacer un TrackControl para cada pista en el flujo
de medios. El Processor debe estar en
el estado Configurado antes de llamar
getTrackControls.
2.
Usar
el método TrackControl setFormat para especificar el formato
a que se quiere convertir la pista seleccionada.
Especificando el formato de salida
Se puede usar el método Processor setContentDescriptor para especificar el formato
de salida de los datos para el Processor.
Se puede tener una lista de los formatos soportados llamando getSupportedContentDescriptors.
Se puede también
seleccionar el formato de salida usando
un Processor-Model para crear el Processor.
Especificando el destino
Se puede especificar un
destino para el flujo de medios seleccionando un particular Renderer para una pista a través de TrackControl, o usando la salida del Processor como entrada a una particular DataSink. También se puede usar la salida del Processor como entrada a otro
reproductor o a un Processor con distinto destino.
Seleccionando un Redender
Para seleccionar el Revender que se desea usar se debe hacer
lo siguiente:
Escribiendo datos de medios en un archivo
Se puede usar un DataSink
para leer datos
desde el objeto de salida del Processor DataSource y enviar los datos a un
archivo.
El formato del dato escrito para el
archivo especificado es controlado a través del Processor.
6. Capturando datos de medios con JMF
Se puede usar JMF para
capturar datos de medios desde un dispositivo de captura como un micrófono o
una cámara de video. Los archivos capturados pueden ser procesados y
almacenados para un uso futuro.
Para capturar datos de
medios se debe hacer lo siguiente:
Accediendo a dispositivos de captura
Para acceder a dispositivos
de captura se debe hacer a través del CaptureDeviceManager. El CaptureDeviceManager es un registro central para todos
los dispositivos de captura disponibles para JMF. Se puede hacer una lista con
los dispositivos disponibles llamando al método CaptureDeviceManager.getDeviceList.
Almacenando datos de medios
Para almacenar los datos
capturados en un archivo, se necesita usar un Processor en lugar de un reproductor. Se usa un DataSink para leer los datos desde la salida del Processor y enviarlos al archivo.
Cuando
el Processor esta cerrado y el DataSink anuncia un EndOfStreamEvent,
llame close sobre el DataSink.