我已经开始与sample app一起探索CameraX库,并且发现在管理生命周期方面存在一些不一致之处。
在此线程中,我将仅讨论预览用例,因为它与生命周期密切相关。
在示例应用程序的CameraFragment
中,用例在CameraX
中绑定到onViewCreated
,在onDestroyView
中未绑定。第一个问题是,如果要将unbind
传递给LifecycleOwner
方法,是否必须使用bind
用例?我们是否可以将它们绑定在onCreate
中,而将生命周期管理留给CameraX
?
我还尝试遵循getting started教程,其中SurfaceTexture
中的TextureView
被替换了。在示例应用程序中,首先从父级中删除TextureView
,然后添加,然后替换SurfaceTexture
。我们必须这样做吗?是什么原因?
另一件事是,在示例应用程序中,用例是通过view.post { }
方法绑定的。我在使用此方法时遇到了很多问题,因为在将片段放回堆栈中,替换为另一个片段,然后重新创建之后,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
答案 0 :(得分:1)
第一个问题是,如果我们将LifecycleOwner传递给绑定方法,我们是否必须取消用例的绑定?我们可以将它们绑定在onCreate上,而将生命周期管理留给CameraX吗?
您是正确的。我认为示例应用程序可以安全地删除CameraX.unbindAll()
调用。
首先从父级中删除TextureView,然后添加它,然后替换SurfaceTexture。我们必须这样做吗?是什么原因?
需要从父视图中删除并重新添加TextureView,以便附加SurfaceTexture。这是因为一旦将TextureView附加到视图层次结构,它就会在内部创建自己的SurfaceTexture,并且只有从视图层次结构中删除了父TextureView之后,内部SurfaceTexture才能正确分离。 getting started codelab已更新,包括重新连接。
另一件事是,在示例应用程序中,用例是通过view.post {}方法绑定的。我在使用此方法时遇到了很多问题,因为在将片段放回堆栈中,替换为另一个片段,然后重新创建之后,CameraX记录了许多消息
在viewFinder.post { ... }
内部绑定用例可以确保在正确布置TextureView之后绑定用例。您从E/CamX
开始看到的错误实际上与CameraX库无关,并且似乎来自设备的本机照相机堆栈(即照相机驱动程序)。如果您没有在应用程序本身中看到任何问题,则错误消息可能会被忽略。
可以只设置OnPreviewOutputUpdateListener而不绑定所有用例吗?
我不确定我是否理解这一点。您必须为CameraX绑定所有用例,以在摄像头会话中实际启动它们。请查看documentation,了解更多详细信息。
答案 1 :(得分:1)
2020年10月10日-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