Camera2 APIを使いこなす(Part 1 : プレビューの表示)

Androidでカメラを使ったアプリを開発するときには、 android.hardware.Camera を使う方法と、 android.hardware.camera2.* を使う方法があります。今回はこのうちCamera2 APIでカメラを実装しながら、使い方を解説していきます。

Camera2 APIはAndroid5.0以降で使える比較的新しいAPIで、既存のCamera APIに比べて細かい設定ができるものの、そのトレードオフとして実装が複雑になってしまいます。

しかし、登場人物をしっかり整理して流れをつかむことさえできれば実装の見通しが一気に立てやすくなるので、順を追って確認していきましょう。今回は手始めにカメラからプレビューを取得してTextureViewに表示するところまでやっていきます。

今回は大まかな流れを掴みやすくするために、画面サイズの調整や複数のカメラ情報の取得、アスペクト比の調整などをスキップして説明しています。今回説明しなかった細かい設定などは次回以降のパートで説明するのでそちらもお読みください。

まず、全体の流れをざっくりと確認すると、

CameraManager#openCameraCameraDeviceを取得する(非同期)

CameraDevice#createCaptureSessionCaptureSessionを作成する(非同期)

CaptureSession#setRepeatingRequest でカメラ画像のキャプチャを開始

ここまでで、カメラから取得した画像をプレビューすることができます。


カメラから取得したプレビューを表示する

①TextureViewを用意する

撮影したカメラのデータをプレビューするためにTextureViewを用意します。今回はわかりやすいように画面幅いっぱいにTextureViewを追加しました。

②TextureViewが使えるようになるのを待つ

プレビュー用のTextureViewの準備が完了するのを待ちます。 Activity#onResume() でTextureViewに SurfaceTextureListener をセットして、次に実装する openCamera() を呼びます。

③カメラをオープンする

先ほどSurfaceTextureListener#onSurfaceTextureAvailable で呼び出していた openCamera メソッドを実装していきます。

Activityから取得した CameraManageropenCamera メソッドを呼び出すことでカメラをオープンすることができます。

openCamera メソッドの第一引数はカメラIDでここでは "0" を決め打ちしています。(実際には使いたいカメラのIDを取得する処理が必要になりますが、ここでは省略しています。 "0" にはほとんどの場合バックカメラが割り当てられているはずです。)

第二引数はコールバックを指定します。 onOpenedCameraDevice を取得して、次で実装する createCameraPreviewSession() を呼びます。

第三引数には Hander を指定できます。 null を指定するとUIスレッドでカメラを開くことになります。カメラを使って重たい処理をする際はバックグラウンドスレッドをバインドした Handler を作成して渡すことでカクツキが軽減できます。

④プレビューを開始する

カメラがオープンできたら、ようやくカメラの画像のキャプチャを開始します。まず、 TextureView から撮影データの受け取り先となる Surface を取得します。この時、 Texture#setDefaultBufferSize() で適切なプレビューサイズを指定する必要がありますが、こちらも今回は多くのデバイスが対応しているVGAサイズ(640 * 480)に固定しています。

次にCameraDevice#createCaptureSession を使って CameraCaptureSession を取得します。 CameraCaptureSession はカメラから送られてくる画像を受け取ったり、同一セッションで前に受け取った画像の再処理などをするクラスです。

セッションが取得できたら、 CameraCaptureSession#setRepeatingRequest でプレビュー画像を TextureView に送ります。

第一引数の CaptureRequestCameraDevice#createCaptureRequest から取得できるBuilder経由で作成します。 CaptureRequest#addTarget で指定したSurfaceに対してキャプチャした画像を送ってくれるので、 TextureView のSurfaceを指定します。

バックグラウンドスレッドに結びつけた Handler を用意している時は第三引数にその Handler を渡します。

ここまででプレビューが表示されます!


次に

ここまででプレビューを表示することはできましたが、カメラの向きやデバイスの回転に合わせてプレビューを補正したり、カメラデバイスから適切なプレビューサイズを指定したり、それ以外にも、写真の撮影、カメラの切り替え、フラッシュ、オートフォーカスなどまだまだやらないといけないことがたくさんあります。

次回はカメラの回転の補正に関しての記事です。

フィードバックや修正、編集リクエストなど大歓迎です。何かありましたら@itometeamまでご連絡ください。