|
| 1 | +page.title=Controlling the Camera |
| 2 | +parent.title=Capturing Photos with the Camera |
| 3 | +parent.link=index.html |
| 4 | + |
| 5 | +trainingnavtop=true |
| 6 | +previous.title=Recording Videos Simply |
| 7 | +previous.link=videobasics.html |
| 8 | + |
| 9 | +@jd:body |
| 10 | + |
| 11 | + |
| 12 | +<div id="tb-wrapper"> |
| 13 | + <div id="tb"> |
| 14 | + |
| 15 | + <h2>This lesson teaches you to</h2> |
| 16 | + <ol> |
| 17 | + <li><a href="#TaskOpenCamera">Open the Camera Object</a></li> |
| 18 | + <li><a href="#camera-preview">Create the Camera Preview</a></li> |
| 19 | + <li><a href="#TaskSettings">Modify Camera Settings</a></li> |
| 20 | + <li><a href="#TaskOrientation">Set the Preview Orientation</a></li> |
| 21 | + <li><a href="#TaskTakePicture">Take a Picture</a></li> |
| 22 | + <li><a href="#TaskRestartPreview">Restart the Preview</a></li> |
| 23 | + <li><a href="#TaskReleaseCamera">Stop the Preview and Release the Camera</a></li> |
| 24 | + </ol> |
| 25 | + |
| 26 | + <h2>You should also read</h2> |
| 27 | + <ul> |
| 28 | + <li><a href="{@docRoot}guide/topics/media/camera.html#custom-camera">Building |
| 29 | + a Camera App</a></li> |
| 30 | + </ul> |
| 31 | + </div> |
| 32 | +</div> |
| 33 | + |
| 34 | +<p>In this lesson, we discuss how to control the camera hardware directly using |
| 35 | +the framework APIs.</p> |
| 36 | + |
| 37 | +<p>Directly controlling a device camera requires a lot more code than requesting pictures or videos |
| 38 | +from existing camera applications. However, if you want to build a specialized camera application or |
| 39 | +or something fully integrated in your app UI, this lesson shows you how.</p> |
| 40 | + |
| 41 | + |
| 42 | +<h2 id="TaskOpenCamera">Open the Camera Object</h2> |
| 43 | + |
| 44 | +<p>Getting an instance of the {@link android.hardware.Camera} object is the first step in the |
| 45 | +process of directly controlling the camera. As Android's own Camera application does, the |
| 46 | +recommended way to access the camera is to open {@link android.hardware.Camera} on a separate thread |
| 47 | +that's launched from {@link android.app.Activity#onCreate onCreate()}. This approach is a good idea |
| 48 | +since it can take a while and might bog down the UI thread. However, in the sample application |
| 49 | +associated with this lesson, opening the camera is deferred to the {@link |
| 50 | +android.app.Activity#onResume onResume()} method to facilitate code reuse and keep the flow of |
| 51 | +control simple.</p> |
| 52 | + |
| 53 | +<pre> |
| 54 | +private void openCameraPerIdAndSetPreview() { |
| 55 | + if (! safeCameraOpen(mCameraId)) { |
| 56 | + mCameraId = getFirstRearCameraID(); |
| 57 | + safeCameraOpen(mCameraId); |
| 58 | + } |
| 59 | + |
| 60 | + mPreview.setCamera(mCamera); |
| 61 | +} |
| 62 | +</pre> |
| 63 | + |
| 64 | +<p>Since API level 9, the camera framework supports multiple cameras. If you use the |
| 65 | +legacy API and call {@link android.hardware.Camera#open open()} without an |
| 66 | +argument, you get the first rear-facing camera. Dealing with multiple cameras |
| 67 | +is an advanced topic and beyond the scope of this lesson. If you are really |
| 68 | +interested, check out the implementation of {@code getFirstRearCameraID()} in |
| 69 | +the sample app (downloadable at the top).</p> |
| 70 | + |
| 71 | +<p>Calling {@link android.hardware.Camera#open Camera.open()} throws an |
| 72 | +exception if the camera is already in use by another application, so we wrap it |
| 73 | +in a {@code try} block.</p> |
| 74 | + |
| 75 | +<pre> |
| 76 | +private boolean safeCameraOpen(int id) { |
| 77 | + boolean qOpened = false; |
| 78 | + |
| 79 | + try { |
| 80 | + releaseCameraAndPreview(); |
| 81 | + mCamera = Camera.open(mCameraId); |
| 82 | + qOpened = (mCamera != null); |
| 83 | + } catch (Exception e) { |
| 84 | + Log.e(getString(R.string.app_name), "failed to open Camera"); |
| 85 | + e.printStackTrace(); |
| 86 | + } |
| 87 | + |
| 88 | + return qOpened; |
| 89 | +} |
| 90 | + |
| 91 | +private void releaseCameraAndPreview() { |
| 92 | + mPreview.setCamera(null); |
| 93 | + if (mCamera != null) { |
| 94 | + mCamera.release(); |
| 95 | + mCamera = null; |
| 96 | + } |
| 97 | +} |
| 98 | +</pre> |
| 99 | + |
| 100 | + |
| 101 | +<h2 id="camera-preview">Create the Camera Preview</h2> |
| 102 | + |
| 103 | +<p>Taking a picture usually requires that your users see a preview of their subject before clicking |
| 104 | +the shutter. To do so, you can use a {@link android.view.SurfaceView} to draw previews of what the |
| 105 | +camera sensor is picking up.</p> |
| 106 | + |
| 107 | +<h3 id="TaskSetPreview">Preview Class</h3> |
| 108 | + |
| 109 | +<p>To get started with displaying a preview, you need preview class. The |
| 110 | +preview requires an implementation of the {@code |
| 111 | +android.view.SurfaceHolder.Callback} interface, which is used to pass image |
| 112 | +data from the camera hardware the application.</p> |
| 113 | + |
| 114 | +<pre> |
| 115 | +class Preview extends ViewGroup implements SurfaceHolder.Callback { |
| 116 | +... |
| 117 | + |
| 118 | + SurfaceView mSurfaceView; |
| 119 | + SurfaceHolder mHolder; |
| 120 | + |
| 121 | +... |
| 122 | + |
| 123 | + Preview(Context context) { |
| 124 | + super(context); |
| 125 | + |
| 126 | + mSurfaceView = new SurfaceView(context); |
| 127 | + addView(mSurfaceView); |
| 128 | + |
| 129 | + // Install a SurfaceHolder.Callback so we get notified when the |
| 130 | + // underlying surface is created and destroyed. |
| 131 | + mHolder = mSurfaceView.getHolder(); |
| 132 | + mHolder.addCallback(this); |
| 133 | + mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); |
| 134 | + } |
| 135 | +... |
| 136 | +} |
| 137 | +</pre> |
| 138 | + |
| 139 | +<p>The preview class must be passed to the {@link android.hardware.Camera} object before the live |
| 140 | +image preview can be started, as seen in {@code setCamera()} method of the sample, |
| 141 | +as shown in the next section.</p> |
| 142 | + |
| 143 | + |
| 144 | +<h3 id="TaskStartPreview">Set and Start the Preview</h2> |
| 145 | + |
| 146 | +<p>A camera instance and its related preview must be created in a specific |
| 147 | +order, with the camera object being first. In the sample application, the |
| 148 | +process of initializing the camera is encapsulated so that {@link |
| 149 | +android.hardware.Camera#startPreview Camera.startPreview()} is called by the |
| 150 | +{@code setCamera()} method, whenever the user does something to change the |
| 151 | +camera. The preview must also be restarted in the preview class {@code |
| 152 | +surfaceChanged()} callback method.</p> |
| 153 | + |
| 154 | +<pre> |
| 155 | +public void setCamera(Camera camera) { |
| 156 | + if (mCamera == camera) { return; } |
| 157 | + |
| 158 | + stopPreviewAndFreeCamera(); |
| 159 | + |
| 160 | + mCamera = camera; |
| 161 | + |
| 162 | + if (mCamera != null) { |
| 163 | + List<Size> localSizes = mCamera.getParameters().getSupportedPreviewSizes(); |
| 164 | + mSupportedPreviewSizes = localSizes; |
| 165 | + requestLayout(); |
| 166 | + |
| 167 | + try { |
| 168 | + mCamera.setPreviewDisplay(mHolder); |
| 169 | + } catch (IOException e) { |
| 170 | + e.printStackTrace(); |
| 171 | + } |
| 172 | + |
| 173 | + /* |
| 174 | + Important: Call startPreview() to start updating the preview surface. Preview must |
| 175 | + be started before you can take a picture. |
| 176 | + */ |
| 177 | + mCamera.startPreview(); |
| 178 | + } |
| 179 | +} |
| 180 | +</pre> |
| 181 | + |
| 182 | + |
| 183 | +<h2 id="TaskSettings">Modify Camera Settings</h2> |
| 184 | + |
| 185 | +<p>Camera settings change the way that the camera takes pictures, from the zoom |
| 186 | +level to exposure compensation. This example doesn’t do a whole lot with camera |
| 187 | +settings, but the APIs provide a wide array of options. The {@code surfaceChanged()} method in the |
| 188 | +sample app demonstrates how to get and set camera parameters:</p> |
| 189 | + |
| 190 | +<pre> |
| 191 | +public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { |
| 192 | + // Now that the size is known, set up the camera parameters and begin |
| 193 | + // the preview. |
| 194 | + Camera.Parameters parameters = mCamera.getParameters(); |
| 195 | + parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height); |
| 196 | + requestLayout(); |
| 197 | + mCamera.setParameters(parameters); |
| 198 | + |
| 199 | + /* |
| 200 | + Important: Call startPreview() to start updating the preview surface. Preview must be |
| 201 | + started before you can take a picture. |
| 202 | + */ |
| 203 | + mCamera.startPreview(); |
| 204 | +} |
| 205 | +</pre> |
| 206 | + |
| 207 | + |
| 208 | +<h2 id="TaskOrientation">Set the Preview Orientation</h2> |
| 209 | + |
| 210 | +<p>Most camera applications lock the display into landscape mode because that is the natural |
| 211 | +orientation of the camera sensor. This setting does not prevent you from taking portrait-mode |
| 212 | +photos, because the orientation of the device is recorded in the EXIF header. The {@link |
| 213 | +android.hardware.Camera#setDisplayOrientation setCameraDisplayOrientation()} method lets you change |
| 214 | +how the preview is displayed without affecting how the image is recorded. However, in Android prior |
| 215 | +to API level 14, you must stop your preview before changing the orientation and then restart it.</p> |
| 216 | + |
| 217 | + |
| 218 | +<h2 id="TaskTakePicture">Take a Picture</h2> |
| 219 | + |
| 220 | +<p>Use the {@link android.hardware.Camera#takePicture Camera.takePicture()} |
| 221 | +method to take a picture once the preview is started. You can create {@link |
| 222 | +android.hardware.Camera.PictureCallback} and {@link |
| 223 | +android.hardware.Camera.ShutterCallback} objects and pass them into {@link |
| 224 | +android.hardware.Camera#takePicture Camera.takePicture()}. Since the Android |
| 225 | +Camera application already does a great job capturing JPEG images, you should |
| 226 | +probably implement the raw-image callback.</p> |
| 227 | + |
| 228 | +<p>If you want to grab images continously, you can create a {@link |
| 229 | +android.hardware.Camera.PreviewCallback} that implements {@link |
| 230 | +android.hardware.Camera.PreviewCallback#onPreviewFrame onPreviewFrame()}. For |
| 231 | +something in between, you can capture only selected preview frames, or set up a |
| 232 | +delayed action to call {@link android.hardware.Camera#takePicture |
| 233 | +takePicture()}.</p> |
| 234 | + |
| 235 | + |
| 236 | +<h2 id="TaskRestartPreview">Restart the Preview</h2> |
| 237 | + |
| 238 | +<p>After a picture is taken, you must to restart the preview before the user |
| 239 | +can take another picture. In the example, the restart is done by overloading |
| 240 | +the shutter button, as shown below.</p> |
| 241 | + |
| 242 | +<pre> |
| 243 | +@Override |
| 244 | +public void onClick(View v) { |
| 245 | + switch(mPreviewState) { |
| 246 | + case K_STATE_FROZEN: |
| 247 | + mCamera.startPreview(); |
| 248 | + mPreviewState = K_STATE_PREVIEW; |
| 249 | + break; |
| 250 | + |
| 251 | + default: |
| 252 | + mCamera.takePicture( null, rawCallback, null); |
| 253 | + mPreviewState = K_STATE_BUSY; |
| 254 | + } // switch |
| 255 | + shutterBtnConfig(); |
| 256 | +} |
| 257 | +</pre> |
| 258 | + |
| 259 | + |
| 260 | +<h2 id="TaskReleaseCamera">Stop the Preview and Release the Camera</h2> |
| 261 | + |
| 262 | +<p>Once your application is done using the camera, it's time to clean up. In |
| 263 | +particular, you must release the {@link android.hardware.Camera} object, or you risk crashing other |
| 264 | +applications, including new instances of your own application.</p> |
| 265 | + |
| 266 | +<p>When should you stop the preview and release the camera? Well, having your |
| 267 | +preview surface destroyed is a pretty good hint that it’s time to stop the |
| 268 | +preview and release the camera, as shown in these methods from the {@code |
| 269 | +Preview} class.</p> |
| 270 | + |
| 271 | +<pre> |
| 272 | +public void surfaceDestroyed(SurfaceHolder holder) { |
| 273 | + // Surface will be destroyed when we return, so stop the preview. |
| 274 | + if (mCamera != null) { |
| 275 | + /* |
| 276 | + Call stopPreview() to stop updating the preview surface. |
| 277 | + */ |
| 278 | + mCamera.stopPreview(); |
| 279 | + } |
| 280 | +} |
| 281 | + |
| 282 | +/** |
| 283 | + * When this function returns, mCamera will be null. |
| 284 | + */ |
| 285 | +private void stopPreviewAndFreeCamera() { |
| 286 | + |
| 287 | + if (mCamera != null) { |
| 288 | + /* |
| 289 | + Call stopPreview() to stop updating the preview surface. |
| 290 | + */ |
| 291 | + mCamera.stopPreview(); |
| 292 | + |
| 293 | + /* |
| 294 | + Important: Call release() to release the camera for use by other applications. |
| 295 | + Applications should release the camera immediately in onPause() (and re-open() it in |
| 296 | + onResume()). |
| 297 | + */ |
| 298 | + mCamera.release(); |
| 299 | + |
| 300 | + mCamera = null; |
| 301 | + } |
| 302 | +} |
| 303 | +</pre> |
| 304 | + |
| 305 | +<p>In the example application, this procedure is also part of the {@code |
| 306 | +setCamera()} method, so initializing a camera always begins with stopping the |
| 307 | +preview.</p> |
| 308 | + |
0 commit comments