Camera2中CameraViewfinder预览画面拉伸问题求助
问题:CameraViewfinder 预览垂直拉伸,fillCenter 未按预期裁剪校正
我正使用Camera2框架开发应用内相机,采用CameraViewfinder实现预览,按文档描述它应该自动处理方向与比例校正。但设置3072x4080(3:4)分辨率并请求Surface后,预览画面出现垂直拉伸。我配置了fillCenter缩放类型,其文档说明“若相机预览比例与CameraViewfinder容器比例不匹配,可能会裁剪取景器”,但实际未出现裁剪,反而拉伸变形。
我尝试过获取取景器比例并匹配最接近的分辨率,但预览仍失真,请问该如何修正?
请求预览Surface的代码
surfaceRequest = ViewfinderSurfaceRequest.Builder( resolution = resolution // Size(3072, 4080) ).build() surfaceRequest?.let { request -> val surfaceListenableFuture: ListenableFuture<Surface> = binding.viewFinder.requestSurfaceAsync(request) Futures.addCallback( surfaceListenableFuture, object : FutureCallback<Surface> { override fun onSuccess(result: Surface?) { // use surface } }, ContextCompat.getMainExecutor(requireContext()) ) }
CameraViewfinder布局代码
<androidx.camera.viewfinder.CameraViewfinder android:id="@+id/view_finder" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginBottom="92dp" android:layout_marginTop="64dp" app:scaleType="fillCenter" />
注:取景器嵌套在FrameLayout中,因相机UI有上下栏设置了边距;对比我的相机预览与Google相机预览,前者画面垂直拉伸。
解决方案
1. 计算取景器实际显示比例
设置的上下边距会改变取景器的实际可用尺寸,CameraViewfinder可能基于原始match_parent尺寸计算比例,而非边距后的实际尺寸。需手动获取实际宽高计算比例:
binding.viewFinder.post { val actualWidth = binding.viewFinder.width val actualHeight = binding.viewFinder.height val viewfinderRatio = actualWidth.toFloat() / actualHeight.toFloat() // 基于此比例匹配相机预览分辨率 }
2. 筛选匹配比例的相机预览分辨率
不要硬编码3072x4080,从Camera2支持的分辨率中筛选与取景器实际比例最接近的选项:
// 已获取相机Characteristics的前提下 val characteristics = cameraManager.getCameraCharacteristics(cameraId) val configMap = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)!! val supportedSizes = configMap.getOutputSizes(SurfaceTexture::class.java) val targetRatio = actualWidth.toFloat() / actualHeight.toFloat() var bestSize: Size? = null var minDiff = Float.MAX_VALUE for (size in supportedSizes) { val sizeRatio = size.width.toFloat() / size.height.toFloat() val diff = abs(sizeRatio - targetRatio) if (diff < minDiff) { minDiff = diff bestSize = size } } // 使用匹配到的最佳分辨率创建SurfaceRequest surfaceRequest = bestSize?.let { ViewfinderSurfaceRequest.Builder(it).build() }
3. 对齐相机预览方向
Camera2预览方向需与屏幕旋转角度匹配,否则会导致比例计算偏差:
// 获取屏幕旋转角度 val screenRotation = requireActivity().windowManager.defaultDisplay.rotation // 转换为相机适配的方向 val cameraOrientation = when (screenRotation) { Surface.ROTATION_0 -> 90 Surface.ROTATION_90 -> 0 Surface.ROTATION_180 -> 270 Surface.ROTATION_270 -> 180 else -> 90 } // 配置CaptureRequest时设置方向 val previewRequest = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW).apply { set(CaptureRequest.JPEG_ORIENTATION, cameraOrientation) addTarget(surface) // surface为从CameraViewfinder获取的预览Surface }
4. 显式设置缩放类型
确保fillCenter缩放类型生效,可在代码中显式设置:
binding.viewFinder.scaleType = CameraViewfinder.ScaleType.FILL_CENTER
内容的提问来源于stack exchange,提问作者Pramath Pancholi
相关产品推荐
相关产品推荐

