Как правильно запускать и останавливать камеру с помощью 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, чтобы фактически запустить их как часть сеанса камеры. Посмотрите на документацию для более подробной информации.