Entwickeln von Java-Komponenten für Netbooks


Leitfaden für die Entwicklung von Bibliotheken der Java* Klasse, die für Entwickler von Netbook-Anwendungen konzipiert sind Einleitung

Netbooks haben in kurzer Zeit stark an Popularität gewonnen. Diese Geräte haben oft in puncto Prozessorleistung, Arbeitsspeicher, Festplattengröße, Displaygröße und DVD-Player eine weniger gute Ausstattung als Notebooks, allerdings punkten sie mit ihrem kompakten Format und langen Akkulaufzeiten. Sie eignen sich ideal für das Surfen im Internet, E-Mails und „Cloud Computing“, bei dem die Dateien der Benutzer in der „Wolke“, also auf Remote-Servern, gespeichert und bearbeitet werden.

Java* ist eine sehr gute Wahl für die Entwicklung kleiner Anwendungen, die Netbook-Nutzern praktische Funktionen zur Verfügung stellen. Java* ist eine perfekte Plattform für die Entwicklung von Netbook-Anwendungen: Java* ist eine ausgereifte, weitverbreitete und gut dokumentierte Entwicklungsplattform. Außerdem ist Java* praktisch kostenlos. Java* Programme werden in einer Java* Virtual Machine (JVM) ausgeführt und verwenden eine gemeinsame Bibliothek, wodurch Anwendungen einen geringen Umfang an binärem Code haben, der eine standardisierte Plattform nutzt. Dadurch lassen sich Java* Anwendungen schnell herunterladen und einfach ausführen. Und Java ist überall installiert und wird auf praktisch jedem System ausgeführt.

In diesem Artikel wird die Verwendung von Java* bei der Entwicklung von Netbook-Anwendungen erklärt sowie das Konzept der Entwicklung von Komponentenbibliotheken der Java* Klassen, die spezielle Toolsammlungen bereitstellen, die von anderen Entwicklern für das Erstellen von Netbook-Anwendungen eingesetzt werden können.

Das Intel AppUp(SM) Developer Program richtet sich an Entwickler, die daran interessiert sind, neue Anwendungen für den wachsenden Markt von Netbooks mit Intel® Atom™ Prozessoren zu erstellen. Im Komponentenkatalog steht eine umfangreiche Auswahl an Bausteinen zur Verfügung, die Sie in Ihrer Anwendung integrieren und damit deren Entwicklung beschleunigen können. Sie können auch selbst Komponenten für andere Entwickler erstellen und veröffentlichen.

Im Folgenden führt Sie ein Anwendungsbeispiel, das wie ein Tutorial aufgebaut ist, durch die Entwicklung einer Java* Komponentenbibliothek, deren Verwendung in einer Anwendung und dem Erstellen der ergänzenden Dokumentation und Metadaten.

Die für dieses Beispiel entwickelte Komponentenbibliothek hat den Namen VideoLibrary. Sie besteht aus einer Sammlung von Java* Klassen, die verwendet werden, um ein Videogerät zu suchen, einen Player für die Wiedergabe des Videostreams zu erstellen, den Videostream anzuzeigen und ein Framebild des Videos aufzunehmen und als JPEG-Datei zu speichern. Anschließend zeigt das Beispiel, wie die Bibliothek in einer Anwendung genutzt und ergänzende Metadaten erstellt werden.

Das Programm

Das Intel AppUp(SM) Developer Program ist Teil eines größeren Systems, zu dem folgende Bereiche gehören:

  • Eine Website, die sich speziell an Entwickler von Netbook-Anwendungen richtet.
  • Ein Validierungsprozess für die Validierung und Annahme von Anwendungen, die über das System vertrieben werden.
  • Ein Vertriebsprogramm, das Ihre Anwendungen für Kunden bereitstellt.
  • Ein Client, der auf den Netbooks von Kunden ausgeführt wird und diese mit dem Vertriebsprogramm verbindet.

Erste Schritte

Software und Ausstattung

Die VideoSource-Bibliothek wurde mit der Java* Standard Edition (SE) mit dem Java* SE Development Kit (JDK) Version 6, dem Java* Media Framework 2.1.1e und NetBeans 6.7.1 erstellt. Folgende Tools und Bibliotheken werden für das Erstellen der Bibliothek und Anwendung benötigt:

Java* SE 6 JRE Für die Ausführung von Java* Anwendungen erforderliche Standardlaufzeit http://java.sun.com/javase/downloads/index.jsp
Java* SE JDK 6 Entwicklungsbibliotheken http://java.sun.com/javase/downloads/index.jsp
Java* NetBeans IDE für SE Entwicklungsumgebung http://www.netbeans.org/downloads/index.html
Java* Media Framework 2.1.1e Framework-Bibliothek mit Unterstützung für Audio- und Videomedien sowie Geräte http://java.sun.com/javase/technologies/desktop/media/jmf/2.1.1/download.html

Die Entwicklung kann auf einem beliebigen System erfolgen, allerdings sollten Komponenten und Anwendungen auf einem Netbook mit Windows XP getestet werden.

Projekt erstellen

Nachdem Sie die benötigten Plattformtools und Bibliotheken installiert haben, starten Sie die NetBeans IDE. Der Begrüßungsbildschirm wird angezeigt.

Wählen Sie die Menüoption "File - New Project“.

Wählen Sie anschließend Java* als Kategorie und Java* Class Library als Projekttyp und klicken Sie auf Next.

Geben Sie den Projektnamen „VideoLibrary“ ein und klicken Sie auf „Finish“.

Damit Ihre Bibliothek bei der Anwendungsentwicklung einfach integriert werden kann, erstellen Sie ein Paket und nennen Sie es VidLib. Um dies auszuführen, klicken Sie mit der rechten Maustaste auf den Projekteintrag „Source Package“ und wählen Sie New und anschließend Java* Package.

Geben Sie den Paketnamen VidLibPkg ein und klicken Sie auf „Finish“.

Im letzten Setupschritt wird die erste Bibliotheksklasse erstellt. Klicken Sie mit der rechten Maustaste auf das neue VidLibPkg-Paket und wählen Sie New – Java Class.

Geben Sie der Klasse den Namen VidLib und klicken Sie auf Finish.

Das Projekt ist nun fertig angelegt und Sie können mit der Programmierung beginnen.

Programmieren der Bibliothek

Nachdem das Bibliotheksprojekt eingerichtet wurde, können Sie mit der Programmierung beginnen. Und damit folgt der schwierigere Teil.

Planung

Beim Erstellen einer Java*-Bibliothek muss zuerst festgelegt werden, was die Bibliothek bereitstellen soll. Am besten wird hierfür ein Konzept erstellt, das aufzeigt, welche Arten von Anwendungen diese Bibliothek verwenden werden. In diesem Tutorial wird folgendes Konzept verwendet: Einem Anwendungsentwickler wird eine Sammlung grundlegender Tools für die Entwicklung einer Anwendung an die Hand gegeben, die einen Videostream anzeigen und daraus ein Einzelbild aufnehmen kann. Dieses Beispiel mag für eine Anwendungsbibliothek recht einfach erscheinen. Aber denken Sie daran: Die Anwendungen richten sich an Netbook-Benutzer und hier gilt – je weniger komplex, desto besser. Bibliotheken können kombiniert werden, um Anwendungen mit einer umfangreicheren Funktionalität zu erstellen. Daher sollten Ihre Bibliotheken jeweils nur auf eine Kernfunktion ausgerichtet sein.

Außerdem sollten Sie ermitteln, für welche Anwendungen Bedarf besteht. Was wünschen sich Netbook-Nutzer? Was steht auf Netbooks zur Verfügung, das sich durch Software erweitern lässt?

Sobald Sie die Funktionalität der Bibliothek definiert haben, sollten Sie sich eingehender mit den Bibliotheken und Klassen beschäftigen, die die grundlegenden Tools bereitstellen werden.

Nach Durchsicht der Java-Dokumentation und Recherchen im Internet werden Sie feststellen, dass das Java Media Framework als Schnittstelle zu und für die Verwendung von Videogeräten benötigt wird. Dies befindet sich in den javax.media.*-Importen.

Code entwickeln

Den gesamten Code für die Bibliothek und die Anwendung finden Sie hier am Ende dieses Artikels.

Der erste Schritt besteht darin festzulegen, ob der Computer, auf dem die Anwendung ausgeführt wird, mit einer Videokamera verbunden ist. Daher muss für diese Klasse als erstes eine Methode geschrieben werden, die eine Liste der potenziell verwendbaren Videogeräte liefert. Die Klasse CaptureDeviceManager ist eine Managerklasse, die Zugriff auf eine Liste verfügbarer Aufnahmegeräte bietet. Sie kann CaptureDeviceInfo-Objekte für verfügbare Geräte lokalisieren und zurückgeben.

Netbooks (und die meisten Computer) verfügen fast immer nur über ein Videogerät. Wenn Einträge vorhanden sein, verwendet der Code den ersten Listeneintrag als Standard, zumindest in diesem Beispiel. Zuerst wird die Methode getVideoDeviceList codiert. Beachten Sie, dass im hinzugefügten Code mehrere Elemente rot unterstrichen sind. Diese Formatierung weist darauf hin, dass die Elemente nicht definiert sind. Um dies zu beheben, müssen die richtigen Bibliotheken importiert werden. In der NetBeans-IDE kann dies automatisch durchgeführt werden. Klicken Sie hierzu im Quellcodebereich mit der rechten Maustaste und wählen Sie Fix Imports.

Nach diesem Schritt werden die richtigen Importeinträge erstellt und der Quellcode ist nun korrekt.

Die korrekten Importeinträge wurden zum Quellcode hinzugefügt.

Beachten Sie, dass die getVideoDeviceList-Methode öffentlich ist. Das bedeutet, dass die Anwendung, die diese Klasse nutzt, Zugriff auf die Funktion hat. Beachten Sie ebenfalls, dass sie als statisch definiert ist. Das bedeutet, dass der Zugriff auf diese Methode ohne Instanziierung erfolgen kann, indem der Klassenname wie folgt angegeben wird: VidLib. getVideoDeviceList(). Unabhängig davon, wie viele Instanzen der VidLib-Klasse erstellt werden, gibt es immer nur eine Instanz dieser Methode.

Im nächsten Schritt erhält der Anwendungsentwickler die Möglichkeit, das ausgewählte Gerät zu verwenden und das Video wiederzugeben. Die Component ist die visuelle Komponente des Players, die für die Darstellung des Videostreams genutzt wird. Es wird eine Methode benötigt, die den Player erstellen und eine Component zurückgeben kann. Das Player-Objekt wird verwendet, um das Video zu starten und die Wiedergabe zu beenden. Da jede VidLib-Klasse ihren eigenen Player haben muss, wird ein Player als Klassenelement hinzugefügt.

Ein MediaLocator-Objekt wird vom CaptureDeviceInfo-Objekt erstellt und als Parameter an den Methodenaufruf übergeben. Die javax.Media.-Manager-Klasse ist der Zugriffspunkt zum Abrufen systemabhängiger Ressourcen. Hier erstellt sie einen Videoplayer und vom Player wird eine visuelle Komponente bezogen. Die zurückgegebene Komponente kann direkt als Videofenster in einem JPanel-Objekt durch die Verwendung der Add-Methode genutzt werden.

Da die Methoden zum Suchen und Anzeigen eines Videos nun erstellt sind, muss als nächstes eine Möglichkeit geschaffen werden, um ein Bild im Videoplayer aufzunehmen und in einer Datei zu speichern. Die getVideoFrameImage-Methode gibt ein Bild vom Player zurück, das anschließend in einer Datei gespeichert werden kann.

FrameGrabbingControl ist eine Schnittstelle, mit der im Videostream ein Standbild aufgenommen und in den javax.media.Buffer eingefügt werden kann. Dieses Steuerelement wird vom Player mit der getControl-Methode exportiert. Das zurückgegebene Einzelbild liegt in einem nicht codierten Rohformat vor. Mithilfe der BufferToImage-Klasse wird es in ein AWT-Bildobjekt konvertiert. Image ist eine abstrakte Klasse und die übergeordnete Klasse aller Klassen, die Grafiken repräsentieren und in einer plattformabhängigen Art abgerufen werden müssen.

Siehe:
Zuletzt benötigt der Anwendungsentwickler eine Methode, die ein aufgenommenes Bild in einer Datei speichert. Die saveVidioFrameImage_to_JPEG_File-Methode verwendet Bild- und Dateipfadargumente zum Erstellen eines im JPEG-Format gespeicherten Bildes.

BufferedImage ist eine Image-Unterklasse, mit der ein Graphics2D-Objekt erstellt wird, das das Bild mit der drawImage-Methode rendert. Die FileOutputStream-Klasse ist einfach eine Ausgabedatei, die vom JPEGImageEncoder verwendet wird, um das Bild nach der Codierung der Bildpufferdaten in einem JPEG-Datenstrom zu speichern. JPEGEncodeParam verkapselt Tabellen und Optionen, die zur Steuerung der Codierung der JPEG-Datenströme erforderlich sind, und legt die Qualität des gespeicherten Bildes fest.

Testen der Klassenbibliothek

Zum Testen der Klassenbibliothek muss keine separate Anwendung erstellt werden. Durch das Erstellen der public static void main(String[] args)-Methode können Sie die Bibliothek als Anwendung ausführen und den Code testen. Wenn die Klassenbibliothek verteilt wird (siehe unten), sollte dieser Code entfernt werden, damit die Bibliothek kleiner ist und keine zusätzlichen UI-Bibliotheken (wie in diesem Fall Swing) verwendet, die in den Anwendungen, die diese Bibliothek nutzen, nicht benötigt werden.

Der folgende Screenshot zeigt die Videoausgabe der Anwendung in einem Anwendungsfenster:

Verwenden der Klassenbibliothek in einer Anwendung

Erstellen Sie das Anwendungsprojekt VideoSave mit der Menüoption File – New Project.

Klicken Sie mit der rechten Maustaste auf das Projekt und wählen Sie „Properties“.

Wählen Sie nun die Kategorie „Libraries“ und klicken Sie im Register Compile auf die Schaltfläche Add JAR/Folder.

Gehen Sie zum Verzeichnis „dist“ (distribution) des VideoLibrary-Projekts.

Öffnen Sie anschließend die Datei VideoLibrary.jar mit der Schaltfläche Open. Dies ist die Klassenbibliothek.

Klicken Sie auf OK und kehren Sie zur Bearbeitungs-IDE zurück. Der Importeintrag, der Ihnen die Verwendung des Klassenbibliothekimports VidLibPkg.VidLib; ermöglicht, wurde hinzugefügt.

Derselbe Code in der main-Methode der VidLib-Klassenbibliothek kann hier zum Testen der Bibliothek verwendet werden.

Dokumentieren der Klassenbibliothek

Einer der besonderen Vorteile von Java* ist die Selbstdokumentation mittels Javadoc. Klicken Sie ein Projekt mit der rechten Maustaste an und wählen Sie den Eintrag „Javadoc“.

Entwickler sollten zur Erläuterung des Codes immer eine ergänzende Dokumentation hinzufügen. Weitere Informationen zu diesem Thema finden Sie hier: „How to Write Doc Comments for the Javadoc Tool“.

Das Javadoc-Tool erstellt HTML-Dateien, die im Distributionsverzeichnis („dist“) gespeichert werden.

Bibliothekverteilung

Das Projektunterverzeichnis „dist“ beinhaltet alle Dateien, die für die Verwendung der Bibliothek benötigt werden.

Weitere Informationen finden Sie unter „JAR File Specification“ und „Packaging Programs in JAR Files“.

Ressourcen
Quellcode

Klassenbibliothek „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);
    }
}

VideoSave-Anwendung 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;
    }

}
Nähere Informationen zur Compiler-Optimierung finden Sie in unserem Optimierungshinweis.