CameraOps.java revision 819a53c75fac8f13b1a01eadf50f36e81f8bf164
1/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.testingcamera2;
18
19import android.content.Context;
20import android.graphics.ImageFormat;
21import android.hardware.photography.CameraAccessException;
22import android.hardware.photography.CameraDevice;
23import android.hardware.photography.CameraManager;
24import android.hardware.photography.CameraProperties;
25import android.hardware.photography.CaptureRequest;
26import android.hardware.photography.CaptureResult;
27import android.hardware.photography.Size;
28import android.media.Image;
29import android.media.ImageReader;
30import android.os.Handler;
31import android.os.Looper;
32import android.os.Message;
33import android.view.SurfaceHolder;
34import android.view.Surface;
35
36import java.lang.Thread;
37import java.util.ArrayList;
38import java.util.List;
39
40/**
41 * A camera controller class that runs in its own thread, to
42 * move camera ops off the UI. Generally thread-safe.
43 */
44public class CameraOps {
45
46    private Thread mOpsThread;
47    private Handler mOpsHandler;
48
49    private CameraManager mCameraManager;
50    private CameraDevice  mCamera;
51
52    private ImageReader mCaptureReader;
53
54    // How many JPEG buffers do we want to hold on to at once
55    private static final int MAX_CONCURRENT_JPEGS = 2;
56
57    private static final int STATUS_ERROR = 0;
58    private static final int STATUS_UNINITIALIZED = 1;
59    private static final int STATUS_OK = 2;
60
61    private int mStatus = STATUS_UNINITIALIZED;
62
63    private void checkOk() {
64        if (mStatus < STATUS_OK) {
65            throw new IllegalStateException(String.format("Device not OK: %d", mStatus ));
66        }
67    }
68
69    private class OpsHandler extends Handler {
70        @Override
71        public void handleMessage(Message msg) {
72
73        }
74    }
75
76    private CameraOps(Context ctx) throws ApiFailureException {
77        mCameraManager = (CameraManager) ctx.getSystemService(Context.CAMERA_SERVICE);
78        if (mCameraManager == null) {
79            throw new ApiFailureException("Can't connect to camera manager!");
80        }
81
82        mOpsThread = new Thread(new Runnable() {
83            @Override
84            public void run() {
85                Looper.prepare();
86                mOpsHandler = new OpsHandler();
87                Looper.loop();
88            }
89        }, "CameraOpsThread");
90        mOpsThread.start();
91
92        mStatus = STATUS_OK;
93    }
94
95    static public CameraOps create(Context ctx) throws ApiFailureException {
96        return new CameraOps(ctx);
97    }
98
99    public String[] getDevices() throws ApiFailureException{
100        checkOk();
101        try {
102            return mCameraManager.getDeviceIdList();
103        } catch (CameraAccessException e) {
104            throw new ApiFailureException("Can't query device set", e);
105        }
106    }
107
108    public void registerCameraListener(CameraManager.CameraListener listener)
109            throws ApiFailureException {
110        checkOk();
111        mCameraManager.registerCameraListener(listener);
112    }
113
114    public CameraProperties getDeviceProperties(String cameraId)
115            throws CameraAccessException, ApiFailureException {
116        checkOk();
117        return mCameraManager.getCameraProperties(cameraId);
118    }
119
120    public void openDevice(String cameraId)
121            throws CameraAccessException, ApiFailureException {
122        checkOk();
123
124        if (mCamera != null) {
125            throw new IllegalStateException("Already have open camera device");
126        }
127
128        mCamera = mCameraManager.openCamera(cameraId);
129    }
130
131    public void closeDevice()
132            throws ApiFailureException {
133        checkOk();
134
135        if (mCamera == null) return;
136
137        try {
138            mCamera.close();
139        } catch (Exception e) {
140            throw new ApiFailureException("can't close device!", e);
141        }
142
143        mCamera = null;
144    }
145
146    private void minimalOpenCamera() throws ApiFailureException {
147        if (mCamera == null) {
148            try {
149                String[] devices = mCameraManager.getDeviceIdList();
150                if (devices == null || devices.length == 0) {
151                    throw new ApiFailureException("no devices");
152                }
153                mCamera = mCameraManager.openCamera(devices[0]);
154            } catch (CameraAccessException e) {
155                throw new ApiFailureException("open failure", e);
156            }
157        }
158
159        mStatus = STATUS_OK;
160    }
161
162    /**
163     * Set up SurfaceView dimensions for camera preview
164     */
165    public void minimalPreviewConfig(SurfaceHolder previewHolder) throws ApiFailureException {
166
167        minimalOpenCamera();
168        try {
169            CameraProperties properties = mCamera.getProperties();
170
171            Size[] previewSizes = null;
172            if (properties != null) {
173                previewSizes = properties.get(
174                    CameraProperties.SCALER_AVAILABLE_PROCESSED_SIZES);
175            }
176
177            if (previewSizes == null || previewSizes.length == 0) {
178                previewHolder.setFixedSize(640, 480);
179            } else {
180                previewHolder.setFixedSize(previewSizes[0].getWidth(), previewSizes[0].getHeight());
181            }
182        }  catch (CameraAccessException e) {
183            throw new ApiFailureException("Error setting up minimal preview", e);
184        }
185    }
186
187    /**
188     * Configure streams and run minimal preview
189     */
190    public void minimalPreview(SurfaceHolder previewHolder) throws ApiFailureException {
191
192        minimalOpenCamera();
193        try {
194            mCamera.stopRepeating();
195            mCamera.waitUntilIdle();
196
197            Surface previewSurface = previewHolder.getSurface();
198
199            List<Surface> outputSurfaces = new ArrayList(1);
200            outputSurfaces.add(previewSurface);
201
202            mCamera.configureOutputs(outputSurfaces);
203
204            CaptureRequest previewRequest = mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
205
206            previewRequest.addTarget(previewSurface);
207
208            mCamera.setRepeatingRequest(previewRequest, null);
209        } catch (CameraAccessException e) {
210            throw new ApiFailureException("Error setting up minimal preview", e);
211        }
212    }
213
214    public void minimalJpegCapture(final CaptureListener listener, Handler h)
215            throws ApiFailureException {
216        minimalOpenCamera();
217
218        try {
219            mCamera.stopRepeating();
220            mCamera.waitUntilIdle();
221
222            CameraProperties properties = mCamera.getProperties();
223            Size[] jpegSizes = null;
224            if (properties != null) {
225                jpegSizes = properties.get(
226                    CameraProperties.SCALER_AVAILABLE_JPEG_SIZES);
227            }
228            int width = 640;
229            int height = 480;
230
231            if (jpegSizes != null && jpegSizes.length > 0) {
232                width = jpegSizes[0].getWidth();
233                height = jpegSizes[0].getHeight();
234            }
235
236            if (mCaptureReader == null || mCaptureReader.getWidth() != width ||
237                    mCaptureReader.getHeight() != height) {
238                if (mCaptureReader != null) {
239                    mCaptureReader.close();
240                }
241                mCaptureReader = new ImageReader(width, height,
242                        ImageFormat.JPEG, MAX_CONCURRENT_JPEGS);
243            }
244
245            List<Surface> outputSurfaces = new ArrayList(1);
246            outputSurfaces.add(mCaptureReader.getSurface());
247
248            mCamera.configureOutputs(outputSurfaces);
249
250            CaptureRequest captureRequest =
251                    mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
252
253            captureRequest.addTarget(mCaptureReader.getSurface());
254
255            ImageReader.OnImageAvailableListener readerListener =
256                    new ImageReader.OnImageAvailableListener() {
257                public void onImageAvailable(ImageReader reader) {
258                    Image i = reader.getNextImage();
259                    listener.onCaptureAvailable(i);
260                    i.close();
261                }
262            };
263            mCaptureReader.setImageAvailableListener(readerListener, h);
264
265            mCamera.capture(captureRequest, null);
266
267        } catch (CameraAccessException e) {
268            throw new ApiFailureException("Error in minimal JPEG capture", e);
269        }
270    }
271
272    public interface CaptureListener {
273        void onCaptureAvailable(Image capture);
274    }
275}
276