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を生成します(cameraonOpened()のパラメータ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 open フロー

撮影サイズと端末の向きからプレビューサイズを決定する方法 Camera2 撮影サイズから最適なプレビューサイズを決定する|Android開発
プレビューサイズからTextureViewのサイズを調整する方法 Camera2 TextureViewの回転(プレビューアスペクト比キープ)|Android開発

Camera2 open フロー Camera2 open フロー

プレビューの実装

  • プレビュー用の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);

プレビュー開始のフロー

Camera2 プレビュー フロー

撮影の実装

  • 撮影用の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()
    撮影完了のタイミングで通知されます。

撮影開始のフロー

Camera2 撮影 フロー

撮影画像の通知

カメラオープン時に指定した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();

撮影画像通知のフロー

Camera2 撮影 フロー

撮影完了通知のフロー

Camera2 撮影完了 フロー

カメラのクローズ

  • CameraCaptureSessionをクローズします
mCaptureSession.close();
  • CameraDeviceをクローズします
mCameraDevice.close();
  • ImageReaderをクローズします
mImageReader.close();

クローズのフロー

Camera2 close フロー
このエントリーをはてなブックマークに追加
にほんブログ村 IT技術ブログへ

関連コンテンツ

スポンサードリンク

Comment

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です