Desarrollo de componentes Java para netbooks


Una guía descriptiva para el desarrollo de bibliotecas de clase Java* dirigida a desarrolladores de aplicaciones para netbook Introducción

Los netbooks se han popularizado mucho en poco tiempo. Estos dispositivos a menudo carecen de la potencia de procesamiento, la memoria, el tamaño de unidad, el tamaño de pantalla y los reproductores de DVD de los equipos portátiles normales, a cambio de un tamaño pequeño y una mayor duración de la batería. Están destinados principalmente a la navegación web, actividades de correo electrónico e "informática en la nube", donde el almacenamiento y manipulación de los archivos del usuario se realizan en una "nube" de servidores remotos.

Java* es una opción obvia para el desarrollo de aplicaciones pequeñas y enfocadas al segmento de los netbooks que ofrecen funciones útiles para estos usuarios. Java* es una plataforma perfecta para el desarrollo orientado a netbooks: Java* es una plataforma de desarrollo madura, popular y bien documentada. Además, el desarrollo de Java* es virtualmente gratuito. Los programas Java* se ejecutan en una Java* Virtual Machine (JVM - Máquina virtual Java) mediante una biblioteca común de manera que la aplicación es un conjunto pequeño de códigos binarios que utiliza una plataforma estandarizada. Esto hace que una aplicación Java* sea rápida de descargar y fácil de ejecutar . Además, Java está instalado y en ejecución en todos los equipos, en todas partes.

Este artículo describe el uso de Java* para desarrollar aplicaciones para netbook y el concepto de desarrollar bibliotecas de componentes de clases Java* que proporcionan un conjunto específico de herramientas que otros desarrolladores pueden utilizar a fin de crear aplicaciones para netbooks.

El Programa Intel AppUp(SM) para desarrolladores es un programa de Intel diseñado para desarrolladores interesados en contribuir al creciente mercado de aplicaciones para netbooks basados en los procesadores Intel® Atom™. El Catálogo para desarrolladores es un depósito de módulos que puede incorporar en su aplicación para un desarrollo acelerado. Incluso puede desarrollar y publicar sus propios componentes para que otros los usen.

Se presenta un caso de practico, estilo tutorial, que guiará al lector durante la creación de una biblioteca de componentes Java* y durante la creación de la documentación y otros metadatos de soporte.

La biblioteca de componentes desarrollada para este ejemplo se denomina VideoLibrary. Se trata de un conjunto de clases Java* que se utilizan para buscar un dispositivo de video, crear un reproductor que muestre el flujo de video y capturar un fotograma del video y lo guarde como un archivo con formato JPEG. El ejemplo, posteriormente, pasa a mostrar el uso de la biblioteca y la creación de los metadatos de apoyo.

El Programa

El programa Intel AppUp(SM) para desarrolladores forma parte de un sistema más grande que incluye:

  • Un sitio web diseñado específicamente para la comunidad de desarrolladores de aplicaciones para netbook.
  • Un proceso de validación para validar y aprobar sus aplicaciones que se implementarán en todo el sistema.
  • Un programa de distribución para poner sus aplicaciones a disposición de los clientes.
  • Un cliente en ejecución en los netbooks de clientes, el cual conecta los clientes con el programa de distribución.

Empecemos

Software y equipo

La biblioteca VideoSource fue creada mediante Java* Standard Edition (SE) usando el Kit para desarrollo Java* SE (JDK) versión 6, Java* Media Framework 2.1.1e y NetBeans 6.7.1. Las herramientas y bibliotecas que son necesarias para crear la biblioteca y la aplicación y la ubicación Web:

Java* SE 6 JRE Este es el runtime básico requerido para ejecutar las aplicaciones Java* http://java.sun.com/javase/downloads/index.jsp
Java* SE JDK 6 Estas son las bibliotecas para desarrollo http://java.sun.com/javase/downloads/index.jsp
Java* NetBeans IDE for SE El entorno de desarrollo http://www.netbeans.org/downloads/index.html
Java* Media Framework 2.1.1e Una biblioteca marco compatible con medios y dispositivos de sonido y videos http://java.sun.com/javase/technologies/desktop/media/jmf/2.1.1/download.html

Desarrollo que se puede realizar en cualquier equipo pero se debe utilizar un netbook de Windows XP para probar los componentes y aplicaciones.

Creación del proyecto

Después de que se instalen las herramientas y bibliotecas de la plataforma, inicie el IDE de NetBeans. Aparece la pantalla de bienvenida.

Seleccione el elemento de menú File (Archivo) - New Project (Nuevo proyecto).

Ahora, seleccione Java* para category (Categoría), Biblioteca clase Java* para Project type (Tipo de proyecto) y seleccione Next (Siguiente).

A continuación, escriba el nombre del proyecto 'VideoLibrary' y seleccione el botón Finish (Finalizar).

A fin de que su biblioteca se pueda incorporar con facilidad en el desarrollo de una aplicación, cree un Paquete y asígnele el nombre VidLib. Para ello, haga clic con el botón secundario del ratón en la entrada de la lista proyectos Source Package (Paquetes de fuente), seleccione New (Nuevo) y seleccione la opción Java* Package (Paquete Java*).

Ahora asigne al paquete el nombre 'VidLibPkg' y seleccione Finish (Finalizar).

El paso final de la configuración es crear una biblioteca de primera clase. Haga clic con el botón secundario del ratón en el nuevo paquete VidLibPkg y seleccione New (Nuevo) y Java Class (Clase Java).

Asigne el nombre de VidLib a la clase y seleccione Finish (Finalizar).

Ahora el proyecto está listo para comenzar la programación.

Programación de la biblioteca

Después de configurar la biblioteca, puede comenzar la programación del proyecto. Esta es la parte difícil.

Planificación

Para crear una biblioteca Java*, el primer dilema es determinar qué debe proporcionar. La mejor manera de hacer esto es idear un concepto con la clase de aplicaciones que utilizaría esta biblioteca. Este tutorial utiliza el concepto de ofrecer a un desarrollador de aplicaciones un conjunto de herramientas básicas para crear una aplicación que muestre una transmisión de video y capture una imagen de marco del mismo. Este ejemplo puede parecer un poco simple para una biblioteca de aplicaciones. Pero recuerde, esta biblioteca ha sido dirigida a aplicaciones para netbook y cuanto más simple mejor. Las bibliotecas se pueden combinar para crear aplicaciones con más características de manera que las bibliotecas deben diseñarse para proporcionar una sola función principal.

Qué es lo que estaría en demanda es otro asunto. ¿Qué le gustaría a un usuario de netbook? ¿Qué está disponible en un netbook que puede ser mejorado con software?

Una vez que sepa lo que la biblioteca debe proporcionar, estudie las bibliotecas y las clases que proporcionarán las herramientas básicas necesarias.

La búsqueda en la documentación de Java* y en Internet determina que se requiere Java* Media Framework para interactuar y usar los dispositivos de videos. Esto se encuentra en las importaciones de javax.media.*.

Codificación

Todo el código para la biblioteca y la aplicación se incluyen al final de este artículo: aquí.

El primer paso consiste en proporcionar un medio para determinar si una cámara de video está conectada con el equipo que está ejecutando la aplicación. Por tanto, el primer método para codificar en las clases es una que proporcione una lista de dispositivos de video potenciales a utilizar. La clase CaptureDeviceManager es una clase administradora que tiene acceso a una lista de dispositivos de captura disponibles. Puede ubicar y regresar los objetos de CaptureDeviceInfo para los dispositivos disponibles.

Existe casi siempre un solo dispositivo de video en un netbook (y en la mayoría de otros equipos). Si existen algunas entradas, el código puede utilizar la primera en la lista como un valor predeterminado, al menos en este ejemplo. El primer método a codificar es getVideoDeviceList. Fíjese que el código agregado tiene varios elementos subrayados color rojo. Esto se debe a que no están definidos. Para solucionar esto, es necesario importar las bibliotecas correctas. En el IDE de NetBeans, esto puede realizarse de forma automática al hacer clic con el botón secundario del ratón y seleccionar Reparar importaciones.

Después de esto, se crean las entradas de importación correctas y se corrige el código fuente.

Las importaciones correctas ahora han sido agregadas al código de fuente.

Observe que el método getVideoDeviceList es público, es decir que la aplicación que utiliza esta clase tiene acceso a la función. Observe también que está definido como estático. Esto significa que este método puede ser accedido sin instantáneas (mediante la opción Nuevo para crear una instancia) al utilizar el nombre de la clase de esta manera: VidLib. getVideoDeviceList(). Además, sin importar cuántas instancias de la clase VidLib se creen, existirá una sola instancia de este método.

El siguiente paso consiste en proporcionar al desarrollador de aplicaciones un medio para que utilice el dispositivo seleccionado y muestre los resultados del video. Component es el componente visual de Player (Reproductor) que sirve para presentar la transmisión del video. Es necesario tener un método para crear el objeto Player y devolver un objeto Component si fuera necesario. El objeto Player sirve para iniciar y detener el video. Cada clase de VidLib debe tener su propio Reproductor, de manera que se agrega como un elemento de clase.

Se crea un objeto MediaLocator a partir del objeto CaptureDeviceInfo proporcionado como un parámetro a la llamada de método. La clase javax.Media.Manager es el punto de acceso para obtener recursos dependientes del sistema. Aquí se crea un reproductor de videos y se obtiene desde el reproductor un componente visual. Al utilizar el método de adición, el componente devuelto puede ser utilizado directamente como una pantalla de video en un objeto JPanel.

Ahora que se han creado los métodos buscar y mostrar, se necesita una manera de capturar una imagen del reproductor de video y guardar la imagen en un archivo. El método getVideoFrameImage devuelve una imagen del reproductor que, posteriormente, puede ser guardada en un archivo.

El método FrameGrabbingControl es una interfaz que sirve para capturar un fotograma de video desde la transmisión del video y lo coloca en javax.media.Buffer. Este control es exportado por Player mediante el método getControl. El fotograma devuelto está en un formato decodificado puro. La clase BufferToImage se utiliza para convertirlo en un objeto de imagen AWT. Image es una clase abstracta y es la superclase de todas las clases que representan las imágenes gráficas y deben ser obtenidas en una manera específica a la plataforma.

Consulte:
El método final que necesita el desarrollador de la aplicación es uno que toma una imagen capturada y guarda la imagen en un archivo. El método saveVidioFrameImage_to_JPEG_File utiliza imágenes y argumentos de ruta del archivo para crear una imagen guardada en el formato JPEG.

La clase BufferedImage es una subclase de Image que sirve para crear un objeto Graphics2D que genera la imagen mediante el método drawImage. La clase FileOutputStream es simplemente un archivo de salida que utiliza JPEGImageEncoder para guardar la imagen después de que codifica los datos de búfer de la imagen en una transmisión de datos JPEG. La clase JPEGEncodeParam encapsula tablas y opciones necesarias para controlar el codificado de las transmisiones de datos JPEG y establece la calidad de la imagen guardada.

Prueba de la Biblioteca de clases

La prueba de la biblioteca de clases no precisa la creación de una aplicación distinta para probar la clase de biblioteca. Al crear un método public static void main(String[] args) le permite ejecutar la biblioteca como una aplicación y probar el código. Cuando la biblioteca de clase se está distribuyendo (consulte a continuación) es prudente eliminar este código para que la biblioteca sea menor en tamaño y que no utilice bibliotecas de interfaz de usuario adicionales (tal como 'swing' en este caso) que no se utilizan en las aplicaciones que usan la biblioteca.

Aquí está una captura de pantalla de la aplicación que muestra los resultados del video de la aplicación en la ventana de la aplicación:

Uso de la biblioteca de clases en una aplicación

Cree un proyecto de aplicación denominada VideoSave usando las selecciones de menú: File (Archivo) - New project (Nuevo proyecto).

Haga clic con el botón secundario en el proyecto y seleccione Properties (Propiedades).

Ahora seleccione Bibliotecas en category (categoría), la ficha Compile (Compilar) y el botón Add JAR/Folder (Agregar JAR/Carpeta).

Ahora busque la carpeta Distribución (dist) del proyecto VideoLibrary.

Ahora seleccione el archivo VideoLibrary.jar con el botón Open (Abrir). Esta es la biblioteca de la clase.

Seleccione el botón OK (Aceptar) y regrese a la edición de IDE. Se ha agregado la entrada de importación que permite utilizar la importación de la biblioteca de clase VidLibPkg.VidLib.

El mismo código en el método main de la biblioteca de clase VidLib puede utilizarse aquí para probar la biblioteca.

Documentación de la biblioteca de clases

Una de las mejores ventajas de Java* es la autodocumentación mediante Javadoc. Haga clic con el botón secundario en un proyecto y seleccione el elemento en Javadoc.

La documentación del desarrollador puede y debería ser agregada para documentar mejor el código. Más información al respecto se encuentra en: Cómo escribir comentarios para documentación para la herramienta Javadoc.

La herramienta Javadoc crea archivos HTML que se colocan en el directorio de distribución dist.

Distribución de bibliotecas

El subdirectorio del proyecto dist contiene todos los archivos necesarios para utilizar la biblioteca.

Para obtener más información examine los archivos JAR File Specification (Especificación de archivo JAR) y Packaging Programs in JAR Files (Programas de encapsulado en archivos JAR).

Recursos
Código de fuente

Biblioteca de clase VidLibPkg VidLib

package VidLibPkg;

import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGEncodeParam;
import com.sun.image.codec.jpeg.JPEGImageEncoder;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Vector;
import javax.media.CannotRealizeException;
import javax.media.CaptureDeviceInfo;
import javax.media.CaptureDeviceManager;
import javax.media.Manager;
import javax.media.MediaLocator;
import javax.media.Player;
import javax.media.control.FrameGrabbingControl;
import javax.media.format.VideoFormat;
import javax.media.util.BufferToImage;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class VidLib {

    public static void main(String[] args) {
        final VidLib vs = new VidLib();
        Vector<CaptureDeviceInfo> dl = VidLib.getVideoDeviceList();
        final Component comp = vs.getVideoComponent(dl.get(0));
        JButton btnCapture = new JButton("Capture");
        btnCapture.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent ae) {
                // capture an image and save it to a file when the button is pressed
                Image img = vs.getVideoFrameImage();
                vs.saveVidioFrameImage_to_JPEG_File(img, ".\\SavedImage.jpg");
            }
        });
        // Create and add a video display panel
        JPanel vp = new JPanel();
        vp.setLayout(new BorderLayout());
        // add the capture button and the video display componnent to the video panel
        vp.add(btnCapture, BorderLayout.SOUTH);
        vp.add(comp, BorderLayout.NORTH);
        // Create the dialog frame
        JFrame f = new JFrame("Video Capture");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setResizable(true);
        f.add("Center", vp);
        // size the Window to fit the preferred size and layouts of its subcomponents.
        f.pack();
        // Center the frame
        f.setLocationRelativeTo(null);
        // let them see it
        f.setVisible(true);
        return;
    }

    public boolean saveVidioFrameImage_to_JPEG_File(Image img, String FilePath) {
        boolean bSuccess = false;
        if ((null == FilePath) || (FilePath.isEmpty())) {
            return (false);
        }
        BufferedImage bi = new BufferedImage(img.getWidth(null),
                img.getHeight(null), BufferedImage.TYPE_INT_RGB);
        Graphics2D g2 = bi.createGraphics();
        g2.drawImage(img, null, null);
        FileOutputStream jpegFileOut = null;
        JPEGImageEncoder encoder = null;
        try {
            jpegFileOut = new FileOutputStream(FilePath);
        } catch (java.io.FileNotFoundException io) {
            io.printStackTrace();
        }
        try {
            encoder = JPEGCodec.createJPEGEncoder(jpegFileOut);
            JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(bi);

            // 0.75 high quality 0.5  medium quality 0.25 low quality
            // forceBaseline - force baseline quantization table
            param.setQuality(1.0f, false);
            encoder.setJPEGEncodeParam(param);
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            encoder.encode(bi);
            jpegFileOut.close();
            bSuccess = true;
        } catch (java.io.IOException io) {
            io.printStackTrace();
        }
        return (bSuccess);
    }

    public Image getVideoFrameImage() {
        Image img = null;
        try {
            FrameGrabbingControl fgc =
                    (FrameGrabbingControl) vidplayer.getControl("javax.media.control.FrameGrabbingControl");
            javax.media.Buffer buf = fgc.grabFrame();
            // Convert it to an image
            BufferToImage btoi = new BufferToImage((VideoFormat) buf.getFormat());
            img = btoi.createImage(buf);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return (img);
    }
    Player vidplayer = null;

    public Component getVideoComponent(CaptureDeviceInfo cdi) {
        Component comp = null;
        MediaLocator ml = null;
        if (null != cdi) {
            try {
                ml = cdi.getLocator();
            } catch (Exception e) {
                e.printStackTrace();
            }
            try {
                try {
                    vidplayer = Manager.createRealizedPlayer(ml);
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (CannotRealizeException e) {
                    e.printStackTrace();
                }
            } catch (javax.media.NoPlayerException e) {
                e.printStackTrace();
            }
            try {
                comp = vidplayer.getVisualComponent();
            } catch (Exception e) {
                e.printStackTrace();
            }
            try {
                vidplayer.start();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return (comp);
    }

    public static Vector<CaptureDeviceInfo> getVideoDeviceList() {

        Vector devices;
        Enumeration dev_enum;
        CaptureDeviceInfo cdi;
        // <CaptureDeviceInfo> checks that the type is CaptureDeviceInfo
        Vector<CaptureDeviceInfo> videoDevices = null;
        try {
            devices = (Vector) CaptureDeviceManager.getDeviceList(null).clone();
            dev_enum = devices.elements();

            if (devices != null && devices.size() > 0) {
                // <CaptureDeviceInfo> checks that the type is CaptureDeviceInfo
                videoDevices = new Vector<CaptureDeviceInfo>();
                javax.media.Format[] formats;

                while (dev_enum.hasMoreElements()) {
                    cdi = (CaptureDeviceInfo) dev_enum.nextElement();
                    formats = cdi.getFormats();

                    for (int j = 0; j < formats.length; j++) {
                        if (formats[j] instanceof VideoFormat) {
                            videoDevices.addElement(cdi);
                            break;
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return (videoDevices);
    }
}

Aplicación VideoSave Main.java

package videosave;

import VidLibPkg.VidLib;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Vector;
import javax.media.CaptureDeviceInfo;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

/**
 *
 * @author me
 */
public class Main {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        final VidLib vs = new VidLib();
        Vector<CaptureDeviceInfo> dl = VidLib.getVideoDeviceList();
        final Component comp = vs.getVideoComponent(dl.get(0));
        JButton btnCapture = new JButton("Capture");
        btnCapture.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent ae) {
                // capture an image and save it to a file when the button is pressed
                Image img = vs.getVideoFrameImage();
                vs.saveVidioFrameImage_to_JPEG_File(img, ".\\SavedImage.jpg");
            }
        });
        // Create and add a video display panel
        JPanel vp = new JPanel();
        vp.setLayout(new BorderLayout());
        // add the capture button and the video display componnent to the video panel
        vp.add(btnCapture, BorderLayout.SOUTH);
        vp.add(comp, BorderLayout.NORTH);
        // Create the dialog frame
        JFrame f = new JFrame("Video Capture");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setResizable(true);
        f.add("Center", vp);
        // size the Window to fit the preferred size and layouts of its subcomponents.
        f.pack();
        // Center the frame
        f.setLocationRelativeTo(null);
        // let them see it
        f.setVisible(true);
        return;
    }

}
Para obtener más información sobre las optimizaciones del compilador, consulte el aviso sobre la optimización.