Как связать предварительный просмотр и текстуру в CameraX

Недавно я попытался разработать плагин флаттера с cameraX, но обнаружил, что просто невозможно связать Preview с текстурой флаттера.

В прошлом мне нужно было только использовать camera.setPreviewTexture(surfaceTexture.surfaceTexture()) для привязки камеры и текстуры, теперь я не могу найти API.

camera.setPreviewTexture(surfaceTexture.surfaceTexture())
        val previewConfig = PreviewConfig.Builder().apply {
            setTargetAspectRatio(Rational(1, 1))
            setTargetResolution(Size(640, 640))
        }.build()

        // Build the viewfinder use case
        val preview = Preview(previewConfig).also{

        }

        preview.setOnPreviewOutputUpdateListener {
//            it.surfaceTexture = this.surfaceTexture.surfaceTexture()
        }

   // how to bind the CameraX Preview surfaceTexture and flutter surfaceTexture?

1 ответ

Думаю, можно привязать текстуру с помощью Preview.SurfaceProvider.

            final CameraSelector cameraSelector = new CameraSelector.Builder().requireLensFacing(CameraSelector.LENS_FACING_BACK).build();
            final ListenableFuture<ProcessCameraProvider> listenableFuture = ProcessCameraProvider.getInstance(appCompatActivity.getBaseContext());
            listenableFuture.addListener(() -> {
                try {
                    ProcessCameraProvider cameraProvider = listenableFuture.get();
                    Preview preview = new Preview.Builder()
                            .setTargetResolution(new Size(720, 1280))
                            .build();
                    cameraProvider.unbindAll();
                    Camera camera = cameraProvider.bindToLifecycle(appCompatActivity, cameraSelector, preview);
                    Preview.SurfaceProvider surfaceProvider = request -> {
                        Size resolution = request.getResolution();
                        surfaceTexture.setDefaultBufferSize(resolution.getWidth(), resolution.getHeight());
                        Surface surface = new Surface(surfaceTexture);
                        request.provideSurface(surface, ContextCompat.getMainExecutor(appCompatActivity.getBaseContext()), result -> {

                        });
                    };
                    preview.setSurfaceProvider(surfaceProvider);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }, ContextCompat.getMainExecutor(appCompatActivity.getBaseContext()));

Кажется, что использование CameraX трудно или невозможно из-за того, что оно абстрагирует более сложные вещи и, следовательно, не раскрывает то, что вам нужно, например, возможность передавать в вашей собственной SurfaceTexture (которая обычно создается Flutter).

Поэтому простой ответ заключается в том, что вы не можете использовать CameraX.

Тем не менее, с некоторой работой вы можете заставить это работать, но я понятия не имею, будет ли это работать наверняка. Это уродливо и непристойно, поэтому я бы не советовал. YMMV.


Если мы собираемся сделать это, давайте сначала посмотрим, как трепетание создает текстуру

    @Override
    public TextureRegistry.SurfaceTextureEntry createSurfaceTexture() {
        final SurfaceTexture surfaceTexture = new SurfaceTexture(0);
        surfaceTexture.detachFromGLContext();
        final SurfaceTextureRegistryEntry entry = new SurfaceTextureRegistryEntry(nextTextureId.getAndIncrement(),
                surfaceTexture);
        mNativeView.getFlutterJNI().registerTexture(entry.id(), surfaceTexture);
        return entry;
    }

Большая часть этого является воспроизводимой, поэтому мы можем сделать это с текстурой поверхности, которую дает нам камера.

Вы можете получить текстуру, которую камера создает следующим образом:

preview.setOnPreviewOutputUpdateListener { previewOutput ->
    SurfaceTexture texture = previewOutput.surfaceTexture
}

Теперь вам нужно будет передать ссылку на ваш FlutterView в ваш плагин (я оставлю это для вас, чтобы разобраться). Тогда позвони flutterView.getFlutterNativeView() чтобы овладеть FlutterNativeView.

К сожалению, getFlutterJni FlutterNativeView является частным пакетом. Так что это то, где это становится действительно хакерским - вы можете создать класс в том же пакете, который вызывает этот закрытый для пакета метод в общедоступном методе. Это ужасно, и вам, возможно, придется возиться с Gradle, чтобы настройки безопасности компиляции позволили это сделать, но это должно быть возможно.

После этого должно быть достаточно просто создать SurfaceTextureRegistryEntry и зарегистрировать текстуру с помощью флаттера jni. Я не думаю, что вы хотите отсоединиться от контекста opengl, и я действительно не знаю, сработает ли это на самом деле. Но если вы хотите попробовать и сообщить, что вы нашли, мне было бы интересно услышать результат!

Другие вопросы по тегам