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 = 1CameraSelector.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相关推荐

  1. Android相机资源占用,为保护用户隐私Android 11调整相机选项 APP调用相机时只可使用默认相机...

    据外媒报道目前谷歌在 Android 11 测试版里带来新的调整,此次调整是关于安卓系统对于默认相机调用选择的. 在安卓旧版本中当APP调用相机时会罗列用户已经安装的所有相机应用,这当然也包括那些自带 ...

  2. Android App开发——使用CameraX打开前后摄像头拍照并保存(Java实现)

    前言 开发环境是Android studio 北极狐,CameraX1.0.0-alpha02,实现语言是Java. 创建工程 1.引入CameraX 在build.gradle添加要引入Camera ...

  3. android 照相机app,Spectre相机

    Spectre相机app全新功能强大的手机拍照美化应用服务平台,这款软件能够更好的去帮助用户去拍出身边美美的照片,记录不同的自己,各种拍照模式等着你来体验,赶快前来下载吧! Spectre相机app应 ...

  4. 软件测试app访问相机,PlayMemories Mobile应用实测,让相机成为你手机的外置摄像头...

    SONY最近推出PlayMemories系列软件,不知所云地围观了一下,最后只被其中的PlayMemories Mobile吸引. 随着智能手机拍摄功能的日益强大,手机.便携相机地盘在重叠,便携相机的 ...

  5. apicloud APP获取相机权限执行操作

    封装JS如下 function checkPermision(name) { return new Promise((resolve, reject) => { var resultList = ...

  6. 有哪些好用的相机软件app?除了轻颜相机,还有两款可能你也认识

    有哪些好用的相机软件app?手机相机的像素越来越高,无论是前置或后置镜头,都可以拍出晰度的照片,但是晰度不代表拍的照片就是好看的. 要想拍出赞爆朋友圈的照片,掌握一定的理论知识是非常必要的,如光圈.感 ...

  7. Android 相机 II-实现自己的相机APP

    概述: 有些开发者可能会需要一个自定义的相机用户接口, 以实现自己独特样式的相机和特殊的功能. 创建一个自定义相机activity比调用系统相机需要更多的代码, 但是它可以为用户提供更加丰富的体验. ...

  8. 深入理解相机体系 三 相机应用层 APP

    和你一起终身学习,这里是程序员Android 经典好文推荐,通过阅读本文,您将收获以下知识点: 一.概览 二.Camera Api v2 三.Camera Framework 四.Camera App ...

  9. Android JetPack组件-CameraX初探

    CameraX 又是一个 Google 推出的 JetPack 组件 ,是一个新鲜玩意儿,故给大家分享下我在项目中的使用过程心得.. CameraX 是什么? Google 开发者文档 对 Camer ...

最新文章

  1. 深入理解 Spring Boot Starters 原理
  2. 在AI Studio上部署外部可以直接调用的云端服务
  3. 哈利波特 pdf_干货!哈利波特英文原版pdf免费领,(含音频)词汇量大于新概念!...
  4. python财务报表分析-需要做财务数据分析,有什么好用的工具?
  5. HTML之页面结构分析
  6. Java中的Serialization
  7. python子进程模块subprocess
  8. PHP 完整实战23种设计模式
  9. javascript数组对象
  10. 全球最大语音识别公司Nuance的衰落与自我救赎
  11. Windows系统结构
  12. 怎么判断有用户在远程连接目标电脑_你的电脑是肉鸡吗?
  13. 小米网技术架构变迁实践
  14. 【UnityEditor】根据枚举的不同显示各自对应的内容
  15. valgrind内存泄漏检测
  16. odd ratio置信区间的计算,你学会了吗?
  17. 这一篇彻底搞懂JS中的prototype、__proto__与constructor真的很好
  18. 零基础转行新媒体运营,有哪些必须要掌握的技能
  19. open3d之体素化Voxelization有关函数详情(笔记6)
  20. 让php返回204,python请求返回HTTP 204

热门文章

  1. java计算机毕业设计springboot+vue园区管理系统
  2. NFC读写芯片15693协议CLRC663国产替代DP1363F兼容详细对比资料
  3. 【Axure教程】穿梭框拖动选择器
  4. ureport 报表合并单元格后双斜表头制作
  5. mysql完整导出身份证
  6. Eclipse Virgo
  7. 注册宝第五期beta2插件模块下载及说明
  8. 如何一招搞定PCB阻焊过孔问题?
  9. php laravel 入门教程,PHP语言菜鸟笔记,laravel 入门教程
  10. idea配置 Tomcat Deployment添加时没有Artifact选择的解决方案