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();