使用摄像头

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 类。

  • 使用 GPU 呈现模式的移动 AIR 应用程序不支持 Camera 类。

  • 在 iOS 上,在同一时间只能有一个摄像头处于活动状态。

  • 在 Android 上,只能访问后置摄像头

连接至用户的摄像头

连接到用户摄像头时,执行的第一步是通过创建一个类型为 Camera 的变量并将其初始化为静态 Camera.getCamera() 方法的返回值来创建一个新的 Camera 实例。

下一步是创建一个新的视频对象并向其附加 Camera 对象。

第三步是向显示列表中添加该视频对象。由于 Camera 类不会扩展 DisplayObject 类,它不能直接添加到显示列表中,因此需要执行第 2 步和第 3 步。若要显示摄像头捕获的视频,需要创建一个新的视频对象并调用 attachCamera() 方法。

以下代码演示这三个步骤:

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

注意,如果用户未安装摄像头,应用程序不会显示任何内容。

在实际情况下,您需要对应用程序执行其他步骤。有关详细信息,请参阅验证是否已安装摄像头检测摄像头的访问权限

验证是否已安装摄像头

在尝试对 Camera 实例使用任何方法或属性之前,您需要验证用户是否已安装了摄像头。检查用户是否已安装摄像头有两种方式:

  • 检查静态 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 应用程序中,您可以访问该设备上的一个或多个摄像头。在 iOS 上,可以使用前置和后置摄像头,但在任何给定时间只能显示一个摄像头输出。(附加第二个摄像头会断开与第一个摄像头的连接。)前置摄像头以水平方式获得镜像。在 Android 上,只能访问后置摄像头。

检测摄像头的访问权限

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

通过检查将要调度的 status 事件,您可以编写代码来处理用户接受或拒绝访问摄像头的操作并进行相应的清理。例如,如果用户单击“拒绝”按钮,则您可以向用户显示一条消息,说明他们如果想要参加视频聊天的话,需要单击“允许”;或者,您也可以确保删除显示列表中的 Video 对象以释放系统资源。

在 AIR 中,由于使用摄像机的权限不是动态的,Camera 对象不调度状态事件。

最优化摄像头视频品质

默认情况下,Video 类的新实例为 320 像素宽乘以 240 像素高。为了最优化视频品质,应始终确保视频对象与 Camera 对象返回的视频具有相同的尺寸。使用 Camera 类的 widthheight 属性,您可以获取 Camera 对象的宽度和高度,然后将该视频对象的 widthheight 属性设置为与 Camera 对象的尺寸相符,也可以将 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),因此,即使用户拒绝访问其摄像头,您也可以访问 Camera 对象的方法和属性。这样可以使用摄像头的本机高度和宽度设置视频实例的尺寸。

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

有关全屏模式的信息,请参阅设置舞台属性下的全屏模式部分。

监控摄像头状态

Camera 类包含多个属性,这些属性允许您监视 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() 函数会更新显示列表上的文本字段。