捕获摄像头输入Flash Player 9 和更高版本,Adobe AIR 1.0 和更高版本 除了外部视频文件外,附加到用户计算机上的摄像头也可以作为您使用 ActionScript 进行显示和操作的视频数据的来源。Camera 类是 ActionScript 中内置的机制,用于使用计算机摄像头。 了解 Camera 类使用 Camera 对象可以连接到用户的本地摄像头并在本地广播视频(播放给用户),或将其广播到远程服务器(比如 Flash Media Server)。 使用 Camera 类可以访问有关用户摄像头的以下各种信息:
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() 方法。
设计摄像头应用程序在编写需要连接到用户摄像头的应用程序时,需要在代码中考虑以下事项:
连接至用户的摄像头连接到用户摄像头时,执行的第一步是通过创建一个类型为 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 类未扩展 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() 函数。使用以下两种方法之一可以检测用户单击了哪个按钮:
通过检查将要调度的 status 事件,您可以编写代码来处理用户接受或拒绝访问摄像头的操作并进行相应的清理。例如,如果用户单击“拒绝”按钮,则您可以向用户显示一条消息,说明他们如果想要参加视频聊天的话,需要单击“允许”;或者,您也可以确保删除显示列表中的 Video 对象以释放系统资源。 在 AIR 中,由于使用摄像机的权限不是动态的,Camera 对象不调度状态事件。 最优化视频品质默认情况下,Video 类的新实例为 320 像素宽乘以 240 像素高。为了最优化视频品质,应始终确保视频对象与 Camera 对象返回的视频具有相同的尺寸。使用 Camera 类的 width 和 height 属性,您可以获取 Camera 对象的宽度和高度,然后将该视频对象的 width 和 height 属性设置为与 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() 函数会更新显示列表上的文本字段。 |
|