调用系统相机拍视频并将视频插入相册

请求相机功能

如果您应用的基本功能是拍照,请将其在 Google Play 上的显示范围限制在装有相机的设备上。如需声明您的应用依赖于相机,请在清单文件中添加 代码:

    
        
        ...
    

如果您的应用使用相机,但不需要相机也可以正常运作,应将 android:required 设为 false。这样,Google Play 便会允许未装有相机的设备下载您的应用。因此,您必须负责通过调用 hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY) 检查相机在运行时的可用性。如果相机不可用,您应停用相机功能。

使用相机应用录制视频

推荐一个比startActivityForResult更方便获取一个Activity的返回结果的方法:

@NonNull
    @Override
    public final  ActivityResultLauncher registerForActivityResult(
            @NonNull ActivityResultContract contract,
            @NonNull ActivityResultCallback callback) {
        return registerForActivityResult(contract, mActivityResultRegistry, callback);
    }
请求录制视频

录视频之前需要先生成视频保存位置Uri,方便后面使用
生成Uri方法如下:

    /**
     * 获取拍视频后的视频Uri
     */
    fun getTakeVideoUri(context: Context): Uri {
        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            val contentValue = contentValuesOf(
                Pair(
                    MediaStore.MediaColumns.DISPLAY_NAME,
                    "VID_${TimeUtil.getCurrentTime_yyyyMMdd_HHmmss()}.mp4"
                ),
                Pair(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_MOVIES)
            )
            context.contentResolver.insert(
                MediaStore.Video.Media.EXTERNAL_CONTENT_URI, contentValue
            )!!
        } else {
            val file = File(
                Environment.getExternalStorageState(),
                "/Movies/VID_${TimeUtil.getCurrentTime_yyyyMMdd_HHmmss()}.mp4"
            )
            context.getExternalFilesDir(Environment.DIRECTORY_MOVIES)?.let {
                val f = File(it, "/VID_${TimeUtil.getCurrentTime_yyyyMMdd_HHmmss()}.mp4")
                FileProvider.getUriForFile(context, authorities, f)
            } ?: FileProvider.getUriForFile(context, authorities, file)
        }
    }

下一步则需要先注册回调,在OnCreate中写就行。

val getVideoResultBack = registerForActivityResult(ActivityResultContractsForCustom.TakeVideo()){
            if (it == true) {
                mVidUri?.let { uri ->
                // 使用Dialog来播放拍完的视频
                val dialog = VideoDialog()
                dialog.setVideoPath(FileUtil.getRealFilePathByUri(this, uri))
                dialog.show(supportFragmentManager, "video")
                    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
                        val absolutePath = FileUtil.getRealFilePathByUri(this, uri)
                        MediaUtil.mediaInsertVideo(this@MainActivity, absolutePath)
                    }
                }
            }
        }
// 调用相机    mVidUri最好在每次拍照前都把其值重新更新,以免发生新拍的照片将旧照片覆盖的情况   下面方法在按钮点击后调用
getVideoResultBack?.launch(mVidUri)

这里并没有使用系统的ActivityResultContracts.TakeVideo(),主要考虑系统提供的返回bitmap,根据判断是否拍摄完成不太方便,所以采用自定义回调方式,自定义类需要继承:ActivityResultContract,返回值类型选择Boolean。

ActivityResultContractsForCustom相关实现

object ActivityResultContractsForCustom {
    class TakeVideo : ActivityResultContract() {
        @CallSuper
        override fun createIntent(context: Context, input: Uri): Intent {
            return Intent(MediaStore.ACTION_VIDEO_CAPTURE)
                .putExtra(MediaStore.EXTRA_OUTPUT, input)
        }

        override fun getSynchronousResult(
            context: Context,
            input: Uri
        ): SynchronousResult? {
            return null
        }

        override fun parseResult(resultCode: Int, intent: Intent?): Boolean? {
            // 根据返回是否成功来判断是否拍完视频后点击完成返回首页
            return resultCode == Activity.RESULT_OK
        }
    }
}

另一种官方文档上提供的Intent方法:

下面都是官方提供的方式

Android 向其他应用委托操作的方法是调用一个 Intent 以描述您要执行的操作。此过程涉及三个部分:Intent 本身,用于启动外部 Activity 的调用,以及用于在焦点返回到 Activity 时处理视频的一些代码。

下面是一个调用 Intent 以拍摄视频的函数。

const val REQUEST_VIDEO_CAPTURE = 1

    private fun dispatchTakeVideoIntent() {
        Intent(MediaStore.ACTION_VIDEO_CAPTURE).also { takeVideoIntent ->
            takeVideoIntent.resolveActivity(packageManager)?.also {
                startActivityForResult(takeVideoIntent, REQUEST_VIDEO_CAPTURE)
            }
        }
    }

请注意,startActivityForResult() 方法受调用 resolveActivity()(返回可处理 Intent 的第一个 Activity 组件)的条件保护。执行此检查非常重要,因为如果您使用任何应用都无法处理的 Intent 调用 startActivityForResult(),您的应用就会崩溃。所以只要结果不是 Null,就可以放心使用 Intent。

观看视频

Android 相机应用会返回 Intent(作为 Uri 传递给 onActivityResult(),指向视频在存储设备中所处的位置)中的视频。下面的代码会检索此视频并将其显示在一个 VideoView 中。

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

项目CameraDemo

你可能感兴趣的:(调用系统相机拍视频并将视频插入相册)