288 lines
9.7 KiB
Plaintext
288 lines
9.7 KiB
Plaintext
page.title=Controlling the Camera
|
||
parent.title=Capturing Photos
|
||
parent.link=index.html
|
||
|
||
trainingnavtop=true
|
||
previous.title=Recording Videos Simply
|
||
previous.link=videobasics.html
|
||
|
||
@jd:body
|
||
|
||
|
||
<div id="tb-wrapper">
|
||
<div id="tb">
|
||
|
||
<h2>This lesson teaches you to</h2>
|
||
<ol>
|
||
<li><a href="#TaskOpenCamera">Open the Camera Object</a></li>
|
||
<li><a href="#camera-preview">Create the Camera Preview</a></li>
|
||
<li><a href="#TaskSettings">Modify Camera Settings</a></li>
|
||
<li><a href="#TaskOrientation">Set the Preview Orientation</a></li>
|
||
<li><a href="#TaskTakePicture">Take a Picture</a></li>
|
||
<li><a href="#TaskRestartPreview">Restart the Preview</a></li>
|
||
<li><a href="#TaskReleaseCamera">Stop the Preview and Release the Camera</a></li>
|
||
</ol>
|
||
|
||
<h2>You should also read</h2>
|
||
<ul>
|
||
<li><a href="{@docRoot}guide/topics/media/camera.html#custom-camera">Building
|
||
a Camera App</a></li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
|
||
<p>In this lesson, we discuss how to control the camera hardware directly using
|
||
the framework APIs.</p>
|
||
|
||
<p>Directly controlling a device camera requires a lot more code than requesting pictures or videos
|
||
from existing camera applications. However, if you want to build a specialized camera application
|
||
or something fully integrated in your app UI, this lesson shows you how.</p>
|
||
|
||
|
||
<h2 id="TaskOpenCamera">Open the Camera Object</h2>
|
||
|
||
<p>Getting an instance of the {@link android.hardware.Camera} object is the first step in the
|
||
process of directly controlling the camera. As Android's own Camera application does, the
|
||
recommended way to access the camera is to open {@link android.hardware.Camera} on a separate thread
|
||
that's launched from {@link android.app.Activity#onCreate onCreate()}. This approach is a good idea
|
||
since it can take a while and might bog down the UI thread. In a more basic implementation,
|
||
opening the camera can be deferred to the {@link
|
||
android.app.Activity#onResume onResume()} method to facilitate code reuse and keep the flow of
|
||
control simple.</p>
|
||
|
||
<p>Calling {@link android.hardware.Camera#open Camera.open()} throws an
|
||
exception if the camera is already in use by another application, so we wrap it
|
||
in a {@code try} block.</p>
|
||
|
||
<pre>
|
||
private boolean safeCameraOpen(int id) {
|
||
boolean qOpened = false;
|
||
|
||
try {
|
||
releaseCameraAndPreview();
|
||
mCamera = Camera.open(id);
|
||
qOpened = (mCamera != null);
|
||
} catch (Exception e) {
|
||
Log.e(getString(R.string.app_name), "failed to open Camera");
|
||
e.printStackTrace();
|
||
}
|
||
|
||
return qOpened;
|
||
}
|
||
|
||
private void releaseCameraAndPreview() {
|
||
mPreview.setCamera(null);
|
||
if (mCamera != null) {
|
||
mCamera.release();
|
||
mCamera = null;
|
||
}
|
||
}
|
||
</pre>
|
||
|
||
<p>Since API level 9, the camera framework supports multiple cameras. If you use the
|
||
legacy API and call {@link android.hardware.Camera#open open()} without an
|
||
argument, you get the first rear-facing camera.</p>
|
||
|
||
|
||
<h2 id="camera-preview">Create the Camera Preview</h2>
|
||
|
||
<p>Taking a picture usually requires that your users see a preview of their subject before clicking
|
||
the shutter. To do so, you can use a {@link android.view.SurfaceView} to draw previews of what the
|
||
camera sensor is picking up.</p>
|
||
|
||
<h3 id="TaskSetPreview">Preview Class</h3>
|
||
|
||
<p>To get started with displaying a preview, you need preview class. The
|
||
preview requires an implementation of the {@code
|
||
android.view.SurfaceHolder.Callback} interface, which is used to pass image
|
||
data from the camera hardware to the application.</p>
|
||
|
||
<pre>
|
||
class Preview extends ViewGroup implements SurfaceHolder.Callback {
|
||
|
||
SurfaceView mSurfaceView;
|
||
SurfaceHolder mHolder;
|
||
|
||
Preview(Context context) {
|
||
super(context);
|
||
|
||
mSurfaceView = new SurfaceView(context);
|
||
addView(mSurfaceView);
|
||
|
||
// Install a SurfaceHolder.Callback so we get notified when the
|
||
// underlying surface is created and destroyed.
|
||
mHolder = mSurfaceView.getHolder();
|
||
mHolder.addCallback(this);
|
||
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
|
||
}
|
||
...
|
||
}
|
||
</pre>
|
||
|
||
<p>The preview class must be passed to the {@link android.hardware.Camera} object before the live
|
||
image preview can be started, as shown in the next section.</p>
|
||
|
||
|
||
<h3 id="TaskStartPreview">Set and Start the Preview</h2>
|
||
|
||
<p>A camera instance and its related preview must be created in a specific
|
||
order, with the camera object being first. In the snippet below, the
|
||
process of initializing the camera is encapsulated so that {@link
|
||
android.hardware.Camera#startPreview Camera.startPreview()} is called by the
|
||
{@code setCamera()} method, whenever the user does something to change the
|
||
camera. The preview must also be restarted in the preview class {@code
|
||
surfaceChanged()} callback method.</p>
|
||
|
||
<pre>
|
||
public void setCamera(Camera camera) {
|
||
if (mCamera == camera) { return; }
|
||
|
||
stopPreviewAndFreeCamera();
|
||
|
||
mCamera = camera;
|
||
|
||
if (mCamera != null) {
|
||
List<Size> localSizes = mCamera.getParameters().getSupportedPreviewSizes();
|
||
mSupportedPreviewSizes = localSizes;
|
||
requestLayout();
|
||
|
||
try {
|
||
mCamera.setPreviewDisplay(mHolder);
|
||
} catch (IOException e) {
|
||
e.printStackTrace();
|
||
}
|
||
|
||
/*
|
||
Important: Call startPreview() to start updating the preview surface. Preview must
|
||
be started before you can take a picture.
|
||
*/
|
||
mCamera.startPreview();
|
||
}
|
||
}
|
||
</pre>
|
||
|
||
|
||
<h2 id="TaskSettings">Modify Camera Settings</h2>
|
||
|
||
<p>Camera settings change the way that the camera takes pictures, from the zoom
|
||
level to exposure compensation. This example changes only the preview size;
|
||
see the source code of the Camera application for many more.</p>
|
||
|
||
<pre>
|
||
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
|
||
// Now that the size is known, set up the camera parameters and begin
|
||
// the preview.
|
||
Camera.Parameters parameters = mCamera.getParameters();
|
||
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
|
||
requestLayout();
|
||
mCamera.setParameters(parameters);
|
||
|
||
/*
|
||
Important: Call startPreview() to start updating the preview surface. Preview must be
|
||
started before you can take a picture.
|
||
*/
|
||
mCamera.startPreview();
|
||
}
|
||
</pre>
|
||
|
||
|
||
<h2 id="TaskOrientation">Set the Preview Orientation</h2>
|
||
|
||
<p>Most camera applications lock the display into landscape mode because that is the natural
|
||
orientation of the camera sensor. This setting does not prevent you from taking portrait-mode
|
||
photos, because the orientation of the device is recorded in the EXIF header. The {@link
|
||
android.hardware.Camera#setDisplayOrientation setCameraDisplayOrientation()} method lets you change
|
||
how the preview is displayed without affecting how the image is recorded. However, in Android prior
|
||
to API level 14, you must stop your preview before changing the orientation and then restart it.</p>
|
||
|
||
|
||
<h2 id="TaskTakePicture">Take a Picture</h2>
|
||
|
||
<p>Use the {@link android.hardware.Camera#takePicture Camera.takePicture()}
|
||
method to take a picture once the preview is started. You can create {@link
|
||
android.hardware.Camera.PictureCallback} and {@link
|
||
android.hardware.Camera.ShutterCallback} objects and pass them into {@link
|
||
android.hardware.Camera#takePicture Camera.takePicture()}.</p>
|
||
|
||
<p>If you want to grab images continously, you can create a {@link
|
||
android.hardware.Camera.PreviewCallback} that implements {@link
|
||
android.hardware.Camera.PreviewCallback#onPreviewFrame onPreviewFrame()}. For
|
||
something in between, you can capture only selected preview frames, or set up a
|
||
delayed action to call {@link android.hardware.Camera#takePicture
|
||
takePicture()}.</p>
|
||
|
||
|
||
<h2 id="TaskRestartPreview">Restart the Preview</h2>
|
||
|
||
<p>After a picture is taken, you must restart the preview before the user
|
||
can take another picture. In this example, the restart is done by overloading
|
||
the shutter button.</p>
|
||
|
||
<pre>
|
||
@Override
|
||
public void onClick(View v) {
|
||
switch(mPreviewState) {
|
||
case K_STATE_FROZEN:
|
||
mCamera.startPreview();
|
||
mPreviewState = K_STATE_PREVIEW;
|
||
break;
|
||
|
||
default:
|
||
mCamera.takePicture( null, rawCallback, null);
|
||
mPreviewState = K_STATE_BUSY;
|
||
} // switch
|
||
shutterBtnConfig();
|
||
}
|
||
</pre>
|
||
|
||
|
||
<h2 id="TaskReleaseCamera">Stop the Preview and Release the Camera</h2>
|
||
|
||
<p>Once your application is done using the camera, it's time to clean up. In
|
||
particular, you must release the {@link android.hardware.Camera} object, or you risk crashing other
|
||
applications, including new instances of your own application.</p>
|
||
|
||
<p>When should you stop the preview and release the camera? Well, having your
|
||
preview surface destroyed is a pretty good hint that it’s time to stop the
|
||
preview and release the camera, as shown in these methods from the {@code
|
||
Preview} class.</p>
|
||
|
||
<pre>
|
||
public void surfaceDestroyed(SurfaceHolder holder) {
|
||
// Surface will be destroyed when we return, so stop the preview.
|
||
if (mCamera != null) {
|
||
/*
|
||
Call stopPreview() to stop updating the preview surface.
|
||
*/
|
||
mCamera.stopPreview();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* When this function returns, mCamera will be null.
|
||
*/
|
||
private void stopPreviewAndFreeCamera() {
|
||
|
||
if (mCamera != null) {
|
||
/*
|
||
Call stopPreview() to stop updating the preview surface.
|
||
*/
|
||
mCamera.stopPreview();
|
||
|
||
/*
|
||
Important: Call release() to release the camera for use by other applications.
|
||
Applications should release the camera immediately in onPause() (and re-open() it in
|
||
onResume()).
|
||
*/
|
||
mCamera.release();
|
||
|
||
mCamera = null;
|
||
}
|
||
}
|
||
</pre>
|
||
|
||
<p>Earlier in the lesson, this procedure was also part of the {@code
|
||
setCamera()} method, so initializing a camera always begins with stopping the
|
||
preview.</p>
|
||
|