音视频学习记录Camera2系列二:录像

本文是关于使用Camera2 API进行音视频录像的学习记录,详细介绍了如何开启、结束录像及退出时的清理工作。录像功能借助MediaRecorder实现,并通过长按事件触发。在录像前后需管理好预览和录像Session。
摘要由CSDN通过智能技术生成

其实录像和拍照的区别并不大,没有看过上一篇拍照的可以先看一下,下文就不会详细说明,文末会附上全代码

录像会使用MediaRecorder作为输出Surface,为了与拍照区别,新创建一个录像用的CaptureRequest.Builder

//录像输出Surface
private lateinit var mediaRecorder: MediaRecorder
//录像CaptureRequest.Builder
private lateinit var videoCaptureRequest:CaptureRequest.Builder

开启录像

通过长按事件开启录像

//长按录像
video.setOnLongClickListener {
    videoStart()
    return@setOnLongClickListener true
}        

录像前需要结束预览和拍照的Session,然后需要创建一个录像Session

    /**
     * 开始录像
     */
    private fun videoStart() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            if (ContextCompat.checkSelfPermission(
                    this,
                    Manifest.permission.RECORD_AUDIO
                ) == PackageManager.PERMISSION_GRANTED
                && ContextCompat.checkSelfPermission(
                    this,
                    Manifest.permission.WRITE_EXTERNAL_STORAGE
                ) == PackageManager.PERMISSION_GRANTED
            ) {
                cameraCaptureSession.close()
                video.text = "停止"

                //获取录制视频的surface
                mediaRecorder = CameraUtil.getMediaRecorder(surface, size)
                //创建一个录像的CaptureRequest
                videoCaptureRequest = CameraUtil.createVideoCaptureRequest(
                    cameraDevice,
                    surface,
                    mediaRecorder.surface
                )
                //创建一个录像Session
                cameraDevice.createCaptureSession(
                    arrayListOf(surface, mediaRecorder.surface),
                    videoSessionCallback,
                    CameraUtil.getBackgroundHandler()
                )
            } else {
                val dialog = AlertDialog.Builder(this)
                dialog.setTitle("无法录制视频").setMessage("缺少录音权限或SD卡权限").setCancelable(false)

                dialog.setNegativeButton("退出") { _, _ ->
                    finish()
                }

                dialog.setPositiveButton("授权") { _, _ ->
                    val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
                    intent.data = Uri.parse("package:$packageName")
                    startActivity(intent)
                }

                dialog.show()
            }
        }
    }

    /**
     * 创建录像Session的回调
     */
    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    private val videoSessionCallback = object : CameraCaptureSession.StateCallback(){
        //
        override fun onConfigured(session: CameraCaptureSession) {
            cameraCaptureSession = session

            // 开始录像
            cameraCaptureSession.setRepeatingRequest(videoCaptureRequest.build(), captureCallback, CameraUtil.getBackgroundHandler())

            mediaRecorder.start()
        }
        //创建失败
        override fun onConfigureFailed(session: CameraCaptureSession) {

        }
    }

工具类

 /**
     * 获取录制视频的surface
     */
    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    fun getMediaRecorder(surface:Surface,size: Size): MediaRecorder {
        val mediaRecorder = MediaRecorder()

        //Initialized状态
        //设置声音来源,一般传入 MediaRecorder. AudioSource.MIC参数指定录制来自麦克风的声音。
        mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC)
        //设置用于录制的视频来源surface。
        mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE)

        //设置所录制的音视频文件的格式。进入DataSourceConfigured状态
        mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)
        //设置所录制的声音的编码格式。
        mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC)
        //设置录制的音频文件的保存位置。
        mediaRecorder.setOutputFile(getFilePath("${System.currentTimeMillis()}.mp4"))

        //设置所录制视频的编码位率。
        mediaRecorder.setVideoEncodingBitRate(10000000)
        //设置录制视频的捕获帧速率。
        mediaRecorder.setVideoFrameRate(30)
        //设置要拍摄的宽度和视频的高度。
        mediaRecorder.setVideoSize(size.width, size.height)
        //设置所录制视频的编码格式。
        mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264)

        //设置录制视频的方向
        setVideoOrientation(mediaRecorder)
        //设置使用哪个SurfaceView来显示视频预览。
        mediaRecorder.setPreviewDisplay(surface)

        //准备录制。
        mediaRecorder.prepare()

        return mediaRecorder
    }

    /**
     * 设置录制视频的方向
     */
    fun setVideoOrientation(mediaRecorder: MediaRecorder) {
        if (index == 0) {
            //设置输出的视频播放的方向提示。
            mediaRecorder.setOrientationHint(90)
        } else {
            //设置输出的视频播放的方向提示。
            mediaRecorder.setOrientationHint(90 * 3)
        }
    }

    /**
     * 创建一个录像的CaptureRequest
     */
    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    fun createVideoCaptureRequest(
        cameraDevice: CameraDevice,
        surface: Surface,
        mediaRecorderSurface: Surface
    ): CaptureRequest.Builder {
        //创建一个拍照的CaptureRequest
        val captureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD)
        // 设置拍照输出的 Surface
        captureRequestBuilder.addTarget(surface)
        captureRequestBuilder.addTarget(mediaRecorderSurface)
        return captureRequestBuilder
    }

 

 

结束录像

长按结束关闭录像

//松开结束录像
video.setOnTouchListener { _, event ->
    val action = event.action
    if (action == MotionEvent.ACTION_UP) { // 松开
        videoStop()
    }
    return@setOnTouchListener false
}

结束录像要切换会预览界面,也需要关闭录像Session,然后重新创建预览Session

    /**
     * 停止录制
     */
    private fun videoStop(){
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            video.text = "长按录制"
            mediaRecorder.stop()
            //将MediaRecorder设为空闲状态,即Initial状态。
            mediaRecorder.reset()

            cameraCaptureSession.close()

            setPreview()
        }
    }

    /**
     * 设置预览
     */
    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    private fun setPreview(){
        //
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值