Open1
【Google I/O 2023】Building high quality Android camera experiences
- このセッションで紹介すること
- Polished camera previews
- Premium visual quality
- What else is new on Android 14
Camera Previews (2:05~)
- プレビューの重要性
- アスペクト比が合ってなくて歪んだプレビューはプレミアム感が損なわれる
- ユーザーはプレビューと実際に保存された写真、動画が合っていることを期待する
Preview Stabilization (2:52~)
- Android 5 から Video Stabilization がある
- Android 13 以降の端末は Preview Stabilization が設定できる
- カメラプレビューと動画の内容が一致する
Camera2 で Preview Stabilization を設定するコードは以下。
// Camera2: When configuring your capture request, check to enable Preview Stabilization.
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
fun setPreviewStabilization(builder: CaptureRequest.Builder, manager: CameraManager, cameraId: String) {
val availableVideoStabilizationModes = manager
.getCameraCharacteristics(cameraId)
.get(CameraCharacteristics.CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES)
if (availableVideoStabilizationModes?.contains(CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION) == true) {
builder.set(CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE,
CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION)
}
}
CameraX の場合は以下。
// CameraX: Use Camera2Interop to set the underlying Camera2 CaptureRequest.
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
@ExperimentalCamera2Interop
fun setPreviewStabilization(camera: Camera) {
val availableVideoStabilizationModes = Camera2CameraInfo.from(camera.cameraInfo)
.getCameraCharacteristic(CameraCharacteristics.CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES)
if (availableVideoStabilizationModes?.contains(CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION) == true) {
Camera2CameraControl.from(camera.cameraControl).setCaputreRequestOptions(
CaptureRequestOptions.Builder().setCaptureRequestOption(
CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE,
CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE_PREVIEW_STABILIZATION
).build()
)
}
}
Jetpack Preview Classes (4:26~)
- Jetpack には2つのプレビュークラスがある
- CameraX : PreviewView
- Camera2 CameraViewfinder
- どちらのプレビュークラスにも6つのスケールタイプが提供されている
CameraX の PreviewView の設定コードは以下。
// CameraX: Using PreviewView
val previewView: PreviewView = viewBinding.viewFinder
cameraController = LifecycleCameraController(baseContext)
cameraController.bindToLifecycle(myActivity)
previewView.controller = cameraController
CameraX は高度なプレビュー機能も提供している。
// Add an image analyzer (including our built-in MlKitAnalyzer),
// with each image's coordinates mapped to the preview.
cameraController.setImageAnalysisAnalyzer(executor, analyzer)
// Add Graphics Library effects to the preview, images, and video.
cameraController.setEffects(effects)
Camera2 の場合。
// Camera2: Using CameraViewFinder
val previewResolution = Size(width, height)
val viewfinderSurfaceRequest = SurfaceRequest(previewResolution, characteristics)
val cameraViewfinder = CameraViewfinder(baseContext)
val surfaceListenableFuture = cameraViewfinder.requestSurfaceAsync(viewfinderSurfaceRequest)
Future.addCallback(surfaceListenableFuture,
object: FutureCallback<Surface> {
override fun onSuccess(surface: Surface) {
// create a CaptureSession using this surface as usual
}
override fun onFailure(t: Throwable) { /* something went wrong */ }
}, ContextCompat.getMainExecuter(context))
Large Screen Previews (8:33~)
- Jetpack のプレビュークラスは大きいスクリーンサイズを考慮している
Premium visual quality (9:41~)
HDR Video (10:02~)
- Android 13 で HDR のビデオキャプチャが導入された
- 10-Bit Color : 1億以上の色が表示できる
10-Bit がサポートされているかのコードは以下。
// Assure Camera has 10-Bit Capabilities
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
fun isTenBitSupported(manager: CameraManager, cameraId: String): Boolean {
val capabilities = manager
.getCameraCharacteristics(cameraId)
.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES)
return capabilities?.contains(CameraMetadata.REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT) ?: false
}
HDR がサポートされているかのコードは以下。
// Assure Camera supports HLG10
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
fun isHDRSupported(manager: CameraManager, cameraId: String): Boolean {
val supportedProfiles = manager
.getCameraCharacteristics(cameraId)
.get(CameraCharacteristics.REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES)
?.supportedProfiles
return supportedProfiles?.contains(DynamicRangeProfiles.HDR10_PLUS) ?: false
}
OutputConfiguration の dynamicRangeProfile を設定する。
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
fun configureSession(device: CameraDevice, targets: List<Surface>, exe: Executor, cb: CameraCaptureSession.StateCallback) {
val configs = targets.map {
val config = OutputConfiguration(it)
config.dynamicRangeProfile = DynamicRangeProfile.HLG10
config
}
val session = SessionConfiguration(
SessionConfiguration.SESSION_REGULAR, configs, exe, cb
)
device.createCaptureSession(session)
}
最後に MediaFormat を設定する。
@RequiresApi(Build.VERSION_CODES.N)
fun configureEncoder(surface: Surface, w: Int, h: Int) {
val format = MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_HEVC, w, h)
// Other Setup
// ...
// Set media format properties
format.setInteger(...)
}
setInteger の部分には以下のパラメータを設定する。
/// Color Format
(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface)
/// HEVC (H.265)
(MediaFormat.KEY_PROFILE, MediaCodecInfo.CodecProfileLevel.HEVCProfileMain10)
/// HLG Color Transfer
(MediaFormat.KEY_COLOR_TRANSFER, MediaFormat.COLOR_TRANSFER_HLG)
/// BT2020 Color Standard
(MediaFormat.KEY_COLOR_STANDARD, MediaFormat.COLOR_STANDARD_BT2020)
Stream Use Cases (12:23~)
- 以下は事前定義された Stream Use Cases
- DEFAULT
- 全ての既存の動作をカバーする設定
- PREVIEW
- Viewfinder やアプリ内の画像解析の用途にオススメ
- STILL_CAPTURE
- VIDEO_RECORD
- VIDEO_CALL
- 長時間カメラを使うような電力消費に関わる場合にオススメ
- PREVIEW_VIDEO_STILL
- ソーシャルメディアアプリや単一の stream use case に推奨される多目的の stream
- VENDOR_START
- OEM が定義した use cases
- DEFAULT
13:15 から以下の use case のデモ動画が見れる。
- PREVIEW
- Viewfinder としてのパフォーマンスと利便性を最適化
- 画像の質は必ずしも最適化されない
- STILL_CAPTURE
- 高品質な画像キャプチャを最適化することが期待される
- プレビューのようにフレームレートを維持することは想定されない
以下は特定の stream use case がサポートされているかどうかをチェックするコード例。
// Check if camera supports the stream use case.
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
fun isStreamUseCaseAvailable(manager: CameraManager, cameraId: String, streamUseCase: Long): Boolean {
val characteristics = manager
.getCameraCharacteristics(id)
.get(CameraCharacteristics.SCALER_AVAILABLE_STREAM_USE_CASES)
return characteristics?.contains(streamUseCase) ?: false
}
以下は stream use case を設定する例。
// Setup Stream Use Case while setting up your Output Configuration.
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
fun configureSession(device: CameraDevice, targets: List<Surface>) {
val configs = mutableListOf<OutputConfiguration>()
val streamUseCase = CameraMetadata
.SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL
targets.forEach {
val config = OutputConfiguration(it)
config.streamUseCase = streamUseCase.toLong()
configs.add(config)
}
...
device.createCaptureSession(session)
}
Extensions (13:56~)
- 端末の製造メーカーはカメラの拡張機能を通じて、ナイトモードやボケ効果などの特別な機能を開発者に提供することができる
- Snapchat はナイトモードの拡張機能で見た目の品質を改善
- 以下が現在利用できる拡張機能
- EXTENSION_NIGHT
- EXTENSION_HDR
- EXTENSION_AUTO
- EXTENSION_BOKEH
- EXTENSION_FACE_RETOUCH
拡張機能がサポートされているかチェックするコードは以下。
@RequireApi(Build.VERSION_CODE.S)
fun isExtensionSupported(manager: CameraManager, id: String, extension: Int): Boolean {
return manger
.getCameraExtensionCharacteristics(id)
.supportedExtensions
.contains(extension)
}
ボケ効果の拡張機能付きのセッションを作成する例は以下。
@RequireApi(Build.VERSION_CODE.S)
private fun createCaptureSession(
device: CameraDevice,
configs: List<OutputConfiguraion>,
extension: Int = CameraExtensionCharacteristics.EXTENSION_BOKEH,
exe: Executor
) {
if (!isExtensionSupported(manager, device.id, extension)) return
// Implement callbacks
val cb = object: CameraExtensionSession.StateCallback() {
// Implement onConfigured & onConfiguredFailed
}
val config = ExtensionSessionConfiguration(extension, configs, exe, cb)
device.createExtensionSession(config)
}
これらの機能は CameraX の 1.3.0-alpha から使用可能。
Android 14 (15:50~)
- Ultra HDR still capture
- AppCompat で後方互換性のある JPEG フォーマットを設計中
- P3 color space
- ズームの最適化