Camera2 APIを使ったカメラ機能の実装|Android開発
Androidの新しいカメラモジュール、Camera2 API(android.hardware.camera2)
を使ったプレビューと撮影の実装方法です。
本記事を見ながら30分程度で撮影まで行えるよう、細かな調整は省略しています。
permissionの追加
カメラを使用するためにはAndroidManifest.xmlで以下を指定する必要があります。
<uses-permission android:name="android.permission.CAMERA"></uses-permission>
layout
プレビュー表示を行うためのTextureViewを用意します。
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextureView
android:id="@+id/camera2_texture"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="visible" />
</FrameLayout>
カメラの利用手順
準備
TextureViewがavailableかどうかをチェックします
mTextureView.isAvailable();
- available(
true)ならカメラのオープン処理を行います - 非available(
false)ならTextureView.SurfaceTextureListenerを設定して、availableになるのを待ちます
mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
TextureView.SurfaceTextureListener mSurfaceTextureListener =
new TextureView.SurfaceTextureListener() {...};
TextureView.SurfaceTextureListener.onSurfaceTextureAvailable()
TextureViewがavailableになったらカメラのオープン処理を行います
カメラのオープン
CameraManagerのインスタンスを取得します
CameraManager cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
- オープンするカメラのIDを決めます
ImageReaderを生成します。ImageReaderは主に撮影時に使用します
ImageReader mImageReader = ImageReader.newInstance(1920, 1080, ImageFormat.JPEG, 3);
mImageReader.setOnImageAvailableListener(mTakePictureAvailableListener, null);
mTakePictureAvailableListenerについては後述。
CameraManagerにオープン要求を出します
cameraManager.openCamera(cameraId, mStateCallback, null);
CameraDevice.StateCallback mStateCallback =
new CameraDevice.StateCallback() {...};
CameraDevice.StateCallback.onOpened()SurfaceTextureにプレビューサイズを設定し、プレビュー用のSurfaceを生成します
SurfaceTexture texture = mTextureView.getSurfaceTexture();
texture.setDefaultBufferSize(1280, 720);
Surface mPreviewSurface = new Surface(texture);
CaptureSessionを生成します(cameraはonOpened()のパラメータCameraDevice)
camera.createCaptureSession(Arrays.asList(mPreviewSurface,
mImageReader.getSurface()),
mSessionCallback,
null);
CameraCaptureSession.StateCallback mSessionCallback =
new CameraCaptureSession.StateCallback() {...};
- パラメータの
CameraDeviceを保持しておきます
mCameraDevice = camera;
CameraCaptureSession.StateCallback.onConfigured()- パラメータの
CameraCaptureSessionを保持しておきます
mCaptureSession = session;
準備からオープン完了までの処理フロー
水色背景は必要に応じて設定する箇所になります。
- 撮影サイズと端末の向きからプレビューサイズを決定する方法
Camera2 撮影サイズから最適なプレビューサイズを決定する|Android開発 - プレビューサイズから
TextureViewのサイズを調整する方法
Camera2 TextureViewの回転(プレビューアスペクト比キープ)|Android開発
プレビューの実装
- プレビュー用の
CaptureRequest.Builderを生成します
CaptureRequest.Builder captureBuilder =
mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
CaptureRequest.Builderにプレビュー用のSurfaceを設定します
captureBuilder.addTarget(mPreviewSurface);
- 必要なパラメータを設定します(下記はサンプル)
captureBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
- プレビューを開始します
captureSession.setRepeatingRequest(captureBuilder.build(), null, null);
プレビュー開始のフロー
撮影の実装
- 撮影用の
CaptureRequest.Builderを生成します
CaptureRequest.Builder captureBuilder =
camera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
CaptureRequest.Builderに撮影用のSurfaceを設定します
captureBuilder.addTarget(mImageReader.getSurface());
- 必要なパラメータを設定します(下記はサンプル)
captureBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, orientation);
captureBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON);
- 現在のプレビューを停止します
captureSession.stopRepeating();
- 撮影を開始します
captureSession.capture(captureBuilder.build(), mCaptureCallback, null);
CameraCaptureSession.CaptureCallback mCaptureCallback =
new CameraCaptureSession.CaptureCallback() {...};
CameraCaptureSession.CaptureCallback.onCaptureCompleted()
撮影完了のタイミングで通知されます。
撮影開始のフロー
撮影画像の通知
カメラオープン時に指定したmTakePictureAvailableListenerが撮影画像を受信します
ImageReader.OnImageAvailableListener mTakePictureAvailableListener =
new ImageReader.OnImageAvailableListener() {...};
- 撮影画像は
ImageReader.OnImageAvailableListener.onImageAvailable()で通知されます android.media.Imageを取得します
Image image = reader.acquireNextImage();
または
Image image = reader.acquireLatestImage();
- 取得した
android.media.Imageを処理します(保存など) android.media.Imageを解放します。これを忘れるとバースト撮影などで失敗します
image.close();
撮影画像通知のフロー
撮影完了通知のフロー
カメラのクローズ
CameraCaptureSessionをクローズします
mCaptureSession.close();
CameraDeviceをクローズします
mCameraDevice.close();
ImageReaderをクローズします
mImageReader.close();
クローズのフロー
