2011年7月8日金曜日

FlexやFlash(not in Air)でローカルのビデオを再生できるか?(2011年版)

以前にもFlexやFlashにおいてFileReferenceを使ってローカルビデオを読み込んで再生できないものかと調べたことがある。その時は結局ムリという結論に達した。

琴線探査: FlexやFlash(not in Air)でローカルのビデオを再生できるか?

現状もあまり変わっていないようだけど、APIドキュメントを改めて見ていて、ひとつだけ重要な変化があったことに気がついた。flash.net.NetStreamだ。

その変更点は10.1から追加されたメソッドappendBytes()。確か以前に調べてたときはこのメソッドは無かったと思う。これがあれば、FileReferenceで読み込んだローカルビデオのバイト列を読み込ませることができるのではないか?

できた!

ポイントとなるコードだけ抜き出しておこう。

protected var netStream:NetStream;
protected var video:Video;


/**
 * アプリケーション初期化完了時
 * 
 */
protected function onCreationComplete():void {

  //NetConnection構築
  var netConn:NetConnection = new NetConnection();
  netConn.connect(null);

  //NetStream構築
  netStream = new NetStream(netConn);
  var client:Object = new Object();
  netStream.client = client;
  client.onMetaData = onMetaData; //これは指定しないとダメ
  function onMetaData(param:Object):void {
    video.width = param.width;
    video.height = param.height;
  }

  //Videoオブジェクト構築
  video = new Video();
  video.attachNetStream(netStream);

  //Videoは直接Groupに追加できないのでUIComponentでラップしてから追加
  var videoUI:UIComponent = new UIComponent();
  videoUI.addChild(video);
  videoGroup.addElement(videoUI);

}


/**
 * ファイル選択時
 * 
 */
protected function onFileSelected():void {

  //FileReferenceに追加するイベントリスナーを掃除するメソッド
  function removeEventListeners():void {
    fileReference.removeEventListener(Event.COMPLETE, onComplete);
    fileReference.removeEventListener(IOErrorEvent.IO_ERROR, onIoError);
  }

  //IOエラー時の処理追加
  fileReference.addEventListener(IOErrorEvent.IO_ERROR, onIoError);
  function onIoError(evt:IOErrorEvent):void {
    log.info("onIoError() IOエラー");
    removeEventListeners();
  }

  //バイト列読み込み完了時の処理追加
  fileReference.addEventListener(Event.COMPLETE, onComplete);
  function onComplete(evt:Event):void {
    log.info("onComplete() バイト列読み込み完了:" + fileReference.size);
    removeEventListeners();
    netStream.play(null); //appendBytes*より前でないとダメ
    netStream.appendBytesAction(NetStreamAppendBytesAction.RESET_BEGIN);
    netStream.appendBytes(fileReference.data);  //ここがミソ
  }

  //バイト列読み込み開始
  fileReference.load();

}

本当はspark.components.VideoDisplayで再生させたいけど、VideoDisplay.sourceがバイト列を受け付けるようになるか、VideoDisplay.loadBytes()とか、そういうのが無いとやっぱ無理。

flash.media.Videoはビデオを表示するだけでまったくコントロールする方法がないけれど、NetStreamの方に色々とコントロールできそうなメソッドがあるので、何とかなりそう。

かと思ったけど、pause()とresume()は正常だけどseek()およびstep()がまともに動作しない由。ネットからストリームしていないからだろうか。原因不明。

とにかく、Flex/Flashでローカルビデオを扱うのはまだまだ難しいということがわかった。