擷取攝影機輸入Flash Player 9 以及更新的版本,Adobe AIR 1.0 以及更新的版本 除了外部視訊檔案之外,連接至使用者電腦的攝影機可以做為使用 ActionScript 來顯示和操作視訊資料的來源。Camera 類別是內建在 ActionScript 中的機制,讓您可以使用電腦攝影機。 瞭解 Camera 類別Camera 物件可讓您連接使用者的本機攝影機,並將視訊廣播回到本機使用者,或廣播至遠端伺服器 (例如 Flash Media Server)。 使用 Camera 類別,您可以存取下列各種關於使用者攝影機的資訊:
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() 方法。
設計攝影機應用程式當您撰寫應用程式以連接使用者的攝影機時,必須在程式碼中說明下列項目:
連接至使用者的攝影機連接至使用者攝影機的第一步就是建立新的攝影機實體,作法是建立 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 類別不會擴充 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() 函數。您可以使用下列兩個方法中的其中一個來偵測使用者按下了哪一個按鈕:
透過檢查要傳送的狀態事件,您可以撰寫程式碼以處理使用者接受或拒絕存取攝影機,並適當進行清理。例如,如果使用者按一下「拒絕」按鈕,您可以對使用者顯示訊息,說明如果他們要參與視訊交談,就必須按一下「允許」;或者您可以改為確認顯示清單上的 Video 物件是否已刪除,以釋放系統資源。 在 AIR 中,Camera 物件不會傳送狀態事件,因為使用攝影機的權限不是動態的。 最佳化視訊品質根據預設,Video 類別的新實體是 320 像素寬 x 240 像素高。為了最佳化視訊品質,您應該永遠確定視訊物件的尺寸與攝影機物件傳回的視訊尺寸相同。您可以使用 Camera 類別的 width 和 height 屬性取得攝影機物件的寬度與高度,接著再設定視訊物件的 width 和 height 屬性以符合攝影機物件的尺寸,或是您可以將攝影機的寬度與高度傳遞至 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() 函數會更新顯示清單上的文字欄位。 |
|