中西研の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()すると送られます。
わぁ、簡単。
という感じで、Processingで簡単なビデオチャットが出来ます。