Как правильно запускать и останавливать камеру с помощью CameraX?

Я начал изучать библиотеку CameraX вместе с примером приложения и заметил некоторую несогласованность в управлении жизненным циклом.

В этой теме я буду говорить только о предварительном использовании, поскольку оно в основном связано с жизненным циклом.

В примере приложения в CameraFragment, варианты использования связаны с CameraX в onViewCreated и не связан в onDestroyView, Первый вопрос: должны ли мы unbind случаи использования, если мы проходим LifecycleOwner в bind метод? Можем ли мы просто связать их в onCreate и оставить управление жизненным циклом CameraX?

Я также пытался следовать учебному пособию по началу работы, где SurfaceTexture из TextureView только что заменили. В примере приложения TextureView сначала удаляется из родительского, затем добавляется, а затем SurfaceTexture заменяется Должны ли мы сделать это? Какова причина?

Другое дело, что в примере приложения варианты использования связаны с view.post { } метод. Я столкнулся со многими проблемами с этим подходом, потому что после того, как фрагмент помещен в backstack, заменен другим фрагментом, а затем воссоздан, CameraX записал много сообщений:

E/CamX: [ERROR][STATS_AEC] aec_led_calibration.cpp:560: aec_led_cal_apply_calibration Invalid pointer 0x7921174000 0x0
E/CamX: [ERROR][STATS_AEC] aec_set.cpp:1346: aec_set_fps_range Aec_Error invalid input 414  E/CamX: [ERROR][STATS_AEC] camxcaecstatsprocessor.cpp:1671 SetAlgoBayerHistValue() Unsupported bayer hist channel! 
E/CamX: [ERROR][STATS  ] camxcaecstatsprocessor.cpp:3194 ProcessRequestFastAE() [FastAE] Failed to apply gain to the stats! E/CamX: [ERROR][STATS_AEC] aec_process.cpp:1229: aec_process_stats_parsing aec is null or invalid 
E/CamX: [ERROR][STATS_AEC] aec_process.cpp:7983: aec_process_preview_and_video Error: invalid stats

Это нормально, чтобы просто установить OnPreviewOutputUpdateListener вместо связывания всех вариантов использования?

редактировать

Чтобы показать точную проблему, я создал простой проект Camera Playground.

Вот CameraFragment со всей логикой.

class CameraFragment : Fragment() {

    private val preview by lazy {
        val configuration = PreviewConfig.Builder().build()
        Preview(configuration)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        CameraX.bindToLifecycle(this, preview)
    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.fragment_camera, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        button_gallery.setOnClickListener {
            requireActivity().supportFragmentManager
                .beginTransaction()
                .replace(R.id.container, GalleryFragment())
                .addToBackStack("GalleryFragment")
                .commit()
        }

        preview.setOnPreviewOutputUpdateListener { texture_view.surfaceTexture = it.surfaceTexture }
    }
}

Теперь после нажатия кнопки галереи, CameraFragment заменяется на GalleryFragment, После нажатия кнопки назад и возврата к CameraFragment CameraX регистрирует такие сообщения:

2019-05-09 14:12:20.969 778-1363/? E/CamX: [ERROR][STATS  ] gcamfastaeutil.cpp:1170 SetTuningData() [FastAE] ERROR! Failed to get the tuning data

2019-05-09 14:12:20.969 778-1363/? E/CamX: [ERROR][HAL    ] camxmetadatapool.cpp:1447 GetMetadataByTag() Invalid Slot to get a metadata from

2019-05-09 14:12:20.969 778-1363/? E/CamX: [ERROR][HAL    ] camxmetadatapool.cpp:1447 GetMetadataByTag() Invalid Slot to get a metadata from

2019-05-09 14:12:20.969 778-1363/? E/CamX: [ERROR][STATS_AEC] aec_led_calibration.cpp:560: aec_led_cal_apply_calibration Invalid pointer 0x7920f1d000 0x0

2019-05-09 14:12:20.969 778-1363/? E/CamX: [ERROR][STATS_AEC] aec_set.cpp:1346: aec_set_fps_range Aec_Error invalid input 0 

2019-05-09 14:12:20.969 778-1363/? E/CamX: [ERROR][STATS  ] camxae.cpp:2203 AECSetSensorInfo() Wrong initial sequence from HAL!

2019-05-09 14:12:20.969 778-1363/? E/CamX: [ERROR][STATS_AEC] aec_get.cpp:777: aec_get_param GET_EXP_PARAMS ERROR, Uninitialized exposure settings requested

2019-05-09 14:12:20.969 778-1363/? E/CamX: [ERROR][HAL    ] camxmetadatapool.cpp:1447 GetMetadataByTag() Invalid Slot to get a metadata from

1 ответ

10 / 2020 - Библиотека CameraX, запуск и остановка камеры с JAVA

Для открытия камеры у нас нет специального кода. Только вы можете использовать bindToLifecycle (). Также НЕ забывайте, реализует LifecycleObserver. Это пример кода кадра для запуска камеры в CameraX.

private void mStartCamera(){
    Camera camera = mCameraProvider.bindToLifecycle(this, cameraSelector, preview, imageAnalysis);
}

Чтобы закрыть камеру, вы должны работать с cameraProvider. Вам НЕ нужно работать с объектом камеры. Пример сокращенного кода.

private void mStopCamera(){
    mCameraProvider.unbindAll();
}
  • БОНУС

Если вы хотите спросить "Как я могу определить cameraProvider?" Вам нужно добавить слушателя на cameraProviderFuture. Пример кода Шора.

private void mDefineCameraProvider() {
    final ListenableFuture<ProcessCameraProvider> cameraProviderFuture = ProcessCameraProvider.getInstance(this);

    cameraProviderFuture.addListener(() -> {
        try {
            ProcessCameraProvider cameraProvider = cameraProviderFuture.get();
            mCameraProvider = cameraProvider;
        } 
        catch (ExecutionException | InterruptedException e) {
            // No errors need to be handled for this Future.
            // This should never be reached.
            Log.e("CANER", "Camera provider error: " +e);
        }
    }, ContextCompat.getMainExecutor(this));
}

Задавайте вопросы откуда угодно: @canerkaseler

Первый вопрос: нужно ли отменять привязку вариантов использования, если мы передаем LifecycleOwner методу связывания? Можем ли мы просто связать их в onCreate и оставить управление жизненным циклом для CameraX?

Ты прав. Я думаю, что образец приложения может безопасно удалить CameraX.unbindAll() вызов.

TextureView сначала удаляется из родительского, затем добавляется, а затем заменяется SurfaceTexture. Должны ли мы сделать это? Какова причина?

TextureView необходимо удалить и повторно добавить из родительского представления для прикрепления SurfaceTexture. Это связано с тем, что TextureView внутренне создает свою собственную SurfaceTexture, как только она присоединена к иерархии представления, и эта внутренняя SurfaceTexture корректно отсоединяется только после удаления родительского TextureView из иерархии представления. Кодовая метка начала работы была обновлена ​​и теперь включает в себя повторное вложение.

Другое дело, что в примере приложения варианты использования связаны с методом view.post { }. Я столкнулся со многими проблемами с этим подходом, потому что после того, как фрагмент помещен в backstack, заменен другим фрагментом и чем потом воссоздан, CameraX записал много сообщений

Обязательные варианты использования внутри viewFinder.post { ... } чтобы убедиться, что варианты использования связаны после правильного размещения TextureView. Ошибки, которые вы видите, начиная с E/CamX на самом деле не связаны с библиотекой CameraX и, похоже, исходят из собственного стека камеры вашего устройства (то есть драйверов камеры). Если вы не видите никаких проблем в самом приложении, сообщения об ошибках, вероятно, можно игнорировать.

Можно ли просто установить OnPreviewOutputUpdateListener вместо привязки всех вариантов использования?

Я не уверен, что понимаю это. Вы должны связать все варианты использования для CameraX, чтобы фактически запустить их как часть сеанса камеры. Посмотрите на документацию для более подробной информации.

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