擷取攝影機輸入

Flash Player 9 以及更新的版本,Adobe AIR 1.0 以及更新的版本

除了外部視訊檔案之外,連接至使用者電腦的攝影機可以做為使用 ActionScript 來顯示和操作視訊資料的來源。Camera 類別是內建在 ActionScript 中的機制,讓您可以使用電腦攝影機。

瞭解 Camera 類別

Camera 物件可讓您連接使用者的本機攝影機,並將視訊廣播回到本機使用者,或廣播至遠端伺服器 (例如 Flash Media Server)。

使用 Camera 類別,您可以存取下列各種關於使用者攝影機的資訊:

  • 可利用使用者電腦安裝的哪些攝影機

  • 是否有安裝攝影機

  • 允許或拒絕 Flash Player 存取使用者的攝影機

  • 哪個是目前為作用中的攝影機

  • 所擷取視訊的寬度與高度

Camera 類別包括幾個有用的方法與屬性,讓您可以搭配攝影機物件使用。例如,靜態的 Camera.names 屬性包含目前安裝在使用者電腦上的攝影機名稱陣列。您也可以使用 name 屬性,顯示目前作用中攝影機的名稱。

備註: 跨網路串流攝影機視訊時,您應該永遠處理網路中斷。網路中斷發生的原因有很多種,特別是在行動裝置上。

在螢幕上顯示攝影機內容

連接至攝影機所需的程式碼會比使用 NetConnection 與 NetStream 類別以載入視訊來得少。Camera 類別也可能很快地變得難以處理,因為您必須先讓使用者允許 Flash Player 連接至他們的攝影機,才可以存取這些攝影機。

下列程式碼將示範如何使用 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 類別。

  • 在使用 GPU 顯示模式的行動 AIR 應用程式中不支援 Camera 類別。

  • 在 iOS 上,一次只能有一個攝影機為作用中。在 Android 上,只能存取面向前的攝影機。

連接至使用者的攝影機

連接至使用者攝影機的第一步就是建立新的攝影機實體,作法是建立 Camera 類型的變數,並將它初始化以傳回靜態 Camera.getCamera() 方法的值。

下一步就是建立新的視訊物件,並將 Camera 物件附加至該視訊物件。

第三步就是將該視訊物件加入顯示清單。您需要執行步驟 2 與步驟 3,因為 Camera 類別並不會擴充 DisplayObject 類別,所以無法將它直接加入至顯示清單。若要顯示攝影機所擷取的視訊,您可以建立新的視訊物件並呼叫 attachCamera() 方法。

下列程式碼會顯示這三個步驟:

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

請注意,如果使用者沒有安裝攝影機,應用程式將不會顯示任何項目。

針對實際的情況,您還必須為應用程式執行額外的步驟。如需詳細資訊,請參閱確定已安裝攝影機偵測存取攝影機的權限

確定已安裝攝影機

在您嘗試針對攝影機實體使用任何方法或屬性之前,必須確定使用者是否已安裝攝影機。有兩個方法可以檢查使用者是否已安裝攝影機:

  • 檢查靜態的 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); 
}

偵測存取攝影機的權限

在 AIR 應用程式安全執行程序中,應用程式可以存取任何攝影機,而不需取得使用者的權限。不過,在 Android 上,應用程式必須在應用程式描述器中指定 Android CAMERA 權限。

使用者必須明確允許 Flash Player 存取攝影機,Flash Player 才能顯示攝影機的輸出內容。呼叫 attachCamera() 方法時,Flash Player 會顯示「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 參數包含 code 屬性,這個屬性含有「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 的唯讀屬性,它會指定使用者在 Flash Player「私用」面板中已拒絕存取攝影機 (true) 或允許存取攝影機 (false)。在下列程式碼片段中,您會看到這種範例:

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

透過檢查要傳送的狀態事件,您可以撰寫程式碼以處理使用者接受或拒絕存取攝影機,並適當進行清理。例如,如果使用者按一下「拒絕」按鈕,您可以對使用者顯示訊息,說明如果他們要參與視訊交談,就必須按一下「允許」;或者您可以改為確認顯示清單上的 Video 物件是否已刪除,以釋放系統資源。

在 AIR 中,Camera 物件不會傳送狀態事件,因為使用攝影機的權限不是動態的。

最佳化視訊品質

根據預設,Video 類別的新實體是 320 像素寬 x 240 像素高。為了最佳化視訊品質,您應該永遠確定視訊物件的尺寸與攝影機物件傳回的視訊尺寸相同。您可以使用 Camera 類別的 widthheight 屬性取得攝影機物件的寬度與高度,接著再設定視訊物件的 widthheight 屬性以符合攝影機物件的尺寸,或是您可以將攝影機的寬度與高度傳遞至 Video 類別的建構函式方法,如下列程式碼片段所示:

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

既然 getCamera() 方法會傳回攝影機物件的參考 (或是如果沒有可用的攝影機,就會傳回 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"); 
}

每 1/10 秒 (100 毫秒) 就會傳送 Timer 物件的 timer 事件,而且 timerHandler() 函數會更新顯示清單上的文字欄位。