カメラの操作

Flash Player 9 以降、Adobe AIR 1.0 以降

ユーザーのコンピューターに接続されたカメラをビデオデータのソースとして使用し、ActionScript で表示および操作することができます。 Camera クラスは、ActionScript に組み込まれているメカニズムで、コンピューターまたはデバイスのカメラを操作するためのものです。

モバイルデバイスでは、 CameraUI クラスを使用することもできます。CameraUI クラスは、個別のカメラアプリケーションを起動し、ユーザーが静止画やビデオをキャプチャできるようにします。ユーザーがキャプチャを終了すると、アプリケーションは MediaPromise オブジェクトを使用して、イメージやビデオにアクセスすることができます。

Camera クラスについて

Camera オブジェクトを使用すると、ユーザーのローカルカメラに接続し、ビデオをローカルでブロードキャスト(ユーザーに表示)したり、リモートで Flash Media Server などのサーバーに表示したりすることができます。

Camera クラスにより、ユーザーのカメラに関する次の情報を入手することができます。

  • ユーザーのコンピューターまたはデバイスにインストールされたカメラのうち、使用可能なもの

  • カメラがインストールされているかどうか

  • Flash Player がユーザーのカメラを使用できるかどうか

  • どのカメラがアクティブか

  • キャプチャされるビデオの幅と高さ

Camera クラスには、Camera オブジェクトの操作で使用できる便利なメソッドとプロパティがいくつかあります。 例えば、静的な Camera.names プロパティには、ユーザーのコンピューターにインストールされているカメラ名の配列があります。また、 name プロパティを使用し、アクティブなカメラの名前を表示することもできます。

注意: ネットワークを介してカメラビデオをストリーミングする際には、必ずネットワーク障害への対応が必要となります。ネットワーク障害は、特にモバイルデバイスにおいて、様々な原因により発生する可能性があります。

カメラコンテンツの画面への表示

カメラに接続すると、NetConnection および NetStream クラスでビデオをロードするよりもコード数が少なくて済みます。Flash Player では、カメラにアクセスする前に、そのカメラに接続するためのユーザーの許可が必要なので、Camera クラスは扱いが面倒になる可能性もあります。

次のコードでは、Camera クラスを使用してユーザーのローカルカメラに接続する方法を示します。

var cam:Camera = Camera.getCamera(); 
var vid:Video = new Video(); 
vid.attachCamera(cam); 
addChild(vid);
注意: Camera クラスには、コンストラクターメソッドはありません。 新しい Camera インスタンスを作成するには、静的な Camera.getCamera() メソッドを使用します。

カメラアプリケーションの設計

ユーザーのカメラに接続されるアプリケーションを作成するには、コードで次の点を考慮する必要があります。

  • カメラがインストールされているかどうかを確認します。使用できるカメラがない状況に対応します。

  • Flash Player の場合のみ、ユーザーがカメラへのアクセスを明示的に許可したかどうかをチェックします。セキュリティの理由から、カメラへのアクセスを許可するか拒否するかを選択するため、Flash Player の設定ダイアログボックスが表示されます。 これにより、Flash Player がユーザーの許可なくカメラに接続し、ビデオストリームをブロードキャストすることができなくなります。ユーザーの許可がある場合は、アプリケーションはユーザーのカメラに接続することができます。ユーザーが拒否した場合、アプリケーションはユーザーのカメラにアクセスすることができません。いずれの場合でも、適切に対応する必要があります。

  • AIR の場合のみ、アプリケーションでサポートされているデバイスプロファイルで Camera クラスがサポートされるかどうかをチェックします。

  • Camera クラスはモバイルブラウザーではサポートされません。

  • Camera クラスは、GPU レンダリングモードを使用するモバイル AIR アプリケーションではサポートされません。

  • モバイルデバイスでは、アクティブにできるカメラは一度に 1 つのみです。

ユーザーのカメラへの接続

ユーザーのカメラに接続するには、最初に、Camera タイプの変数を作成して新しい Camera インスタンスを作成し、静的な Camera.getCamera() メソッドの値を返すように初期化する必要があります。

次に、新しい Video オブジェクトを作成し、それに Camera オブジェクトを関連付けます。

次に、表示リストに Video オブジェクトを追加します。 Camera クラスは DisplayObject クラスを拡張せず、表示リストに直接追加することができないので、手順 2 および 3 を実行する必要があります。 カメラでキャプチャしたビデオを表示するには、新しい Video オブジェクトを作成し、 attachCamera() メソッドを呼び出します。

次のコードは、上記の 3 つの手順を示します。

var cam:Camera = Camera.getCamera(); 
var vid:Video = new Video(); 
vid.attachCamera(cam); 
addChild(vid);

カメラがインストールされていない場合、アプリケーションでは何も表示されません。

実際には、アプリケーションで追加手順を実行する必要があります。 詳しくは、 カメラのインストールの確認 および カメラのアクセス許可の検知 を参照してください。

カメラのインストールの確認

Camera インスタンスでメソッドまたはプロパティを使用する前に、カメラがインストールされているかどうかを確認します。そのためには、次の 2 つの方法があります。

  • 使用可能なカメラ名の配列を含む、静的な Camera.names プロパティを確認します。一度に複数のカメラをインストールしているユーザーはあまりいないので、この配列には通常は少数のストリングしか含まれていません。 次のコードでは、 Camera.names プロパティをチェックして、使用可能なカメラの有無を確認する方法を示します。

    if (Camera.names.length > 0) 
    { 
        trace("User has at least one camera installed."); 
        var cam:Camera = Camera.getCamera(); // Get default camera. 
    } 
    else 
    { 
        trace("User has no cameras installed."); 
    }
  • 静的な Camera.getCamera() メソッドの戻り値を確認します。使用可能またはインストールされているカメラがない場合、このメソッドは null を返します。それ以外の場合は、Camera オブジェクトへの参照を返します。次のコードでは、 Camera.getCamera() メソッドをチェックして、使用可能なカメラの有無を確認する方法を示します。

    var cam:Camera = Camera.getCamera(); 
    if (cam == null) 
    { 
        trace("User has no cameras installed."); 
    } 
    else 
    { 
        trace("User has at least 1 camera installed."); 
    }

Camera クラスは DisplayObject クラスを拡張しないので、 addChild() メソッドを使用して表示リストに直接追加することはできません。カメラでキャプチャしたビデオを表示するには、新しい Video オブジェクトを作成し、Video インスタンスで attachCamera() メソッドを呼び出す必要があります。

次のコード例では、カメラがある場合にそれを付加する方法を示します。カメラがない場合、アプリケーションには何も表示されません。

var cam:Camera = Camera.getCamera(); 
if (cam != null) 
{ 
    var vid:Video = new Video(); 
    vid.attachCamera(cam); 
    addChild(vid); 
}

モバイルデバイスのカメラ

モバイルブラウザーの Flash Player ランタイムでは、Camera クラスはサポートされていません。

モバイルデバイスの AIR アプリケーションでは、デバイス上のカメラにアクセスできます。モバイルデバイスでは、前面カメラと背面カメラの両方を使用できますが、特定の時点で表示可能なカメラ出力は 1 つだけです(2 番目のカメラを接続すると、最初のカメラは切断されます)。iOS 上では前面カメラの水平方向のミラー処理が行われますが、Android では行われません。

カメラのアクセス許可の検知

AIR アプリケーションサンドボックスでは、アプリケーションはユーザーの許可なくカメラにアクセスすることができます。ただし、Android では、アプリケーション記述子に Android の CAMERA 権限を指定する必要があります。

Flash Player がカメラの出力を表示する前に、ユーザーが Flash Player にカメラへのアクセスを明示的に許可する必要があります。 attachCamera() メソッドが呼び出されると、Flash Player によって設定ダイアログボックスが表示されます。このダイアログボックスで、ユーザーは Flash Player にカメラとマイクへのアクセスを許可するかどうかを指定します。ユーザーが「許可」ボタンをクリックした場合、Flash Player では、カメラの出力がステージの Video インスタンスに表示されます。「拒否」ボタンをクリックした場合は、Flash Player はカメラに接続できないので、Video オブジェクトは何も表示しません。

Flash Player がカメラへのアクセスを許可されているかどうかを確認するには、次のコードで示すように、カメラの status イベント( StatusEvent.STATUS )を監視します。

var cam:Camera = Camera.getCamera(); 
if (cam != null) 
{ 
    cam.addEventListener(StatusEvent.STATUS, statusHandler); 
    var vid:Video = new Video(); 
    vid.attachCamera(cam); 
    addChild(vid); 
} 
function statusHandler(event:StatusEvent):void 
{ 
    // This event gets dispatched when the user clicks the "Allow" or "Deny" 
    // button in the Flash Player Settings dialog box. 
    trace(event.code); // "Camera.Muted" or "Camera.Unmuted" 
}

「許可」または「拒否」のいずれかがクリックされると同時に、 statusHandler() 関数が呼び出されます。次のいずれかのメソッドを使用し、どのボタンがクリックされたかを検知することができます。

  • statusHandler() 関数の event パラメーターには、「Camera.Muted」または「Camera.Unmuted」というストリングを含むコードプロパティがあります。値が「Camera.Muted」であれば、「拒否」ボタンがクリックされているので、Flash Player はカメラにアクセスできません。次に例を示します。

    function statusHandler(event:StatusEvent):void 
    { 
        switch (event.code) 
        { 
            case "Camera.Muted": 
                trace("User clicked Deny."); 
                break; 
            case "Camera.Unmuted": 
                trace("User clicked Accept."); 
                break; 
        } 
    }
  • Camera クラスには muted という名前の読み取り専用のプロパティがあり、ユーザーがカメラへのアクセスを拒否したか( true )または許可したか( false )が、「Macromedia Flash Player 設定」の「プライバシー」パネルに表示されます。次に例を示します。

    function statusHandler(event:StatusEvent):void 
    { 
        if (cam.muted) 
        { 
            trace("User clicked Deny."); 
        } 
        else 
        { 
            trace("User clicked Accept."); 
        } 
    }

送出されるステータスイベントを確認すると、カメラへのアクセスの可否を処理するコードを記述し、適切にクリーンアップすることができます。例えば、「拒否」ボタンがクリックされた場合、ビデオチャットに参加するには「許可」ボタンをクリックする必要があるというメッセージを表示することができます。または、表示リストの Video オブジェクトが削除され、システムリソースが解放されていることを確認します。

AIR では、カメラを使用するための許可は動的ではないので、Camera オブジェクトはステータスイベントを送出しません。

カメラビデオ品質の最大化

デフォルトでは、Video クラスの新規インスタンスは幅 320 ピクセル、高さ 240 ピクセルです。 ビデオ品質を最大化するには、Video オブジェクトと、Camera オブジェクトによって返されるビデオのサイズを一致させる必要があります。 Camera クラスの width および height プロパティを使用して Camera オジェクトの幅と高さを取得し、Video オブジェクトの width および height プロパティを Camera オブジェクトと同じサイズに設定するか、次に示すようにカメラの幅と高さを Video クラスのコンストラクターメソッドに渡すことができます。

var cam:Camera = Camera.getCamera(); 
if (cam != null) 
{ 
    var vid:Video = new Video(cam.width, cam.height); 
    vid.attachCamera(cam); 
    addChild(vid); 
}

getCamera() メソッドは Camera オブジェクトへの参照を返すので(カメラがない場合は null )、ユーザーがカメラへのアクセスを拒否している場合でも、カメラのメソッドとプロパティにアクセスすることができます。これにより、カメラのネイティブの高さと幅を使用してビデオインスタンスのサイズを設定することができます。

var vid:Video; 
var cam:Camera = Camera.getCamera(); 
 
if (cam == null) 
{ 
    trace("Unable to locate available cameras."); 
} 
else 
{ 
    trace("Found camera: " + cam.name); 
    cam.addEventListener(StatusEvent.STATUS, statusHandler); 
    vid = new Video(); 
    vid.attachCamera(cam); 
} 
function statusHandler(event:StatusEvent):void 
{ 
    if (cam.muted) 
    { 
        trace("Unable to connect to active camera."); 
    } 
    else 
    { 
        // Resize Video object to match camera settings and  
        // add the video to the display list. 
        vid.width = cam.width; 
        vid.height = cam.height; 
        addChild(vid); 
    } 
    // Remove the status event listener. 
    cam.removeEventListener(StatusEvent.STATUS, statusHandler); 
}

フルスクリーンモードについて詳しくは、 Stage プロパティの設定 のフルスクリーンモードに関する節を参照してください。

カメラステータスの監視

カメラクラスには、Camera オブジェクトの現在のステータスを監視するためのプロパティがいくつかあります。例えば次のコードでは、表示リストで Timer オブジェクトとテキストフィールドインスタンスを使用して、カメラのプロパティをいくつか表示します。

var vid:Video; 
var cam:Camera = Camera.getCamera(); 
var tf:TextField = new TextField(); 
tf.x = 300; 
tf.autoSize = TextFieldAutoSize.LEFT; 
addChild(tf); 
 
if (cam != null) 
{ 
    cam.addEventListener(StatusEvent.STATUS, statusHandler); 
    vid = new Video(); 
    vid.attachCamera(cam); 
} 
function statusHandler(event:StatusEvent):void 
{ 
    if (!cam.muted) 
    { 
        vid.width = cam.width; 
        vid.height = cam.height; 
        addChild(vid); 
        t.start(); 
    } 
    cam.removeEventListener(StatusEvent.STATUS, statusHandler); 
} 
 
var t:Timer = new Timer(100); 
t.addEventListener(TimerEvent.TIMER, timerHandler); 
function timerHandler(event:TimerEvent):void 
{ 
    tf.text = ""; 
    tf.appendText("activityLevel: " + cam.activityLevel + "\n"); 
    tf.appendText("bandwidth: " + cam.bandwidth + "\n"); 
    tf.appendText("currentFPS: " + cam.currentFPS + "\n"); 
    tf.appendText("fps: " + cam.fps + "\n"); 
    tf.appendText("keyFrameInterval: " + cam.keyFrameInterval + "\n"); 
    tf.appendText("loopback: " + cam.loopback + "\n"); 
    tf.appendText("motionLevel: " + cam.motionLevel + "\n"); 
    tf.appendText("motionTimeout: " + cam.motionTimeout + "\n"); 
    tf.appendText("quality: " + cam.quality + "\n"); 
}

Timer オブジェクトの timer イベントは 10 分の 1 秒、つまり 100 ミリ秒ごとに送出され、 timerHandler() 関数は表示リストのテキストフィールドを更新します。