summaryrefslogtreecommitdiffstats
path: root/docs/html/training/camera/cameradirect.jd
blob: 03ad119bbde6cb74b893a9d1b389464ee2ba37ae (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
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
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 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&lt;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 to restart the preview before the user
can take another picture. In this example, the restart is done by overloading
the shutter button.</p>

<pre>
&#64;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>