APP使用相机CameraX
APP使用相机
Android 开发者>文档>指南 - 选择相机库
- CameraX
- Camera2
- Camera(已废弃)
CameraX 示例应用
Sample | Description |
---|---|
CameraXBasic | Demonstrates how to use CameraX APIs. |
CameraXAdvanced | Demonstrates how to use CameraX APIs with TFLite and others |
CameraXVideo | Demonstrates how to use CameraX VideoCapture API. |
Camera2Basic | Demonstrates capturing JPEG, RAW and DEPTH images, e.g. unprocessed pixel data directly from the camera sensor. |
Camera2SlowMotion | Demonstrates capturing high-speed video in a constrained camera capture session. |
Camera2Video | Demonstrates recording video using the Camera2 API and MediaRecorder. |
Camera2Extensions | Demonstrates Camera2 extension live preview and still capture. |
HdrViewfinder | Demonstrates use of RenderScript to display a live HDR feed from camera frames using Camera2 API. |
0. CameraX 概览 | Android Jetpack 的一部分
- CameraX 架构
- 配置选项
- 实现预览
- 图片分析
- 图片拍摄
- 视频拍摄
- 供应商扩展
- 转换输出
- 用例旋转
- 实验室测试设备
1. CameraX获取Context.CAMERA_SERVICE服务
CameraXBasic 的
setUpCamera()
方法第一次调用 ProcessCameraProvider.getInstance() 期间,初始化 CameraX 会cameraFactory.getAvailableCameraIds()
枚举和查询设备上可用摄像头的特性。其中
cameraFactory
在com/android/example/cameraxbasic/MainApplication.kt中调用CameraXConfig.Builder.fromConfig(Camera2Config.defaultConfig())
初始化对象Camera2CameraFactory、CameraXConfig
1.1 获取Context.CAMERA_SERVICE服务
下面获取Context.CAMERA_SERVICE服务,实际获取 SystemServiceRegistry.java中注册的CameraManager.java。通过CameraManagerGlobal连接CameraService
androidx/camera/camera2/internal/Camera2CameraFactory.java
androidx/camera/camera2/internal/compat/CameraManagerCompat.java
androidx/camera/camera2/internal/compat/CameraManagerCompatApi29Impl.java
androidx/camera/camera2/internal/compat/CameraManagerCompatApi28Impl.java
androidx/camera/camera2/internal/compat/CameraManagerCompatBaseImpl.java
frameworks/base/core/java/android/app/SystemServiceRegistry.java
frameworks/base/core/java/android/hardware/camera2/CameraManager.java
public ICameraService getCameraService() {synchronized(mLock) {connectCameraServiceLocked();if (mCameraService == null && !sCameraServiceDisabled) {Log.e(TAG, "Camera service is unavailable");}return mCameraService;}
}private void connectCameraServiceLocked() {// Only reconnect if necessaryif (mCameraService != null || sCameraServiceDisabled) return;Log.i(TAG, "Connecting to camera service");IBinder cameraServiceBinder = ServiceManager.getService(CAMERA_SERVICE_BINDER_NAME);if (cameraServiceBinder == null) {// Camera service is now down, leave mCameraService as nullreturn;}try {cameraServiceBinder.linkToDeath(this, /*flags*/ 0);} catch (RemoteException e) {// Camera service is now down, leave mCameraService as nullreturn;}ICameraService cameraService = ICameraService.Stub.asInterface(cameraServiceBinder);try {CameraMetadataNative.setupGlobalVendorTagDescriptor();} catch (ServiceSpecificException e) {handleRecoverableSetupErrors(e);}try {CameraStatus[] cameraStatuses = cameraService.addListener(this);for (CameraStatus c : cameraStatuses) {onStatusChangedLocked(c.status, c.cameraId);if (c.unavailablePhysicalCameras != null) {for (String unavailPhysicalCamera : c.unavailablePhysicalCameras) {onPhysicalCameraStatusChangedLocked(ICameraServiceListener.STATUS_NOT_PRESENT,c.cameraId, unavailPhysicalCamera);}}}mCameraService = cameraService;} catch(ServiceSpecificException e) {// Unexpected failurethrow new IllegalStateException("Failed to register a camera service listener", e);} catch (RemoteException e) {// Camera service is now down, leave mCameraService as null}try {ConcurrentCameraIdCombination[] cameraIdCombinations =cameraService.getConcurrentCameraIds();for (ConcurrentCameraIdCombination comb : cameraIdCombinations) {mConcurrentCameraIdCombinations.add(comb.getConcurrentCameraIdCombination());}} catch (ServiceSpecificException e) {// Unexpected failurethrow new IllegalStateException("Failed to get concurrent camera id combinations",e);} catch (RemoteException e) {// Camera service died in all probability}
}
1.2 枚举和查询设备上可用摄像头
CameraX 初始化时
cameraFactory.getAvailableCameraIds()
枚举和查询设备上可用摄像头的特性。最终调用CameraSelectionOptimizer.getSelectedAvailableCameraIds(this, availableCamerasSelector)
通过cameraFactory.getCameraManager().getCameraIdList()
获取。FWK层中
CameraManager.java中CameraManagerGlobal的getCameraIdList()
:connectCameraServiceLocked()
连接CameraService服务CAMERA_SERVICE_BINDER_NAME = "media.camera"
摄像头限制器 如果传递给 CameraXConfig.Builder.setAvailableCamerasLimiter() 的 CameraSelector 过滤掉了某个摄像头,则 CameraX 在运行时会假定该摄像头不存在。
CameraSelector.DEFAULT_BACK_CAMERA
后置摄像头LENS_FACING_BACK = 1
;CameraSelector.DEFAULT_FRONT_CAMERA
前置摄像头LENS_FACING_FRONT = 0
。
com/android/example/cameraxbasic/fragments/CameraFragment.kt
androidx/camera/core/CameraX.java
androidx/camera/core/impl/CameraRepository.java
public void init(@NonNull CameraFactory cameraFactory) throws InitializationException {synchronized (mCamerasLock) {try {Set<String> camerasList = cameraFactory.getAvailableCameraIds();for (String id : camerasList) {Logger.d(TAG, "Added camera: " + id);mCameras.put(id, cameraFactory.getCamera(id));}} catch (CameraUnavailableException e) {throw new InitializationException(e);}}
}
androidx/camera/camera2/internal/Camera2CameraFactory.java
public Camera2CameraFactory(@NonNull Context context,@NonNull CameraThreadConfig threadConfig,@Nullable CameraSelector availableCamerasSelector) throws InitializationException {mThreadConfig = threadConfig;mCameraStateRegistry = new CameraStateRegistry(DEFAULT_ALLOWED_CONCURRENT_OPEN_CAMERAS);mCameraManager = CameraManagerCompat.from(context, mThreadConfig.getSchedulerHandler());List<String> optimizedCameraIds = CameraSelectionOptimizer.getSelectedAvailableCameraIds(this, availableCamerasSelector);mAvailableCameraIds = getBackwardCompatibleCameraIds(optimizedCameraIds);
}public Set<String> getAvailableCameraIds() {// Use a LinkedHashSet to preserve orderreturn new LinkedHashSet<>(mAvailableCameraIds);
}
androidx/camera/camera2/internal/CameraSelectionOptimizer.java
static List<String> getSelectedAvailableCameraIds(@NonNull Camera2CameraFactory cameraFactory,@Nullable CameraSelector availableCamerasSelector)throws InitializationException {try {List<String> availableCameraIds = new ArrayList<>();List<String> cameraIdList =Arrays.asList(cameraFactory.getCameraManager().getCameraIdList());if (availableCamerasSelector == null) {for (String id : cameraIdList) {availableCameraIds.add(id);}return availableCameraIds;}// Skip camera ID by heuristic: 0 is back lens facing, 1 is front lens facing.String skippedCameraId;try {Integer lensFacingInteger = availableCamerasSelector.getLensFacing();skippedCameraId = decideSkippedCameraIdByHeuristic(cameraFactory.getCameraManager(), lensFacingInteger, cameraIdList);} catch (IllegalStateException e) {// Don't skip camera if there is any conflict in camera lens facing.skippedCameraId = null;}List<CameraInfo> cameraInfos = new ArrayList<>();for (String id : cameraIdList) {if (id.equals(skippedCameraId)) {continue;}Camera2CameraInfoImpl cameraInfo = cameraFactory.getCameraInfo(id);cameraInfos.add(cameraInfo);}List<CameraInfo> filteredCameraInfos =availableCamerasSelector.filter(cameraInfos);for (CameraInfo cameraInfo : filteredCameraInfos) {String cameraId = ((CameraInfoInternal) cameraInfo).getCameraId();availableCameraIds.add(cameraId);}return availableCameraIds;} catch (CameraAccessExceptionCompat e) {throw new InitializationException(CameraUnavailableExceptionHelper.createFrom(e));} catch (CameraUnavailableException e) {throw new InitializationException(e);}
}
2. 拍照按钮执行
除了
setUpCamera()
初始化CameraX,其中重要查看updateCameraUi()
布局更新;camera_capture_button按钮cameraUiContainerBinding?.cameraCaptureButton?.setOnClickListener
设置
com/android/example/cameraxbasic/fragments/CameraFragment.kt
// Listener for button used to capture photo
cameraUiContainerBinding?.cameraCaptureButton?.setOnClickListener {// Get a stable reference of the modifiable image capture use caseimageCapture?.let { imageCapture ->// Create output file to hold the imageval photoFile = createFile(outputDirectory, FILENAME, PHOTO_EXTENSION)// Setup image capture metadataval metadata = Metadata().apply {// Mirror image when using the front cameraisReversedHorizontal = lensFacing == CameraSelector.LENS_FACING_FRONT}// Create output options object which contains file + metadataval outputOptions = ImageCapture.OutputFileOptions.Builder(photoFile).setMetadata(metadata).build()// Setup image capture listener which is triggered after photo has been takenimageCapture.takePicture(outputOptions, cameraExecutor, object : ImageCapture.OnImageSavedCallback {override fun onError(exc: ImageCaptureException) {Log.e(TAG, "Photo capture failed: ${exc.message}", exc)}override fun onImageSaved(output: ImageCapture.OutputFileResults) {val savedUri = output.savedUri ?: Uri.fromFile(photoFile)Log.d(TAG, "Photo capture succeeded: $savedUri")// We can only change the foreground Drawable using API level 23+ APIif (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {// Update the gallery thumbnail with latest picture takensetGalleryThumbnail(savedUri)}// Implicit broadcasts will be ignored for devices running API level >= 24// so if you only target API level 24+ you can remove this statementif (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {requireActivity().sendBroadcast(Intent(android.hardware.Camera.ACTION_NEW_PICTURE, savedUri))}// If the folder selected is an external media directory, this is// unnecessary but otherwise other apps will not be able to access our// images unless we scan them using [MediaScannerConnection]val mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(savedUri.toFile().extension)MediaScannerConnection.scanFile(context,arrayOf(savedUri.toFile().absolutePath),arrayOf(mimeType)) { _, uri ->Log.d(TAG, "Image capture scanned into media store: $uri")}}})// We can only change the foreground Drawable using API level 23+ APIif (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {// Display flash animation to indicate that photo was capturedfragmentCameraBinding.root.postDelayed({fragmentCameraBinding.root.foreground = ColorDrawable(Color.WHITE)fragmentCameraBinding.root.postDelayed({ fragmentCameraBinding.root.foreground = null }, ANIMATION_FAST_MILLIS)}, ANIMATION_SLOW_MILLIS)}}
}
3. 前置/后置 摄像头切换
查看
updateCameraUi()
布局更新;camera_switch_button按钮cameraUiContainerBinding?.cameraSwitchButton?.let
设置,CameraSelector.LENS_FACING_BACK、CameraSelector.LENS_FACING_FRONT
前后置属性,bindCameraUseCases()
更新预览preview、捕获imageCapture和分析imageAnalyzer用例;observeCameraState(camera?.cameraInfo!!)
监听Camera状态com/android/example/cameraxbasic/fragments/CameraFragment.kt
// Setup for button used to switch cameras
cameraUiContainerBinding?.cameraSwitchButton?.let {// Disable the button until the camera is set upit.isEnabled = false// Listener for button used to switch cameras. Only called if the button is enabledit.setOnClickListener {lensFacing = if (CameraSelector.LENS_FACING_FRONT == lensFacing) {CameraSelector.LENS_FACING_BACK} else {CameraSelector.LENS_FACING_FRONT}// Re-bind use cases to update selected camerabindCameraUseCases()}
}/** Declare and bind preview, capture and analysis use cases */
private fun bindCameraUseCases() {// Get screen metrics used to setup camera for full screen resolutionval metrics = windowManager.getCurrentWindowMetrics().boundsLog.d(TAG, "Screen metrics: ${metrics.width()} x ${metrics.height()}")val screenAspectRatio = aspectRatio(metrics.width(), metrics.height())Log.d(TAG, "Preview aspect ratio: $screenAspectRatio")val rotation = fragmentCameraBinding.viewFinder.display.rotation// CameraProviderval cameraProvider = cameraProvider?: throw IllegalStateException("Camera initialization failed.")// CameraSelectorval cameraSelector = CameraSelector.Builder().requireLensFacing(lensFacing).build()// Previewpreview = Preview.Builder()// We request aspect ratio but no resolution.setTargetAspectRatio(screenAspectRatio)// Set initial target rotation.setTargetRotation(rotation).build()// ImageCaptureimageCapture = ImageCapture.Builder().setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)// We request aspect ratio but no resolution to match preview config, but letting// CameraX optimize for whatever specific resolution best fits our use cases.setTargetAspectRatio(screenAspectRatio)// Set initial target rotation, we will have to call this again if rotation changes// during the lifecycle of this use case.setTargetRotation(rotation).build()// ImageAnalysisimageAnalyzer = ImageAnalysis.Builder()// We request aspect ratio but no resolution.setTargetAspectRatio(screenAspectRatio)// Set initial target rotation, we will have to call this again if rotation changes// during the lifecycle of this use case.setTargetRotation(rotation).build()// The analyzer can then be assigned to the instance.also {it.setAnalyzer(cameraExecutor, LuminosityAnalyzer { luma ->// Values returned from our analyzer are passed to the attached listener// We log image analysis results here - you should do something useful// instead!Log.d(TAG, "Average luminosity: $luma")})}// Must unbind the use-cases before rebinding themcameraProvider.unbindAll()try {// A variable number of use-cases can be passed here -// camera provides access to CameraControl & CameraInfocamera = cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageCapture, imageAnalyzer)// Attach the viewfinder's surface provider to preview use casepreview?.setSurfaceProvider(fragmentCameraBinding.viewFinder.surfaceProvider)observeCameraState(camera?.cameraInfo!!)} catch (exc: Exception) {Log.e(TAG, "Use case binding failed", exc)}
}
APP使用相机CameraX相关推荐
- Android相机资源占用,为保护用户隐私Android 11调整相机选项 APP调用相机时只可使用默认相机...
据外媒报道目前谷歌在 Android 11 测试版里带来新的调整,此次调整是关于安卓系统对于默认相机调用选择的. 在安卓旧版本中当APP调用相机时会罗列用户已经安装的所有相机应用,这当然也包括那些自带 ...
- Android App开发——使用CameraX打开前后摄像头拍照并保存(Java实现)
前言 开发环境是Android studio 北极狐,CameraX1.0.0-alpha02,实现语言是Java. 创建工程 1.引入CameraX 在build.gradle添加要引入Camera ...
- android 照相机app,Spectre相机
Spectre相机app全新功能强大的手机拍照美化应用服务平台,这款软件能够更好的去帮助用户去拍出身边美美的照片,记录不同的自己,各种拍照模式等着你来体验,赶快前来下载吧! Spectre相机app应 ...
- 软件测试app访问相机,PlayMemories Mobile应用实测,让相机成为你手机的外置摄像头...
SONY最近推出PlayMemories系列软件,不知所云地围观了一下,最后只被其中的PlayMemories Mobile吸引. 随着智能手机拍摄功能的日益强大,手机.便携相机地盘在重叠,便携相机的 ...
- apicloud APP获取相机权限执行操作
封装JS如下 function checkPermision(name) { return new Promise((resolve, reject) => { var resultList = ...
- 有哪些好用的相机软件app?除了轻颜相机,还有两款可能你也认识
有哪些好用的相机软件app?手机相机的像素越来越高,无论是前置或后置镜头,都可以拍出晰度的照片,但是晰度不代表拍的照片就是好看的. 要想拍出赞爆朋友圈的照片,掌握一定的理论知识是非常必要的,如光圈.感 ...
- Android 相机 II-实现自己的相机APP
概述: 有些开发者可能会需要一个自定义的相机用户接口, 以实现自己独特样式的相机和特殊的功能. 创建一个自定义相机activity比调用系统相机需要更多的代码, 但是它可以为用户提供更加丰富的体验. ...
- 深入理解相机体系 三 相机应用层 APP
和你一起终身学习,这里是程序员Android 经典好文推荐,通过阅读本文,您将收获以下知识点: 一.概览 二.Camera Api v2 三.Camera Framework 四.Camera App ...
- Android JetPack组件-CameraX初探
CameraX 又是一个 Google 推出的 JetPack 组件 ,是一个新鲜玩意儿,故给大家分享下我在项目中的使用过程心得.. CameraX 是什么? Google 开发者文档 对 Camer ...
最新文章
- 深入理解 Spring Boot Starters 原理
- 在AI Studio上部署外部可以直接调用的云端服务
- 哈利波特 pdf_干货!哈利波特英文原版pdf免费领,(含音频)词汇量大于新概念!...
- python财务报表分析-需要做财务数据分析,有什么好用的工具?
- HTML之页面结构分析
- Java中的Serialization
- python子进程模块subprocess
- PHP 完整实战23种设计模式
- javascript数组对象
- 全球最大语音识别公司Nuance的衰落与自我救赎
- Windows系统结构
- 怎么判断有用户在远程连接目标电脑_你的电脑是肉鸡吗?
- 小米网技术架构变迁实践
- 【UnityEditor】根据枚举的不同显示各自对应的内容
- valgrind内存泄漏检测
- odd ratio置信区间的计算,你学会了吗?
- 这一篇彻底搞懂JS中的prototype、__proto__与constructor真的很好
- 零基础转行新媒体运营,有哪些必须要掌握的技能
- open3d之体素化Voxelization有关函数详情(笔记6)
- 让php返回204,python请求返回HTTP 204