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 |
댓글