https://developer.android.com/reference/android/hardware/camera2/package-summary.html
https://inducesmile.com/android/android-camera2-api-example-tutorial/
http://pierrchen.blogspot.kr/2015/01/android-camera2-api-explained.html
-
API Level 21 ( Marshmellow ) 부터 사용 가능하다.
기존에 쓰이던 android.hardware.Camera 패키지의 camera 는 deprecated 되었다.
-
android.hardware.camera2 패키지의 카메라는 장비를 pipeline 으로 본다.
Single frame capture request 는 1개의 output 을 image buffer, metadata 와 함께 제공해준다.
Request 들은 순서대로 처리되며 여러개의 request 를 한번에 요청할 수도 있다.
-
CameraManager instance 를 통해 작업한다.
각각의 CameraDevice 는 CameraCharacteristics 라는 카메라 속성에 대한 Model 을 가지고 있고, CameraManager.getCameraCharacteristics(String cameraId) 을 통해 얻어 올 수 있다.
-
stream 혹은 image 를 가져오기 위해서는 먼저 void createCaptureSession(List, CameraCaptureSession.StateCallback, Handler) 를 통해 camera capture session 이라는 것을 만들어야 한다. 이 session 은 surface 와 연결되어 있다.
이 때 각각의 surface 는 적당한 사이즈와 포맷으로 미리 설정되어 있어야 한다.
-
Preview 는 보통 SurfaceTexture, Still picture 는 ImageReader, 그리고 video 는 MediaRecorder 에 연결된다.
-
앱은 request builder 등을 통해 CaptureRequest 를 만들고, active capture session 에게 전달하면 image 를 얻어올 수 있다.
-
CaptureRequestSession 은 CaptureRequest 가 전달될 context 이다.
initialized 된 surface 를 제공함으로서 session 을 얻어올 수 있다.
capture api 는 still picture 를 얻을 때 사용하고,
setRepeatingRequest 는 preview 를 보여줄 때 사용한다.
-
@ manifest
minSdkVersion 이 21(Marshmellow) 이상이여야 한다. ( 그 이전버전을 지원하려면 기존의 camera package 를 사용해야 한다. )
아래의 permission 과 uses-feature 설정이 필요하다.
... <uses-permission android:name="android.permission.CAMERA" /> ... <uses-feature android:name="android.hardware.camera2.full" /> ...
-
@ Source
public class MainActivity extends Activity { private static final int REQUEST_CAMERA_PERMISSION = 1234; private TextureView mTextureView; private CameraDevice mCamera; private Size mPreviewSize; private CameraCaptureSession mCameraSession; private CaptureRequest.Builder mCaptureRequestBuilder; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 카메라 권한 체크 if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, REQUEST_CAMERA_PERMISSION); return; } initTextureView(); } private void initTextureView() { mTextureView = (TextureView) findViewById(R.id.texture); mTextureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() { @Override public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) { Log.e("cklee", "MMM onSurfaceTextureAvailable"); openCamera(); } @Override public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int width, int height) { Log.e("cklee", "MMM onSurfaceTextureSizeChanged"); } @Override public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) { Log.e("cklee", "MMM onSurfaceTextureDestroyed"); return false; } @Override public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) { // 화면 갱신시마다 불림 // Log.e("cklee", "MMM onSurfaceTextureUpdated"); } }); } private void openCamera() { CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE); try { String[] cameraIdArray = manager.getCameraIdList(); Log.e("cklee", "MMM cameraIds = " + Arrays.deepToString(cameraIdArray)); // test 로 0 번 camera 를 사용 String oneCameraId = cameraIdArray[0]; CameraCharacteristics cameraCharacter = manager.getCameraCharacteristics(oneCameraId); Log.e("cklee", "MMM camraCharacter = " + cameraCharacter); StreamConfigurationMap map = cameraCharacter.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); Size[] sizesForStream = map.getOutputSizes(SurfaceTexture.class); Log.e("cklee", "MMM sizesForStream = " + Arrays.deepToString(sizesForStream)); // 가장 큰 사이즈부터 들어있다 mPreviewSize = sizesForStream[0]; manager.openCamera(oneCameraId, new CameraDevice.StateCallback() { @Override public void onOpened(@NonNull CameraDevice cameraDevice) { mCamera = cameraDevice; showCameraPreview(); } @Override public void onDisconnected(@NonNull CameraDevice cameraDevice) { mCamera.close(); } @Override public void onError(@NonNull CameraDevice cameraDevice, int errorCode) { Log.e("cklee", "MMM errorCode = " + errorCode); mCamera.close(); mCamera = null; } }, null); } catch (CameraAccessException e) { Log.e("cklee", "MMM openCamera ", e); } } private void showCameraPreview() { try { SurfaceTexture texture = mTextureView.getSurfaceTexture(); texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight()); Surface textureViewSurface = new Surface(texture); mCaptureRequestBuilder = mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); mCaptureRequestBuilder.addTarget(textureViewSurface); mCaptureRequestBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO); mCamera.createCaptureSession(Arrays.asList(textureViewSurface), new CameraCaptureSession.StateCallback() { @Override public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) { mCameraSession = cameraCaptureSession; updatePreview(); } @Override public void onConfigureFailed(@NonNull CameraCaptureSession cameraCaptureSession) { Log.e("cklee", "MMM onConfigureFailed"); } }, null); } catch (CameraAccessException e) { Log.e("cklee", "MMM showCameraPreview ", e); } } private void updatePreview() { try { mCameraSession.setRepeatingRequest(mCaptureRequestBuilder.build(), null, null); } catch (CameraAccessException e) { Log.e("cklee", "MMM updatePreview", e); } } public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { if (requestCode == REQUEST_CAMERA_PERMISSION) { if (grantResults[0] == PackageManager.PERMISSION_DENIED) { Toast.makeText(this, "Permission denied", Toast.LENGTH_LONG).show(); finish(); } } else { openCamera(); } } }
-
request 관련하여 마지막 param 은 대부분 handler 인데, background handler 를 사용하는 것이 좋다.
'프로그래밍 놀이터 > 안드로이드, Java' 카테고리의 다른 글
[android] Low Memory Kill ( LMK ) (0) | 2019.01.09 |
---|---|
[android] 언어 변경(language change)했을 때 동작 실험 (0) | 2019.01.08 |
[Java8 In Action] #16 결론 그리고 자바의 미래 (0) | 2019.01.05 |
[Java8 In Action] #15 OOP 와 FP 의 조합 : 자바8과 스칼라 비교 (0) | 2019.01.04 |
[Java8 In Action] #14 함수형 프로그래밍 기법 (0) | 2019.01.03 |
댓글