Current Page: Greybox » Authoring » Course ID: medieninformatik » Modules » Module ID: m06 » Learning Units » Unit ID: 3_03
Last Modified:Tuesday, 2015-05-05 - 08:09:01
 
Tools: ValidatePreview XML Preview HTML Preview PDF
Alternative: Printable HTML

 

Learning Unit ID: 3_03
Title: JMF Plug-Ins - Codecs und Effekte
Abstract: In dieser LU wird die Funktionsweise von Codecs und Effekten in JMF erläutert. Neben der Vorstellung in JMF vorhandener Codecs und Effekte, wird besonders auf die Gestaltung eigener Codecs und Effekte eingegangen. Es werden Beispiele und lauffähige Applets für Bild-, Video und Audioeffekte präsentiert.
 
Status:

 

Version: 7.1
History:

Acronyme done.

Rechtschreibung gecheckt.

Unbekannte Character ausgebessert.

Sourcecode repariert.

Sourcecode formatiert.


Author
Author 1: Bernhard Tatzmann E-Mail: bernhard@isys.uni-klu.ac.at
Author 2: (empty) E-Mail: (empty)
Author 3: (empty) E-Mail: (empty)
Author 4: (empty) E-Mail: (empty)
Author 5: (empty) E-Mail: (empty)
Organization: Universität Klagenfurt - Institut für Informatik-Systeme

Content

Einleitung

1

Auto

  • Codecs und Effekte werden durch Plug-Ins realisiert (untersten Ebene der JMF464-Architektur)
    • JMF464 stellt bereits einige Codecs und Konverter zur Verfügung
    • JMF464 erlaubt die Implementierung neuer Plug-Ins durch das Bereitstellen von Interfaces

Installierten Codecs und Filter werden in der JMF464 Registry angezeigt (Karteikarte "Plug-Ins"):

Auto PC

JMF Registry Editor - PlugIns

Auto PDA_Phone

JMF Registry Editor - PlugIns

2

Auto

Wie in LU Das Java Media Framework erläutert wird, können diverse Codecs und Effekte in das JMF464 Datenverarbeitungsmodell eingebaut werden. Diese werden ebenso wie das Multiplexen und Demultiplexen durch Plug-Ins realisiert, die in der untersten Ebene der JMF464-Architektur angesiedelt sind. JMF464 stellt bereits einige Codecs und Konverter zur Verfügung und erlaubt die Implementierung neuer Plug-Ins durch das Bereitstellen von Interfaces.

Die installierten Codecs und Filter werden in der JMF464 Registry in der Karteikarte "Plug-Ins" angezeigt (siehe folgende Abbildung).

Auto PC

JMF Registry Editor - PlugIns

Auto PDA_Phone

JMF Registry Editor - PlugIns

Video Codecs

1

Auto

  • Codecs können zur Verarbeitung von Daten eines komprimierten Datenformats angewendet werden
  • Decoder:
    • Steht am Beginn des Verarbeitungsprozesses
    • Videodaten: Decoder wandelt komprimierte Daten in das RGB302 bzw. YUV304 Format um
  • Encoder:
    • Ist nötig wenn die Daten in einem bestimmten Videoformat in eine Datensenke geschrieben oder "gestreamt" werden sollen

JMF464 stellt nicht für jedes Videoformat, für das ein Decoder bereitgestellt wird, auch einen Encoder zur Verfügung:

Video Codecs: Liste aller von JMF 2.1.1 Windows Performance Pack zur Verfügung gestellten Video Codecs (Caption)
Videoformate Klassenname De- Encoder
MPEG31 com.ibm.media.codec.video.mpeg.MpegVideo x  
Cinepak

com.sun.media.codec.video.cinepak.NativeEncoder/
com.sun.media.codec.video.cinepak.NativeDecoder

x x
H261 com.sun.media.codec.video.h261.NativeDecoder x  
H263

com.sun.media.codec.video.vh263.NativeEncoder/
com.sun.media.codec.video.vh263.NativeDecoder/
com.sun.media.codec.video.h263.JavaDecoder

x x
JPEG29 com.sun.media.codec.video.jpeg.NativeEncoder/
com.sun.media.codec.video.jpeg.NativeDecoder
x x
MJPG467 com.sun.media.codec.video.jpeg.NativeEncoder/
com.sun.media.codec.video.jpeg.NativeDecoder
x x

JavaRGBConverter und RGBScaler

  • Abgesehen von Codecs für komprimierte Videoformate stellt JMF464 auch Codecs für andere Zwecke bereit
  • JavaRGBConverter und RGBScaler beschäftigen sich nicht mit komprimierten Videoformaten
  • Daten im RGB302 Format können hinsichtlich ihrer Formateigenschaften (Größe, Farbtiefe, usw.) bearbeitet werden
  • JavaRGBConverter:
    • Im Paket com.sun.media.codec.video.colorspace
    • Funktioniert jedoch nur, wenn er vom Prozessor selbst eingesetzt wird
      • Bsp.: Ein- und Ausgabeformat unterscheiden sich leicht voneinander
  • RGBScaler: Lässt sich vom Programmierer gezielt einsetzen
    • colorspace Package
    • Dient zum Verändern der PAL167-Auflösung

 

  • Hinzufügen eines Codecs zum Verarbeitungsprozess:
    • Zugriff auf die entsprechende Spur mit getTrackControls
    • Array der Methode setCodecChain enthält alle Codecs, die im Verarbeitungsprozess angewendet werden sollen
Beispiel Videoskalierungseffekt
Anwendungsbeispiel der Klasse RGBScaler
 //Erzeuge eine Instanz des RGBScaler Codecs
 RGBScaler scaler = new RGBScaler(new Dimension(20,20));
 Codec codecs[] = new Codec[1];
 codecs[0] = scaler;
 //Füge den Codec der Liste der TrackControls hinzu
 TrackControl tracks[] = processor.getTrackControls();
 tracks[0].setCodecChain(codecs);
Videoskalierungseffekt

Verwendung des Applets

VCM-Konverter

  • VCM468 (Video Compression Manager)-Konverter:
    • Wrapper-Codec
    • Nur in Windowsversionen von JMF464 enthalten
    • Erlaubt es Codecs zu verwenden, die im Betriebssystem installiert sind (siehe Systemsteuerung - > Geräte Manager), auch wenn gar keine JMF464 Implementierung für diesen Codec zur Verfügung steht
    • Bsp. Lesen einer mit DivX (Digital Video Express) komprimierte Videodatei:
      • Decoder im Betriebssystem installiert
      • Mit VCM468-Konverters kann auf diese Datei zugegriffen werden

2

Auto

Sollen Daten verarbeitet werden, die in Form eines komprimierten Datenformats zur Verfügung stehen, so muss zu Beginn des Verarbeitungsprozesses der Decoder stehen. Im Falle von Videodaten wandelt dieser die komprimierten Daten in das RGB302 bzw. YUF304 Format um ED04. Sollen die Daten in einem bestimmten Videoformat in eine Datensenke geschrieben werden oder "gestreamt" werden, so ist es nötig, den erforderlichen Encoder zur Verfügung zu haben. Wie aus folgender Tabelle entnommen werden kann, stellt JMF464 nicht für jedes Videoformat, für das ein Decoder bereitgestellt wird, auch einen Encoder zur Verfügung.

JMF464 stellt bereits folgende Video-Codecs bereit:

Video Codecs: Liste aller von JMF 2.1.1 Windows Performance Pack zur Verfügung gestellten Video Codecs (Caption)

Videoformate Klassenname De- Encoder
MPEG31 com.ibm.media.codec.video.mpeg.MpegVideo x  
Cinepak

com.sun.media.codec.video.cinepak.NativeEncoder/
com.sun.media.codec.video.cinepak.NativeDecoder

x x
H261 com.sun.media.codec.video.h261.NativeDecoder x  
H263

com.sun.media.codec.video.vh263.NativeEncoder/
com.sun.media.codec.video.vh263.NativeDecoder/
com.sun.media.codec.video.h263.JavaDecoder

x x
JPEG29 com.sun.media.codec.video.jpeg.NativeEncoder/
com.sun.media.codec.video.jpeg.NativeDecoder
x x
MJPG467 com.sun.media.codec.video.jpeg.NativeEncoder/
com.sun.media.codec.video.jpeg.NativeDecoder
x x

JavaRGBConverter und RGBScaler

Abgesehen von den oben erwähnten Codecs, die sich mit komprimierten Videoformaten beschäftigen, stehen auch zwei Codecs zur Verfügung, mit Hilfe derer es möglich ist, die im RGB Format vorliegenden Daten hinsichtlich ihrer Formateigenschaften (Größe, Farbtiefe, usw.) zu bearbeiten.

Der erste dieser beiden Codecs nennt sich JavaRGBConverter und ist im Paket com.sun.media.codec.video.colorspace zu finden. Er funktioniert jedoch nur, wenn er vom Prozessor selbst eingesetzt wird. Dies geschieht z.B. dann, wenn sich Ein- und Ausgabeformat leicht voneinander unterscheiden. Wird der Codec vom Programmierer selbst in Verarbeitungsprozess eingebunden hat dies keine Auswirkungen, da die gesetzten Werte vom Codec-Aufruf des Prozessors wieder überschrieben werden.

Im Gegensatz zum Vorigen lässt sich der Codec RGBScaler vom Programmierer gezielt einsetzen. Er ist ebenfalls im colorspace Package enthalten und dient zum Verändern der PAL167-Auflösung.

Das Hinzufügen eines Codecs zum Verarbeitungsprozess durch den Programmierer wird folgendermaßen durchgeführt:

Hinzufügen eines Codecs
 TrackControl tracks[] = processor.getTrackControls();
 tracks[0].setCodecChain(Codec[]);
Auto

Über die Methode getTrackControls erhält man Zugriff auf die entsprechende Spur, die mit einem Codec versehen werden soll. Das Array, das der Methode setCodecChain übergeben wird, enthält alle Codecs, die im Verarbeitungsprozess in vorgegebener Reihenfolge zur Anwendung kommen sollen. Die Verwendung des RGBScaler Codec wird im folgenden Beispielapplet unter Anwendung dieser Methodik gezeigt.

Beispiel Videoskalierungseffekt
Auto
 //Erzeuge eine Instanz des RGBScaler Codecs
 RGBScaler scaler = new RGBScaler(new Dimension(20,20));
 Codec codecs[] = new Codec[1];
 codecs[0] = scaler;
 //Füge den Codec der Liste der TrackControls hinzu
 TrackControl tracks[] = processor.getTrackControls();
 tracks[0].setCodecChain(codecs);
Videoskalierungseffekt

Verwendung des Applets

Das Applet bietet die Möglichkeit der Betrachtung einer über die Appletparameter definierten Videodatei, wobei die Auflösung durch den angewendeten Effekt drastisch reduziert wird. Zum Betrachten des Applets ist eine lokale Installation des Java Media Frameworks(http://java.sun.com/products/java-media/jmf/2.1.1/download.html), sowie eine Webcam nötig.

VCM-Konverter

Ein weiterer bereits in JMF464 enthaltener Codec ist der VCM468 (Video Compression Manager)-Konverter. Dieser Wrapper-Codec ist nur in Windowsversionen von JMF464 enthalten und erlaubt es Codecs zu verwenden, die im Betriebssystem installiert sind (siehe Systemsteuerung - > Geräte Manager), auch wenn gar keine JMF464 Implementierung für diesen Codec zur Verfügung steht. Soll z.B. eine mit DivX323 (Digital Video Express) komprimierte Videodatei gelesen werden, und ist der Decoder im Betriebssystem installiert, so kann mit Hilfe des VCM468-Konverters auf diese Datei zugegriffen werden ED04.

Audio Codecs

1

Auto

  • JMF464 stellt auch bereits einige Audio Codecs zur Verfügung
  • Nicht für jedes Format ein Encoder verfügbar
  • Aus lizenzrechtlichen Gründen musste die Unterstützung des MP395 (MPEG Audio Layer III) Formats wieder aus JMF464 entfernt werden

Audio Codecs: Liste aller von JMF 2.1.1 Windows Performance Pack zur Verfügung gestellten Audio Codecs (Caption)

Audioformate Klassenname De- Encoder
G.723 com.ibm.media.codec.audio.g723.NativeDecoder,
com.ibm.media.codec.audio.g723.JavaDecoder/
com.ibm.media.codec.audio.g723.NativeEncoder
x x
GSM436 com.ibm.media.codec.audio.gsm.NativeDecoder,
com.ibm.media.codec.audio.gsm.NativeDecoder_ms,
com.ibm.media.codec.audio.gsm.JavaDecoder,
com.ibm.media.codec.audio.alaw.JavaDecoder_ms/
com.ibm.media.codec.audio.gsm.NativeEncoder,
com.ibm.media.codec.audio.gsm.JavaEncoder,
com.ibm.media.codec.audio.gsm.JavaEncoder_ms
x x
MPEG31 Layer II Audio com.ibm.media.codec.audio.mpa.NativeDecoder,
com.ibm.media.codec.audio.mpa.JavaDecoder/
com.ibm.media.codec.audio.mpa.NativeEncoder
x x
IMA4 com.ibm.media.codec.audio.ima4.JavaDecoder,
com.ibm.media.codec.audio.ima4.JavaDecoder_ms/
com.ibm.media.codec.audio.ima4.JavaEncoder,
com.ibm.media.codec.audio.ima4.JavaEncoder_ms
x x
DVI com.ibm.media.codec.audio.dvi.JavaDecoder/
com.ibm.media.codec.audio.dvi.JavaEncoder
x x
MS ADPCM470 com.ibm.media.codec.audio.msadpcm.JavaDecoder x  
μ -LAW (US Telephony Format) com.ibm.media.codec.audio.ulaw.JavaDecoder/
com.ibm.media.codec.audio.ulaw.JavaEncoder
x x
a-LAW (European Telephony Format) com.ibm.media.codec.audio.alaw.JavaDecoder x  

ACM-Codec

  • ACM469-Codec (Audio Compression Manager):
    • Pendant zum VCM468-Konverter bei den Video Codecs
    • Audio Codec Wrapperklasse
    • Im Windows Performance Pack (JMF464 Version 2.1.1) in der Klasse com.ibm.media.codec.audio.ACMCodec implementiert
    • Im Windows Betriebsystem installierte Codecs können ohne die Existenz einer JMF464 Implementierung verwenden werden

PCMtoPCM-Codec

  • PCMtoPCM-Codec:
    • Pendant zu den Video Codecs JavaRGBConverter und RGBScaler
    • Ein- und Ausgabeformate lassen sich innerhalb einer Verarbeitungskette (abgesehen von den Abtastraten) auf das gleiche Format bringen
    • PCMtoPCM-Codec wird von JMF464 automatisch eingesetzt, wenn es notwendig ist
    • Kann jedoch keine Konvertierung der Abtastrate durchführen

Rate-Cvrt-Codec und RCModule-Codec

  • Rate-Cvrt Codec wandelt verschiedenste Samplingraten in einander um
  • Vorerst nur Konvertierungen auf 8 kHz, 16 Bit Stereo möglich

2

Auto

JMF464 stellt auch bereits einige Audio Codecs zur Verfügung. Die Kodierung und Dekodierung werden dabei wieder von separaten Klassen durchgeführt, wobei im Gegensatz zum Decoder nicht für jedes Format ein Encoder zur Verfügung steht.

Audio Codecs: Liste aller von JMF 2.1.1 Windows Performance Pack zur Verfügung gestellten Audio Codecs (Caption)

Audioformate Klassenname De- Encoder
G.723 com.ibm.media.codec.audio.g723.NativeDecoder,
com.ibm.media.codec.audio.g723.JavaDecoder/
com.ibm.media.codec.audio.g723.NativeEncoder
x x
GSM436 com.ibm.media.codec.audio.gsm.NativeDecoder,
com.ibm.media.codec.audio.gsm.NativeDecoder_ms,
com.ibm.media.codec.audio.gsm.JavaDecoder,
com.ibm.media.codec.audio.alaw.JavaDecoder_ms/
com.ibm.media.codec.audio.gsm.NativeEncoder,
com.ibm.media.codec.audio.gsm.JavaEncoder,
com.ibm.media.codec.audio.gsm.JavaEncoder_ms
x x
MPEG31 Layer II Audio com.ibm.media.codec.audio.mpa.NativeDecoder,
com.ibm.media.codec.audio.mpa.JavaDecoder/
com.ibm.media.codec.audio.mpa.NativeEncoder
x x
IMA4 com.ibm.media.codec.audio.ima4.JavaDecoder,
com.ibm.media.codec.audio.ima4.JavaDecoder_ms/
com.ibm.media.codec.audio.ima4.JavaEncoder,
com.ibm.media.codec.audio.ima4.JavaEncoder_ms
x x
DVI com.ibm.media.codec.audio.dvi.JavaDecoder/
com.ibm.media.codec.audio.dvi.JavaEncoder
x x
MS ADPCM470 com.ibm.media.codec.audio.msadpcm.JavaDecoder x  
μ -LAW (US Telephony Format) com.ibm.media.codec.audio.ulaw.JavaDecoder/
com.ibm.media.codec.audio.ulaw.JavaEncoder
x x
a-LAW (European Telephony Format) com.ibm.media.codec.audio.alaw.JavaDecoder x  

Auto

Zusätzlich zu den hier genannten Codecs enthielten frühere Versionen von JMF464 auch den Codec für die Unterstützung des populären MP395 (MPEG Audio Layer III) Formats. Aus lizenzrechtlichen Gründen musste dieser Codec aber von SUN wieder aus JMF464 entfernt werden ED04.

ACM-Codec

Analog zum VCM468-Konverter bei den Video Codecs gibt es auch eine Audio Codec Wrapperklasse. Der Wrapper nennt sich ACM469-Codec (Audio Compression Manager) und ist im Windows Performance Pack der JMF464 Version 2.1.1 in der Klasse com.ibm.media.codec.audio.ACMCodec implementiert. Mit dieser Klasse lassen sich wiederum im Windows Betriebsystem installierte Codecs ohne die Existenz einer JMF464 Implementierung verwenden ED04.

PCMtoPCM-Codec

Das Pendant zu den Video Codecs JavaRGBConverter und RGBScaler ist bei den Audio Codecs der PCMtoPCM-Codec. Mit Hilfe dieses Codecs lassen sich Ein- und Ausgabeformate innerhalb einer Verarbeitungskette (abgesehen von den Abtastraten) auf das gleiche Format bringen. Ebenso wie der JavaRGBConverter wird auch der PCMtoPCM-Codec von JMF464 automatisch eingesetzt, wenn es notwendig ist ED04.

Rate-Cvrt-Codec und RCModule-Codec

Da der PCMtoPCM Codec keine Konvertierung der Abtastrate durchführen kann, sind weitere Codecs nötig. Der Rate-Cvrt Codec wandelt verschiedenste Samplingraten in einander um, wogegen der RCMModule Codec vorerst nur Konvertierungen auf 8 kHz, 16 Bit Stereo durchführen kann.

Implementierung eigener Codecs und Effekte

1

Einleitung

  • JMF464 unterstützt die Erstellung eigener Codecs und Effekte durch das Bereitstellen zweier Interfaces:
    • javax.media.Codec:
      • wird verwendet, wenn sich das Format der Frames ändern soll
    • javax.media.Effect:
      • wird verwendet wenn sich der Inhalt ändert
  • Prinzipiell sind die beiden Interfaces aber identisch

Die wichtigsten Methoden zur Implementierung eines Codec oder Effect Interfaces:

  • getInputFormat und getOutputFormat:
    • Abfrage der Ein-/Ausgabeformate
    • Beide Methoden geben ein Array mit allen verfügbaren Formaten zurück
  • setInputFormat und setOutputFormat:
    • Festlegung der Eingabe und Ausgabeformate
  • open:
    • Aufgerufen, nachdem der Codec (Effect) zur Verarbeitungskette des Prozessors hinzugefügt wurde
    • Kann die verwendet werden um allgemeine Berechnungen durchzuführen oder Ressourcen anzufordern
  • reset:
    • Wird nach einem EndOfMediaEvent aufgerufen um Codec (Effect) zurückzusetzen
  • close:
    • Zur Freigabe der Ressourcen
  • process:
    • Wird vom Prozessor auf jeden zu verarbeitenden Frame angewendet
    • Parameter:
      • zwei Buffer Objekte (Eingang bzw. Ausgang)
    • Methode bearbeitet die Daten des Eingangspuffers und schreibt sie in den Ausgangspuffer

2

Einleitung

In den folgenden Abschnitten wird auf die Erstellung eigener Codecs und Effekte eingegangen. JMF464 unterstützt dies durch das Bereitstellen zweier Interfaces: javax.media.Codec und javax.media.Effect. Das Codec Interface wird verwendet, wenn sich das Format der Frames ändern soll, das Effect Interface hingegen, wenn sich der Inhalt ändert. Prinzipiell sind die beiden Interfaces aber identisch. Die wichtigsten Methoden zur Implementierung eines Codec oder Effect Interfaces werden im Folgenden beschrieben ED04:

  1. Implementierung der Methoden getInputFormat und getOutputFormat zur Abfrage der Ein-/Ausgabeformate. Beide Methoden geben ein Array mit allen verfügbaren Formaten zurück. Um eine möglichst vielseitig anwendbare Codec bzw. Effect Implementierung zu gestalten, empfiehlt es sich, die Formatangaben möglichst allgemein zu halten. Außerdem müssen die Methoden setInputFormat und setOutputFormat implementiert werden. Mit diesen Methoden kann der Benützer des Codec bzw. Effect Objekts die Eingabe und Ausgabeformate festlegen.
  2. Die Methode open wird aufgerufen, nachdem der Codec (Effect) zur Verarbeitungskette des Prozessors hinzugefügt wurde und alle Parameter des Codecs (Effects) feststehen. Demnach kann die Methode verwendet werden um allgemeine Berechnungen durchzuführen oder Ressourcen anzufordern ED04. reset hingegen wird nach einem EndOfMediaEvent aufgerufen wird und kann dazu verwendet werden den Codec (Effect) zurückzusetzen. Zur Freigabe der Ressourcen muss zusätzlich noch die Methode close implementiert werden.
  3. Die eigentliche Arbeit des Codecs bzw. Effekts geschieht in der Methode process. Sie wird vom Prozessor auf jeden zu Verarbeitenden Frame angewendet. Als Parameter werden zwei Buffer Objekte übergeben, die den Eingang bzw. Ausgang darstellen. Die Methode bearbeitet die Daten des Eingangspuffers und schreibt sie in den Ausgangspuffer.

Bildeffekte

1

Einleitung

  • Bildeffekte können auf Bilder und Einzelframes von Videos angewendet
  • Videos:
    • Jedes Bild wird unabhängig von den anderen separat mit dem Effekt belegt
    • Bsp.:
      • Scharf-/Weichzeichner
      • Änderung der Bildhelligkeit, des Kontrasts

Beispiel DrawEffect

Effekt lässt den Benutzer bestimmte Bildbereiche eines laufenden Videos durch Interaktion mit der Maus markieren oder aufhellen

Einbindung des Effekts im Applet
Instantierung eines Prozessors mit dem ersten im System verfügbaren Gerät
 Vector device_list = CaptureDeviceManager.getDeviceList(new
 javax.media.format.RGBFormat());
 CaptureDeviceInfo dev_info = (CaptureDeviceInfo) device_list.firstElement();
 DataSource source = Manager.createDataSource(dev_info.getLocator());
 Processor processor = Manager.createProcessor(source);
 ...
Konfiguration des Prozessors und Zuordnung des eigenen Effekts
 ...
 DrawEffect draw_effect = new DrawEffect(mask, mode);
 //Definition der Klasse DrawEffect folgt
 Codec codecs[] = new Codec[1];
 odecs[0] = draw_effect;
 TrackControl tracks[] = processor.getTrackControls();
 tracks[0].setCodecChain(codecs);
Veranschaulichung der JMF Verarbeitungskette durch JMF PlugIn Viewer PC

Datenverarbeitungsmodell im JMF PlugIn Viewer

Veranschaulichung der JMF Verarbeitungskette durch JMF PlugIn Viewer PDA_Phone

Datenverarbeitungsmodell im JMF PlugIn Viewer

Anbinden eines Players zur Darstellung und starten der beiden Komponenten
 ...
   player = Manager.createRealizedPlayer(processor.getDataOutput());
   player.start();
   processor.start();
 ...
Implementierung des Effekts
Variablendeklaration
 public class DrawEffect
   implements Effect {
   //Parameter des Effekts
   private Set mask;
   private BitSet mode;
   
   public final static int MODE_PAINT = 1;
   public final static int MODE_BRIGHTEN = 2;
   //Formate
   private Format input_format;
   private Format output_format;
   private Format input_formats[] = new Format[] {
     new RGBFormat(null,
       Format.NOT_SPECIFIED,
       Format.byteArray,
       Format.NOT_SPECIFIED,
       24,
       3, 2, 1,
       3, Format.NOT_SPECIFIED,
       Format.NOT_SPECIFIED,
       Format.NOT_SPECIFIED)
   };
   private Format output_formats[] = new Format[] {
     new RGBFormat(null,
       Format.NOT_SPECIFIED,
       Format.byteArray,
       Format.NOT_SPECIFIED,
       24,
       3, 2, 1,
       3, Format.NOT_SPECIFIED,
       Format.NOT_SPECIFIED,
       Format.NOT_SPECIFIED)
   };
 ...
Implementierung des Konstuktors und Methoden zum Setzen und Abfragen der Formate
 public DrawEffect(Set mask, BitSet mode) {
   this.mask = mask;
   this.mode = mode;
 }
 public Format setInputFormat(Format input_format) {
   this.input_format = input_format;
   return this.input_format;
 }
 public Format setOutputFormat(Format output_format) {
   this.output_format = input_format;
   return this.output_format;
 }
 public Format[] getSupportedInputFormats() {
   return this.input_formats;
 }
 public Format[] getSupportedOutputFormats(Format in_format) {
   return new Format[] {
   output_formats[0].intersects(input_format)};
 }
Auto
  • Das Eingangsformat wird auch als Ausgangsformat verwendet

 

  • process:
    • Initialisierung des Ausgabepuffers
    • Umwandlung der beiden Buffer Objekte in ein byte Array
    • Schreiben der einzelnen Pixel vom Eingabearray in das Ausgabearray
    • Ist ein Pixel in der übergebenen Maske enthalten, so wird es mit es mit Hilfe der Methode processPixel bearbeitet
    • Ansonsten wird es unverändert übernommen
    • Für jede der drei Farbkomponenten durchgeführt
Auto
 public int process(Buffer in_buffer, Buffer out_buffer) {
   int data_lenght=((RGBFormat)this.output_format).getMaxDataLength();
   out_buffer.setLength(in_buffer.getLength());
   out_buffer.setFormat(this.output_format);
   out_buffer.setFlags(in_buffer.getFlags());
   out_buffer.setData(new byte[data_lenght]);
   byte output_data[] = (byte[]) out_buffer.getData();
   byte input_data[] = (byte[]) in_buffer.getData();
   int width = ((RGBFormat)this.output_format).getSize().width;
   int height = ((RGBFormat)this.output_format).getSize().height;
   for (int y = 0; y < height; y++) {
     for (int x = 0; x < width; x++) {
       int index = linearIndex(x, y);
       Point p = new Point(x * 50 / width, 50 - y * 50 / height);
       if (mask.contains(p)) {
         processPixel(input_data, output_data, index);
       }
       else {
         output_data[index] = input_data[index];
         output_data[index + 1] = input_data[index + 1];
         output_data[index + 2] = input_data[index + 2];
       }
     }
   }
   return BUFFER_PROCESSED_OK;
 }
Auto
  • Methode processPixel weist einem zu bearbeitenden Pixel einen neuen Farbwert zu
  • Aufhellungsmodus:
    • Berechnung des Durchschnitts zwischen dem aktuellen Farbwert des Pixels und dem Maximalwert
    • byte Werte müssen zuerst in den primitiven Typ int umgewandelt werden
    • Nur Werte zwischen 0 und 255 machen Sinn (Bitmaske, die nur die ersten 8 Bits durchlässt, wird mit dem byte Wert UND-verknüpft)
  • Zeichenmodus:
    • Weist dem aktuellen Pixel die Farbe Rot zu
Auto
 private void processPixel(byte[] input_data, byte[] output_data, int index) {
   if (mode.get(MODE_BRIGHTEN)) {
     output_data[index] = (byte)((((int) input_data[index] 
       & 0xff) + 255) / 2);
     output_data[index + 1] = (byte)((((int)
     input_data[index + 1] & 0xff) + 255) / 2);
     output_data[index + 2] = (byte)((((int)
     input_data[index + 2] & 0xff) + 255) / 2);
     return;
   }
   if (mode.get(MODE_PAINT)) {
     output_data[index] = 0;
     output_data[index + 1] = 0;
     output_data[index + 2] = (byte) 255;
     return;
   }
 }
Annotation von Videodaten

Verwendung des Applets

2

Einleitung

Bildeffekte können entweder auf Bilder oder auf Einzelframes von Videos angewendet werden. Handelt es sich um Videos, so ist weder die Kenntnis der Lage des betroffenen Frames im Video, noch die Kenntnis vorangegangener oder nachfolgender Bilder notwendig, da jedes Bild separat mit dem Effekt belegt wird. Vertreter dieser Effekte sind z.B. Scharf-/Weichzeichner oder aber einfach auch Effekte, die die Bildhelligkeit oder den Kontrast ändern. Solche Effekte sind in fast jeder Bildbearbeitungssoftware enthalten.

Im Folgenden soll anhand eines Beispieleffekts nochmals die Methoden eines Effect Interfaces erläutert werden. Die Implementierung eines Codecs würde fast analog erfolgen.

Beispiel DrawEffect

Der Effekt lässt den Benutzer bestimmte Bildbereiche eines laufenden Videos durch Interaktion mit der Maus markieren oder aufhellen.

Initialisierung im Applet

Zuerst wird ein Processor mit dem ersten im System verfügbaren Video Eingabegerät instanziert.

Auto
 Vector device_list = CaptureDeviceManager.getDeviceList(new
 javax.media.format.RGBFormat());
 CaptureDeviceInfo dev_info = (CaptureDeviceInfo) device_list.firstElement();
 DataSource source = Manager.createDataSource(dev_info.getLocator());
 Processor processor = Manager.createProcessor(source);
 ...
Auto

Danach muss der Prozessor konfiguriert werden (Methode configure ; siehe Echtzeiterfassung mit JMF - Capturing). Als nächstes wird der eigene Effekt erzeugt und dem Prozessor zugeordnet:

Auto
 ...
 DrawEffect draw_effect = new DrawEffect(mask, mode);


 //Definition der Klasse DrawEffect folgt
 Codec codecs[] = new Codec[1];
 codecs[0] = draw_effect;
 TrackControl tracks[] = processor.getTrackControls();
 tracks[0].setCodecChain(codecs);
Auto

Die folgende Abbildung zeigt das Datenverarbeitungsmodell, das das DrawEffect -Objekt enthält, im JMF464 PlugIn Viewer, welcher zur Veranschaulichung der JMF464 Verarbeitungskette dient.

AutoPC

Datenverarbeitungsmodell im JMF PlugIn Viewer

Auto PDA_Phone

Datenverarbeitungsmodell im JMF PlugIn Viewer

Auto

Anschließend muss die Processor -Instanz realisiert werden (siehe Das Java Media Framework). Um den Ausgang des Prozessors mit dem erzielten Effekt darstellen zu können, wird noch ein Player hinter den Prozessor geschalten. Anschließend können der Player und der Prozessor gestartet werden.

Auto
 ...
   player = Manager.createRealizedPlayer(processor.getDataOutput());
   player.start();
   processor.start();
 ...
Implementierung des Effekts

Zuerst müssen die für die Effect Klasse nötigen Variable deklariert werden. Darunter sind auch die später benötigten, sehr allgemein deklarierten Ein-/Ausgabeformate.

Auto
 public class DrawEffect
   implements Effect {
   //Parameter des Effekts
   private Set mask;
   private BitSet mode;
   
   public final static int MODE_PAINT = 1;
   public final static int MODE_BRIGHTEN = 2;
   //Formate
   private Format input_format;
   private Format output_format;
   private Format input_formats[] = new Format[] {
     new RGBFormat(null,
       Format.NOT_SPECIFIED,
       Format.byteArray,
       Format.NOT_SPECIFIED,
       24,
       3, 2, 1,
       3, Format.NOT_SPECIFIED,
       Format.NOT_SPECIFIED,
       Format.NOT_SPECIFIED)
   };
   private Format output_formats[] = new Format[] {
     new RGBFormat(null,
       Format.NOT_SPECIFIED,
       Format.byteArray,
       Format.NOT_SPECIFIED,
       24,
       3, 2, 1,
       3, Format.NOT_SPECIFIED,
       Format.NOT_SPECIFIED,
       Format.NOT_SPECIFIED)
   };
 ...
Auto

Weiters müssen der Konstruktor und die für das Setzen bzw. Abfragen der Formate nötigen Methoden implementiert werden.

Auto
 public DrawEffect(Set mask, BitSet mode) {
   this.mask = mask;
   this.mode = mode;
 }
 public Format setInputFormat(Format input_format) {
   this.input_format = input_format;
   return this.input_format;
 }
 public Format setOutputFormat(Format output_format) {
   this.output_format = input_format;
   return this.output_format;
 }
 public Format[] getSupportedInputFormats() {
   return this.input_formats;
 }
 public Format[] getSupportedOutputFormats(Format in_format) {
   return new Format[] {
   output_formats[0].intersects(input_format)};
 }
Auto

Da dieser Effekt das Eingangsformat beibehalten soll, kann man sehen, dass es in der Methode setOutputFormat auch als Ausgangsformat verwendet wird. Der übergebene Parameter in_format der Methode getSupportedOutputFormats wird also ignoriert. Wird die Methode getSupportedOutputFormats zur Ausgabe verfügbarer Ausgangsformate für ein bestimmtes Eingangsformat aufgerufen, wird das oben definierte Ausgangsformat mit dem übergebenen geschnitten retourniert. Dies bedeutet, dass Formatattribute, die in nur in einem der beiden Formate spezifiziert sind direkt ins Ausgabeformat übernommen werden. Ist ein Attribut in beiden Formaten spezifiziert so erhält jenes Formatobjekt auf das die Methode intersect angewendet wird den Vorzug.

In der Methode process wird die eigentliche Filteroperation durchgeführt. Um in den Ausgabepuffer schreiben zu können, muss er zunächst initialisiert werden. Dabei wird er unter anderem auf die richtige Größe und das richtige Format gebracht.

Nach Umwandlung der beiden Buffer Objekte in ein byte Array kann damit begonnen werden, die einzelnen Pixel vom Eingabearray in das Ausgabearray zu schreiben. Ist ein Pixel in der übergebenen Maske enthalten, so wird es mit es mit Hilfe der Methode processPixel bearbeitet. Ansonsten wird es unverändert übernommen. Dies wird für jede der drei Farbkomponenten durchgeführt.

Auto
 public int process(Buffer in_buffer, Buffer out_buffer) {
   int data_lenght=((RGBFormat)this.output_format).getMaxDataLength();
   out_buffer.setLength(in_buffer.getLength());
   out_buffer.setFormat(this.output_format);
   out_buffer.setFlags(in_buffer.getFlags());
   out_buffer.setData(new byte[data_lenght]);
   byte output_data[] = (byte[]) out_buffer.getData();
   byte input_data[] = (byte[]) in_buffer.getData();
   int width = ((RGBFormat)this.output_format).getSize().width;
   int height = ((RGBFormat)this.output_format).getSize().height;
   for (int y = 0; y < height; y++) {
     for (int x = 0; x < width; x++) {
       int index = linearIndex(x, y);
       Point p = new Point(x * 50 / width, 50 - y * 50 / height);
       if (mask.contains(p)) {
         processPixel(input_data, output_data, index);
       }
       else {
         output_data[index] = input_data[index];
         output_data[index + 1] = input_data[index + 1];
         output_data[index + 2] = input_data[index + 2];
       }
     }
   }
   return BUFFER_PROCESSED_OK;
 }
Auto

Die Hilfsmethode Methode linearIndex rechnet die zweidimensionalen Pixelkoordinaten in die entsprechende Position im linearen Buffer um. Dabei wird die x-Koordinate mit der Anzahl der pro Pixel benötigten Bytes (pixel_stride) multipliziert und zum Produkt der Zeilennummer mit der Zeilenlänge (line_stride) addiert.

Auto
 private int linearIndex(int x, int y) {
   int pixel_stride = ((RGBFormat)this.output_format).getPixelStride();
   int line_stride = ((RGBFormat)this.input_format).getLineStride();
   return (x * pixel_stride) + (y * line_stride);
 }
Auto

Die Methode processPixel weist einem zu bearbeitenden Pixel einen neuen Farbwert zu. Im Aufhellungsmodus geschieht dies durch Berechnung des Durchschnitts zwischen dem aktuellen Farbwert des Pixels und dem Maximalwert. Um mit den byte Werten rechnen zu können, müssen diese zuerst in den primitiven Typ int umgewandelt werden. Dabei ist zu beachten, dass nur Werte zwischen 0 und 255 Sinn machen. Daher wird eine Bitmaske, die nur die ersten 8 Bits durchlässt, mit dem byte Wert UND-verknüpft.

Auto
 private void processPixel(byte[] input_data, byte[] output_data, int index) {
   if (mode.get(MODE_BRIGHTEN)) {
     output_data[index] = (byte)((((int) input_data[index] 
       & 0xff) + 255) / 2);
     output_data[index + 1] = (byte)((((int)
     input_data[index + 1] & 0xff) + 255) / 2);
     output_data[index + 2] = (byte)((((int)
     input_data[index + 2] & 0xff) + 255) / 2);
     return;
   }
   if (mode.get(MODE_PAINT)) {
     output_data[index] = 0;
     output_data[index + 1] = 0;
     output_data[index + 2] = (byte) 255;
     return;
   }
 }
Auto

Der Zeichenmodus ist einfacher. Er weist dem aktuellen Pixel einfach die Farbe Rot zu.

Annotation von Videodaten

Verwendung des Applets

Das Applet bietet die Möglichkeit das Videobild einer an das System angeschlossenen Webcam zu annotieren bzw. punktuell aufzuhellen. Zum Betrachten des Applets ist eine lokale Installation des Java Media Frameworks(http://java.sun.com/products/java-media/jmf/2.1.1/download.html), sowie eine Webcam nötig.

Videoeffekte

1

Einleitung

  • Videoeffekte nehmen im Gegensatz zu Bildeffekten auch Bezug auf vorangegangene Bilder oder zumindest auf die zeitliche Lage des aktuellen Bildes

Beispiel Video Overlay-Effekt

  • Effekt zeigt am unteren Bildrand des Videos einen animierten Balken
  • Balken repräsentiert die Anzahl der Frames, die in der aktuellen Sekunde bereits angezeigt wurden
  • Kopieren des Eingangspuffers in den Ausgangspuffer und Überlagerung durch Balken
Auto
 public int process(Buffer in_buffer, Buffer out_buffer) {
   out_buffer.copy(in_buffer);
   byte output_data[] = (byte[]) out_buffer.getData();
   int width = ((RGBFormat)this.output_format).getSize().width;
   for (int y = 0; y < 5; y++) {
     for (int x = 0; x < (frame_nr - 1) * width / (frame_rate - 1); x++)
     {
       int index = linearIndex(x, y);
       output_data[index] = (byte) 255;
       output_data[index + 1] = 0;
       output_data[index + 2] = 0;
     }
   }
   frame_nr++;
  
   if (frame_nr > frame_rate) {
     frame_nr = 1;
   }
   return BUFFER_PROCESSED_OK;
 }
Speichern der Bildrate des Videosignals
 public void open() throws javax.media.ResourceUnavailableException {
   if (input_format instanceof VideoFormat) {
   frame_rate = ((VideoFormat) input_format).getFrameRate();
   }
 }
Zurücksetzen des Bildzählers
 public void reset() {
   frame_nr = 1;
 }
Video Overlay-Effekt

Verwendung des Applets
  • Betrachtung einer über die Appletparameter definierten Videodatei, wobei am unteren Bildrand die Anzahl der in der aktuellen Sekunde bereits dargestellten Frames durch einen Balken repräsentiert wird
  • Anforderungen:

Beispiel Stroboskopeffekt

  • Schlüsselbilder (engl.: keyframes) werden gespeichert und für eine bestimmte Zeit statt dem aktuellen Frame dargestellt
  • Führt zu einem strobuskopartigen Effekt.

 

  • process kopiert bei jedem fünften Frame den Eingangspuffer in den Keyframepuffer
  • Zur Darstellung wird jedes Mal der Keyframepuffer in den Ausgangspuffer kopiert
Methode process
 public int process(Buffer in_buffer, Buffer out_buffer) {
   if (frame_nr % 5 == 0) 
   {
     key_frame.copy(in_buffer);
   }
   
   out_buffer.copy(key_frame);
   
   frame_nr++;
   return BUFFER_PROCESSED_OK;
 }
Stroboskopeffekt

Verwendung des Applets

2

Einleitung

Die oben beschriebenen Bildeffekte berücksichtigen für die Berechnung nur den Inhalt des aktuellen Bildes. Videoeffekte hingegen nehmen auch Bezug auf vorangegangene Bilder oder zumindest auf die zeitliche Lage des aktuellen Bildes. Im Folgenden wird nun für jede Methode ein Beispiel gezeigt.

Beispiel Video Overlay-Effekt

In diesem Beispiel wird ein Effekt präsentiert, der am unteren Bildrand des Videos einen animierten Balken anzeigt. Der Balken repräsentiert die Anzahl der Frames die in der aktuellen Sekunde bereits angezeigt wurden. Dazu ist es nötig, einen Zähler in der process Methode des Effekts mitlaufen zu lassen, der die Frames zählt, die ja für jeden Frame einmal aufgerufen wird.

Da sich nur ein kleiner Teil des Bildes verändert, kann zuerst mit Hilfe der copy Methode der Eingangspuffer in den Ausgangspuffer kopiert werden. Anschließend wird die aktuelle Länge des Balkens berechnet und der Balken gezeichnet.

Auto
 public int process(Buffer in_buffer, Buffer out_buffer) {
   out_buffer.copy(in_buffer);
   byte output_data[] = (byte[]) out_buffer.getData();
   int width = ((RGBFormat)this.output_format).getSize().width;
   for (int y = 0; y < 5; y++) {
     for (int x = 0; x < (frame_nr - 1) * width / (frame_rate - 1); x++)
     {
       int index = linearIndex(x, y);
       output_data[index] = (byte) 255;
       output_data[index + 1] = 0;
       output_data[index + 2] = 0;
     }
   }
   frame_nr++;
  
   if (frame_nr > frame_rate) {
     frame_nr = 1;
   }
   return BUFFER_PROCESSED_OK;
 }
Auto

In der open Methode muss die Bildrate des Videosignals berechnet werden.

Auto
 public void open() throws javax.media.ResourceUnavailableException {
   if (input_format instanceof VideoFormat) {
   frame_rate = ((VideoFormat) input_format).getFrameRate();
   }
 }
Auto

Die reset Methode setzt den Bildzähler zurück.

Auto
 public void reset() {
   frame_nr = 1;
 }
Video Overlay-Effekt

Verwendung des Applets

Das Applet bietet die Möglichkeit der Betrachtung einer über die Appletparameter definierten Videodatei, wobei am unteren Bildrand die Anzahl der in der aktuellen Sekunde bereits dargestellten Frames durch einen Balken repräsentiert wird. Zum Betrachten des Applets ist eine lokale Installation des Java Media Frameworks(http://java.sun.com/products/java-media/jmf/2.1.1/download.html), sowie eine Webcam nötig.

Beispiel Stroboskopeffekt

In diesem Beispiel werden im Gegensatz zu obigem auch vorhergehende Frames berücksichtigt. Im Detail werden spezielle Schlüsselbilder ("Keyframes") gespeichert und dann für eine bestimmte Zeit statt dem aktuellen Frame dargestellt. Dies führt zu einem strobuskopartigen Effekt.

Die Methode process kopiert bei jedem fünften Frame den Eingangspuffer in den Keyframepuffer. Zur Darstellung wird dann jedes Mal der Keyframepuffer in den Ausgangspuffer kopiert.

Auto
 public int process(Buffer in_buffer, Buffer out_buffer) {
   if (frame_nr % 5 == 0) 
   {
     key_frame.copy(in_buffer);
   }
   
   out_buffer.copy(key_frame);
   
   frame_nr++;
   return BUFFER_PROCESSED_OK;
 }

Stroboskopeffekt

Verwendung des Applets

Das Applet bietet die Möglichkeit der Betrachtung einer über die Appletparameter definierten Videodatei, wobei die Bildrate reduziert wird. Zum Betrachten des Applets ist eine lokale Installation des Java Media Frameworks(http://java.sun.com/products/java-media/jmf/2.1.1/download.html), sowie eine Webcam nötig.

Audioeffekte

1

Einleitung

  • Für Audioeffekte werden die gleichen Interfaces verwendet wie für Videoeffekte
  • Auch die Zuweisung eines Effekts zum Processor Objekt erfolgt über dieselben Methoden (setCodecChain)

Beispiel Sinuseffekt

  • Filter der die Lautstärke eines Audiosignals nach einer Sinusfunktion verändert
Variable Definition der Eingangs- und Ausgangsformate
 public AudioEffect() {
   this(Format.NOT_SPECIFIED);
 }
 public AudioEffect(int num_of_chan)
 {
   this.input_formats = new Format[]{
     new AudioFormat(
     AudioFormat.LINEAR,
     Format.NOT_SPECIFIED,
     16,
     num_of_chan,
     AudioFormat.LITTLE_ENDIAN,
     AudioFormat.SIGNED,
     Format.NOT_SPECIFIED,
     Format.NOT_SPECIFIED,
     Format.byteArray)
   };
   this.output_formats = new Format[]{
     new AudioFormat(
     AudioFormat.LINEAR,
     Format.NOT_SPECIFIED,
     16,
     num_of_chan,
     AudioFormat.LITTLE_ENDIAN,
     AudioFormat.SIGNED,
     Format.NOT_SPECIFIED,
     Format.NOT_SPECIFIED,
     Format.byteArray)
   };
}
Auto
  • Format-get/set-Methoden werden gleich wie bei den Videofiltern implementiert
  • Zugriff auf die Audiodaten in der process Methode erfolgt hingegen etwas anders:
    • Zugriff auf die Daten aus dem Eingangspuffer in zwei verschachtelten Schleifen
    • Ein Sample erstreckt sich über zwei Indizes des byte Arrays (Samplerate von 16 Bits)
    • Niederwertigen Bits kommen dabei immer vor den höherwertigen 8
    • Erzeugen eines Integers durch Shiften der zweiten 8 Bits
    • Multiplizieren dieses Wertes mit dem Sinus der halben Frame-Nummer (Lautstärke verändert sich wellenförmig)
Methode process
 public int process(Buffer in_buffer, Buffer out_buffer) {
   byte input_data[] =(byte[]) in_buffer.getData();
   int offset = in_buffer.getOffset();
   int length = in_buffer.getLength();
   out_buffer.setFormat(this.output_format);
   out_buffer.setFlags(in_buffer.getFlags());
   byte data[]=new byte[length];
   out_buffer.setData(data);
   byte output_data[] =(byte[]) out_buffer.getData();
   int num_of_channels = this.output_format.getChannels();
   int num_of_samples = length / (2*num_of_channels);
   int input_index = offset;
   int output_index = 0;
 for(int i=0;i<num_of_samples;i++)
   for(int j=0;j<num_of_channels;j++)
   {
     //Zusammensetzen des Samples. Oderverknüpfung
     //der niederwertigen Bits [i]
     //und der 8 höherwertigen Bits [i+1] (geshiftet <<8)
     int sample_value = (input_data[input_index] & 0xff)|
       (input_data[input_index+1]<<8);
     //Verändern der Lautstärke durch Multiplikation mit Sinus
     sample_value*=Math.sin(frame_nr*0.5);
     output_data[output_index] = (byte)sample_value;
     output_data[output_index+1] = (byte)(sample_value>>8);
     input_index+=2;
     output_index+=2;
   }
   out_buffer.setOffset(0);
   out_buffer.setLength(output_index);
   frame_nr++;
   return BUFFER_PROCESSED_OK;
 }
Audio-Sinuseffekt

Verwendung des Applets

2

Einleitung

Für die Implementierung von Audioeffekten werden die gleichen Interfaces verwendet wie für Videoeffekte. Auch die Zuweisung eines Effekts zum Processor Objekt erfolgt über dieselben Methoden (setCodecChain), wie sie für Videoeffekte verwendet werden. Im Folgenden wird nun anhand eines Beispiels auf die Implementierung von Audioeffekten im Detail eingegangen.

Beispiel Sinuseffekt

Das Bespiel SinusEffect definiert einen Filter, der die Lautstärke eines Audiosignals nach einer Sinusfunktion verändert.

Da die Anzahl der Kanäle variabel sein soll, werden die Eingangs- und Ausgangsformate im Gegensatz zu den obigen Videofiltern hier im Konstruktor unter Berücksichtigung dieser Parameter definiert.

Auto
 public AudioEffect() {
   this(Format.NOT_SPECIFIED);
 }
 public AudioEffect(int num_of_chan)
 {
   this.input_formats = new Format[]{
     new AudioFormat(
       AudioFormat.LINEAR,
       Format.NOT_SPECIFIED,
       16,
       num_of_chan,
       AudioFormat.LITTLE_ENDIAN,
       AudioFormat.SIGNED,
       Format.NOT_SPECIFIED,
       Format.NOT_SPECIFIED,
       Format.byteArray)
   };
   this.output_formats = new Format[]{
     new AudioFormat(
       AudioFormat.LINEAR,
       Format.NOT_SPECIFIED,
       16,
       num_of_chan,
       AudioFormat.LITTLE_ENDIAN,
       AudioFormat.SIGNED,
       Format.NOT_SPECIFIED,
       Format.NOT_SPECIFIED,
       Format.byteArray)
   };
 }
Auto

Die Format-get/set-Methoden werden wieder gleich wie bei den Videofiltern implementiert. Der Zugriff auf die Audiodaten in der process Methode erfolgt hingegen etwas anders.

Auto
 public int process(Buffer in_buffer, Buffer out_buffer) {
   byte input_data[] =(byte[]) in_buffer.getData();
   int offset = in_buffer.getOffset();
   int length = in_buffer.getLength();
   out_buffer.setFormat(this.output_format);
   out_buffer.setFlags(in_buffer.getFlags());
   byte data[]=new byte[length];
   out_buffer.setData(data);
   byte output_data[] =(byte[]) out_buffer.getData();
   int num_of_channels = this.output_format.getChannels();
   int num_of_samples = length / (2*num_of_channels);
   int input_index = offset;
   int output_index = 0;
   for(int i=0;i<num_of_samples;i++)
     for(int j=0;j<num_of_channels;j++)
     {
       //Zusammensetzen des Samples. Oderverknüpfung
       //der niederwertigen Bits [i]
       //und der 8 höherwertigen Bits [i+1] (geshiftet <<8)
       int sample_value = (input_data[input_index] & 0xff)|
         (input_data[input_index+1]<<8);
       //Verändern der Lautstärke durch Multiplikation mit Sinus
       sample_value*=Math.sin(frame_nr*0.5);
       output_data[output_index] = (byte)sample_value;
       output_data[output_index+1] = (byte)(sample_value>>8);
       input_index+=2;
       output_index+=2;
     }
   out_buffer.setOffset(0);
   out_buffer.setLength(output_index);
   frame_nr++;
   return BUFFER_PROCESSED_OK;
 }
Auto

Zunächst muss darauf geachtet werden, dass mit dem Lesen der Inputdaten erst beim Offset des Eingangspuffers begonnen wird. In zwei verschachtelten Schleifen über die Anzahl der Samples und die Anzahl der Kanäle wird dann auf die Daten aus dem Eingangspuffer zugegriffen. Ein Sample erstreckt sich dabei über zwei Indizes des byte Arrays, da mit einer Samplerate von 16 Bits(also 2 Bytes) gearbeitet wird. Die niederwertigen Bits kommen dabei immer vor den höherwertigen 8. Durch Shiften der zweiten 8 Bits lässt sich ein Integer erzeugen, dessen Wert dem Sample entspricht. Durch modifizieren dieses Wertes lässt sich dann auf das Signal Einfluss nehmen. In diesem Fall wird dieser Wert mit dem Sinus der halben Frame-Nummer multipliziert. Dadurch verändert sich die Lautstärke wellenförmig. Anschließend kann der verändertet Samplewert in den Ausgangsbuffer geschrieben werden.

Audio-Sinuseffekt

Verwendung des Applets

Das Applet bietet die Möglichkeit des Abspielens einer über die Appletparameter definierten WAV Datei, wobei die Lautstärke sinusförmig verändert wird. Zum Betrachten des Applets ist eine lokale Installation des Java Media Frameworks(http://java.sun.com/products/java-media/jmf/2.1.1/download.html), sowie eine Webcam nötig.

Bibliographie

2

Auto

AG04

ED04


Notes
(empty)