Java Media Framework の使い方と動画・音声再生サンプル

リソース を resouce と書いているのに気づいた.resource のつもりだったのに.

Java で 動画・音声を扱う手段として,公式的には JMF(Java Media Framework)が用意されている.公式の説明書を読むとかサンプルコードを読むとかが王道だろうが,面倒だった.イケてる日本語文献が見つかったから使ってみる.

本エントリでは情報元,インストール方法,やったことを記述した.

インストール

Sun から jmf-2_1_1e-windows-i586.exe を入手して実行する.Javadoc はないみたい.

NetBeans を使用している場合は不要かもしれないが,インストールしてしまったから確認が面倒だ.

教科書 JMFyy.pdf

習作目標「AVI ファイルを読み込み,全フレームをどこかのフォルダに PNG 形式で出力する」を設定した.

ひとまず教科書どおりのコードを書く.NetBeansJava ファイルを作り,「ファイルを実行」していく.どれもこれも,ウインドウの閉じるボタンをクリックしてもプロセスが走りっぱなしだったから,IDE 右下の running... のバツボタンをクリックする手間がある.

mp3play.java

音声を再生する.教科書どおりの q.mp3 が手元になくて,Help - MP3 Search & Free Mp3 Downloads から拾った.しかし聴いていて気分が悪いから,C:\WINDOWS\Media のファイルを使用した.

  1. Windows XP Startup.wav
  2. Windows XP Shutdown.wav を ffmpeg -i "Windows XP Shutdown.wav" "Windows XP Shutdown.mp3" したもの
  3. onestop.mid
package test;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.media.CannotRealizeException;
import javax.media.Manager;
import javax.media.NoPlayerException;
import javax.media.Player;

public class mp3play {

    public static void main(String[] args) {
	try {
//	    File file = new File("resouce/Windows XP Shutdown.mp3");
//	    File file = new File("resouce/Windows XP Startup.wav");
	    File file = new File("resouce/onestop.mid");
	    URL url = file.toURL();
	    Player player = Manager.createRealizedPlayer(url);
	    player.start();
	} catch (MalformedURLException ex) {
	    Logger.getLogger(mp3play.class.getName()).log(Level.SEVERE, null, ex);
	} catch (IOException ex) {
	    Logger.getLogger(mp3play.class.getName()).log(Level.SEVERE, null, ex);
	} catch (NoPlayerException ex) {
	    Logger.getLogger(mp3play.class.getName()).log(Level.SEVERE, null, ex);
	} catch (CannotRealizeException ex) {
	    Logger.getLogger(mp3play.class.getName()).log(Level.SEVERE, null, ex);
	}
    }

}

MIDI ファイルは再生できなかった.

Error: Unable to prefetch com.sun.media.content.audio.midi.Handler$MidiController@197d257
mp3play_control.java

mp3play に GUI を取り付けたもの.ウインドウが出現し再生ボタン,シークバー,ファイル情報表示ボタンが表示される.ウインドウが青いバーしかなく,コントロールはマウスでぐいーんとサイズ変更しないと表示されない.

package test;

import java.awt.Component;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.media.CannotRealizeException;
import javax.media.Manager;
import javax.media.NoPlayerException;
import javax.media.Player;
import javax.swing.JFrame;

public class mp3play_control extends JFrame {

    public static void main(String[] args) {
	JFrame frame = new JFrame();
	try {
	    File file = new File("resouce/Windows XP Shutdown.mp3");
//	    File file = new File("resouce/Windows XP Startup.wav");
//	    File file = new File("resouce/onestop.mid");
	    URL url = file.toURL();
	    Player player = Manager.createRealizedPlayer(url);
	    Component cp = player.getControlPanelComponent();
	    frame.getContentPane().add(cp);
	    frame.setVisible(true);
	    player.start();
	} catch (MalformedURLException ex) {
	    Logger.getLogger(mp3play_control.class.getName()).log(Level.SEVERE, null, ex);
	} catch (IOException ex) {
	    Logger.getLogger(mp3play_control.class.getName()).log(Level.SEVERE, null, ex);
	} catch (NoPlayerException ex) {
	    Logger.getLogger(mp3play_control.class.getName()).log(Level.SEVERE, null, ex);
	} catch (CannotRealizeException ex) {
	    Logger.getLogger(mp3play_control.class.getName()).log(Level.SEVERE, null, ex);
	}
    }
}
videoplay.java

mp3play_control の動画版.動画を3種類だけ入力してみた.

  1. スーパーメトロイドのボムジャンプを収録した bombjump.avi 3IV2 256x224 60.00fps 1327Kbps
  2. 何度かの野球の投球シーン 0001.avi DivX 5 720x480 29.97fps 1043Kbps
  3. エンコードされていない動画ファイル 256x256 5.00fps 7864Kbps
package test;

import java.awt.Component;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.media.CannotRealizeException;
import javax.media.Manager;
import javax.media.NoPlayerException;
import javax.media.Player;
import javax.swing.JFrame;

public class videoplay {

    public static void main(String[] args) {
	try {
	    JFrame frame = new JFrame();
	    File file = new File("resouce/bombjump.avi"); // 3IV2 256x224 60.00fps 1327Kbps 
//	    File file = new File("resouce/0001.avi"); // DivX 5 720x480 29.97fps 1043Kbps
//	    File file = new File("resouce/90frame.avi"); // エンコードなし 256x256 5.00fps 7864Kbps
	    URL url = file.toURL();
	    Player player = Manager.createRealizedPlayer(url);
	    Component vc = player.getVisualComponent();
	    frame.getContentPane().add(vc, "Center");
	    Component cp = player.getControlPanelComponent();
	    frame.getContentPane().add(cp, "South");
	    frame.pack();
	    frame.setVisible((true));
	    player.start();
	} catch (MalformedURLException ex) {
	    Logger.getLogger(videoplay.class.getName()).log(Level.SEVERE, null, ex);
	} catch (IOException ex) {
	    Logger.getLogger(videoplay.class.getName()).log(Level.SEVERE, null, ex);
	} catch (NoPlayerException ex) {
	    Logger.getLogger(videoplay.class.getName()).log(Level.SEVERE, null, ex);
	} catch (CannotRealizeException ex) {
	    Logger.getLogger(videoplay.class.getName()).log(Level.SEVERE, null, ex);
	}
    }
}

1と2がダメだった.

run:
  Unable to handle format: 3IV2, 256x224, FrameRate=59.9, Length=172032 1068 extra bytes
Exception in thread "main" java.lang.NullPointerException
        at java.awt.Container.addImpl(Container.java:1041)
        at java.awt.Container.add(Container.java:927)
        at test.videoplay.main(videoplay.java:31)
構築停止 (合計時間: 5 秒)
run:
  Unable to handle format: DX50, 720x480, FrameRate=29.9, Length=1036800 0 extra bytes
  Unable to handle format: mpeglayer3, 22050.0 Hz, 0-bit, Stereo, Unsigned, 12000.0 frame rate, FrameSize=8 bits
Failed to realize: com.sun.media.PlaybackEngine@1372a1a
Error: Unable to realize com.sun.media.PlaybackEngine@1372a1a
2009/07/13 22:48:18 test.videoplay main
致命的: null
javax.media.CannotRealizeException
        at javax.media.Manager.blockingCall(Manager.java:2005)
        at javax.media.Manager.createRealizedPlayer(Manager.java:528)
        at test.videoplay.main(videoplay.java:29)
構築成功 (合計時間: 2 秒)

出力内容には温度差があるなあ.

device.java

JMF はデータ入力にはファイルだけでなく,カメラやマイクも利用できる.各デバイスを使用するにはその識別名が必要で,まずはこちらを取得してみようね,という内容だ.

package test;

import java.util.Vector;
import javax.media.CaptureDeviceInfo;
import javax.media.CaptureDeviceManager;
import javax.media.MediaLocator;
import javax.media.format.AudioFormat;
import javax.media.format.VideoFormat;

public class device {

    public static void main(String[] args) {
	Vector vlist = CaptureDeviceManager.getDeviceList(
		new VideoFormat(VideoFormat.YUV));
	for (int i = 0; i < vlist.size(); i++) {
	    CaptureDeviceInfo vinfo = (CaptureDeviceInfo) vlist.elementAt(i);
	    MediaLocator camera = vinfo.getLocator();
	    System.out.println(camera.toString());
	}
	Vector alist = CaptureDeviceManager.getDeviceList(
		new AudioFormat(AudioFormat.LINEAR));
	for (int i = 0; i < alist.size(); i++) {
	    CaptureDeviceInfo ainfo = (CaptureDeviceInfo) alist.elementAt(i);
	    MediaLocator mic = ainfo.getLocator();
	    System.out.println(mic.toString());
	}
    }
}
run:
dsound://
javasound://44100
構築成功 (合計時間: 0 秒)

カメラなんて接続していないから,こんなものだろう.安い USB カメラでも接続したら増えるかな.

「やったこと」のまとめ

JMF には Player と Processor があり,教科書ではこの2つを分けている.今回のエントリは Player 部分を,私の環境で可能な分だけやったというメモとなる.次は Processor 部分をメモしたい.習作目標「AVI ファイルを読み込み,全フレームをどこかのフォルダに PNG 形式で出力する」は Processor で処理する必要がある.