RED5を用いたVideo映像のストリーミング配信実験
November 14, 2009 – 2:23 pm前回(FLEXの学習:TV画像のブラウザ上への出力)、BS Digital用のチューナーからのTV画像をブラウザ上に出力した。これに引き続き、今回は、このTV画像を、RED5を用いて、ストリーミング配信してみた。予想以上に美しい画像を、インターネットを介して、配信することができた。今回のビデオ配信実験の概要をメモしておく。
Video映像のストリーミング配信実験では、BS Digital用のチューナーからのTV画像(Video映像)を手元(クライアント側)のローカルPCに取り込み、これをRED5が動作するサーバーマシンに送り、サーバーから配信されるVideo映像を、映像を取り込んだのと同じローカルPC上のブラウザに描画している。
下図は、今回行ったストリーミング配信実験に用いたクライアント側PCスクリーンをスナップショットしたものだ。画面の左上(「Test for Publisher」と表示されているウィンドウ)は、BSチューナーから取り込んだVideo映像(前回の「FLEXの学習:TV画像のブラウザ上への出力」にて説明したもの)がそのまま出力されている。一方、画面右下(「Test for Subscribe」と表示されているウィンドウ)は、RED5から配信されたVideo映像を受信したものが別のブラウザ上に出力されている。因みに、左下で、サーバーマシン上のRED5の動作状況(出力)をSSHを介してモニターしている。

このスナップショットを通じ、それなりのVideo映像がストリーミング配信されていることが理解されるだろう。ここで示したスナップショットでは、Video映像の動きを見ることはできないが、ストリーム配信されたVideo映像がチューナーから取り込まれた映像に比し、遜色ない動きとなっていることを付記しておきたい。
今回の配信実験では、クライアントサイドのプログラミングのみ行っており、サーバーサイドはRED5のパッケージで提供されているサンプルoflaDemoを用いている。クライアントサイドのプログラミングは、ThinkITの記事「【現場に学ぶWeb動画配信】Red5でストリーミング」に紹介されていた一連の手続きと、これからダウンロードしたActionScriptソースを参考に行っている。
クライアントサイドのプログラミングにあたっては、上記のThinkITのプログラムソースを映像取り込み(映像発信)側とストリーミング映像受信側に分割している。以下、映像発信(Publish)側と、映像受信側の各々について具体的なソースプログラムを示しながら説明しよう。
Publish側のプログラミング: PCに取り込んだBSチューナーからの映像と音声をRED5サーバーに送る。これを行うための一連の手続きは以下のようなものになる:
- まず、映像、音声情報(カメラ、マイク情報)のオブジェクトを作成する。これには、ローカルのPCに接続した映像・音声情報にアクセスするのに、映像、音声
情報を取得するために、夫々、クラスflash.media.Camera、flash.media.Microphoneを用いる。オブジェクトの作成にあたっては、Camera.getCamera()メソッド、Microphone.getMicrophone()メソッドを用いる。
- サーバーサイドと連携した処理を行うため、まず、NetConnectionを確立させる。
具体的な手続きとしては、
var pub_nc:NetConnection = new NetConnection();
pub_nc.connect(“rtmp://ip-address/oflaDemo”);これが確立すると、
- 映像・音声情報を送るためのストリームを生成し、これに映像・音声情報結びつける。映像・音声情報をのせるストリーム生成には、クラスflash.net.NetStreamが用いる。
具体的な手続きとしては、
var pub_ns:NetStream = new NetStream(pub_nc);
pub_ns.attacheAudio(myMicrophone):
pub_ns.attach(myCamera);
- 映像・音声情報をサーバー側に送信(publish)開始する。
pub_ns.publish(“demo”, “live”)
ここで、第1引数は、映像・音声の識別子となる文字列(demo)を、第2引数にはストリームのタイプ(live)を指定する。因みにサーバー上に映像・音声を録画・録音する場合には、この引数としてrecordが用いられる。
以上の手続きを具体的にプログラム化したmxmlのソースが下記である。なお、ここに示したソースでは、映像を取り込んだローカルPC上に表示するため、MXコントロールVideoDisplayを用いている。
Publish.mxml:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="publishVideo()"
width="640" height="360" layout="absolute">
<mx:Script>
<![CDATA[
import flash.net.NetConnection;
import flash.media.Camera;
import flash.media.Microphone;
import flash.net.NetStream;
import flash.events.*;
private var pub_nc:NetConnection;
private var pub_ns:NetStream;
private var myCamera:Camera;
private var myMic:Microphone;
public function publishVideo():void {
myCamera = Camera.getCamera();
myCamera.setMode(640,360, 30, true );
myCamera.setQuality(0,30);
myMic = Microphone.getMicrophone();
myMic.rate = 44;
vid.attachCamera(myCamera);
pub_nc = new NetConnection();
pub_nc.client = new CustomClient();
pub_nc.connect("rtmp://ip-address/oflaDemo");
pub_nc.addEventListener(NetStatusEvent.NET_STATUS,pub_netStatus);
pub_nc.addEventListener(SecurityErrorEvent.SECURITY_ERROR,onSecurityError);
}
private function pub_netStatus(event:NetStatusEvent):void {
if (event.info.code == "NetConnection.Connect.Success") {
pub_ns = new NetStream(pub_nc);
pub_ns.attachAudio(myMic);
pub_ns.attachCamera(myCamera);
pub_ns.publish("demo", "live");
}
else if (event.info.code == "NetConnection.Connect.Closed") {
pub_ns.close();
}
else {
trace("error");
}
}
private function onSecurityError(event:SecurityErrorEvent):void {
trace("netSecurityError:" + event);
}
]]>
</mx:Script>
<mx:VideoDisplay x="0" y="0" width="640" height="360" id="vid" />
</mx:Application>
Subscribe側のプログラミング: RED5から配信される映像・音声データは、映像・音声データをのせるストリームにかかわるクラスflash.net.NetStreamと、これを再生するためのクラスflash.media.Videoが用いられる。
具体的な手続きを書き下すと:
- 映像・音声を再生するエリアを作成する
var video:Video = new Video(640,360);
- 受信(再生)側のローカルPCとRED5サーバーをコネクトするため,NetConnectionを確立させる。
var play_nc:NetConnection = new NetConnection();
play_nc.connect(“rtmp//ip-address/oflaDemo”);
- NetConnectionが確立したら、ストリームを生成し、生成したストリームをvideoオブジェクトに結びつける
var play_ns:NetStream = new NetStream(play_nc);
play_ns.attachNetStream(play_ns);
- 受信(再生)側ローカルPCにおいて映像・音声の再生を行う
play_ns.play(“demo”);
ここで、メソッドsub_ns.play()の引数は、publish側で与えた映像・音声データの識別子(ここでは”demo”)与える。
以上の手続きをプログラム化したActionScriptソースを以下に与える。なお、当初、Publish側と同様に映像・音声の再生にあたってもMXコントロールVideoDisplay()を用いる計画であったが、これをVideoオブジェクトに結びつけることができなかった(理由はわからない)ため、ここでは生のActionScriptを用いている。
Subscribe.as:
package {
import flash.display.Sprite;
import flash.media.Video;
import flash.net.NetConnection;
import flash.net.NetStream;
import flash.events.*;
[SWF(width="640",height="360",frameRate="30",backgroundColor="#000066")]
public class Subscribe extends Sprite {
private var streamingURL:String = "rtmp://ip-address/oflaDemo";
private var play_nc:NetConnection;
private var play_ns:NetStream;
private var stat:Number;
private var video:Video;
public function Subscribe(){
video = new Video(640,360);
this.addChild(video);
playVideo();
}
public function playVideo():void{
play_nc = new NetConnection();
play_nc.client = new CustomClient();
play_nc.addEventListener(NetStatusEvent.NET_STATUS, play_netStatus);
play_nc.addEventListener(SecurityErrorEvent.SECURITY_ERROR, netSecurityError);
play_nc.connect(streamingURL);
}
private function play_netStatus(event:NetStatusEvent):void {
trace("netStatus: " + event.info.code);
if (event.info.code == "NetConnection.Connect.Success") {
play_ns = new NetStream(play_nc);
play_ns.play("demo");
video.attachNetStream(play_ns);
} else{
trace("error");
}
}
private function netSecurityError(event:SecurityErrorEvent):void {
trace("netSecurityError:" + event);
}
}
}
class CustomClient {
public function onBWDone():void {
trace("onBWDone");
}
public function onMetaData(infoObj:Object):void {
trace("onMetaData");
}
public function onPlayStatus(infoObj:Object):void {
trace("playStatus");
}
}
flashファイル(SWF)の作成とHTMLへの貼り付け: 上記したMXMLならびにActionScriptのソースをmxmlcによりコンパイルすることにより、flashファイル(SWF)が作成される。
これを前回の記事同様、swfobject.jsを用いてHTMLに貼り付ける。HTMLのソース(Publish側)を以下に示す。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>Red5 Test Page</title>
</head>
<body>
<h1>Test for Publisher</h1>
<script type="text/javascript" src="swfobject.js"></script>
<script type="text/javascript">
swfobject.embedSWF("Publish.swf","myContent","640","360","9.0.0",
"expressInstall.swf" );
</script>
<div id="myContent">
このテキストはflashコンテンツで置き換えられます。
</div>
</body>
</html>
RED5を起動(RED5パッケージを展開したディレクトリ上で ./red5.sh & )させた後、ローカルPC上でブラウザを開くことにより冒頭にしめした形で、映像・音声のストリーミング配信を確認することができる。
まとめ: 以上記したように、RED5を用いることにより、映像・音声のストリーミング配信が、かなりの性能で実現できた。この方式を、監視カメラの設置など、様々の用途に用いることが可能と考えられる。
技術的な課題としては、上記の手続きの説明のなかで言及したように、VideoオブジェクトとMXコントロールVideoDisplayとが結び付けられなかったあたり、更に検討を要するものと考えられる。
今回の作業では、クライアント側のプログラミングのみについて記した。理由は簡単。私がRED5においてサーバー側のプログラミングで必要とされるJavaプログラミングのスキルを持ち合わしていないためだ。今後、このあたりにも挑戦したいと考えている。
注意: なお、ここで記した技術、方式により、通常のテレビ番組の同時再送信が可能になることを理解していただけるだろう。しかし、こうした行為は、著作権等に触れる可能性もあることから十分に注意が必要だ。RED5とは直接関係ないが、TV映像の配信を可能とするサービスKeyHoleTVのサイトの冒頭で、次のような注意が行われている:
INFORMATION
不特定多数に見せたいコンテンツ以外は、パスワードを!!
不特定対数に見せたいコンテンツ以外は、パスワードをおかけください。
また、テレビ番組の同時再送信を行う場合は、ご自身並びにご家族とこれに準ずる方のみにパスワードをお教えください。尚、親しいご友人の場合でも、テレビ番組の再送信は家族と見なされず著作権侵害とされる場合があります。
この技術の使用にあたっては、このあたりを十分注意する必要がある。
今回のストリーミング配信実験でBSチューナーからの映像を利用したのは、利用可能な良質な映像ソースとして利用可能な例として用いているに過ぎない。
ご注意を!!
1 Trackback(s)