Processingでビデオチャットを作ってみる

ここしばらくはKivyの記事を書くつもりが、成り行きで脱線中…。

TV会議システム実現に向けて、前回の音声チャットに続き、今回はProcessingビデオチャットを作ってみたいと思います。

今回も説明少なめ、コード多めでお送りします。

ビデオチャットの流れ

音声チャットの時同様、コードをシンプルにするために、映像送信用のスケッチと受信用のスケッチを別々に作ります。以下、処理の流れです。

  1. 映像送信用スケッチで、Webカメラに入力された画像を取得
  2. 取得した画像を画面に描画
  3. 取得した画像をjpgフォーマットに変換してサイズを圧縮
  4. UDPで圧縮したjpgデータを受信用スケッチに送信
  5. 映像受信用スケッチで、UDPで送られて来たjpgデータを受信
  6. 取得したjpgデータを画像(PImage)に展開
  7. 展開した画像を画面に表示

使用する外部ライブラリ

外部ライブラリとして、Webカメラの映像取得用に標準のvideoライブラリを、UDPの通信にUDPライブラリを使用します。

videominim共に、メニューのSketchImport Libraryから、videominimを選択することで追加できます。

映像送信用スケッチ

映像送信用のスケッチのコードは以下になります。

前回同様、冒頭のIPPORT定数を変更することで送信先と利用するポート番号を変更できます。ポート番号変更の際には、受信用スケッチ側のポート番号も併せて変更する必要があるので注意してください。

import java.io.*;
import java.awt.image.*;
import javax.imageio.*;
import processing.video.*;
import hypermedia.net.*;

final String IP = "localhost";
final int PORT = 6000;

UDP udp;
Capture cam;

void setup() {
  size(640, 480);

  udp = new UDP(this, 6100);

  cam = new Capture(this, Capture.list()[0]);
  cam.start();
}

void draw() {
  image(cam, 0, 0);

  if (cam.available()) {
    cam.read();
    broadcast(cam);
  }
}

void broadcast(PImage img) {
  img.loadPixels();

  BufferedImage bimg = new BufferedImage(img.width, img.height, BufferedImage.TYPE_INT_RGB);
  bimg.setRGB(0, 0, img.width, img.height, img.pixels, 0, img.width);

  ByteArrayOutputStream baos = new ByteArrayOutputStream();

  try {
    ImageIO.write(bimg, "jpg", new BufferedOutputStream(baos));
  }
  catch (IOException e) {
    e.printStackTrace();
  }

  udp.send(baos.toByteArray(), IP, PORT);
}

映像受信用スケッチ

映像受信用のスケッチのコードは以下になります。

import java.io.*;
import java.awt.image.*;
import javax.imageio.*;
import hypermedia.net.*;

final int PORT = 6000;

UDP udp;
PImage video;

void setup() {
  size(640, 480);

  udp = new UDP(this, PORT);
  udp.listen(true);

  video = createImage(640, 480, RGB);
}

void draw() {
  background(0);
  image(video, 0, 0);
}

void receive(byte[] data) {
  video.loadPixels();

  ByteArrayInputStream bais = new ByteArrayInputStream(data);

  try {
    ImageIO.read(bais).getRGB(0, 0, video.width, video.height, video.pixels, 0, video.width);
  }
  catch (Exception e) {
    e.printStackTrace();
  }

  video.updatePixels();
}

動作確認

実際の動作画面がこちらです。左がWebカメラの映像、右がUDP経由で受信した映像になります。

どちらも同一の画像が表示されていることがわかります。

f:id:tkitao:20140920173609p:plain

関係ないですが、映像は今戻って来ている実家です。

終わりに

2回にわたり、Processingでの音声、映像の送受信方法についてまとめてみました。TV会議については結局「WebRTCを使った方が手軽だよね☆」というオチがついたのですが、きっといつか面白い用途に使える日が来るのではないかと思います。

次回こそは、再びKivyの記事に戻ります。