Praca z kamerami

Flash Player 9 i nowsze wersje, Adobe AIR 1.0 i nowsze wersje

Źródłem danych wideo, które wyświetla i na których operuje kod ActionScript, może być kamera podłączona do komputera użytkownika. Klasa Camera stanowi mechanizm wbudowany w kod ActionScript przeznaczony do pracy z kamerą komputera lub urządzenia.

Na urządzeniach przenośnych można również używać klasy CameraUI . Klasa CameraUI powoduje uruchomienie oddzielnej aplikacji kamery, przy użyciu której użytkownik może rejestrować obrazy nieruchome lub wideo. Po zakończeniu pracy przez użytkownika aplikacja może uzyskać dostęp do obrazów lub filmów wideo za pośrednictwem obiektu MediaPromise .

Omówienie klasy Camera

Obiekt Camera umożliwia nawiązanie połączenia z lokalną kamerą użytkownika i rozgłaszanie wideo z kamery lokalnie (na komputerze użytkownika) lub zdalnie do serwera (np. Flash Media Server).

Korzystając z klasy Camera, można uzyskać dostęp do następujących rodzajów informacji o kamerze użytkownika:

  • które z kamer zainstalowanych na komputerze lub na urządzeniu użytkownika są dostępne;

  • czy w ogóle jest zainstalowana kamera;

  • czy program Flash Player ma zezwolenie na dostęp do kamery użytkownika;

  • która kamera jest obecnie aktywna;

  • szerokość i wysokość przechwytywanego wideo.

Klasa Camera zawiera kilka użytecznych metod i właściwości służących do pracy z obiektami kamer. Na przykład statyczna właściwość Camera.names zawiera tablicę nazw kamer zainstalowanych obecnie w komputerze użytkownika. Można również skorzystać z właściwości name w celu wyświetlenia nazwy kamery, która jest obecnie aktywna.

Uwaga: Podczas przesyłania strumieniowego w sieci wideo z aparatu należy zawsze obsługiwać przerwy w działaniu sieci. Przerwy w działaniu sieci mogą być spowodowane szeregiem czynników, szczególnie na urządzeniach przenośnych.

Wyświetlanie obrazu z kamery na ekranie

Połączenie z kamerą można zrealizować w prostszy sposób niż ładowanie wideo przy użyciu klas NetConnection i NetStream. Z drugiej strony, sposób użycia klasy Camera nie zawsze jest oczywisty, ponieważ w programie Flash Player dostęp do kamery jest możliwy dopiero po udzieleniu przez użytkownika zgody na taki dostęp.

Poniższy kod ilustruje sposób użycia klasy Camera do nawiązania połączenia z lokalną kamerą użytkownika:

var cam:Camera = Camera.getCamera(); 
var vid:Video = new Video(); 
vid.attachCamera(cam); 
addChild(vid);
Uwaga: Klasa Camera nie ma konstruktora. Do tworzenia nowych instancji klasy Camera służy statyczna metoda Camera.getCamera() .

Projektowanie aplikacji współpracującej z kamerą

Pisząc aplikację nawiązującą połączenie z kamerą użytkownika, należy uwzględnić następujące uwarunkowania:

  • Należy sprawdzić, czy użytkownik ma zainstalowaną kamerę. Należy obsłużyć sytuację, w której nie jest dostępny żadna kamera.

  • Tylko w przypadku programu Flash Player — należy sprawdzić, czy użytkownik jawnie zezwolił na dostęp do kamery. Ze względów bezpieczeństwa wyświetlane jest okno dialogowe ustawień programu Flash Player, w którym użytkownik może zezwolić na dostęp do kamery lub odmówić takiego dostępu. Uniemożliwia to programowi Flash Player nawiązanie połączenia z kamerą i rozgłaszanie strumienia wideo bez zgody użytkownika. Jeśli użytkownik kliknie opcję zezwolenia, aplikacja może nawiązać połączenie z kamerą użytkownika. Jeśli użytkownik kliknie opcję odmowy, aplikacja nie będzie miała dostępu do kamery. Aplikacja powinna zawsze prawidłowo reagować na obie decyzje użytkownika.

  • Tylko w środowisku AIR należy sprawdzić, czy klasa Camera jest obsługiwana dla profilów urządzeń obsługiwanych przez aplikację.

  • Klasa Camera nie jest obsługiwana w przeglądarkach na urządzeniach przenośnych.

  • Klasa Camera nie jest obsługiwana w aplikacjach AIR na urządzeniach przenośnych, w których jest używany tryb renderowania GPU.

  • W urządzeniach przenośnych może być aktywna tylko jedna kamera naraz.

Nawiązywanie połączenia z kamerą użytkownika

Pierwszym krokiem przy nawiązywaniu połączenia z kamerą użytkownika jest utworzenie nowej instancji kamery poprzez utworzenie zmiennej typu Camera i zainicjowanie jej wartością zwróconą ze statycznej metody Camera.getCamera() .

Następnym krokiem jest utworzenie obiektu wideo i przyłączenie do niego obiektu Camera.

Trzecim krokiem jest dodanie obiektu wideo do listy wyświetlania. Kroki 2 i 3 są konieczne, ponieważ klasa Camera nie rozszerza klasy DisplayObject i obiektów klasy Camera nie można dodawać bezpośrednio do listy wyświetlania. Aby wyświetlać obraz wideo przechwytywany z kamery, należy utworzyć nowy obiekt wideo i wywołać metodę attachCamera() .

Poniższy kod ilustruje wymienione trzy kroki:

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

Należy zwrócić uwagę, że jeśli użytkownik nie ma zainstalowanej kamery, aplikacja nie wyświetla żadnych informacji.

W prawdziwej aplikacji konieczne jest wykonanie dodatkowych kroków. Więcej informacji zawierają sekcje Sprawdzanie, czy kamera jest zainstalowania oraz Wykrywanie uprawnień dostępu do kamery .

Sprawdzanie, czy kamera jest zainstalowania

Przed próbą użycia jakichkolwiek metod lub właściwości instancji kamery należy sprawdzić, czy w komputerze użytkownika jest zainstalowana kamera. Istnieją dwa sposoby sprawdzenia, czy użytkownik ma zainstalowaną kamerę:

  • Odczyt statycznej właściwości Camera.names , która zawiera listę nazw dostępnych kamer. Zwykle ta tablica będzie zawierała jeden ciąg znaków lub w ogóle nie będzie zawierała ciągów znaków, ponieważ użytkownicy rzadko mają zainstalowaną więcej niż jedną kamerę. Poniższy kod ilustruje sposób odczytywania właściwości Camera.names w celu sprawdzenia, czy w komputerze użytkownika są dostępne kamery:

    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."); 
    }
  • Sprawdzenie wartości zwracanej przez statyczną metodę Camera.getCamera() . Jeśli żadne kamery nie są dostępne lub zainstalowane, metoda ta zwraca null , w przeciwnym razie zwraca odwołanie do obiektu Camera. Poniższy kod ilustruje sposób odczytywania wyniku metody Camera.getCamera() w celu sprawdzenia, czy w komputerze użytkownika są dostępne kamery:

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

Ponieważ klasa Camera nie rozszerza klasy DisplayObject, obiektów Camera nie można dodawać bezpośrednio do listy wyświetlania przy użyciu metody addChild() . Aby wyświetlać obraz wideo z kamery, należy utworzyć nowy obiekt Video i wywołać metodę attachCamera() w instancji obiektu Video.

Poniższy urywek kodu ilustruje sposób przyłączania kamery (jeśli kamera istnieje); w razie braku kamery aplikacja nie wyświetla żadnego obrazu:

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

Kamery w urządzeniach przenośnych

Klasa Camera nie jest obsługiwana w środowisku wykonawczym Flash Player w przeglądarkach na urządzeniach przenośnych.

W aplikacjach AIR na urządzeniach przenośnych można uzyskiwać dostęp do kamer urządzeń. W urządzeniach przenośnych można używać kamery przedniej lub tylnej, ale w danej chwili może być wyświetlany obraz tylko z jednej kamery. (Podłączenie drugiej kamery spowoduje odłączenie pierwszej). W systemie iOS obraz z kamery przedniej jest poddawany odbiciu lustrzanemu w poziomie. Nie dzieje się tak w systemie Android.

Wykrywanie uprawnień dostępu do kamery

W obszarze izolowanym aplikacji środowiska AIR aplikacja ma dostęp do każdej kamery, bez pytania użytkownika o zgodę. W systemie Android w deskryptorze aplikacji musi być określone uprawnienie CAMERA systemu Android.

Jednak aby program Flash Player mógł wyświetlać obraz z kamery, użytkownik musi jawnie zezwolić mu na dostęp do kamery. Po wywołaniu przez aplikację metody attachCamera() program Flash Player wyświetla okno dialogowe Ustawienia Flash Player z monitem o zezwolenie lub odmowę dostępu do kamery i mikrofonu zainstalowanych w systemie. Jeśli użytkownik kliknie przycisk zezwolenia, program Flash Player wyświetli obraz z kamery w instancji Video na stole montażowym. Jeśli użytkownik kliknie przycisk odmowy, program Flash Player nie będzie mógł nawiązać połączenia z kamerą, a obiekt Video nie wyświetli żadnych informacji.

Aby sprawdzić, czy użytkownik zezwolił programowi Flash Player na dostęp do kamery, można wykrywać zdarzenia status kamery ( StatusEvent.STATUS ), co ilustruje poniższy kod:

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" 
}

Funkcja statusHandler() jest wywoływana w momencie, gdy użytkownik kliknie przycisk zezwolenia albo odmowy. Aby sprawdzić, który przycisk został kliknięty, można skorzystać z jednej z dwóch metod:

  • Parametr event funkcji statusHandler() zawiera właściwość code, która z kolei zawiera ciąg znaków "Camera.Muted" albo "Camera.Unmuted". Wartość "Camera.Muted" oznacza, że użytkownik kliknął przycisk odmowy, a program Flash Player nie ma dostępu do kamery. Oto przykład zastosowania tej metody:

    function statusHandler(event:StatusEvent):void 
    { 
        switch (event.code) 
        { 
            case "Camera.Muted": 
                trace("User clicked Deny."); 
                break; 
            case "Camera.Unmuted": 
                trace("User clicked Accept."); 
                break; 
        } 
    }
  • Klasa Camera zawiera właściwość muted przeznaczoną tylko do odczytu; właściwość ta określa, czy użytkownik odmówił dostępu do kamery ( true ), czy zezwolił na taki dostęp ( false ) w panelu Prywatność programu Flash Player. Oto przykład zastosowania tej metody:

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

Wykrywając zdarzenie status, kod może odpowiednio reagować na zgodę lub odmowę użytkownika na dostęp do kamery i wykonać odpowiednie czynności porządkowe. Na przykład, jeśli użytkownik kliknie przycisk odmowy, może zostać wyświetlony komunikat informujący, że bez zgody na dostęp do kamery nie będzie możliwy udział użytkownika w wideoczacie. Kod może także usuwać obiekt Video z listy wyświetlania w celu zwolnienia zasobów systemowych.

W środowisku AIR obiekt Camera nie wywołuje zdarzeń stanu, ponieważ uprawnienie do używania kamery nie jest dynamiczne.

Uzyskiwanie jak najlepszej jakości wideo z kamery

Domyślnie nowe instancje klasy Video mają szerokość 320 pikseli i wysokość 240 pikseli. Aby uzyskać jak najlepszą jakość wideo, należy zawsze dbać o to, aby obiekt wideo aplikacji miał te same wymiary, co obraz wideo przesyłany z obiektu kamery. Szerokość i wysokość obrazu z obiektu kamery można uzyskać, odczytując właściwości width i height klasy Camera. Następnie można przypisać właściwościom width i height obiektu wideo wymiary obrazu lub przekazać szerokość i wysokość obrazu z kamery do konstruktora klasy Video, co ilustruje poniższy fragment:

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

Ponieważ metoda getCamera() zwraca odwołanie do obiektu kamery (lub null , jeśli nie ma dostępnej kamery), możliwe jest uzyskiwanie dostępu do metod i właściwości kamery nawet wówczas, gdy użytkownik odmówi dostępu do swojej kamery. Dzięki temu możliwe jest dopasowanie rozmiaru instancji Video do natywnej wysokości i szerokości obrazu z kamery.

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); 
}

Informacje na temat trybu pełnoekranowego zawiera punkt dotyczący tego trybu w sekcji Ustawianie właściwości obiektu Stage .

Monitorowanie stanu kamery

Klasa Camera zawiera kilka właściwości umożliwiających monitorowanie bieżącego statusu obiektu Camera. Na przykład poniższy kod wyświetla kilka właściwości kamery przy użyciu obiektu Timer i instancji pola tekstowego na liście wyświetlania:

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"); 
}

Co 1/10 sekundy (100 milisekund) wywoływane jest zdarzenie timer obiektu Timer, a funkcja timerHandler() aktualizuje pole tekstowe na liście wyświetlania.