- PR -

JMF BufferからBufferedImageへの変換

投稿者投稿内容
fuzuki
常連さん
会議室デビュー日: 2003/08/23
投稿数: 48
投稿日時: 2004-05-09 18:16
こんにちは。JMFを使用して、動画ファイルを読み込んでフレーム毎のイメージをぼかしなどのフィルター処理を加えた上で再生していくものを作成したいと思っています。

JMFのProcesserを使用して動画ファイルを表示させるのはうまくできています。
困っているのは、フレーム毎の画像にフィルター処理をかけるためにその画像をBufferedImage型に変換する段階です。

具体的には下記にコードの一部を書きましたが、動画を描画していく中でそれぞれのフレームの情報はBufferとしてPreAccessCodecクラスの中のprocessメソッドで受け取り、何かしらの編集をしてアウトプットさせられるはずです。

このコードの中のBufferからBufferedImageへの変換部分は
http://www.cmt.phys.kyushu-u.ac.jp/~M.Sakurai/diary/200306.html
を参考にしていますが、RGBFormatへキャストする段階でClassCastExceptionが出てしまいます。

JMFに関しては
JMF 2.1.1 Solutions
http://java.sun.com/products/java-media/jmf/2.1.1/solutions/
を参考にコードを書いています。ここにもいろいろな例がたくさんあるのですが、どうも自分が欲しい機能が見つかりません。

とにかく下記の方法はこだわらず、BufferをBufferedImageに変換し、それをさらにBuffer型に戻せればいいのですが。どなたか分かる方いらっしゃいますか?

コード:
Codec codec[] = {new PreAccessCodec(), new PostAccessCodec()};

public class PreAccessCodec implements Codec
{
  public int process(Buffer in, Buffer out)
  {
    RGBFormat format = (RGBFormat)in.getFormat();
    frameImage = new BufferedImage(format.getLineStride(),
                                   format.getSize().height,
                                   BufferedImage.TYPE_INT_BGR);

    frameImage.getRaster().setDataElements(0,0,format.getLineStride(),
                                           format.getSize().height,
                                           data);
    // ここでBufferedImageを編集し、さらにそのイメージをBuffer型に変換する
    out.setData(modifiedImageBuffer); // 編集済みのBufferを出力させる
  }
}

fuzuki
常連さん
会議室デビュー日: 2003/08/23
投稿数: 48
投稿日時: 2004-05-10 01:27
いろいろ試しているのですが、どうもうまくいきません。

MemoryImageSourceを使ってデータの配列からイメージを生成しようとしたのですが、動きはするもののこれによって生成されたイメージは真っ黒の画面でした。

何もせずにinからoutへ入れてやると動画はきちんと再生されるので、ここで何か処理を行えるのではないかと思っているのですが。何か根本的に間違っているのでしょうか・・・

コード:
public int process(Buffer in, Buffer out)
{
  data = (byte[])in.getData();
  int[] pixels = new int[data.length]; // intの配列を用意

  for(int i=0; i<data.length; i++) // byte配列からint配列に変換
    pixels[i] = (int)data[i];

  // int配列からイメージを生成
  MemoryImageSource memoryImageSource = new MemoryImageSource(width, height, pixels, 0, width);
  Image filteredImage = Toolkit.getDefaultToolkit().createImage(memoryImageSource);
}

sakurai
会議室デビュー日: 2004/05/10
投稿数: 7
投稿日時: 2004-05-10 06:58
上のあんまり役に立たないコードを書いたものです。
先ほど FrameGrabbingControl を使う一般的な方法を書いてみました。これでいかがでしょうか?

http://www.cmt.phys.kyushu-u.ac.jp/~M.Sakurai/diary/200405.html#09_t3
fuzuki
常連さん
会議室デビュー日: 2003/08/23
投稿数: 48
投稿日時: 2004-05-10 14:35
sakuraiさん、ご返事ありがとうございます。まさか、参考にしていたページの作者の方からご返事をいただけるとは思ってませんでした。最初はメールで直接お聞きしようかと思っていたのですが、ページのトップに忙しいということが書かれていたので迷惑かと思って諦めていたのです。

結果についてですが、いただいたアドバイスを元に、うまくフレームの内容をイメージにすることができました。あのソースのままだと、イメージは取り出せるのですがキャプチャした時点で画像が止まってしまうので、FramePositioningControlの部分を抜いてやったところうまくいきました。あとは、このイメージを編集した後にbuffer outに戻してやれば自分が望んでいる処理が出来るはずです。戻す時にまた苦労しそうな気配がしますが(^^;

コードは以下のような感じです。(書くまでも無いかもしれませんが、念のため)

コード:
public int process(Buffer in, Buffer out)
{
  FrameGrabbingControl frameGrabbingCtrl = (FrameGrabbingControl)
                p.getControl("javax.media.control.FrameGrabbingControl");
  Buffer buf = frameGrabbingCtrl.grabFrame();

  // 以下sakuraiさんのbuffer2imageの内容で。
}



あれ?でもこれだと引数として受け取っているBuffer inは何も使う必要が無いような・・・ま、いいか。
fuzuki
常連さん
会議室デビュー日: 2003/08/23
投稿数: 48
投稿日時: 2004-05-11 12:04
予想通り、バッファを書き戻す段階でつまってしまいました。

FrameGrabbingControlでgrabFrameしたフレームをBufferのoutに書き戻す処理を行うとエラーは出ないのですが、画面が固まって音声だけ先に進んでいく状態になってしまいます。PCの処理が追いつかないだけならコマ送り状態でも画面は表示されると思うのですが、全く動かなくなるのです。どうもgrabFrameしたものを書き戻すのは私が望むような処理を行うには何か問題があるようです。

以下のコードは、Bufferを途中でイメージに変換したりせずに単純にgrabFrameで得られたBufferをoutに書き出している処理ですが、これだけでも同様の問題が出てしまいます。

すみませんが、どなたか分かる方いらっしゃいましたらよろしくお願いします。

コード:
public int process(Buffer in, Buffer out)
{
  FrameGrabbingControl frameGrabbingCtrl =
 (FrameGrabbingControl)p.getControl("javax.media.control.FrameGrabbingControl");

  Buffer inBuffer = frameGrabbingCtrl.grabFrame();
  out.setData(inBuffer.getData());
  out.setFormat(in.getFormat());
  out.setLength(in.getLength());
  out.setOffset(in.getOffset());
}

sakurai
会議室デビュー日: 2004/05/10
投稿数: 7
投稿日時: 2004-05-11 14:09
おそらく、やろうとされていることはこれに近いのではないかと思うのですがどうでしょうか。

「Code sample Rotation Effect」
http://java.sun.com/products/java-media/jmf/2.1.1/solutions/RotationEffect.html

Grabberはストリームに関係なく画像をとりたいときに使うもので、ストリームの流れの中で何かをしたいときには、ちゃんとJMFの作法に従う必要があるようです。ここでは、出力エンコーダーとして画像エフェクトを構築しるようです。
fuzuki
常連さん
会議室デビュー日: 2003/08/23
投稿数: 48
投稿日時: 2004-05-11 14:25
sakuraiさん、こんにちは。

> おそらく、やろうとされていることはこれに近いのではないかと思うのですがどうでしょうか。

はい、その例に似ています。

実はつい先程から、そのRotation Effectのサンプルを見ていて、それを元にBufferのbyteデータを直接編集することによって画像自体を明るくするなどの処理はできました。ただ、他のぼかしやシャープ化などの処理を行う際に、Graphics2Dを使用していて、それにはBufferedImage型のデータを与えてやら無いとならないので、なんとかBufferをイメージ型に変換→画像処理→Bufferに戻すという手順を踏みたかったのです。

どうも、イメージ型からBufferに書き戻す処理はうまくいきそうにないので、画像処理をGraphics2Dを使用せずにやる方法を考えないとなら無そうですね・・・
sakurai
会議室デビュー日: 2004/05/10
投稿数: 7
投稿日時: 2004-05-11 16:20
ちなみに、 javax.media.util.ImageToBuffer は試されましたか?

スキルアップ/キャリアアップ(JOB@IT)