赞
踩
Google 原来提供了Camera,后面又推出了Camera2,然后几年前在Jetpack里面推出了CameraX
CameraX其实内部是封装Camera2的。但是它比Camera2使用起来更加简便,性能也比Camera2提高了。
废话少说,直接上代码:
要用CameraX,第一是要引入其 dependencies
- // CameraX core library
- def camerax_version = '1.1.0-beta01'
- implementation "androidx.camera:camera-core:$camerax_version"
-
- // CameraX Camera2 extensions
- implementation "androidx.camera:camera-camera2:$camerax_version"
-
- // CameraX Lifecycle library
- implementation "androidx.camera:camera-lifecycle:$camerax_version"
-
- // CameraX View class
- implementation "androidx.camera:camera-view:$camerax_version"
进而上个布局;
- <?xml version="1.0" encoding="utf-8"?>
- <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- tools:context=".CameraActivity">
-
- <!--预览的控件-->
- <androidx.camera.view.PreviewView
- android:id="@+id/preview_view"
- android:layout_width="0dp"
- android:layout_height="0dp"
- app:scaleType="fillCenter"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintLeft_toLeftOf="parent"
- app:layout_constraintRight_toRightOf="parent"
- app:layout_constraintTop_toTopOf="parent" />
-
- <androidx.appcompat.widget.AppCompatButton
- android:id="@+id/switchCamera"
- android:layout_width="100dp"
- android:layout_height="50dp"
- android:layout_marginTop="10dp"
- android:text="切换相机"
- app:layout_constraintLeft_toLeftOf="parent"
- app:layout_constraintRight_toRightOf="parent"
- app:layout_constraintTop_toTopOf="parent">
- </androidx.appcompat.widget.AppCompatButton>
-
- <androidx.appcompat.widget.AppCompatTextView
- android:id="@+id/tvFps"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- app:layout_constraintTop_toBottomOf="@id/switchCamera"
- app:layout_constraintLeft_toLeftOf="parent"
- android:textSize="20sp"
- android:gravity="center"
- android:padding="5dp"
- android:text="12456"
- android:textColor="@color/white">
- </androidx.appcompat.widget.AppCompatTextView>
-
- </androidx.constraintlayout.widget.ConstraintLayout>
然后上个Activity代码:
-
-
- import androidx.appcompat.app.AppCompatActivity
- import android.os.Bundle
- import android.os.SystemClock
- import android.util.Log
- import android.view.View
- import androidx.appcompat.widget.AppCompatTextView
- import androidx.camera.core.*
- import androidx.camera.lifecycle.ProcessCameraProvider
- import androidx.camera.view.PreviewView
- import androidx.core.content.ContextCompat
-
- class CameraActivity : AppCompatActivity() {
-
- companion object{
- private const val TAG = "CameraActivity"
- }
-
- private var cameraProvider: ProcessCameraProvider? = null
- private var previewUseCase: Preview? = null
- private lateinit var previewView: PreviewView
- private lateinit var tvFps: AppCompatTextView
- private var cameraSelector: CameraSelector? = null
- private var lensFacing = CameraSelector.LENS_FACING_FRONT
- private var camera: Camera? = null
- private var analysisUseCase: ImageAnalysis? = null
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_camera)
- previewView = findViewById(R.id.preview_view)
- tvFps = findViewById(R.id.tvFps)
- findViewById<View>(R.id.switchCamera).setOnClickListener {
- switchCamera()
- }
- cameraSelector = CameraSelector.Builder().requireLensFacing(lensFacing).build()
-
- if (PermissionsUtil.allPermissionsGranted(this)){
- start()
- }else{
- PermissionsUtil.requestPermission(this)
- }
- }
-
- private fun start() {
- /*
- 通过 ProcessCameraProvider 获取 cameraProvider
- cameraProvider 就是我们持有的相机实例
- */
- val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
- cameraProviderFuture.addListener(Runnable {
- cameraProvider = cameraProviderFuture.get()
- startCamera()
- }, ContextCompat.getMainExecutor(this))
- }
-
- override fun onRequestPermissionsResult(
- requestCode: Int,
- permissions: Array<out String>,
- grantResults: IntArray
- ) {
- super.onRequestPermissionsResult(requestCode, permissions, grantResults)
- if (PermissionsUtil.allPermissionsGranted(this)){
- start()
- }
- }
-
- /**
- * 启动相机
- * */
- private fun startCamera() {
- if (cameraProvider != null) {
- cameraProvider!!.unbindAll()
- /*
- 这一步是绑定预览界面,如果不需要预览界面,这一步克注释掉
- CameraX优势体验之一:预览界面可以根据开发者需求去取舍,而Camera1和Camera2则必须要预览界面
- */
- bindPreviewUseCase()
- // 这一步是绑定相机预览数据,可以获得相机每一帧的数据
- bindAnalysisUseCase()
- }
- }
-
- /**
- * 绑定预览界面。不需要预览界面可以不调用
- * */
- private fun bindPreviewUseCase() {
- if (previewUseCase != null) {
- cameraProvider!!.unbind(previewUseCase)
- }
-
- val builder = Preview.Builder()
- builder.setTargetAspectRatio(AspectRatio.RATIO_16_9).build()
- previewUseCase = builder.build()
- previewUseCase!!.setSurfaceProvider(previewView.surfaceProvider)
- cameraProvider!!.bindToLifecycle(
- this,
- cameraSelector!!,
- previewUseCase
- )
- }
-
- private var lastTime = 0L
- private var lastShowTime = 0L
- private var count = 0
- private var maxFrameMs = 0L
- private var minFrameMs = Long.MAX_VALUE
-
-
- private fun bindAnalysisUseCase() {
- if (analysisUseCase != null) {
- cameraProvider!!.unbind(analysisUseCase)
- }
- val builder = ImageAnalysis.Builder().setTargetAspectRatio(AspectRatio.RATIO_16_9)
- analysisUseCase = builder.build()
- analysisUseCase?.setAnalyzer(
- ContextCompat.getMainExecutor(this)
- ) { imageProxy: ImageProxy ->
- count += 1
- val currentTime = SystemClock.elapsedRealtime()
- val d = currentTime - lastShowTime
- maxFrameMs = maxFrameMs.coerceAtLeast(d)
- minFrameMs = minFrameMs.coerceAtMost(d)
- if ((currentTime - lastTime) >= 1000){
- tvFps.text = "fps: ${count}, 两帧最大:${maxFrameMs}, 最小:${minFrameMs}"
- lastTime = currentTime
- count = 0
- maxFrameMs = 0
- minFrameMs = Long.MAX_VALUE
- }
- lastShowTime = currentTime
- Log.d(TAG,"ImageProxy: 宽高: ${imageProxy.width} * ${imageProxy.height}")
-
- //必须close,相机才会下发下一帧数据,否则会一直阻塞相机下发数据
- imageProxy.close()
- }
- camera = cameraProvider!!.bindToLifecycle(
- this,
- cameraSelector!!,
- analysisUseCase
- )
- }
-
- private fun switchCamera() {
- if (cameraProvider == null) {
- return
- }
- val newLensFacing =
- if (lensFacing == CameraSelector.LENS_FACING_FRONT) {
- CameraSelector.LENS_FACING_BACK
- } else {
- CameraSelector.LENS_FACING_FRONT
- }
- val newCameraSelector = CameraSelector.Builder().requireLensFacing(newLensFacing).build()
- try {
- if (cameraProvider!!.hasCamera(newCameraSelector)) {
- lensFacing = newLensFacing
- cameraSelector = newCameraSelector
- startCamera()
- return
- }
- } catch (e: CameraInfoUnavailableException) {
- // Falls through
- }
- }
- }
添加权限工具类代码
- object PermissionsUtil {
-
- private const val TAG = "PermissionsUtil"
- private const val PERMISSION_REQUESTS = 1
-
- fun requestPermission(context: Context) {
- if (!allPermissionsGranted(context)) {
- runtimePermissions(context)
- }
- }
-
- private fun isPermissionGranted(context: Context, permission: String?): Boolean {
- if (ContextCompat.checkSelfPermission(context, permission!!) ==
- PackageManager.PERMISSION_GRANTED
- ) {
- return true
- }
- return false
- }
-
- fun allPermissionsGranted(context: Context): Boolean {
- for (permission in requiredPermissions(context)) {
- if (!isPermissionGranted(context, permission)) {
- return false
- }
- }
- return true
- }
-
- private fun requiredPermissions(context: Context): Array<String?> {
- val info =
- context.packageManager.getPackageInfo(context.packageName, PackageManager.GET_PERMISSIONS)
- val ps = info.requestedPermissions
- if (ps != null && ps.isNotEmpty()) {
- ps
- } else {
- arrayOfNulls(0)
- }
- return ps
- }
-
- private fun runtimePermissions(context: Context) {
- val allNeededPermissions: MutableList<String?> = ArrayList()
- for (permission in requiredPermissions(context)) {
- if (!isPermissionGranted(context, permission)) {
- allNeededPermissions.add(permission)
- }
- }
- if (allNeededPermissions.isNotEmpty()) {
- ActivityCompat.requestPermissions(
- getActivity(context),
- allNeededPermissions.toTypedArray(),
- PERMISSION_REQUESTS
- )
- }
- }
-
- @SuppressLint("UseRequireInsteadOfGet")
- private fun getActivity(context: Context) = when (context) {
- is Fragment -> {
- (context as Fragment).activity!!
- }
- is Activity -> {
- context
- }
- else -> {
- throw RuntimeException("context 必须是 Activity 或者 Fragment ")
- }
- }
- }
运行起来看下效果
ok,没问题
有问题请留言!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。