自定义音视频基类四:采集篇总结

音视频开发采集部分需要的知识前三章中已经写明,这章是对前面三章的整理简化,首先上实现类,代码很简单,文末为基类代码

class LiveBroadcastActivity : BaseVideoActivity() {

    //预览CaptureRequest.Builder
    private lateinit var previewCaptureRequest: CaptureRequest.Builder

    override fun getLayoutId(): Int {
        return R.layout.activity_live_broadcast;
    }

    override fun init() {
        //开启surfaceTextureListener监听
        textureView.surfaceTextureListener = surfaceTextureListener

        //切换相机
        switchCamera.setOnClickListener {
            switchCamera()
        }

    }

    /**
     * 创建一个Session
     */
    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    override fun createCaptureSession(camera: CameraDevice):List<Surface>{
        //创建一个预览的CaptureRequest
        previewCaptureRequest = camera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)
        // 设置预览输出的 Surface
        previewCaptureRequest.addTarget(surface)

        val outputs = ArrayList<Surface>()
        outputs.add(surface)

        return outputs
    }

    /**
     * 返回预览的CaptureRequest
     */
    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    override fun setRepeatingRequest(session: CameraCaptureSession): CaptureRequest{
        //开始录音
        startRecording()
        return previewCaptureRequest.build()
    }

    /**
     * 音频编码,注意这里是在子线程中的
     */
    override fun audioCoding(buffer: ByteArray, len: Int) {

    }

    /**
     * 老相机API数据回调接口
     */
    override fun oldSendVideoData(data: ByteArray) {

    }

    /**
     * 自动修改textureView宽高以适应不同预览比例
     */
    override fun onWindowFocusChanged(hasFocus: Boolean) {
        super.onWindowFocusChanged(hasFocus)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            val width = textureView.width
            val height = textureView.height
            val proportion1 = size.width.toFloat() / size.height
            val proportion2 = height.toFloat() / width
            if (proportion1 > proportion2) {
                val layoutParams = textureView.layoutParams
                layoutParams.width = (height * proportion1 + .5).toInt()
                textureView.layoutParams = layoutParams
            } else if (proportion1 < proportion2) {
                val layoutParams = textureView.layoutParams
                layoutParams.height = (width * proportion1 + .5).toInt()
                textureView.layoutParams = layoutParams
            }
        }
    }
}

是不是感觉瞬间解脱,再也不用去写那些繁琐的代码了,接下来总结一下是如何实现的,开启定义好的surfaceTextureListener便会自动采集音视频

textureView.surfaceTextureListener = surfaceTextureListener

使用是不是很简单,然后来看一下基类是怎么实现的

    /**
     * 获取Surface的回调
     */
    val surfaceTextureListener = object : TextureView.SurfaceTextureListener {
        //SurfaceTexture大小发生变化时调用
        @SuppressLint("Recycle")
        override fun onSurfaceTextureSizeChanged(
            surfaceTexture: SurfaceTexture,
            width: Int,
            height: Int
        ) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                //获取相机属性类
                val cameraCharacteristics = getCameraCharacteristics()
                //设置预览尺寸
                size = setPreviewSize(surfaceTexture, cameraCharacteristics)

                surface = Surface(surfaceTexture)
            }
        }

        override fun onSurfaceTextureUpdated(surface: SurfaceTexture?) {

        }

        override fun onSurfaceTextureDestroyed(surfaceTexture: SurfaceTexture?): Boolean {
            //关闭老相机API预览
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
                stopPreview()
            }
            surface.release()
            return true
        }

        override fun onSurfaceTextureAvailable(
            surfaceTexture: SurfaceTexture,
            width: Int,
            height: Int
        ) {
            //初始化AudioRecord
            initAudioRecord()

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                //初始化Camera2
                initCamera2()

                //获取相机属性类
                val cameraCharacteristics = getCameraCharacteristics()
                //设置预览尺寸
                size = setPreviewSize(surfaceTexture, cameraCharacteristics)

                surface = Surface(surfaceTexture)

                //开启摄像头
                openCamera()
            }else{
                //开启老相机API预览
                startPreview(surfaceTexture)
            }
        }
    }

在onSurfaceTextureAvailable方法中初始化AudioRecord和Camera,初始化完成后便会开启摄像头

/**
     * 打开摄像头
     */
    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    fun openCamera() {
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
            cameraManager.openCamera(cameraId, callback, getBackgroundHandler())
        } else {
            val dialog = AlertDialog.Builder(this)
            dialog.setTitle("开启相机失败").setMessage("缺少开启相机的权限").setCancelable(false)

            dialog.setNegativeButton("取消") { _, _ ->

            }

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

            dialog.show()
        }
    }

     /**
     * 打开摄像头的回调
     */
    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    private val callback = object : CameraDevice.StateCallback() {
        //成功打开时的回调,可以得到一个 CameraDevice 实例
        override fun onOpened(camera: CameraDevice) {
            cameraDevice = camera
            outputs = createCaptureSession(camera)

            //创建一个Session
            camera.createCaptureSession(
                outputs,
                mSessionCallback,
                getBackgroundHandler()
            )
        }

        //当 camera 不再可用时的回调,通常在该方法中进行资源释放的操作
        override fun onDisconnected(camera: CameraDevice) {
            showToast("camera不再可用")
        }

        // 当 camera 打开失败时的回调,error 为具体错误原因,通常在该方法中也要进行资源释放的操作
        override fun onError(camera: CameraDevice, error: Int) {
            camera.close()
            showError(error)
            releaseBackgroundThread()
        }

        //相机关闭时回调
        override fun onClosed(camera: CameraDevice) {
            super.onClosed(camera)
            cameraCaptureSession?.close()
        }
    }

    /**
     * 创建一个Session
     */
    abstract fun createCaptureSession(camera: CameraDevice): List<Surface>

在开启摄像头的回调中可以看到使用了一个抽象方法,继承这个基类需要重写这个方法,便可以得到CameraDevice,接下来你想怎么玩就是你的事了

    /**
     * 创建一个Session
     */
    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    override fun createCaptureSession(camera: CameraDevice):List<Surface>{
        //创建一个预览的CaptureRequest
        previewCaptureRequest = camera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)
        // 设置预览输出的 Surface
        previewCaptureRequest.addTarget(surface)

        val outputs = ArrayList<Surface>()
        outputs.add(surface)

        return outputs
    }

接下来是创建预览Session的回调

    /**
     * 创建预览Session的回调
     */
    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    val mSessionCallback = object : CameraCaptureSession.StateCallback() {

        override fun onConfigured(session: CameraCaptureSession) {
            cameraCaptureSession = session
            val captureRequest = setRepeatingRequest(session)

            session.setRepeatingRequest(
                captureRequest,
                captureCallback,
                getBackgroundHandler()
            )
        }

        //创建失败
        override fun onConfigureFailed(session: CameraCaptureSession) {
            showToast("创建Session失败")
        }
    }

    /**
     * 开始预览,即设置反复请求
     */
    abstract fun setRepeatingRequest(session: CameraCaptureSession):CaptureRequest

同样使用了一个抽象方法,定义这个抽象方法主要是灵活性考虑,当然如果你不考虑可以写在基类中

    /**
     * 返回预览的CaptureRequest
     */
    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    override fun setRepeatingRequest(session: CameraCaptureSession): CaptureRequest{
        //开始录音
        startRecording()
        return previewCaptureRequest.build()
    }

为了兼容5.0以下的手机,定义了一个老相机API数据回调接口,只有5.0以下的手机这个方法才会生效

    /**
     * 老相机API数据回调接口
     */
    override fun oldSendVideoData(data: ByteArray) {

    }

最后是音频的抽象方法,可以直接在这里得到音频数据

    /**
     * 音频编码,注意这里是在子线程中的
     */
    override fun audioCoding(buffer: ByteArray, len: Int) {

    }

为了防止内存泄露做了一些处理

    override fun onDestroy() {
        super.onDestroy()
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            cameraDevice?.close()
            if(outputs != null){
                for (surface in outputs!!) {
                    surface.release()
                }
            }
            endRecording()
            releaseBackgroundThread()
        }else{
            stopPreview()
        }
    }

最后附上一个自适应比例

    /**
     * 自动修改textureView宽高以适应不同预览比例
     */
    override fun onWindowFocusChanged(hasFocus: Boolean) {
        super.onWindowFocusChanged(hasFocus)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            val width = textureView.width
            val height = textureView.height
            val proportion1 = size.width.toFloat() / size.height
            val proportion2 = height.toFloat() / width
            if (proportion1 > proportion2) {
                val layoutParams = textureView.layoutParams
                layoutParams.width = (height * proportion1 + .5).toInt()
                textureView.layoutParams = layoutParams
            } else if (proportion1 < proportion2) {
                val layoutParams = textureView.layoutParams
                layoutParams.height = (width * proportion1 + .5).toInt()
                textureView.layoutParams = layoutParams
            }
        }
    }

基类

abstract class BaseVideoActivity() : BaseActivity() {

    private lateinit var mBackgroundThread: HandlerThread
    private var mBackgroundHandler: Handler? = null

    //摄像头管理类
    lateinit var cameraManager: CameraManager

    //摄像头id列表
    lateinit var cameraIdList: Array<String>

    //第几个摄像头
    var index = 0

    //当前摄像头id
    lateinit var cameraId: String

    //Surface集合
    private var outputs: List<Surface>? = null

    //当前摄像头
    private var cameraDevice: CameraDevice? = null

    //Session
    private var cameraCaptureSession: CameraCaptureSession? = null

    //预览Surface
    lateinit var surface: Surface

    //相机预览分辨率
    lateinit var size: Size

    /**
     * 获取Surface的回调
     */
    val surfaceTextureListener = object : TextureView.SurfaceTextureListener {
        //SurfaceTexture大小发生变化时调用
        @SuppressLint("Recycle")
        override fun onSurfaceTextureSizeChanged(
            surfaceTexture: SurfaceTexture,
            width: Int,
            height: Int
        ) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                //获取相机属性类
                val cameraCharacteristics = getCameraCharacteristics()
                //设置预览尺寸
                size = setPreviewSize(surfaceTexture, cameraCharacteristics)

                surface = Surface(surfaceTexture)
            }
        }

        override fun onSurfaceTextureUpdated(surface: SurfaceTexture?) {

        }

        override fun onSurfaceTextureDestroyed(surfaceTexture: SurfaceTexture?): Boolean {
            //关闭老相机API预览
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
                stopPreview()
            }
            surface.release()
            return true
        }

        override fun onSurfaceTextureAvailable(
            surfaceTexture: SurfaceTexture,
            width: Int,
            height: Int
        ) {
            //初始化AudioRecord
            initAudioRecord()

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                //初始化Camera2
                initCamera2()

                //获取相机属性类
                val cameraCharacteristics = getCameraCharacteristics()
                //设置预览尺寸
                size = setPreviewSize(surfaceTexture, cameraCharacteristics)

                surface = Surface(surfaceTexture)

                //开启摄像头
                openCamera()
            }else{
                //开启老相机API预览
                startPreview(surfaceTexture)
            }
        }
    }

    /**
     * 初始化Camera2
     */
    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    fun initCamera2() {
        cameraManager = application.getSystemService(Context.CAMERA_SERVICE) as CameraManager
        cameraIdList = cameraManager.cameraIdList
        cameraId = cameraIdList[index]
    }

    /**
     * 获取CameraCharacteristics相机属性类
     */
    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    fun getCameraCharacteristics(): CameraCharacteristics {
        return cameraManager.getCameraCharacteristics(cameraId)
    }

    /**
     * 设置预设的预览尺寸
     */
    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    fun setPreviewSize(@NotNull surfaceTexture: SurfaceTexture, cameraCharacteristics: CameraCharacteristics): Size {
        val aspectRatios = ArrayList<Float>()
        aspectRatios.add(16.toFloat() / 9)
        aspectRatios.add(4.toFloat() / 3)
        aspectRatios.add(18.toFloat() / 9)

        val size = getPreviewSize(cameraCharacteristics, aspectRatios)
        surfaceTexture.setDefaultBufferSize(size.width, size.height)

        return size
    }

    /**
     * 获取预览尺寸
     * 参数2:预览尺寸比例的集合,按加入顺序寻找预览尺寸并返回
     */
    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    fun getPreviewSize(@NotNull cameraCharacteristics: CameraCharacteristics, aspectRatios: ArrayList<Float>): Size {
        for (aspectRatio in aspectRatios) {
            val size = getPreviewSize(cameraCharacteristics, aspectRatio)
            if (size != null) {
                return size
            }
        }
        return Size(1280, 720)
    }

    /**
     * 获取预览尺寸
     * 参数2:预览尺寸比例,如4:3,16:9
     */
    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    fun getPreviewSize(@NotNull cameraCharacteristics: CameraCharacteristics, aspectRatio: Float): Size? {
        val streamConfigurationMap =
                cameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)
        val supportedSizes = streamConfigurationMap.getOutputSizes(SurfaceTexture::class.java)
        for (size in supportedSizes) {
            if (size.width.toFloat() / size.height == aspectRatio) {
                return size
            }
        }
        return null
    }

    /**
     * 打开摄像头
     */
    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    fun openCamera() {
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
            cameraManager.openCamera(cameraId, callback, getBackgroundHandler())
        } else {
            val dialog = AlertDialog.Builder(this)
            dialog.setTitle("开启相机失败").setMessage("缺少开启相机的权限").setCancelable(false)

            dialog.setNegativeButton("取消") { _, _ ->

            }

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

            dialog.show()
        }
    }

    /**
     * 打开摄像头的回调
     */
    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    private val callback = object : CameraDevice.StateCallback() {
        //成功打开时的回调,可以得到一个 CameraDevice 实例
        override fun onOpened(camera: CameraDevice) {
            cameraDevice = camera
            outputs = createCaptureSession(camera)

            //创建一个Session
            camera.createCaptureSession(
                outputs!!,
                mSessionCallback,
                getBackgroundHandler()
            )
        }

        //当 camera 不再可用时的回调,通常在该方法中进行资源释放的操作
        override fun onDisconnected(camera: CameraDevice) {

        }

        // 当 camera 打开失败时的回调,error 为具体错误原因,通常在该方法中也要进行资源释放的操作
        override fun onError(camera: CameraDevice, error: Int) {
            camera.close()
            showError(error)
            releaseBackgroundThread()
        }

        //相机关闭时回调
        override fun onClosed(camera: CameraDevice) {
            super.onClosed(camera)
            cameraCaptureSession?.close()
        }
    }

    /**
     * 创建一个Session
     */
    abstract fun createCaptureSession(camera: CameraDevice): List<Surface>

    /**
     * 创建预览Session的回调
     */
    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    val mSessionCallback = object : CameraCaptureSession.StateCallback() {

        override fun onConfigured(session: CameraCaptureSession) {
            cameraCaptureSession = session
            val captureRequest = setRepeatingRequest(session)

            session.setRepeatingRequest(
                captureRequest,
                captureCallback,
                getBackgroundHandler()
            )
        }

        //创建失败
        override fun onConfigureFailed(session: CameraCaptureSession) {
            showToast("创建Session失败")
        }
    }

    /**
     * 开始预览,即设置反复请求
     */
    abstract fun setRepeatingRequest(session: CameraCaptureSession):CaptureRequest

    /**
     * Session进度的回调
     */
    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    val captureCallback = object : CameraCaptureSession.CaptureCallback() {
        override fun onCaptureCompleted(
                session: CameraCaptureSession,
                request: CaptureRequest,
                result: TotalCaptureResult
        ) {
            super.onCaptureCompleted(session, request, result)
        }

        override fun onCaptureFailed(
                session: CameraCaptureSession,
                request: CaptureRequest,
                failure: CaptureFailure
        ) {
            super.onCaptureFailed(session, request, failure)
        }
    }

    /**
     * 切换摄像头
     */
    fun switchCamera() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            if (cameraDevice != null) {
                if (index < cameraIdList.size - 1) {
                    index++
                } else {
                    index = 0
                }
                cameraId = cameraIdList[index]
                cameraDevice?.close()
                openCamera()
            } else {
                showToast("请先开启摄像头")
            }
        }else{
            oldSwitchCamera()
        }
    }

    /**
     * 获取BackgroundHandler
     */
    fun getBackgroundHandler(): Handler {
        if (mBackgroundHandler == null) {
            //设置摄像头线程
            mBackgroundThread = HandlerThread("CameraBackground")
            mBackgroundThread.start()
            mBackgroundHandler = Handler(mBackgroundThread.looper)
        }
        return mBackgroundHandler as Handler
    }

    /**
     * 释放线程资源
     */
    fun releaseBackgroundThread() {
        mBackgroundHandler?.removeCallbacksAndMessages(null)
        mBackgroundHandler = null
        mBackgroundThread.quitSafely()
        mBackgroundThread.join()
    }

    /**
     * 开启摄像头错误提示
     */
    fun showError(error: Int) {
        when (error) {
            CameraDevice.StateCallback.ERROR_CAMERA_IN_USE -> {
                showToast("当前相机设备已经在一个更高优先级的地方打开了")
            }
            CameraDevice.StateCallback.ERROR_MAX_CAMERAS_IN_USE -> {
                showToast("已打开相机数量到上限了,无法再打开新的相机了")
            }
            CameraDevice.StateCallback.ERROR_CAMERA_DISABLED -> {
                showToast("由于相关设备策略该相机设备无法打开")
            }
            CameraDevice.StateCallback.ERROR_CAMERA_DEVICE -> {
                showToast("相机设备发生了一个致命错误")
            }
            CameraDevice.StateCallback.ERROR_CAMERA_SERVICE -> {
                showToast("相机服务发生了一个致命错误")
            }
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            cameraDevice?.close()
            if(outputs != null){
                for (surface in outputs!!) {
                    surface.release()
                }
            }
            endRecording()
            releaseBackgroundThread()
        }else{
            stopPreview()
        }
    }

    // 采样率
    private val sampleRateInHz = 44100

    // 音频通道 立体声:
    val stereo = AudioFormat.CHANNEL_IN_STEREO

    lateinit var audioRecord: AudioRecord

    //audioRecord能接受的最小的buffer大小
    private var bufferSizeInBytes: Int = 0

    //录音线程
    private var recordingJob: Job? = null

    /**
     * 初始化AudioRecord
     */
    fun initAudioRecord(channelConfig: Int = AudioFormat.CHANNEL_IN_MONO) {
        //audioRecord能接受的最小的buffer大小
        bufferSizeInBytes = AudioRecord.getMinBufferSize(sampleRateInHz, channelConfig, AudioFormat.ENCODING_PCM_16BIT)
        audioRecord = AudioRecord(MediaRecorder.AudioSource.MIC, sampleRateInHz, channelConfig, AudioFormat.ENCODING_PCM_16BIT, bufferSizeInBytes)
    }

    /**
     * 开始录音
     */
    fun startRecording() {
        recordingJob = GlobalScope.launch(Dispatchers.IO) {
            if (bufferSizeInBytes > 0) {
                audioRecord.startRecording()

                while (isActive) {
                    val buffer = ByteArray(bufferSizeInBytes)
                    val len = audioRecord.read(buffer, 0, buffer.size)
                    if (len > 0) {
                        //音频编码
                        audioCoding(buffer, len)
                    }
                }
            } else {
                launch(Dispatchers.Main) {
                    showToast("请先初始化AudioRecord类")
                }
            }
        }
    }

    /**
     * 音频编码
     */
    abstract fun audioCoding(buffer: ByteArray, len: Int)

    /**
     * 结束录音
     */
    fun endRecording() {
        if (audioRecord.recordingState == AudioRecord.RECORDSTATE_RECORDING) {
            audioRecord.stop()
        }
        if (audioRecord.state == AudioRecord.STATE_INITIALIZED) {
            audioRecord.release()
        }
        recordingJob?.cancel()
    }

    //老相机id
    private var oldCameraId = Camera.CameraInfo.CAMERA_FACING_BACK
    //老相机SurfaceTexture
    private var oldSurfaceTexture:SurfaceTexture? = null
    //老相机数据存储数组
    private var oldBuffers:ByteArray? = null
    //老相机
    private var oldCamera:Camera? = null
    //老相机预览尺寸
    lateinit var oldSize:Camera.Size

    /**
     * 老相机API开始预览
     */
    fun startPreview(surfaceTexture:SurfaceTexture){
        if (oldSurfaceTexture == null){
            oldSurfaceTexture = surfaceTexture;
        }

        // 打开摄像头并将展示方向旋转90度
        oldCamera = Camera.open(oldCameraId)
        oldCamera!!.setDisplayOrientation(90)

        val parameters = oldCamera!!.parameters

        // 选择合适的预览尺寸
        val sizeList = parameters.supportedPreviewSizes
        oldSize = getOldSize(sizeList)

        parameters.previewFormat = ImageFormat.NV21
        //设置预览图像参数
        parameters.setPictureSize(oldSize.width,oldSize.height)
        parameters.setPreviewSize(oldSize.width,oldSize.height)

        oldCamera!!.parameters = parameters
        oldCamera!!.setPreviewTexture(oldSurfaceTexture)
        //获取预览数据
        oldBuffers = ByteArray(oldSize.width * oldSize.height * 4)
        oldCamera!!.addCallbackBuffer(oldBuffers)
        oldCamera!!.setPreviewCallbackWithBuffer(previewCallback)
        oldCamera!!.startPreview()
    }

    /**
     * 获取老相机预览数据回调
     */
    private val previewCallback = Camera.PreviewCallback { data, camera ->
        camera?.addCallbackBuffer(oldBuffers)
        oldSendVideoData(data)
    }

    /**
     * 老相机API预览数据回调
     */
    abstract fun oldSendVideoData(data:ByteArray)

    /**
     * 停止预览
     */
    fun stopPreview(){
        if (oldCamera != null){
            oldCamera!!.stopPreview()
            oldCamera!!.release()
            oldCamera = null
        }
    }

    /**
     * 老camera切换摄像头
     */
    private fun oldSwitchCamera(){
        if (oldSurfaceTexture != null){
            oldCameraId = if (oldCameraId == Camera.CameraInfo.CAMERA_FACING_BACK){
                Camera.CameraInfo.CAMERA_FACING_FRONT
            }else{
                Camera.CameraInfo.CAMERA_FACING_BACK
            }
            stopPreview()
            startPreview(oldSurfaceTexture!!)
        }
    }

    /**
     * 获取老相机API的预览大小
     */
    private fun getOldSize(sizeList:List<Camera.Size>):Camera.Size{
        val aspectRatios = ArrayList<Float>()
        aspectRatios.add(16.toFloat() / 9)
        aspectRatios.add(4.toFloat() / 3)
        aspectRatios.add(18.toFloat() / 9)
        for (aspectRatio in aspectRatios){
            for (size in sizeList){
                if (size.width.toFloat() / size.height == aspectRatio) {
                    return size
                }
            }
        }
        return sizeList[0]
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值