Android 音视频知识点(三)

202 阅读2分钟

本文着重介绍 CameraX 的使用

CameraX 是 Jatpack 组件中的一个,基于 Camera2 做的再封装,使用较 Camera2 简单,性能较 Camera1 好

1、引入 CameraX 库

[versions]
camerax = "1.3.0"

[libraries]
camera-camera2 = { group = "androidx.camera", name = "camera-camera2", version.ref = "camerax" }
camera-lifecycle = { group = "androidx.camera", name = "camera-lifecycle", version.ref = "camerax" }
camera-view = { group = "androidx.camera", name = "camera-view", version.ref = "camerax" }
dependencies {

    implementation libs.camera.camera2
    implementation libs.camera.lifecycle
    implementation libs.camera.view
 
}

2、打开摄像头,并渲染摄像头画面

要使用 PreviewView 布局对象

    <androidx.camera.view.PreviewView
            android:id="@+id/camera_preview"
            android:layout_width="0dp"
            android:layout_height="0dp"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintBottom_toBottomOf="parent" />

打开摄像头逻辑 ImageCapture 对象会持续收集摄像头数据

lateinit var imageCapture: ImageCapture

fun startCamera() {
        var cameraProviderFuture = ProcessCameraProvider.getInstance(this)
        cameraProviderFuture.addListener({
            try {
                // 将相机的生命周期和 activity 生命周期绑定
                val cameraProvider = cameraProviderFuture.get()
                // 预览 capture,支持角度转换
                val preview = Preview.Builder()
                    .setTargetRotation(currentRotation)
                    .build().also {
                        it.setSurfaceProvider(camera_preview.surfaceProvider)
                    }

                // 创建图片的 capture
                imageCapture = ImageCapture.Builder()
                    .setTargetRotation(camera_preview.display.rotation)
                    .setFlashMode(ImageCapture.FLASH_MODE_AUTO)
                    .build()

                // 选择后置摄像头
                val cameraSlactor = CameraSelector.Builder().requireLensFacing(mFacing).build()

                // 预览之前先接棒
                cameraProvider.unbindAll()

                // 将数据绑定到相机的生命周期中
                cameraProvider.bindToLifecycle(this@CameraXActivity, cameraSlactor,
                    preview, imageCapture)
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }, ContextCompat.getMainExecutor(this))
    }

3、拍摄照片并保存照片图像 使用 imageCapture.takePicture 方法抓取某一帧画面。 由于直接输出的图片方向是摄像头的默认朝向,当拍摄的时候,手机的朝向可以随意,所以要用 fixImageRotation 方法将图片的朝向调整为手机拍照瞬间的方向,再进行照片的保存

fun cameraCapture() {
        val dir = File(PATH)
        if (!dir.exists()) {
            dir.mkdirs()
        }

        // 创建文件
        val photoFile = File(PATH, "testx.jpg")
        if (photoFile.exists()) {
            photoFile.delete()
        }

        // 创建包文件的数据
        var outputFileOptions = ImageCapture.OutputFileOptions.Builder(photoFile).build()

        // 开始拍照
        imageCapture.takePicture(outputFileOptions, ContextCompat.getMainExecutor
            (this@CameraXActivity), object: OnImageSavedCallback {
            override fun onImageSaved(outputFileResults: ImageCapture.OutputFileResults) {
                runOnUiThread {
                    val bitmap = fixImageRotation(photoFile)
                    Toast.makeText(this@CameraXActivity, "保存成功", Toast.LENGTH_LONG).show()
                }

            }

            override fun onError(exception: ImageCaptureException) {
                Toast.makeText(this@CameraXActivity, "保存失败", Toast.LENGTH_LONG).show()
            }
        })
    }

    fun fixImageRotation(file: File): Bitmap {
        val bitmap = BitmapFactory.decodeFile(file.absolutePath)
        val exif = ExifInterface(file.absolutePath)
        val orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL)

        val matrix = Matrix()
        val routationDegress = when (orientation) {
            ExifInterface.ORIENTATION_ROTATE_90 -> 90f
            ExifInterface.ORIENTATION_ROTATE_90 -> 90f
            ExifInterface.ORIENTATION_ROTATE_180 -> 180f
            ExifInterface.ORIENTATION_ROTATE_270 -> 270f
            else -> 0f
        }

        matrix.postRotate(routationDegress)
        return Bitmap.createBitmap(bitmap, 0, 0 ,bitmap.width, bitmap.height, matrix, true)
    }

4、翻转摄像头 使用 CameraSelector 选择需要显示的摄像头类型。前置摄像头,还是后置摄像头

    fun switchCamera() {
        mFacing = if (mFacing == CameraSelector.LENS_FACING_BACK) CameraSelector
            .LENS_FACING_FRONT else  CameraSelector.LENS_FACING_BACK
        startCamera()
    }