中西研のB4関口です。
今回もProcessingネタになってしまうのですが、今回はProcessingを使ったビデオチャットを実装したいと思います。
方針としては、画像をバイト配列に変換して、データグラム通信で別のPCへ送ってあげる感じにします。今回はわかりやすさのために、スレッドとか使いません。
さくっとまずはソースを乗せてしまいます。
[java]
import processing.video.*;
import java.awt.image.*;
import java.awt.*;
import javax.imageio.*;
import java.net.DatagramPacket;  
InetSocketAddress remoteAddress;
DatagramPacket sendPacket;
DatagramPacket receivePacket;
DatagramSocket receiveSocket;
Capture capture;
//送信するバイト配列
byte[] sendBytes;
//受信するバイト配列を格納する箱
byte[] receivedBytes = new byte[300000];
void setup() {
  size(600,480);
capture = new Capture(this,640,480);
  try {
    //受信ポート
    receiveSocket = new DatagramSocket(5101);
  }
  catch(SocketException e) {
  }
  //受信用パケット
  receivePacket = new DatagramPacket(receivedBytes,receivedBytes.length);
  //送り先
  remoteAddress = new InetSocketAddress(“localhost”,5100);
  try{
    receiveSocket.setSoTimeout(1000);
  }catch(SocketException e){
  }
}
void draw() {
  capture.read();
  /* ここから受信 */
  println(receiveSocket.isBound());
  try {
    receiveSocket.receive(receivePacket);
  }
  catch(IOException e) {
  }
  Image awtImage = Toolkit.getDefaultToolkit().createImage(receivedBytes);
  PImage receiveImage = loadImageMT(awtImage);
  /* 受信終了 */
  /* ここから送信 */
  //バッファーイメージに変換
  BufferedImage bfImage = (BufferedImage)(capture.getImage());
  //ストリームの準備
  ByteArrayOutputStream bos = new ByteArrayOutputStream();
  BufferedOutputStream os = new BufferedOutputStream(bos);
  try {
    bfImage.flush();
    ImageIO.write(bfImage,”jpg”,os);
    os.flush();
    os.close();
  }
  catch(IOException e) {
  }
  sendBytes = bos.toByteArray();
  try {
    sendPacket = new DatagramPacket(sendBytes, sendBytes.length, remoteAddress);
    try{
      new DatagramSocket().send(sendPacket);
    } catch(IOException e){
    }
    println(“bufferImageSended:”+sendBytes.length+” bytes #2″);
  }
  catch(SocketException e) {
  }
  /* 送信終了 */
  //描画
  image(receiveImage,0,0);
  image(capture,width-width/4,height-height/4,capture.width/4,capture.height/4);
}
[/java]
横着して、catchではなにもしません。
setup()
具体的にsetup()内について見ていきます。
[java]
receiveSocket = new DatagramSocket(5101);
receivePacket = new DatagramPacket(buf,buf.length);
[/java]
ここで、受信ソケットのポートの設定をします(適当に5101番)。今回は、localhost内では2つアプリを起動することになるのですが、受信と送信ポートを互い違いにしないと動かないので注意です。(別のIPが振られてるところに飛ばすなら、全く同じアプリを起動させれば通信するはず)
その下で受信したデータをどこに格納するかを指定します。予め用意しておいたbyte[]を渡すと、受信するたびにそこに値が入っていきます。
[java]
 remoteAddress = new InetSocketAddress(“localhost”,5100);
[/java]
ここで、送信先とポートを設定します。今回はlocalhostですが、普通にIPでも大丈夫です。
[java]
 receiveSocket.setSoTimeout(1000);
[/java]
最後に受信のタイムアウトを設定します。今回は1000ミリ秒=1秒をタイムアウト時間に設定しました。これを指定してあげないと、受信データが来ない場合に永遠に待ち続けてしまうので、適当な値を指定してあげましょう。
draw()
次に描画部分です。まずは受信部。
[java]
  try {
    receiveSocket.receive(receivePacket);
  }
  catch(IOException e) {
  }
  Image awtImage = Toolkit.getDefaultToolkit().createImage(receivedBytes);
  PImage receiveImage = loadImageMT(awtImage);
[/java]
凄く簡単ですね。receiveメソッドを呼んであげれば、予め設定しておいたbyte[]にバイト配列が格納されます。ので、それをまずImageにしてあげて、さらにそれをPImageに変換してます。
次は送信部です。
[java]
  //バッファーイメージに変換
  BufferedImage bfImage = (BufferedImage)(capture.getImage());
  //ストリームの準備
  ByteArrayOutputStream bos = new ByteArrayOutputStream();
  BufferedOutputStream os = new BufferedOutputStream(bos);
[/java]
まず、キャプチャ画像をBufferedImageにしてあげて、ストリームの準備をします。
[java]
  try {
    bfImage.flush();
    ImageIO.write(bfImage,”jpg”,os);
    os.flush();
    os.close();
  }
  catch(IOException e) {
  }
  sendBytes = bos.toByteArray();
  try {
    sendPacket = new DatagramPacket(sendBytes, sendBytes.length, remoteAddress);
    try{
      new DatagramSocket().send(sendPacket);
    } catch(IOException e){
    }
    println(“bufferImageSended:”+sendBytes.length+” bytes #2″);
  }
  catch(SocketException e) {
  }
[/java]
次にImageIOを使ってjpgに変換します。そしてストリームに流し込んで、byteArrayにしてあげます。
DatagramPacketにbyte配列と宛先情報を渡して、それをDatagramSocket.send()すると送られます。
わぁ、簡単。
.png)