【问题标题】:How to mirror the PreviewView in CameraX?如何在 CameraX 中镜像 PreviewView?
【发布时间】:2021-01-06 05:08:40
【问题描述】:

免责声明:我知道this question 的存在,但它目前尚未解决,我正在尝试提供额外的信息,而不会用无用的答案污染该信息,无论如何也无法解决问题。

我有一个自定义设备,前置摄像头默认是镜像的,所以想正常显示预览,需要水平翻转 PreviewView 的内容,但是卡住了。过去其他人建议使用PreviewView#setScaleX(-1),但它要么根本不起作用,要么需要在代码中非常特定的位置调用,我还没有找到。

下面的代码是官方CameraXBasic例子中CameraFragment.kt的简化版;我已经添加了 cmets,我已经厌倦了调用 viewFinder.scaleX = -1f,但没有成功。老实说,我真的不认为这个地方有什么不同,因为如果我用除 1 以外的任何值调用它,scaleXscaleY 都可以正常工作,但 它总是忽略负号 所以它永远不会翻转。

private lateinit var viewFinder: PreviewView

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    ...
    viewFinder = view.findViewById(R.id.view_finder)
    // HERE
    viewFinder.post {
        // HERE
        setupCamera()
    }
}

private fun setupCamera() {
    val cameraProviderFuture = ProcessCameraProvider.getInstance(requireContext())
    cameraProviderFuture.addListener(Runnable {
        val cameraProvider = cameraProviderFuture.get()

        val cameraSelector = CameraSelector.Builder()
            .requireLensFacing(CameraSelector.LENS_FACING_FRONT)
            .build()

       val preview = Preview.Builder()
            .build()
            .also {
                // HERE
                it.setSurfaceProvider(viewFinder.surfaceProvider)
            }

       cameraProvider.unbindAll()

        try {
            cameraProvider.bindToLifecycle(this, cameraSelector, preview)
            // HERE
        } catch (exc: Exception) {
            Log.e(TAG, "Use case binding failed", exc)
        }
        // HERE
    }, ContextCompat.getMainExecutor(requireContext()))
    // HERE
}

【问题讨论】:

    标签: android android-view android-camerax


    【解决方案1】:

    根据实现类型(COMPATIBLE vs PERFORMANCE)和设备,PreviewView 可以使用TextureViewSurfaceView,在您的情况下,我假设PreviewView 使用的是SurfaceView,您可以通过访问 PreviewView 的第一个子视图 (View.getChildAt(0)) 来确认这一点。

    TextureView 与任何其他View 一样,这就是为什么当PreviewView 使用它时,将其 scaleX 设置为 -1 应该反映显示的预览。创建布局后,您可以调用PreviewView.setScaleX(-1F)(例如在onViewCreated() 中)。

    对于SurfaceView,这有点棘手,因为SurfaceView 在某些方面是独立Surface 放置在包含@987654339 的窗口后面@,并且视图层次结构通过在窗口中打孔以显示SurfaceViewSurface 来正确组合整个布局。这可以解释为什么无法镜像SurfaceView 显示的内容,尽管我不确定为什么放大(scaleX 设置为值 > 1)和缩小(scaleX 设置为 0 和 1 之间的值)仍然有效。

    【讨论】:

    • 设备在 Android 7.1 上运行,日志记录 viewFinder.getChildAt(0) 显示 nullscaleX 设置为 -1 并且...现在可以使用了吗?但是我刚刚在我自己的手机上使用 Android 10 试用了该应用程序,尽管预览仍然没有翻转,但我得到了相同的结果。我不知道。
    • 您应该在预览开始后致电getChildAt(0)
    • 您的意思是在致电bindToLifecycle() 之后?仍然收到null
    • 不,预览不会在调用binToLifecycle() 后立即开始。您可以使用PreviewView.getPreviewStreamState() 并等待STREAMING 状态被调度。只有在看到预览开始后,您也可以使用任何其他方式调用该方法,例如在PreviewView 上设置一个点击监听器,当你看到预览开始点击它时,在点击监听器中你可以记录它的第一个孩子。
    • 谢谢。令人惊讶的是,在自定义设备上默认使用TextureView,这可能就是它实际工作的原因,而我手机上使用的SurfaceView 仍然不想协作。需要明确的是,可靠地镜像SurfaceView 的唯一方法是将每一帧实时转换为位图并将它们绘制回表面?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-29
    相关资源
    最近更新 更多