Capturing media

Using your cell phone to take pictures, record memos, films short videos, and so on are all features now expected of any such device. In this section we are going to not only look at how to capture media from the microphone and camera but also write these files to the simulated SD card image we created previously.

To get started let's examine how to use the Android Camera class to capture images and save them to a file.

10.4.1 Understanding the camera

A very important feature of modern cell phones is their ability to take pictures or even video using a built-in camera. Some phones even support using the camera's microphone to capture audio. Android, of course, supports all three features and provides a variety of ways to interact with the camera. In this section we're going to look at how to interact with the camera and take photographs. In the next section we'll use the camera to take video and save it to an SD card.

We will be creating a new project called SimpleCamera to demonstrate how to connect to a phone's camera to capture images. For this project we will be using the Camera class (http://code.google.com/android/reference/android/hardware/ Camera. html) to tie the emulator's (or phone's) camera to a View. Most of the code that we create for this project will be about showing the input from the camera, but the main work for taking a picture is done by a single method called take-Picture(Camera.ShutterCallback shutter, Camera.PictureCallback raw, Cam-era.PictureCallback jpeg), which has three callbacks that allow you to control how a picture is taken. Before we get any further into the Camera class and how to use the camera, let's create a project. We will be creating two classes, and since the main class is long, we will break it into two sections. For the first section look at listing 10.5, CameraExample.java.

NOTE The Android Emulator does not allow you to connect to camera devices on your computer such as a webcam, and thus all your pictures will display a chessboard like the one shown in figure 10.4. It is possible to connect to a web camera and get live images and video, but it requires some hacking. An excellent example on how to do this can be found at Tom Gibara's website, where he has an open source project for obtaining live images from a webcam: http://www.tomgibara.com/android/camera-source. It is possible that in latter versions of the SDK the emulator will support connections to cameras on the hardware the emulator is running on.

Listing 10.5 CameraExample.java public class SimpleCamera extends Activity implements SurfaceHolder.Callback { private Camera camera;

private boolean isPreviewRunning = false; private SimpleDateFormat timeStampFormat = new SimpleDateFormat("yyyyMMddHHmmssSS");

private SurfaceView surfaceView; private SurfaceHolder surfaceHolder;

private Uri targetResource = Media.EXTERNAL_CONTENT_URI;

public void onCreate(Bundle icicle) { super.onCreate(icicle) ;

Log.e(getClass().getSimpleName(), "onCreate"); getWindow().setFormat(PixelFormat.TRANSLUCENT); setContentView(R.layout.main);

surfaceView = (SurfaceView)findViewById(R.id.surface); surfaceHolder = surfaceView.getHolder(); surfaceHolder.addCallback(this);

surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS)

@Override public boolean onCreateOptionsMenu(android.view.Menu menu) {

Menultem item = menu.add(0, 0, 0, "View Photos?") ; <1— item.setOnMenultemClickListener(new

Menultem.OnMenultemClickListener () { O Gallery public boolean onMenultemClick(Menultem item) { Intent intent = new Intent(Intent.ACTION_VIEW,

SimpleCamera.this.targetResource); startActivity(intent); return true;

return true;

Create menu to Android's Photo

@Override protected void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState) ;

Camera.PictureCallback mPictureCallbackRaw = new

Camera. PictureCallback () { <-1 Create a public void onPictureTaken(byte [] data, Camera c) { Q PictureCallback SimpleCamera.this.camera.startPreview();

Camera.ShutterCallback mShutterCallback = new Camera.ShutterCallback () {

Public void onShutter () {} Create a ShutterCallback

Listing 10.5 is pretty straightforward. First we set variables for managing a surfaceView and then set up the View. Next we create a simple menu and menu option that will float over our surface when the user clicks the MENU button on the phone while the application is running O. Doing so will open Android's picture browser and let the user view the photos on the camera. Next we create the first PictureCallback, which is called when a picture is first taken ©. This first callback captures the Pic-tureCallback's only method, onPictureTaken(byte[] data, Camera camera), to grab the raw image data directly from the camera. Next we create a ShutterCallback, which can be used with its method, onShutter(), to play a sound, but here we do not call the method Q. We will continue with the CameraExample.java in listing 10.6.

Listing 10.6 CameraExample.java continued

@Override Create method to detect key events Q

public boolean onKeyDown(int keyCode, KeyEvent event) { <-1

ImageCaptureCallback camDemo = null;

if(keyCode == KeyEvent.KEYCODE_DPAD_CENTER) { <-

String filename = this.timeStampFormat.format(new Date()); ContentValues values = new ContentValues(); values.put(MediaColumns.TITLE, filename); values.put(ImageColumns.DESCRIPTION,

"Image from Android Emulator") ; Uri uri = getContentResolver().insert( Media. EXTERNAL_CONTENT_URI, values) ; camDemo = new ImageCaptureCallback(

getContentResolver().openOutputStream(uri)); } catch(Exception ex ) {

} If center key was depressed, write a file to sdcard C

if (keyCode == KeyEvent.KEYCODE_BACK) {

return super.onKeyDown(keyCode, event);

if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {

this.camera.takePicture(this.mShutterCallback, this.mPictureCallbackRaw, this.camDemo); return true;

return false;

If center key was depressed, take D a picture

@Override protected void onResume() {

Log.e(getClass () .getSimpleName(), "onResume"); super.onResume();

@Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState);

@Override protected void onStop()

public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { if (this.isPreviewRunning) { this.camera.stopPreview();

Camera.Parameters p = this.camera.getParameters();

p.setPreviewSize(w, h) ;

this.camera.setParameters(p);

this.camera.setPreviewDisplay(holder);

this.camera.startPreview();

this.isPreviewRunning = true;

public void surfaceCreated(SurfaceHolder holder) { this.camera = Camera.open();

public void surfaceDestroyed(SurfaceHolder holder) { this.camera.stopPreview(); this.isPreviewRunning = false; this.camera.release();

Listing 10.6 is more complicated than listing 10.5 although a large amount of the code in this listing is really about managing the surface for the camera preview. But as you can see, the very first line is the start of an implementation of the method onKey-Down O, which checks to see if the center key on the dpad was depressed. If it was, we set up the creation of a file, and by using the ImageCaptureCallback, which we will define in listing 10.7, we create an Outputstream to write our image data to Q, including not only the image but the filename and other metadata. Next we call the method takePicture() and pass it the three callbacks mShutterCallback, mPictureCall-backRaw, and camDemo, where mPictureCallbackRaw is our raw image and camDemo writes the image to a file on the SD card ©, as you can see in listing 10.7.

Listing 10.7 ImageCaptureCallback.java public class ImageCaptureCallback implements PictureCallback {

private OutputStream filoutputStream; Write file to

public ImageCaptureCallback(Outputstream filoutputStream) {

this.filoutputstream = filoutputStream; }

public void onPictureTaken(byte[] data, Camera camera) {

this . filoutputStream.write (data) ; | Capture image this, f iloutputstream. f lush () ; C from camera this.filoutputStream.close(); } catch(Exception ex) { ex.printStackTrace() ;

operating system

In listing 10.7 the class implements the Picture-Callback interface and provides two methods. The constructor creates a stream to write data to O, and the second method, onPictureTaken, takes binary data and writes to the SD card as a JPEG Q. Now if you build this project and start the emulator running using the SD card image from previously in this chapter, you should see something like figure 10.4 when you start the SimpleCamera application from the Android menu. If you look at figure 10.4 you will notice an odd black-and-white checked background with a bouncing gray box. This is a test pattern that the Android Emulator generates to simulate an image feed since the emulator is not actually pulling a live feed from the camera.

Now if you click the center button on the dpad in the emulator, the application will take a picture. To see the picture click the MENU button, which will cause a menu to appear on the camera view window with a single option, View Pictures. If you select View Pictures, you will be taken to the Android picture explorer, and you should see Android's image placeholders representing the number of camera captures. You can also see the JPEG files that were written to the SD card by opening the DDMS in Eclipse and navigating to sdcard > dcim > Camera. You can see an example of what this might look like in figure 10.5.

Figure 10.4 Test pattern coming from the emulator camera and displayed in the SimpleCamera application
Figure 10.5 The Android Emulator shows placeholder images for each photo taken.

As you can see, working with the camera in Android is not particularly complicated. To see how a real camera will behave, you will have to test on a real handset until the emulator provides a simple way to connect to a camera on your computer. This should not stop you from developing your camera applications, however, and a wealth of Android applications already make sophisticated use of the camera, ranging from games to an application that uses a picture of your face to unlock your phone. Now that you have seen how the Camera class works in Android, let's look at how to capture or record audio from a camera's microphone. In the next section we'll explore the MediaRecorder class and write recordings to an SD card.

10.4.2 Capturing audio

Now we'll look at using the onboard microphone to record audio. In this section we're going to use the Android MediaRecorder example from Google Android Developers list, which you can find at http://groups.google.com/group/android-developers/files. The code shown here has been slightly updated.

NOTE At the time the book was written, Google Android SDK 1 does not allow you to capture audio from the emulator via your computer, but it is likely that later versions of the SDK will.

In general recording audio or video follows the same process in Android:

1 Create an instance of android.media.MediaRecorder.

2 Create an instance of andriod.content.ContentValues, and add properties like TITLE, TIMESTAMP, and the all-important MIME_TYPE.

3 Create a file path for the data to go to using android.content.Content-Resolver.

4 To set a preview display on a view surface, use MediaRecorder.setPreview-Display().

5 Set the source for audio, using MediaRecorder.setAudioSource().

6 Set output file format using MediaRecorder.setOutputFormat().

7 Set your encoding for audio, using MediaRecorder.setAudioEncoder().

8 Use prepare() and start() to prepare and start your recordings.

9 Use stop() and release() to gracefully stop and clean up your recording process.

While recording media is not especially complex, it is, as you can see, more complex than playing it. To really understand how to use the MediaRecorder class, we'll look at an application. Create a new application called SoundRecordingDemo. Next you need to edit the AndroidManifest.xml file and add the following line:

<uses-permission android:name="android.permission.RECORD_AUDIO" />

This will allow the application to record the audio files and play them. Then create the class shown in listing 10.8.

Listing 10.8 SoundRecordingdemo.java public class SoundRecordingDemo extends Activity {

MediaRecorder mRecorder; File mSampleFile = null;

static final String SAMPLE_PREFIX = "recording"; static final String SAMPLE_EXTENSION = ".mp3";

private static final String TAG="SoundRecordingDemo";

@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); this.mRecorder = new MediaRecorder();

Button startRecording = (Button)findViewById(R.id.startrecording); Button stopRecording = (Button)findViewById(R.id.stoprecording);

startRecording.setOnClickListener(new View.OnClickListener(){

public void onClick(View v) { startRecording();

stopRecording.setOnClickListener (new View.OnClickListener(){

public void onClick(View v) { stopRecording(); addToDB();

protected void addToDB () {

ContentValues values = new ContentValues(3);

Set the metadata long current = System.currentTimeMillis (); for the audio values.put(MediaColumns.TITLE, "test_audio"); values.put(MediaColumns.DATE_ADDED, (int) (current / 1000)); values.put(MediaColumns.MIME_TYPE, "audio/mp3"); values.put(MediaColumns.DATA, mSampleFile.getAbsolutePath()); ContentResolver contentResolver = getContentResolver();

Notify music C

Uri base = MediaStore .Audio .Media . EXTERNAL_CONTENT_URI ; pla.yer new aUdi0

Uri newUri = contentResolver. insert (base, values); file created sendBroadcast (new Intent ( Intent .ACTION_MEDIA_SCANNER_SCAN_FILE, newUri) ) ; d-1

} D Start recording protected void startRecording ( ) { <1-' the file this.mRecorder = new MediaRecorder();

this.mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);

this.mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);

this.mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);

this.mRecorder.setOutputFile(this.mSampleFile.getAbsolutePath());

this.mRecorder.prepare();

this.mRecorder.start();

File sampleDir = Environment.getExternalStorageDirectory();

this.mSampleFile = File.createTempFile( SoundRecordingDemo.SAMPLE_PREFIX, SoundRecordingDemo.SAMPLE_EXTENSION, sampleDir); } catch (IOException e) {

Log.e(TAG,"sdcard access error"); return;

} Q Stop recording and protected void stopRecording () { <-1 release MediaRecorder this.mRecorder.stop(); this.mRecorder.release();

As you can see in listing 10.8, the first part of the code is creating the buttons and button listeners to start and stop the recording. The first part of the listing you need to pay attention to is the addToDB() method. In this method we set all the metadata for the audio file we plan to save, including the title, date, and type of file O. Next we call the Intent ACTION_MEDIA_SCANNER_SCAN_FILE to notify applications like Android's Music Player that a new audio file has been created ©. This will allow us to use the Music Player to look for new files in a playlist and play the file.

Now that we have finished the addToDB method, we create the startRecording method, which creates a new MediaRecorder Q. As in the steps in the beginning of this section we set a audio source, which is the microphone, set an output format as THREE_GPP, set the audio encoder type to AMR_NB, and then set the output file path to write the file. Next we use the methods prepare() and start() to enable the recording of audio.

Finally we create the stopRecording() method to stop the MediaRecorder from saving audio Q. We do this by using the methods stop() and release(). Now if you build this application and run the emulator with the SD card image from the previous section, you should be able to launch the application from Eclipse and press the Start Recording button. After a few seconds, press the Stop Recording button and open the DDMS; you should be able to navigate to the sdcard folder and see your recordings, as shown in figure 10.6.

If you have music playing on your computer's audio system, the Android Emulator will pick it up and record it directly from the audio buffer (it is not actually recording from a microphone). You can then easily test this by opening the Android Music Player and selecting Playlists > Recently Added. It should play your recorded file, and you should be able to hear anything that was playing on your computer at the time. While Android currently lets you record only audio, Google plans to soon add support for recording video. This will also use the MediaRecorder class to allow you to record video coming in from the camera much like you would audio.

Figure 10.6 An example of audio files being saved to the SD card image in the emulator

0 0

Post a comment