AS3 Quickie – Event.VIDEO_FRAME and Camera.drawToBitmapData()

In the past, if we wanted to copy some data from a camera object to a bitmap, we would need to draw the data from the display object using flash.display.BitmapData.draw() and then manipulate it in some way. This is problematic at times… if there is no way of knowing whether we have valid bitmap data to draw from!

Using Flash Player 11.4, we have a number of alternatives to this workflow which allow us to both listen for an event to fire once a frame is available to have its data harvested, and a number of methods from retrieving the frame data from the camera object in order to manipulate it.

The example below demonstrates this through the capture of bitmap data through a Camera object. This data is then sent directly to a Bitmap object on the display list, enabling a sort of picture-in-picture view of the camera feed.

If you have a camera attached to whatever you are using to read this, try out the demo below. You will need to be sure an allow camera and microphone access for Flash Player.

[kml_flashembed publishmethod=”static” fversion=”11.4.0″ movie=”/wp-content/uploads/2012/11/copyBitmapData.swf” width=”550″ height=”400″ targetclass=”flashmovie” play=”true” loop=”true” menu=”false” quality=”high” wmode=”direct” allowfullscreen=”true” allowscriptaccess=”always” allownetworking=”all”]
Requires Flash Player 11.4 or above!

To get this working only takes a few steps in your ActionScript code. The main classes we need to work with are flash.events.Event to listen for a video frame event, and flash.media.Camera to grab a local camera object to attach the event listener to. For any of this to work, you must target Flash Player 11.4 or above.

Now… this tutorial SORT OF builds upon the Quickie which demos how to attach a Camera to StageVideo – so we won’t be covering those bits, exactly… have a look at that demo if you need a refresher for this area.

In ActionScript, we must perform the necessary imports:

import flash.events.Event;
import flash.media.Camera;
import flash.display.Bitmap;
import flash.display.BitmapData;

The first thing we do is to assign an event listener to our Camera instance. To do this, it is safest to wait until our object has been added to the stage, and then add an event listener to check for flash.events.Event.VIDEO_FRAME.

camera = Camera.getCamera();
camera.setMode(512, 384, 24);
camera.addEventListener(Event.VIDEO_FRAME, onVideoFrame);

The second bit is to listen for a flash.events.Event.VIDEO_FRAME to fire; at which time we can feel safe that the camera bitmap data is available for us to use in some way. In this example, we are invoking Camera.drawToBitmapData() to render the video frame to a bitmap object on the stage. We could alternatively use Camera.copyToByteArray() or Camera.copyToVector() as well!

protected function onVideoFrame(e:Event):void {
	camera.drawToBitmapData(bmd);
}

The full code is below. Note that the FLA contains upon the Stage a TextField with the instance ID of statusField:

package  {
	import flash.display.MovieClip;
	import flash.text.TextField;
	import flash.media.StageVideo;
	import flash.media.StageVideoAvailability;
	import flash.media.Camera;
	import flash.events.Event;
	import flash.events.StageVideoAvailabilityEvent;
	import flash.events.StageVideoEvent;
	import flash.geom.Rectangle;
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	
	public class Main extends MovieClip {
		
		public var statusField:TextField;
		
		private var camera:Camera;
		private var stageVideo:StageVideo;
		private var bmd:BitmapData;
		private var bm:Bitmap;
		
		public function Main() {
			this.addEventListener(Event.ADDED_TO_STAGE, init);
		}
		
		protected function init(e:Event):void {
			stage.addEventListener(StageVideoAvailabilityEvent.STAGE_VIDEO_AVAILABILITY, availabilityChanged);
		}
		
		protected function availabilityChanged(e:StageVideoAvailabilityEvent):void {
			statusField.appendText("StageVideo => " + e.availability + "\n");
			if(e.availability == StageVideoAvailability.AVAILABLE){
				stageVideo = stage.stageVideos[0];
				bmd = new BitmapData(512, 384);
				bm = new Bitmap(bmd);
				bm.scaleX = 0.25;
				bm.scaleY = 0.25;
				bm.x = stage.stageWidth-bm.width;
				bm.y = stage.stageHeight-bm.height;
				addChild(bm);
				attachCamera();
			}
		}
		
		protected function attachCamera():void {
			statusField.appendText("Camera.isSupported => " + Camera.isSupported + "\n");
			if(Camera.isSupported){
				camera = Camera.getCamera();
				camera.setMode(512, 384, 24);
				camera.addEventListener(Event.VIDEO_FRAME, onVideoFrame);
				stageVideo.addEventListener(StageVideoEvent.RENDER_STATE, onRenderState);
				stageVideo.attachCamera(camera);
			}
		}
		
		protected function onRenderState(e:StageVideoEvent):void {
			stageVideo.viewPort = new Rectangle(0, 0, stage.stageWidth, stage.stageHeight);
		}
		
		protected function onVideoFrame(e:Event):void {
			camera.drawToBitmapData(bmd);
		}
		
	}
	
}

Want the full package? Download below:
Packaged code and Flash Professional CS6 project

3 thoughts on “AS3 Quickie – Event.VIDEO_FRAME and Camera.drawToBitmapData()”

    1. Which part? This is sort of like a part 2 since you need to know how to display video in the first place. All this demonstrates is that you can know when the data from a camera feed is available to you.

  1. Pingback: AS3 Quickie – Event.VIDEO_FRAME and Camera.drawToBitmapData() | In Flagrante Delicto! « eaflash

Leave a Reply to Joseph Labrecque Cancel Reply

Your email address will not be published. Required fields are marked *