Android使用MediaRecorder进行录像,暂停和继续录像的VideoUtils

使用MediaRecorder进行录像,要注意再设置MediaRecorder的参数的时候设置,这里也是查了网上很多代码都没有一个完整能实现的,或多或少都有点问题。
还有再暂停/继续录制的时候要注意将Camera的预览关闭camera.stopPreview()不然预览的界面还是会继续动给人暂停了还在录制的错觉。
还有camera再使用之前记得要unlock一下。至于设置MediaRecorder的参数,也是尝试了好多次,最后选择了使用profile选择视频质量来进行配置,这样最简单,可以考虑到视频大小的要求选择默认的 720P等,但是注意要硬件适配的大小。
所以如果出现media start failed,那么可以尝试降低视频录制参数来重新尝试。
完整的VideoUtils代码如下:


import android.hardware.Camera
import android.media.CamcorderProfile
import android.media.MediaRecorder
import android.os.Build
import android.view.Surface
import android.view.TextureView
import com.blankj.utilcode.util.PathUtils
import com.blankj.utilcode.util.PermissionUtils
import com.blankj.utilcode.util.ToastUtils
import java.io.File
import java.io.IOException
import java.lang.Exception

// 签署时候,录制视频的工具,包含录制和播放
class VideoUtils {

    companion object {

        private var instance: VideoUtils ?= null

        fun getInstance(): VideoUtils {
            if (instance == null) {
                instance = VideoUtils()
            }
            return instance!!
        }
    }

    private var camera: Camera? = null

    // 是否正在录制
    var isRecording: Boolean = false
    // 是否开启了录制,初始化并开启录制,之后是暂停
    var started: Boolean = false
    private var mMediaRecorder: MediaRecorder ?= null

    init {
        mMediaRecorder = MediaRecorder()
    }

    private fun configMediaRecorder(textureView: TextureView){
        val videoFile = File(PathUtils.getExternalDownloadsPath(),"record.mp4")
        if (videoFile.exists()){
            videoFile.delete()
        }
        camera = Camera.open(0)
        camera?.stopPreview()
        camera?.unlock()

        val profile = CamcorderProfile.get( 0, CamcorderProfile.QUALITY_480P )

//        val sizeList = camera.parameters.supportedVideoSizes
//        val videoSize = sizeList.first()
        mMediaRecorder?.setCamera(camera)
        mMediaRecorder?.setAudioSource(MediaRecorder.AudioSource.CAMCORDER)//设置音频输入源  也可以使用 MediaRecorder.AudioSource.MIC
        mMediaRecorder?.setVideoSource(MediaRecorder.VideoSource.CAMERA)//设置视频输入源


        mMediaRecorder?.setOutputFormat(profile.fileFormat)//音频输出格式
        mMediaRecorder?.setAudioEncoder(profile.audioCodec)//设置音频的编码格式
        mMediaRecorder?.setVideoEncoder(profile.videoCodec)//设置图像编码格式

        mMediaRecorder?.setVideoSize(profile.videoFrameWidth, profile.videoFrameHeight)
        mMediaRecorder?.setVideoFrameRate(profile.videoFrameRate)
        mMediaRecorder?.setVideoEncodingBitRate(profile.videoBitRate)
        mMediaRecorder?.setAudioEncodingBitRate(profile.audioBitRate)

        mMediaRecorder?.setAudioSamplingRate(profile.audioSampleRate)
        mMediaRecorder?.setAudioChannels(profile.audioChannels)

//        mMediaRecorder?.setVideoFrameRate(20)//要录制的视频帧率 帧率越高视频越流畅 如果设置设备不支持的帧率会报错  按照注释说设备会支持自动帧率所以一般情况下不需要设置
//        mMediaRecorder?.setVideoSize(1080,780)//设置录制视频的分辨率  如果设置设备不支持的分辨率会报错
//        mMediaRecorder?.setVideoEncodingBitRate(5 * 100 * 100) //设置比特率,比特率是每一帧所含的字节流数量,比特率越大每帧字节越大,画面就越清晰,算法一般是 5 * 选择分辨率宽 * 选择分辨率高,一般可以调整5-10,比特率过大也会报错
//        mMediaRecorder?.setOrientationHint(360)//设置视频的摄像头角度 只会改变录制的视频文件的角度(对预览图像角度没有效果)

        val surface = Surface(textureView.getSurfaceTexture())
        mMediaRecorder?.setOutputFile(videoFile.getAbsolutePath())//MP4文件保存路径
        mMediaRecorder?.setPreviewDisplay(surface)//设置拍摄预览

    }

    fun startRecorder(textureView: TextureView) {
        try {
            MyPermissionUtils.requestMicrophonePermissions(object: PermissionUtils.SimpleCallback{
                override fun onGranted() {
                    MyPermissionUtils.requestCameraPermissions(object: PermissionUtils.SimpleCallback{
                        override fun onGranted() {
                            try {
                                configMediaRecorder(textureView) //配置MediaRecorder  因为每一次停止录制后调用重置方法后都会取消配置,所以每一次开始录制都需要重新配置一次
                                mMediaRecorder!!.prepare() //准备
                                mMediaRecorder!!.start() //开启
                                isRecording = true
                                started = true
                            } catch (e: Exception) {
                                ToastUtils.showShort(e.message)
                                e.printStackTrace()
                            }
                        }

                        override fun onDenied() {
                            ToastUtils.showShort("请开启录像权限")
                        }

                    })
                }

                override fun onDenied() {
                    ToastUtils.showShort("请开启录音权限")
                }

            })
        } catch (e: IOException) {
            e.printStackTrace()
        }
    }

    fun stopRecorder() {
        mMediaRecorder!!.stop() //暂停
        mMediaRecorder!!.reset() //重置 重置后将进入空闲状态,再次启动录制需要重新配置MediaRecorder
        camera?.stopPreview()
        camera?.release()
        camera?.lock()
        isRecording = false
        started = false
    }

    fun pauseRecorder() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            mMediaRecorder!!.pause() //暂停
            camera?.stopPreview()
            isRecording = false
        }
    }

    fun resumeRecorder() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            mMediaRecorder!!.resume() //恢复
            camera?.startPreview()
            isRecording = true
        }
    }

    fun destroy() {
        if (mMediaRecorder != null) {
            mMediaRecorder!!.stop()
            mMediaRecorder!!.release() //释放 释放之前需要先调用stop()
            // 摄像头关闭预览和释放
            camera?.stopPreview()
            camera?.release()
            mMediaRecorder = null
        }
        instance = null
    }

}
posted @ 2024-03-20 09:35  乌拉小考  阅读(350)  评论(0编辑  收藏  举报