2008年9月29日月曜日

JMF(Java Media Framework) による data strage memo

import java.awt.BorderLayout;
import java.awt.Frame;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import javax.media.DataSink;
import javax.media.Format;
import javax.media.Manager;
import javax.media.MediaLocator;
import javax.media.NoDataSinkException;
import javax.media.NoDataSourceException;
import javax.media.NoProcessorException;
import javax.media.Processor;
import javax.media.control.TrackControl;
import javax.media.format.VideoFormat;
import javax.media.protocol.DataSource;
import javax.media.protocol.FileTypeDescriptor;
import javax.media.protocol.SourceCloneable;

/**
* DVカメラからの動画キャプチャとそのデータをファイルに保存する方法。
* ついでに動画表示をする。
* @author Yuko
*/
public class CaptureAndDisplay {

public static void main(String[] args){

/** * 入力もと */
MediaLocator in=null;

/** * 出力先 */
MediaLocator out=null;

/** DVカメラを入力先とする */
final String VFW="vfw://0";
in = new MediaLocator( VFW );

/** 出力先ファイル名を指定 */
try {
File file = new File("C:\\test\\test.avi");
  out = new MediaLocator( file.toURI().toURL() );
} catch (MalformedURLException e2) {

  e2.printStackTrace(); }
/**

* 書き込み用DataSinkに色々設定するためのProcessor
*/
Processor processor4DataSink =null;
/**
* 画像表示用のProcessor。別にPlayerでもよい。
*/
Processor processor4Display=null;
/**
* DVカメラのデータ。MediaLocatorより。
* これの複製を作って、DataSink用Processor、Player(ディスプレー)用Processorに渡す。
 */
DataSource ds =null;
/**
* これはProcessorに使用するDataSource
*/
DataSource ds4Processor=null;
/**
* これはProcessorに使用するDataSource
*/
DataSource ds4DataSink=null;
/**
* 画像データをファイルに書き込むためのもの
*/
DataSink filewriter = null;
/*
* Windowsでmpegを再生する場合、最適化のためにWindowsの一部の機能を使っていたりするため
* 一部javaの機能が使えない場合がある。
* このためJMFでは、javaの機能が使えるようなmpeg再生モジュールを別途用意しているとのこと
* デフォルトでは前期のWindows最適化のモジュールが選択されているため
* java用再生モジュールを使用するには下記のようなsetHintが必要。
*/
Manager.setHint(Manager.PLUGIN_PLAYER,Boolean.TRUE);//これだけ実行すれば何となくうまく行く様子。
// Manager.setHint(Manager.LIGHTWEIGHT_RENDERER,Boolean.TRUE); //この文を生かすと画像がちらつく。

  try {
//とりあえず、おおもとのDataSourceを作る
    ds = Manager.createDataSource(in);
} catch (NoDataSourceException e2) {
    e2.printStackTrace();
  } catch (IOException e2) {
    e2.printStackTrace(); }
/*

* DataSourceの複製の作成。
* Processorは、画像表示とDataSinkによる動画データのファイル書き込みの両方を一度にはできないらしい。
* このためDataSourceを複製し、別々のDataSourceをつくり、それからそれぞれのProcessorを作成しないといけない。
* (表示のためだけならPlayerで良い)
*/
 ds=Manager.createCloneableDataSource(ds);
 ds4Processor=((SourceCloneable)ds).createClone();

try {
   processor4DataSink=Manager.createProcessor(ds4Processor);
   processor4Display=Manager.createProcessor(ds);
} catch (NoProcessorException e3) {
   e3.printStackTrace();
  } catch (IOException e3) {
   e3.printStackTrace();
 }

  processor4DataSink.configure();
  while(processor4DataSink.getState()!=Processor.Configured);
 
  processor4Display.configure();
  while(processor4Display.getState()!=Processor.Configured);

TrackControl[] tc= processor4DataSink.getTrackControls();

//tc[0]がVideoFormatと決めつけていますが、場合によっては違うことが十分あると思うので
//instanceof とかでちゃんと調べた方がいいと思います。
 TrackControl t=tc[0];
//Formatの確認。本来不必要。
Format f=t.getFormat();
  System.out.println("format > "+f.toString());

//Formatを設定する
  t.setFormat(new Format(VideoFormat.MJPG));

// t.setFormat(new YUVFormat());// <= これはデータサイズが大きいので困る。

//Formatの確認。本来不必要。
f=t.getFormat();
System.out.println("format > "+f.toString());

//.avi形式を指定。これをしないとNoDataSinkExceptionが出るらしい。
processor4DataSink.setContentDescriptor(new FileTypeDescriptor(FileTypeDescriptor.MSVIDEO));

//ProcessorをPlayerと同じように使うための作法
  processor4Display.setContentDescriptor(null);
//Realizeの状態にする。

 processor4Display.realize();
 processor4DataSink.realize();
 while(processor4DataSink.getState()!=Processor.Realized);
 while(processor4Display.getState()!=Processor.Realized);//realize待ち

//表示用のFrame作成
Frame myframe=new Frame("MONITOR");

// myf2.add(display.getControlPanelComponent(),BorderLayout.SOUTH);

myframe.add(processor4Display.getVisualComponent(),BorderLayout.CENTER);

//720×480を美しく表示するためにはこのサイズがよさそう。
myframe.setSize(728,535); myframe.setVisible(true);

/*
* Processorをスタートさせておかないと、ファイル書き込みは始まらない。
* しかしAPIGuideにはそのようには書いていない。(多分)
* 困ったもんです。
*/
  processor4DataSink.start();
processor4Display.start();

//上記のように設定したのち、改めてここで、DataSourceを取得する必要あるらしい。
ds4DataSink = processor4DataSink.getDataOutput();

try {
filewriter=Manager.createDataSink(ds4DataSink, out);
//filewriter=Manager.createDataSink(ds, out); // <= このような使い方はできなかった

//ファイルオープン
filewriter.open();

//ファイル書き込み開始。ただし前述のようにProcessorをスタートさせておかないと、ファイル書き込みは始まらない。
 filewriter.start();

} catch (NoDataSinkException e) {
   e.printStackTrace();
  } catch (SecurityException e) {
   e.printStackTrace();
  } catch (IOException e) {
   e.printStackTrace();
}
//とりあえず30secだけ録画
try {
  Thread.sleep(30000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}

try {
//書き込み停止。ただしこれはやらなくても良い様子。
filewriter.stop();
} catch (IOException e) {
e.printStackTrace();
}
/*
* Processor停止。
* これをやらないと読めないファイルになるらしい。
* Processor stop()では読めるファイルにならなかった。
* しかしAPIGuideには多分書いていない。
*/
processor4DataSink.close();
filewriter.close();
System.out.println("file closed");
System.exit(0);
}
}

0 件のコメント: