阅读 374

使用手机相机拍照、录制视频

音视频的整个开发流程抛开技术层面业务逻辑来讲当然是音视频采集,这也是整个音视频开发的第一步,当我们有数据源之后才会进行下一不的操作,

在手机端首先想到的肯定是摄像头以及麦克风,这篇文章是先看一下手机自带的相机在工作中的使用方法

  • 选取头像
  • 聊天发送即时图片
  • 发送朋友圈等等

这些是我们不需要从数据源头来处理的,手机相机完全可以满足需求

[toc]

一、 使用相机拍照

1.1 申请权限


 <uses-permission android:name="android.permission.CAMERA" />
 // 麦克风权限
 <uses-permission android:name="android.permission.RECORD_AUDIO" />
 
 <!--表示该应用必须在有相机功能的设备上才能使用-->
 <uses-feature android:name="android.hardware.camera" />
复制代码

Android 6.0 以上系统需要在代码中进行动态申请权限

动态权限申请可以使用:

implementation 'com.yanzhenjie:permission:2.0.3'
复制代码

在需要使用的地方或者统一一个位置进行申明(因为动态权限的申请方式就那几个步骤,没必要自己进行封装)

AndPermission.with(this)
            .runtime()
            .permission(Permission.Group.STORAGE)
            .permission(Permission.Group.CAMERA)
            .onGranted {
                // 次回调中进行逻辑操作
                thread {
                    copyFromAssetcFiles()
                }
            }.start()
复制代码

1.2 调用相机

Intent(MediaStore.ACTION_IMAGE_CAPTURE).also { takePictureIntent ->
            /**
             * startActivityForResult() 方法受调用 resolveActivity()(返回可处理 Intent 的第一个 Activity 组件)的条件保护。
             * 执行此检查非常重要,因为如果您使用任何应用都无法处理的 Intent 调用 startActivityForResult(),您的应用就会崩溃。所以只要结果不是 Null,
             * 就可以放心使用 Intent。
             */
            takePictureIntent.resolveActivity(packageManager)?.also {
                startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE)
            }
        }
复制代码

1.3 使用

// 拍完照之后会返回data 转换成bitmao 进行使用
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
            val imageBitmap = data?.extras?.get("data") as Bitmap
            cameraIv.setImageBitmap(imageBitmap)
        }
    }
复制代码

完成了一个完整的拍照功能,是不是感觉缺了什么?是的我们需要将拍照的照片进行保存或者拿到他的本地地址

1.4 设定一个路径并且拍照

  1. 创建文件
@Throws(IOException::class)
    fun createImageFile(): File {
        val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss").format(Date())
        val externalFilesDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES)
        return File.createTempFile(
            "JPEG_${timeStamp}_", //前缀
            ".jpg", //后缀
            externalFilesDir //路径
        ).apply {
            // 用于预览
            currentPhotoPath = absolutePath
        }
    }
复制代码
  1. 调用相机并传入路径
Intent(MediaStore.ACTION_IMAGE_CAPTURE).also { takePictureIntent ->
            try {
                takePictureIntent.resolveActivity(packageManager)?.also {
                    val photoFile: File? = try {
                        createImageFile()
                    } catch (ex: IOException) {
                        LogUtils.e("create File error ${ex.message}")
                        null
                    }
                    photoFile?.also {
                        val photoURI: Uri = FileProvider.getUriForFile(
                            this,
                            "com.kpa.android.fileprovider",
                            it
                        )
                        LogUtils.e(photoURI)
                        takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI)
                        startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO)
                    }
                }
            } catch (e: Exception) {
                LogUtils.e("error ---> ${e.message}")
            }
        }
复制代码

在Android 7.0以上路径是被私有化的,所以使用FileProvider

  1. 在onActivityResult 中通知相册同步到相册中
Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE).also { mediaScanIntent ->
            val file = File(currentPhotoPath)
            mediaScanIntent.data = Uri.fromFile(file)
            LogUtils.e(mediaScanIntent.data)
            sendBroadcast(mediaScanIntent)
        }

复制代码
  1. 在在onActivityResult中对图片进行尺寸压缩等进行使用
private fun setPic() {
        val targetW: Int = cameraIv.width
        val targetH: Int = cameraIv.height

        val bmOptions = BitmapFactory.Options().apply {
        
            inJustDecodeBounds = true

            val photoW: Int = outWidth
            val photoH: Int = outHeight

        
            val scaleFactor: Int = Math.min(photoW / targetW, photoH / targetH)

            inJustDecodeBounds = false
            inSampleSize = scaleFactor
            inPurgeable = true
        }
        BitmapFactory.decodeFile(currentPhotoPath, bmOptions)?.also { bitmap ->
            cameraIv.setImageBitmap(bitmap)
        }
    }
复制代码

二、录制视频

1.1 添加权限(同一中的权限申请)

1.2 调用相机

Intent(MediaStore.ACTION_VIDEO_CAPTURE).also { takeVideoIntent ->
            takeVideoIntent.resolveActivity(packageManager)?.also {
                startActivityForResult(takeVideoIntent, REQUEST_VIDEO_CAPTURE)
            }
        }
复制代码

1.3 预览

使用VideoView 进行播放

override fun onActivityResult(requestCode: Int, resultCode: Int, intent: Intent?) {
        super.onActivityResult(requestCode, resultCode, intent)
        if (requestCode == REQUEST_VIDEO_CAPTURE && resultCode == RESULT_OK) {
            val videoUri: Uri? = intent?.data
            videoVv.setVideoURI(videoUri)
            videoVv.start()
        }
    }

复制代码