前書き
前編ではAndroidカメラのプレビュー表示(Camera API + SurfaceView)について述べました。本編ではそれを踏まえて、Camera API + TextureViewの実装方法を紹介します。注意点は前編と同じで、TextureViewについての注意点は特にありません。
実装方法はCamera API + SurfaceViewのとかなり被る部分があるので、ここではあえて実装の差分のみ説明します。Androidカメラのプレビュー表示(Camera API + SurfaceView)と合わせてお読みいただければ幸いです。
実装
レイアウト
SurfaceViewをTextureViewに置き換えます。
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/main_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:keepScreenOn="true">
<!-- SurfaceViewをTextureViewに置き換える -->
<TextureView
android:id="@+id/texture_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
カメラ起動
camera.setPreviewDisplay(surfaceHolder)をcamera.setPreviewTexture(surfaceTexture)に置き換えます。
surfaceViewをtextureViewに置き換えます。
private fun openCamera() {
val context = context ?: return
val windowManager = activity?.windowManager ?: return
// カメラIDを特定
val cameraId = getCameraId(cameraType) ?: return
// カメラを取得
camera = Camera.open(cameraId)
camera?.let { camera ->
try {
// camera.setPreviewDisplay(surfaceHolder)
// カメラ出力先を指定
// TextureViewに出力するので、setPreviewTexture()を使って、SurfaceTextureを設定
camera.setPreviewTexture(surfaceTexture)
} catch (ioException: IOException) {
ioException.printStackTrace()
}
// [注意点]:端末の回転角度に合わせて、カメラの回転角度を設定
camera.setDisplayOrientation(
when (windowManager.defaultDisplay.rotation) {
Surface.ROTATION_0 -> 90
Surface.ROTATION_90 -> 0
Surface.ROTATION_180 -> 270
Surface.ROTATION_270 -> 180
else -> 0
}
)
// カメラのパラメータを設定
cameraParam = camera.parameters.apply {
// プレビュー可能サイズを取得
val size = supportedPreviewSizes.firstOrNull()
size?.let { size ->
// プレビューサイズを設定
setPreviewSize(size.width, size.height)
}
}
// カメラのパラメータを設定
camera.parameters = camera.parameters.apply {
val size = supportedPreviewSizes.firstOrNull()
size?.let { size ->
setPreviewSize(size.width, size.height)
}
}
// カメラプレビューを開始
camera.startPreview()
// [注意点]:プレビューサイズに合わせて、TextureViewのサイズを調整する。
// この処理が抜けると、プレビューのアスペクト比がおかしくなる可能性がある
// surfaceViewをtextureViewに置き換える
updateSurfaceSize(
// binding.surfaceView,
binding.textureView,
camera.parameters.previewSize.width,
camera.parameters.previewSize.height.
surfaceWidth,
surfaceHeight
)
}
}
TextureView
SurfaceViewをTextureViewに置き換えます。
// SurfaceHolderをSurfaceTextureに置き換える
// private var surfaceHolder: SurfaceHolder? = null
private var surfaceTexture: SurfaceTexture? = null
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = DataBindingUtil.inflate<MainFragmentBinding>(
inflater,
R.layout.main_fragment,
container,
false
)
// SurfaceViewをTextureViewに置き換える
binding.textureView.surfaceTextureListener = object : TextureView.SurfaceTextureListener {
override fun onSurfaceTextureAvailable(surface: SurfaceTexture, width: Int, height: Int) {
surfaceTexture = surface
surfaceWidth = width
surfaceHeight = height
checkAndAskPermission()
}
override fun onSurfaceTextureSizeChanged(surface: SurfaceTexture, width: Int, height: Int) {
surfaceWidth = width
surfaceHeight = height
}
override fun onSurfaceTextureUpdated(surface: SurfaceTexture) {
}
override fun onSurfaceTextureDestroyed(surface: SurfaceTexture): Boolean {
return false
}
}
return binding.root
}
まとめ
ご覧になればおわかりだと思いますが、Camera API + SurfaceViewとCamera API + TextureViewの差分がかなり少ないです。しかもカメラ制御方法もほぼ一緒です。コツさえつかめば、SurfaceViewとTextureViewの双方向変換は簡単にできてしまいます。