CameraX 三:获取预览流

前言

话接上文,本篇将要学习如何获取预览流,有了预览流我们可以做很多场景,如人形、人脸、车牌识别,如推流到流媒体服务器等等。

如果感到不适,强烈建议从CameraX 一看过来

源码机票

布局文件
 <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <Button
            android:id="@+id/h264Record"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="录制h264" />

        <Button
            android:id="@+id/disableH264Record"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="10dp"
            android:text="结束录制" />
    </LinearLayout>

    <androidx.camera.view.PreviewView
        android:id="@+id/previewView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

提供了两个按钮,分别用于开始录制和结束录制,PreviewView用于显示预览界面

绑定相机到应用程序
private fun initCamera() {
        cameraProviderFuture = ProcessCameraProvider.getInstance(this)
        //请求 CameraProvider 后,请验证它能否在视图创建后成功初始化。以下代码展示了如何执行此操作:
        cameraProviderFuture.addListener(Runnable {
            val cameraProvider = cameraProviderFuture.get()
            bindPreview(cameraProvider)
        }, ContextCompat.getMainExecutor(this))
    }

    @SuppressLint("RestrictedApi", "UnsafeOptInUsageError")
    fun bindPreview(cameraProvider: ProcessCameraProvider) {
        //预览
        var preview: Preview = Preview.Builder()
            .build()

//        选择相机
        var cameraSelector: CameraSelector = CameraSelector.Builder()
            .requireLensFacing(CameraSelector.LENS_FACING_BACK) //后置
            .build()

//        提供previewView预览控件
        preview.setSurfaceProvider(previewView.surfaceProvider)

//        图片分析
        imageAnalysis = ImageAnalysis.Builder()
            .setTargetResolution(size) //设置分辨率
            .setBackpressureStrategy(ImageAnalysis.STRATEGY_BLOCK_PRODUCER)  //阻塞模式,setAnalyzer过于耗时会导致预览卡顿
            .setTargetRotation(Surface.ROTATION_90)
            .build()

//        在绑定之前 你应该先解绑
        cameraProvider.unbindAll()
        var camera = cameraProvider.bindToLifecycle(
            this as LifecycleOwner,
            cameraSelector,
            imageAnalysis,
            preview
        )
    }

setBackpressureStrategy方法支持阻塞和非阻塞的方式获取帧,他们的区别介绍如下:

在这里插入图片描述

开始录制/结束录制
 /**
     * 结束录制
     */
    private fun customDisableStopRecording() {
        //停止h264编码
        avcEncoder?.stop()
        avcEncoder = null
        //取消分析器
        imageAnalysis!!.clearAnalyzer()
    }

    /**
     * 开始录制
     */
    private fun customRecording() {
        //保存为h264
        val file = File(
            getExternalFilesDir(Environment.DIRECTORY_MOVIES)!!.path,
            "${System.currentTimeMillis()}.h264"
        )
        if (!file.exists()) {
            file.createNewFile()
        }

        imageAnalysis?.let {
            it.setAnalyzer(mainExecutor, ImageAnalysis.Analyzer { image ->
                if (avcEncoder == null) {
                    avcEncoder = AvcEncoder()
                    //如果设置的默认分辨率不支持,则使用自动选择的分辨率,否则编码器将会报错
                    if (image.width != size.width) {
                        Log.d(TAG, "customRecording: 不支持默认分辨率,新的分辨率为:${image.width }")
                        size = Size(image.width,image.height)
                    }
                    avcEncoder?.config(size, file)
                    avcEncoder?.start()
                }
                Log.d(TAG, "width: ${image.width}")
                Log.d(TAG, "height: ${image.height}")
                //编码为h624
                avcEncoder?.addPlanes(ImageUtil.yuv_420_888toNv21(image))
                image.close()
            })
        }
    }

由于得到的图片格式是YUV_420_888的,这里我采用先转为NV21再转为NV12然后编码H264

图片分析得到的数据是不会自动处理旋转的,所以我们需要再处理旋转角度,setTargetRotation(Surface.ROTATION_90)是目标角度,不代表输出数据角度。

分辨率我们可以设置一个默认的值如Size(1920, 1080),当然你的设备可能不支持,会自动降低,所以编码时需要做好处理。上面提到的代码已有处理。可以正常编码。

注意:ImageAnalysis和VideoCapture不可以同时绑定。

如果你下载了Demo,结束录制之后,依然在外部存储目录下会生成.h264的文件,可以使用VLC播放器来验证是否录制成功。

在这里插入图片描述

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值