Until recently, a significant difference between the BlackBerry platform and its much-discussed competitors (Android, iPhone, and WebOS) was that BlackBerry did not support capturing video within programs. The recent release of BlackBerry OS version 5 remedies this problem with a well-established and proven interface. Now BlackBerry developers can impress their customers and peers by demonstrating that their little device can record video just as well as devices running on those other platforms that seem to be getting so much attention.
This article shows how with roughly a dozen lines of code you can upgrade your existing BlackBerry applications to add video support. Consider the following use case.
With the recent softness in the US housing market, people are increasingly interested in finding bargain properties to buy, or searching for a good apartment to rent. As anyone who has been through this process knows, it can be difficult to remember the details of potential homes by the end of the day, let alone after a month of searching. Wouldn’t it be great if you could recall what each place looked like?
Well, you will make a BlackBerry app for that. This sample application will be called HomeHunter, and will present a simple interface that allows users to store each place they have visited, attach notes to each one, and, more impressively, insert a video as well.
What You Need |
---|
Eclipse 3.4 (Ganymede) |
BlackBerry Plug-in for Eclipse |
BlackBerry Device Simulators for 5.0 |
A BlackBerry device running OS version 5.0 or higher |
Building the UI
To get started, you will write a simple application screen that allows the user to enter all relevant information about a location: address, date of visit, and any notes. You’ll also put in some placeholders for starting and stopping a recording. Figure 1 shows what this early version of the application looks like.
Figure 1. HomeHunter Screen: The basic screen shows all visual elements in place, right before adding video capture.
Video Capture at Last
Rather than re-invent the wheel, BlackBerry has taken advantage of the existing Multi-Media API (MMAPI) that was created for Java-enabled phones. BlackBerry has supported this API for several years, but only with the release of the 5.0 OS has it expanded its support to include video recording.
MMAPI centers on a class called Player. Many developers have experience creating Players to play back music within their apps, but fewer realize that they can use the same Player class for recording media as well.
Creating a Player for recording is similar to creating one for playback. You might play back audio using something like this:
Manager.createPlayer("file:///SDCard/BlackBerry/music.pcm");
If you wanted to create a Player suitable for recording, you could instead do this:
Manager.createPlayer("capture://audio");
When you get a Player, you should start it. Unlike playback, which would start playing the music at this point, starting a capture-mode player simply places it into a state where it can begin recording data.
To start the actual recording process, you must obtain a RecordControl. This is a special interface that you can use to manipulate how the recording is supposed to work. It contains options for starting and stopping the recording, and also lets you set a limit on the size of the recorded file. You can obtain a RecordControl in the same way you would retrieve another type of Control for a Player:
RecordControl recorder =
(RecordControl)player.getControl("RecordControl");
Now it’s time to do a quick proof of concept that uses a recorder to capture audio. This would be useful if the user wants to speak notes into HomeHunter, and would be a great solution for phones that aren’t yet running the 5.0 OS. You should run audio capture in a separate thread; otherwise, the whole user interface will freeze while the player is initializing. This code shows how to start recording when the user makes a selection from the BlackBerry menu:
private volatile boolean recording;
private Player player;
private RecordControl recorder;
private MenuItem startRecording = new MenuItem("Start Recording",
0, 0)
{
public void run()
{
if (!recording)
{
new StartRecordingThread().start();
}
}
};
private class StartRecordingThread extends Thread
{
public void run()
{
try
{
if (player == null || recorder == null)
{
player = Manager.createPlayer("capture://audio");
player.start();
recorder = (RecordControl) player
.getControl("RecordControl");
}
recorder.setRecordLocation
("file:///SDCard/BlackBerry/temp.amr");
recorder.startRecord();
recording = true;
}
catch (Throwable t)
{
t.printStackTrace();
}
}
}
Similarly, the code to stop recording will run in a separate thread and clean up the operation:
private MenuItem stopRecording = new MenuItem("Stop Recording",
0, 0)
{
public void run()
{
if (recording)
{
new StopRecordingThread().start();
}
}
};
private class StopRecordingThread extends Thread
{
public void run()
{
try
{
recorder.stopRecord();
recorder.commit();
recording = false;
}
catch (Throwable t)
{
t.printStackTrace();
}
}
}
Finally, when the screen closes, you will clean up the player’s resources and ensure that all its capture buffers get flushed out. If you skip this step, the user sometimes will be left with a 0-byte file.
public boolean onClose()
{
if (player != null)
{
player.close();
}
return super.onClose();
}
Go ahead and run this. On the simulator, configure the memory settings to use the PC filesystem for SD Card files. It will record a silent AMR file. If you try it on a device, you will be able to speak into the microphone and have it capture your words.
Lights, Camera…
Now, on to the video proper. First of all, if you want our app to run on both 5.0 and older versions of the OS, you should query the device to see whether it supports video capture. You can check this with just two lines of code:
String videoEncodings = System.getProperty("video.encodings");
boolean hasVideoRecording = videoEncodings != null
&& videoEncodings.length() > 0;
Creating the video player is a little more complicated than the audio player. With audio, you could specify a desired audio format, or just use “capture://audio” and have it select an appropriate default. With video, you must say exactly what video format to use. If you already know what formats are available on a particular device, you can specify one directly; this might look something like this:
capture://video?encoding=video/3gpp&width=480&height=352&video_codec=H263&audio_codec=AMR
If you don’t care what particular format the device uses, you can grab the first format from the space-delimited videoEncodings value. BlackBerry doesn’t support the StringTokenizer class, which would be useful here, but you can pull the first token out manually:
int encodingSpace = videoEncodings.indexOf(' ');
if (encodingSpace != -1)
{
videoEncodings = videoEncodings.substring(0, encodingSpace);
}
If the user tries to use an invalid video format, BlackBerry will not complain initially, but the device will produce an error when the user tries to commit the video at the very end.
Getting a View
When you have a video player, you should add a viewfinder to your app. This will let users see just what they’re recording–an important feature! You gain access to video-specific capabilities by retrieving a VideoControl object, in the same way you got a RecordControl.
Now, you need to put something on the screen. You can retrieve an appropriate component by invoking the initDisplayMode() method. Because you are building a BlackBerry CLDC UI application, you will request a Field for your screen:
Field cameraView = (Field)control.initDisplayMode
(VideoControl.USE_GUI_PRIMITIVE, "net.rim.device.api.ui.Field");
Author’s Note: If you’re creating a BlackBerry MIDlet application, you could instead have asked for a “javax.microedition.lcdui.Item” display component. You could then insert this component into a MIDlet’s Form.
When and where should you create the viewfinder? Ordinarily, you would create all of your Field objects within the constructor. That’s fine to do here, but it can take a while for the device to initialize the camera, which will cause a noticeable pause at that stage. Instead, you will wait until the user starts recording. If a Field hasn’t already been created, you can do it then.
Be sure not to skip the viewfinder! Even after you create the viewfinder, if it isn’t visible on the screen, the video will not record properly.
Once the viewfinder is in place, you can see the camera’s current perspective (see Figure 2).
Figure 2. HomeHunter Actively Recording: Insert a viewfinder into the screen to hook into the camera.
Wrapping Up
Believe it or not, you’re almost done. The final recording method looks like this:
String videoEncodings = System.getProperty("video.encodings");
boolean hasVideoRecording = videoEncodings != null && videoEncodings.length() > 0;
if (player == null || recorder == null)
{
if (hasVideoRecording)
{
int encodingSpace = videoEncodings.indexOf(' ');
if (encodingSpace != -1)
{
videoEncodings = videoEncodings
.substring(0, encodingSpace);
}
player = Manager.createPlayer("capture://video?"
+ videoEncodings);
player.start();
VideoControl video = (VideoControl) player
.getControl("VideoControl");
final Field cameraView = (Field) video.initDisplayMode(
VideoControl.USE_GUI_PRIMITIVE,
"net.rim.device.api.ui.Field");
getApplication().invokeLater(new Runnable()
{
public void run()
{
add(cameraView);
}
});
}
else
{
player = Manager.createPlayer("capture://audio");
player.start();
}
recorder = (RecordControl) player.getControl("RecordControl");
}
recorder.setRecordLocation("file:///store/home/user/hunted.3gp");
recorder.startRecord();
recording = true;
When you run this on your computer, the simulator will check to see if you have a supported webcam installed. If so, you will be able to test the video recording function with your webcam. Otherwise, you will be prompted to select a still image file like a JPG or PNG; this is still useful for testing, if less interesting. On the actual device, you can see the video being captured by the camera.
To play back your captured video, you can browse the phone filesystem. The easiest way to do this is to visit the Media application, press the BlackBerry menu key, and then select Explore.
Author’s Note: Be sure to test on your target devices before shipping your application. Video support varies from device to device and from version to version. For example, recording to a file works well on version 5.0.0.252, but the same code may freeze on 5.0.0.328. Considering Research In Motion’s track record, video recording should become more stable and reliable in future versions.
In addition to saving the captured video to a file, you can also direct the video to an OutputStream. This is very useful if you intend to process the video in memory or upload it to a network. Unfortunately, early versions of the 5.0 OS contain a bug that throws a NullPointerException when you attempt to commit a video to a stream. If this problem occurs for you, you can save to a file and then open the file for further processing.
Just like that, you’ve taken a useful app and made it more useful, more flashy, and more compelling. Because video uses existing APIs, you can even create a single application that displays video on recent BlackBerry devices and also runs on older devices without video. Video makes a statement, and it will show even skeptics that BlackBerry devices stand up to today’s hottest phones.
About the Author
Chris King is a senior software engineer at Gravity Mobile and is the author of Advanced BlackBerry Development (published by Apress). When he isn’t programming or writing for fun or profit, Chris can be found reading, baking, cycling, or hiking throughout the San Francisco Bay Area.