雪下的回忆 2021-06-02 15:27 采纳率: 75%
浏览 816
已采纳

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条回答 默认 最新

  • 雪下的回忆 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还是默认大小

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 ai创想家对战模式代码
  • ¥15 集合A由3个2行4列二维数组构成,从集合A中任意取一个二维数组元素、如果该二维数组元素的对应列位置的上、下两数都是奇数,而且仅有2个列是奇数/奇数,则该数组有意义,并放入集合B中打印输出。
  • ¥15 电信IPV6 无法外网访问吗
  • ¥15 有偿求效果比较好的遥感影像匹配的c++代码
  • ¥15 博主,你好,我下载了你的智能网联汽车辅助驾驶安全信息检测系统,现在不会运行,可以教我吗,
  • ¥15 怎么在excle输入下列公式
  • ¥15 Arduino,利用modbus的RS485协议,进行对外置的温湿度传感器进行数据读取
  • ¥15 vhdl+MODELSIM
  • ¥20 simulink中怎么使用solve函数?
  • ¥30 dspbuilder中使用signalcompiler时报错Error during compilation: Fitter failed,求解决办法