MaxstARSDK  3.5.0
All Classes Functions Variables
Camera2Controller.java
1 /*
2  * Copyright 2016 Maxst, Inc. All Rights Reserved.
3  */
4 package com.maxst.ar;
5 
6 import android.annotation.TargetApi;
7 import android.content.Context;
8 import android.content.pm.PackageManager;
9 import android.graphics.ImageFormat;
10 import android.hardware.camera2.CameraAccessException;
11 import android.hardware.camera2.CameraCaptureSession;
12 import android.hardware.camera2.CameraCharacteristics;
13 import android.hardware.camera2.CameraDevice;
14 import android.hardware.camera2.CameraManager;
15 import android.hardware.camera2.CaptureRequest;
16 import android.hardware.camera2.params.StreamConfigurationMap;
17 import android.media.Image;
18 import android.media.ImageReader;
19 import android.os.Build;
20 import android.os.Handler;
21 import android.os.HandlerThread;
22 import android.util.Log;
23 import android.util.Size;
24 import android.view.Surface;
25 
26 import junit.framework.Assert;
27 
28 import java.util.ArrayList;
29 import java.util.List;
30 
31 @TargetApi(Build.VERSION_CODES.M)
32 class Camera2Controller extends CameraController /*implements SurfaceHolder.Callback*/ {
33  private static final String TAG = Camera2Controller.class.getSimpleName();
34 
35  private CameraSize cameraSize = new CameraSize(0, 0);
36  private byte[] yuvBuffer = null;
37 
38  private static final int REQUEST_CAMERA_PERMISSION = 1;
39 
40  private HandlerThread backgroundThread;
41  private Handler backgroundHandler;
42  private ImageReader previewReader;
43  private CameraDevice cameraDevice;
44 
45  private CaptureRequest.Builder previewRequestBuilder;
46  private CameraCaptureSession captureSession;
47  private CaptureRequest previewRequest;
48  private boolean keepSendNewFrame = false;
49 
51 // cameraHandler = new Handler(Looper.getMainLooper());
52  }
53 
54  private void startInternal(int id, int width, int height) {
55  startBackgroundThread();
56 
57  try {
58  CameraManager manager = (CameraManager) MaxstARJNI.getContext().getSystemService(Context.CAMERA_SERVICE);
59  String strCameraId = manager.getCameraIdList()[id];
60  CameraCharacteristics characteristics = manager.getCameraCharacteristics(strCameraId);
61 
62  StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
63  Size[] sizes = map.getOutputSizes(ImageFormat.YUV_420_888);
64 
65  ArrayList<CameraSize> cameraSizes = new ArrayList<>();
66  for (Size size : sizes) {
67  cameraSizes.add(new CameraSize(size.getWidth(), size.getHeight()));
68  }
69 
70  cameraSize = getOptimalPreviewSize(cameraSizes, width, height);
71 
72  previewReader = ImageReader.newInstance(cameraSize.width, cameraSize.height, ImageFormat.YUV_420_888, 2);
73  previewReader.setOnImageAvailableListener(mOnPreviewFrameListener, null);
74 // manager.openCamera(strCameraId, mStateCallback, backgroundHandler);
75  manager.openCamera(strCameraId, mStateCallback, null);
76  } catch (CameraAccessException e) {
77  e.printStackTrace();
78  cameraState = CameraState.None;
79  }
80  }
81 
82  private int testCount = 0;
83 
84  @Override
85  public int start(final int cameraId, final int width, final int height) {
86  if (!checkPermission()) {
87  return ResultCode.CameraPermissionIsNotGranted.getValue();
88  } else {
89 // cameraHandler.post(new Runnable() {
90 // @Override
91 // public void run() {
92  if (cameraState != CameraState.None && cameraState != CameraState.Closed) {
93  return ResultCode.CameraAlreadyOpened.getValue();
94  }
95 
96  cameraState = CameraState.Opening;
97  startInternal(cameraId, width, height);
98 // }
99 // });
100  return ResultCode.Success.getValue();
101  }
102  }
103 
104  @Override
105  public void stop() {
106 
107  keepSendNewFrame = false;
108 
109 // cameraHandler.post(new Runnable() {
110 // @Override
111 // public void run() {
112  if (cameraState != CameraState.Opened) {
113  return;
114  }
115 
116  cameraState = CameraState.Closing;
117 
118  closeCamera();
119  stopBackgroundThread();
120  cameraSize.width = 0;
121  cameraSize.height = 0;
122  if (cameraSurfaceTexture != null) {
123  cameraSurfaceTexture.release();
124  cameraSurfaceTexture = null;
125  }
126 
127  cameraState = CameraState.Closed;
128 // }
129 // });
130  }
131 
132  private final ImageReader.OnImageAvailableListener mOnPreviewFrameListener = new ImageReader.OnImageAvailableListener() {
133  @Override
134  public void onImageAvailable(final ImageReader reader) {
135  ColorFormat colorFormat = ColorFormat.YUV420_888;
136 
137  Image acquiredImage = reader.acquireNextImage();
138  if (acquiredImage == null) {
139  return;
140  }
141 
142  Assert.assertTrue("Image format is not ImageFormat.YUV_420_888", acquiredImage.getFormat() == ImageFormat.YUV_420_888);
143 
144  int width = acquiredImage.getWidth();
145  int height = acquiredImage.getHeight();
146 
147 
148  Image.Plane yPlane = acquiredImage.getPlanes()[0];
149  int ySize = yPlane.getBuffer().remaining();
150 
151  Image.Plane uPlane = acquiredImage.getPlanes()[1];
152  Image.Plane vPlane = acquiredImage.getPlanes()[2];
153 
154  // be aware that this size does not include the padding at the end, if there is any
155  // (e.g. if pixel stride is 2 the size is ySize / 2 - 1)
156  int uSize = uPlane.getBuffer().remaining();
157  int vSize = vPlane.getBuffer().remaining();
158 
159  int margin = 0;
160  if (ySize / 2 - vSize > 0) {
161  margin = ySize / 2 - vSize;
162  }
163 
164  if (yuvBuffer == null || yuvBuffer.length < ySize + uSize + vSize) {
165  yuvBuffer = new byte[ySize + uSize + vSize + 100]; // Preventing overflow. 100 has no meaning.
166  }
167 
168  yPlane.getBuffer().get(yuvBuffer, 0, ySize);
169 
170  int uvPixelStride = uPlane.getPixelStride(); //stride guaranteed to be the same for u and v planes
171  if (uvPixelStride == 1) {
172  uPlane.getBuffer().get(yuvBuffer, ySize, uSize);
173  vPlane.getBuffer().get(yuvBuffer, ySize + uSize, vSize);
174  colorFormat = ColorFormat.YUV420;
175  } else {
176  vPlane.getBuffer().get(yuvBuffer, ySize, vSize);
177  uPlane.getBuffer().get(yuvBuffer, ySize + vSize + margin, uSize);
178  colorFormat = ColorFormat.YUV420_888;
179 
180  // Below code consume cpu very high!!
181 // vPlane.getBuffer().get(yuvBuffer, ySize, vSize);
182 // for (int i = 0; i < uSize; i += 2) {
183 // yuvBuffer[ySize + i + 1] = uPlane.getBuffer().get(i);
184 // }
185  }
186 
187  if (keepSendNewFrame) {
188  CameraController.setNewCameraFrame(yuvBuffer, yuvBuffer.length, width, height, colorFormat.getValue());
189  }
190 
191  acquiredImage.close();
192  }
193  };
194 
195  private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
196 
197  @Override
198  public void onOpened(CameraDevice cameraDevice) {
199  Camera2Controller.this.cameraDevice = cameraDevice;
200  createCameraPreviewSession();
201  }
202 
203  @Override
204  public void onDisconnected(CameraDevice cameraDevice) {
205  cameraDevice.close();
206  Camera2Controller.this.cameraDevice = null;
207  cameraState = CameraState.None;
208  }
209 
210  @Override
211  public void onError(CameraDevice cameraDevice, int error) {
212  cameraDevice.close();
213  Camera2Controller.this.cameraDevice = null;
214  cameraState = CameraState.None;
215  }
216  };
217 
218  @TargetApi(Build.VERSION_CODES.LOLLIPOP)
219  private void createCameraPreviewSession() {
220  try {
221 // int[] textureID = new int[1];
222 // GLES20.glGenTextures(1, textureID, 0);
223 // GLES20.glBindTexture(GL_TEXTURE_EXTERNAL_OES, textureID[0]);
224 // GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
225 // GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
226 // GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
227 // GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
228 // GLES20.glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0);
229 //
230 // if (cameraSurfaceTexture == null) {
231 // cameraSurfaceTexture = new SurfaceTexture(textureID[0]);
232 // }
233 //
234 // Surface surface = new Surface(cameraSurfaceTexture);
235  Surface surface = previewReader.getSurface();
236  List<Surface> surfaces = new ArrayList<Surface>();
237  surfaces.add(surface);
238 
239  previewRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
240  previewRequestBuilder.addTarget(surface);
241 // previewRequestBuilder.addTarget(previewReader.getSurface());
242 
243  cameraDevice.createCaptureSession(surfaces, new CameraCaptureSession.StateCallback() {
244  @Override
245  public void onConfigured(CameraCaptureSession cameraCaptureSession) {
246  if (null == cameraDevice) {
247  return;
248  }
249  captureSession = cameraCaptureSession;
250  previewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
251 // previewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_VIDEO);
252 // previewRequestBuilder.set(CaptureRequest.CONTROL_SCENE_MODE, CaptureRequest.CONTROL_SCENE_MODE_SPORTS);
253  previewRequest = previewRequestBuilder.build();
254  try {
255 // captureSession.setRepeatingRequest(previewRequest, null, backgroundHandler);
256  captureSession.setRepeatingRequest(previewRequest, null, null);
257  cameraState = CameraState.Opened;
258  keepSendNewFrame = true;
259  } catch (CameraAccessException e) {
260  e.printStackTrace();
261  cameraState = CameraState.None;
262  }
263 
264 // cameraOpenCloseLock.release();
265  }
266 
267  @Override
268  public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) {
269 // cameraOpenCloseLock.release();
270  cameraState = CameraState.None;
271  }
272  }, null
273  );
274  } catch (CameraAccessException e) {
275  e.printStackTrace();
276  cameraState = CameraState.None;
277  }
278  }
279 
280  private void closeCamera() {
281  if (null != captureSession) {
282  captureSession.close();
283  captureSession = null;
284  }
285 
286  if (null != previewReader) {
287  previewReader.setOnImageAvailableListener(null, null);
288  previewReader.close();
289  previewReader = null;
290  }
291 
292  if (null != cameraDevice) {
293  cameraDevice.close();
294  cameraDevice = null;
295  }
296 
297  Log.i(TAG, "Android closeCamera completed");
298 
299  yuvBuffer = null;
300  }
301 
302  private void startBackgroundThread() {
303  backgroundThread = new HandlerThread("CameraBackground");
304  backgroundThread.start();
305  backgroundHandler = new Handler(backgroundThread.getLooper());
306  }
307 
308  private void stopBackgroundThread() {
309  backgroundThread.quitSafely();
310  try {
311  backgroundThread.join();
312  backgroundThread = null;
313  } catch (InterruptedException e) {
314  e.printStackTrace();
315  }
316  }
317 
318  @Override
319  int getWidth() {
320  return cameraSize.width;
321  }
322 
323  @Override
324  int getHeight() {
325  return cameraSize.height;
326  }
327 
328  @Override
329  boolean setFocusMode(int focusMode) {
330  return false;
331  }
332 
333  @Override
334  boolean setFlashLightMode(boolean on) {
335  return false;
336  }
337 
338  @Override
339  boolean setAutoWhiteBalanceLock(boolean toggle) {
340  return false;
341  }
342 
343  @Override
344  Object[] getParamList() {
345  return new String[0];
346  }
347 
348  @Override
349  boolean setParam(String key, String value) {
350  return false;
351  }
352 
353  private boolean checkPermission() {
354  Context androidContext = MaxstARJNI.getContext();
355  PackageManager pm = androidContext.getPackageManager();
356  int permissionIsGranted = pm.checkPermission("android.permission.CAMERA", androidContext.getPackageName());
357  return permissionIsGranted == 0;
358  }
359 }