Capturing Video

The native video camera can be used to capture video within AIR.

Video and the CameraUI Class

You can use the native camera within AIR to capture video. Your application needs to have permission. In Flash Professional, select File→AIR Android settings→Permissions→ Camera. In Flash Builder, add the following permission:

[code]<uses-permission android:name=”android.permission.CAMERA”/>[/code]

The flash.media.CameraUI class is an addition to the ActionScript language to support the device’s native camera application. It is a subclass of the EventDispatcher class and is only supported on AIR for mobile.

This object allows you to launch the native camera application to shoot a video while your AIR application moves to the background.

When you use the native camera, it comes to the foreground, your AIR application moves to the background, and NativeApplication Event.DEACTIVATE is fired. Make sure you don’t have any logic that could interfere with the proper running of your application, such as exiting. Likewise, when the native camera application quits and your AIR comes back to the foreground, Event.ACTIVATE is called.

The first step is to verify that your device supports access to the camera by checking the CameraUI.isSupported property. Note that, as of this writing, Android does not support the front camera natively, and therefore neither does AIR:

[code]

import flash.media.CameraUI;
if (CameraUI.isSupported == false) {
trace(“no camera accessible”);
return;
}

[/code]

If it is supported, create an instance of the CameraUI class.

Register your application to receive camera events. A MediaEvent.COMPLETE is dispatched after a picture is taken, an Event.CANCEL if no media is selected, and an ErrorEvent if there is an error in the process:

[code]

import flash.events.MediaEvent;
import flash.events.ErrorEvent;
import flash.media.CameraUI;
var cameraUI:CameraUI = new CameraUI();
cameraUI.addEventListener(MediaEvent.COMPLETE, onComplete);
cameraUI.addEventListener(Event.CANCEL, onCancel);
cameraUI.addEventListener(ErrorEvent.ERROR, onError);

[/code]

Call the launch function and pass the type MediaType.VIDEO as a parameter. This will launch the camera in video mode automatically:

[code]

import flash.media.MediaType;
var cameraUI:CameraUI = new CameraUI();
cameraUI.launch(MediaType.VIDEO);
function onError(event:ErrorEvent):void {
trace(event.text);
}

[/code]

The camera application is now active and in the foreground. The AIR application moves to the background and waits.

Once the event is received, the camera application automatically closes and the AIR application moves back to the foreground.

Video capture on Android requires a lot of memory. To avoid having the Activity Manager terminate the application, the capture setting is restricted to low resolution by default, which requires a smaller memory buffer.

MPEG-4 Visual, Android low-resolution video, is not supported by AIR. Therefore, captured videos cannot be played back in AIR. The native application can be used to play back the recorded videos.

Currently, this functionality should only be used for capturing and not viewing unless you use the native application in the Gallery. The video is saved in a 3GP format that AIR does not support. Trying to play it back will just display a white screen.

In the following example, I provide the code for playback in AIR in case this is resolved in the future.

On select, a MediaEvent object is returned:

[code]

import flash.media.Video;
import flash.net.netConnection;
import flash.net.netStream;
var videoURL:String;
var connection:NetConnection;
function onComplete(event:MediaEvent):void {
videoURL = event.data.file.url;
connection = new NetConnection();
connection.addEventListener(NetStatusEvent.NET_STATUS, onStatus);
}
function onStatus(event:NetStatusEvent):void {
switch(event.info.code) {
case “NetConnection.Connect.Success” :
connectStream();
break;
case “NetStream.Play.StreamNotFound” :
trace(“video not found ” + videoURL);
break;
}
}
function connectStream():void {
stream = new NetStream(connection);
stream.addEventListener(NetStatusEvent.NET_STATUS, onStatus);
stream.addEventListener(AsyncErrorEvent.ASYNC_ERROR, onAsyncError);
var video:Video = new Video();
video.attachNetStream(stream);
stream.play(videoURL);
addChild(video);
}
function onAsyncError(event:AsyncErrorEvent):void {
trace(“ignore errors”);
}

[/code]

The Camera Class

The device’s camera, using the flash.media.Camera class, can be attached to a Video object in the AIR application. You can use this approach to simulate a web cam or for an Augmented Reality project.

The hardware orientation of the camera is landscape, so try to make your application’s orientation landscape too by changing the aspectRatio tag in your application descriptor:

[code]<aspectRatio>landscape</aspectRatio>[/code]

The setMode function is used to determine the video’s resolution:

[code]

import flash.media.Camera;
import flash.media.Video;
var camera:Camera = Camera.getCamera();
if (camera != null) {
camera.setMode(stage.stageWidth, stage.stageHeight, 15, true);
var video:Video = new Video(camera.width, camera.height);
video.x = 100;
video.y = 100;
video.attachCamera(camera);
addChild(video);
}

[/code]

Note that frames are only captured when the application is in the foreground. If the application moves to the background, capturing is paused but will resume automatically when the application moves to the foreground again.

You can query for the camera properties. Here are a few queries which may be helpful in your development:

[code]

camera.height;
camera.width;
camera.bandwidth;
camera.fps;
camera.muted
camera.name

[/code]

Documentation and Tutorials

Development around video is constantly evolving. The following two resources are among those that will help you to stay informed:

  • The Open Source Media Framework (http://www.opensourcemediaframework .com/resources.html) helps developers with video-related products. It is a good place to find code samples, tutorials, and other materials.
  • Lisa Larson-Kelly specializes in web video publishing and, more recently, mobilepublishing. She offers free tutorials and a newsletter on the latest technology (http://learnfromlisa.com/).

Audio and Application Activity

The Android Activity Manager controls applications moving to the foreground or the background based on the user’s decision, but doesn’t terminate them.

When your application goes to the background, most processes are paused, but audio and timers continue to run. Unless you want your audio to keep playing, you need to listen to two events to monitor a play and pause scenario:

[code]

import flash.desktop.NativeApplication;
import flash.events.Event;
NativeApplication.nativeApplication.addEventListener
(Event.ACTIVATE, onActivate);
NativeApplication.nativeApplication.addEventListener
(Event.DEACTIVATE, onDeactivate);
function onDeactivate(event:Event):void {
// pause or stop audio
}
function onActivate(event:Event):void {
// play audio
}

[/code]

Geolocation Classes

The flash.events.GeolocationEvent class is a new Event object that contains updated geolocation information. The new flash.sensors.Geolocation class is a subclass of the EventDispatcher class. It listens for and receives information from the device’s location sensor in the form of a GeolocationEvent.

To use the geolocation classes, first you must add the necessary permissions. In Flash Professional, enable ACCESS_FINE_LOCATION and ACCESS_COARSE_LOCATION device permissions under File→AIR Android Settings→Permissions. In Flash Builder, select ACCESS_NETWORK_STATE and ACCESS_WIFI_STATE under Mobile Settings→Permissions. To make changes, append your application manifest file as follows:

<uses-permission android:name=”android.permission.ACCESS_FINE_LOCATION” />
<uses-permission android:name=”android.permission.ACCESS_COARSE_LOCATION” />

Fine location refers to GPS communication, while coarse location refers to network communication.

During development and testing, you must select the checkboxes on your device in Android Settings→Location and Security→Use GPS satellites and Android Settings→Location and Security→Use wireless networks to enable both sensors, as shown in Figure 10-1.

Enabling sensors for wireless networks and GPS satellites

Next, verify that the device running your application supports geolocation:

import flash.sensors.Geolocation;
import flash.events.GeolocationEvent;
if (Geolocation.isSupported) {
// geolocation supported
}

Now let’s write a simple application to listen to geolocation event updates. Make geolocation a class variable, not a local variable, to guarantee that it does not get out of scope:

import flash.sensors.Geolocation;
import flash.events.GeolocationEvent;
var geolocation:Geolocation;
if (Geolocation.isSupported) {
geolocation = new Geolocation();
geolocation.addEventListener(GeolocationEvent.UPDATE, onTravel);
}
function onTravel(event:GeolocationEvent):void {
trace(event.latitude);
trace(event.longitude);
}

You should see your current latitude and longitude in degrees as floating-point values. My home location, for instance, is latitude 40.74382781982420 and longitude 74.00146007537840.

The user has the ability to enable or disable access to the location sensor on the device. Check the geolocation muted boolean property when you first run your application to see its value. You should also create a listener to receive status updates in case the property changes while the application is running:

import flash.events.StatusEvent;
if (!geolocation.muted) {
geolocation.addEventListener(StatusEvent.STATUS, onStatusChange);
} else {
// inform the user to turn on the location sensor
}
function onStatusChange(event:StatusEvent):void {
trace(“status:” + event.code);
if (event.code == “Geolocation.Muted”) {
// inform the user to turn on the location sensor
}
}

If muted is true, or if event.code is equal to Geolocation.Muted, display a message to the user requesting the need for location data.

The GeolocationEvent Class

A GeolocationEvent.UPDATE event is delivered when the listener is first created. Then, it is delivered when a new location update is received from the device/platform. An event is also delivered if the application wakes up after being in the background.

Using the geolocation API drains the battery very quickly. In an effort to save battery life, control the frequency of updates by setting an update interval on the geoloca tion object. Unless you are moving very quickly and want to check your speed, you don’t need to check your location more than once every few seconds or minutes:

geolocation.setRequestedUpdateInterval(10000);

If not specified by you, the updates are based on the device/platform default interval. Look up the hardware documentation if you want to know the device default interval; this is not something you can get in the Android or AIR API.

The Earth is divided using a grid system with latitude from the equator toward the North and South Poles and longitude from Greenwich, England, to the international date line in the Pacific Ocean. Values are positive from the equator going north and from Greenwich going east. Values are negative from the equator going south and from Greenwich going west.

The GeolocationEvent properties are as follows:

  • event.latitude ranges from ‒90 to 90 degrees and event.longitude ranges from ‒ 180 to 180 degrees. They are both of data type Number for greater precision.
  • event.horizontalAccuracy and event.verticalAccuracy are in meters. This value comes back from the location service and represents how accurate the data is. A small number represents a better reading. Less than 60 meters is usually considered GPS accurate. This measurement may change as the technology improves.
  • event.timeStamp is in milliseconds and starts counting from the moment the application initializes. If you need to get a regular update, use a timer instead of GeolocationEvent because it may not fire up at regular intervals.
  • event.altitude is in meters and event.speed is in meters/second.
  • event.heading, moving toward true north, is an integer. It is not supported on Android devices at the time of this writing, and it returns a value of NaN (Not a Number). However, you can calculate it by comparing longitude and latitude over time to determine a direction, assuming your device moves fast enough.

When your application moves to the background, the geolocation sensor remains active. If you want to overwrite the default behavior, listen to Native Application Event.DEACTIVATE to remove the event listener and Event.ACTIVATE to set it again.

When you first register for geolocation updates, AIR sets location listeners. It also queries for the LastKnownLocation and sends it as the first update. Because it is cached, the initial data may be incorrect until a first real location update is received.