qq_42158560
雪下的回忆
2021-06-02 15:27
采纳率: 83.3%
浏览 95

camera2在设置surfaceview大小后预览依然变形

在网上找资料后说预览变形是因为surfaceview的大小和传入的大小不匹配导致的,但是我在设置surfaceview的大小后预览为什么依然是变形的,我少做了哪一步吗。

 

经过实际测试,只有在surfaceview的长宽比设为1:1的时候预览图片才是不会变形的,但是camera2理应会根据surface的大小比例来动态调整输出,而我并没有找到跳过surfaceview直接设置surface的长宽比例的办法,想来是不可行的。

 

直接设置一个固定1:1的预览并不是不可行,但是我依然想要知道错在哪里

 

以下是我的代码:

 

通过characteristics获取合适的尺寸。

//获取适配尺寸                
val map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)
if (map == null) {
    Toast.makeText(this@MainActivity, "您的手机不支持预览", Toast.LENGTH_SHORT).show()
    return
}
    viewSize = map.getOutputSizes(ImageFormat.JPEG).getOptimalPreviewSize(windowWidth, ratio)

getOptimalPreviewSize方法


fun Array<Size>.getOptimalPreviewSize(height: Int, ratio: Float): Size {
    val TAG = "Utils.Array<Size>"
    var minDiff = Double.MAX_VALUE
    var optimalSize: Size = Size(0, 0)

    for (size in this) {
        if (abs(size.height - height) < minDiff && ratio == size.height.toFloat() / size.width) {
            minDiff = abs(size.height - height).toDouble()
            optimalSize = size
        }
    }
    if (minDiff == Double.MAX_VALUE) {
        for (size in this) {
            if (abs(size.height - height) < minDiff) {
                minDiff = Math.abs(size.height - height).toDouble()
                optimalSize = size
            }
        }
    }
    if (optimalSize == Size(0, 0))
        Log.d(TAG, "getOptimalPreviewSize: List<Size> is empty")
    return optimalSize
}

修改surfaceview大小并获取surfaceview

        //配置预览view
        //这里用holder.setFixedSize(viewSize.height, viewSize.width)一样会变形
        val preview: SurfaceView = findViewById<SurfaceView>(R.id.preview)
        val layoutParams = preview.layoutParams
        layoutParams.width = viewSize.height
        layoutParams.height = viewSize.width
        
        //从holder获取surface并传入camera
        val holder = preview.holder
        previewSurface = holder.surface
        holder.setKeepScreenOn(true)
        holder.addCallback(object : SurfaceHolder.Callback {
            override fun surfaceCreated(holder: SurfaceHolder) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
                    outputs.add(PREVIEW_INDEX, OutputConfiguration(previewSurface))
//                    outputs.add(PICTURE_INDEX, OutputConfiguration(imageReader.surface))
                    createCameraDevice(cameraManager, cameraId, outputs)
                }
            }

            override fun surfaceChanged(
                holder: SurfaceHolder,
                format: Int,
                width: Int,
                height: Int,
            ) {
                return
            }

            override fun surfaceDestroyed(holder: SurfaceHolder) {
                return
            }
        })

创建预览会话

    @RequiresApi(Build.VERSION_CODES.P)
    private fun createCaptureSession(
        cameraDevice: CameraDevice,
        outputs: List<OutputConfiguration>,
    ) {
        Log.i(TAG, "myCreateCaptureSession: ====>Create Capture Session init")
        cameraDevice.createCaptureSession(
            SessionConfiguration(
                SessionConfiguration.SESSION_REGULAR,
                outputs,
                { runnable -> runnable.run() },
                object : CameraCaptureSession.StateCallback() {
                    override fun onConfigured(session: CameraCaptureSession) {
                        Log.i(TAG, "onConfigured: ====>CreateCameraCaptureSession Successful")
                        //开启预览
                        val previewBuilder =
                            cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)

                        previewBuilder.addTarget(previewSurface)
                        cameraCaptureSession = session
                        cameraCaptureSession.setRepeatingRequest(previewBuilder.build(), null, null)
                    }

                    override fun onConfigureFailed(session: CameraCaptureSession) {
                        Log.e(TAG, "onConfigureFailed: ====>Create CameraCaptureSession Failed")
                    }
                })
        )
    }

最后结果

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

1条回答 默认 最新

  • qq_42158560
    雪下的回忆 2021-06-07 09:09
    已采纳

    在surfaceview的holder的callback内有一个surfaceChanged方法,需要在方法内再次修改大小。

    override fun surfaceChanged(
        holder: SurfaceHolder,
        format: Int,
        width: Int,
        height: Int,
    ) {
        holder.setFixedSize(viewSize.width, viewSize.height)
                    return
    }

    结论就是使用在主线程使用lp修改view的大小真的就是只改大小而已,surface该多大还是多大,camera2底层拿到的surface还是默认大小

    点赞 评论

相关推荐