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