wap网站系统,成都百度网站优化,公众平台网站开发哪家好,怎么重置wordpress在“Android笔记#xff08;八#xff09;#xff1a;基于CameraX库结合Compose和传统视图组件PreviewView实现照相机画面预览和照相功能”#xff0c;文中介绍了拍照功能的实现#xff0c;在本文中将介绍结合JetPack Compose和CameraX实现视频的录制。 新建一个项目 在项…在“Android笔记八基于CameraX库结合Compose和传统视图组件PreviewView实现照相机画面预览和照相功能”文中介绍了拍照功能的实现在本文中将介绍结合JetPack Compose和CameraX实现视频的录制。 新建一个项目 在项目中做如下处理
一、增视频录制的相关依赖库
在项目的模块对应的build.gradle.kt中增加如下的依赖库 增加CameraX相关库 val camerax_version 1.3.0-alpha04implementation(androidx.camera:camera-core:$camerax_version)implementation(androidx.camera:camera-camera2:${camerax_version})implementation(androidx.camera:camera-lifecycle:${camerax_version})implementation(androidx.camera:camera-video:${camerax_version})implementation(androidx.camera:camera-view:${camerax_version} )implementation(androidx.camera:camera-extensions:${camerax_version})增加Material3中扩展的图标库 val icon_extended_version 1.5.4implementation(androidx.compose.material:material-icons-extended:$icon_extended_version)注意因为在前面展示的Android移动应用中使用的图标可选有限因此增加“androidx.compose.material:material-icons-extended”图标扩展库丰富图标的选择。
二、在AndroidManifest.xml权限设置使用照相机 uses-feature android:nameandroid.hardware.camera android:requiredfalse /uses-permission android:nameandroid.permission.CAMERA /uses-permission android:nameandroid.permission.RECORD_AUDIO /三、CameraX视频捕获架构
视频录制需要做两个方面的处理需要录制视频流和同时录制音频流。然后对音频流和视频流进行压缩处理最终写入到磁盘保存起来。在图1展示的是这样工作的示意图。 图1 LifecycleCameraController CameraX提供了LifecycleCameraController。LifecycleCameraController提供了CameraX的大部分的特性它是一个高级的控制器类提供了CameraX的核心特性用于处理照相机的初始化、创建和配置用例这里的用例提供了将用例参数映射到相机的可用参数的功能具体这些用例是指拍照用例CameraController.IMAGE_CAPTURE、 图像分析用例CameraController.IMAGE_ANALYSIS、视频录制用例CameraController.VIDEO_CAPTURE…并将它们绑定到一个生命周期拥有者对象。LifecycleCamera监听设备的Motion Sensor(运动感应器),设置目标的旋转参数。 val cameraController: LifecycleCameraController LifecycleCameraController(applicationContext).apply { setEnabledUseCases(CameraController.VIDEO_CAPTURE) //设置用例 } CameraSelector CameraSelector用于选择摄像头具体选择包括 使用 CameraSelector.DEFAULT_FRONT_CAMERA 请求默认的前置摄像头。 使用 CameraSelector.DEFAULT_BACK_CAMERA 请求默认的后置摄像头。 使用CameraSelector.Builder.addCameraFilter() 按 CameraCharacteristics 过滤可用设备列表。 Recording Recording是实际上执行录制视频的对象,在活动录制视频时提供暂停、恢复或停止录制的控件。如果在录制的过程中发生错误则会初始化一个VideoRecordEvent.Finalized状态所有的控制将进入空操作。 //创建Recording对象并启动视频录制 val recording cameraController.startRecording(…) 在这里startRecording根据录制得到的视频存储处理方式不同有三种形式 1写入到文件 public Recording startRecording( NonNull FileOutputOptions outputOptions, //写入到文件的输出参数 NonNull AudioConfig audioConfig, //音频的配置 NonNull Executor executor,//将在其上运行事件侦听器的线程池 NonNull Consumer listener)//处理视频录制的事件监听器 (2)根据文件描述写入到文件 public Recording startRecording( NonNull FileDescriptorOutputOptions outputOptions,//写入到文件描述的输出参数 NonNull AudioConfig audioConfig,//音频的配置 NonNull Executor executor,//将在其上运行事件侦听器的线程池 NonNull Consumer listener)//处理视频录制的事件监听器 3写入到媒体库 public Recording startRecording( NonNull MediaStoreOutputOptions outputOptions,//写入到媒体库的输出参数 NonNull AudioConfig audioConfig,//音频的配置 NonNull Executor executor,//将在其上运行事件侦听器的线程池 NonNull Consumer listener)//处理视频录制的事件监听器 四、结合Compose和CameraX实现视频的录制实例
1.在主活动中设置权限处理
class MainActivity : ComponentActivity() {companion object{//定义权限数组val CAMERAX_PERMISSIONS arrayOf(android.Manifest.permission.CAMERA, //请求相机android.Manifest.permission.RECORD_AUDIO) //请求录制音频}override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)//检查权限若无就请求权限handlePermissions()setContent {val cameraController: LifecycleCameraController remember {LifecycleCameraController(applicationContext).apply {setEnabledUseCases(CameraController.VIDEO_CAPTURE)}}VideoCaptureAppTheme {MainScreen(cameraController)}}}/*** 检查权限* return Boolean*/private fun hasRequiredPermissions():Boolean CAMERAX_PERMISSIONS.all{ContextCompat.checkSelfPermission(applicationContext,it) PackageManager.PERMISSION_GRANTED}/*** Handle permissions* 处理权限的操作*/private fun handlePermissions(){if(!hasRequiredPermissions()){//请求权限ActivityCompat.requestPermissions(this, CAMERAX_PERMISSIONS,0)}}
}运行结果如图2所示 图2
2. 定义视频预览界面定义
利用view视图组件PreviewView来定义视频预览的界面同时处理将LifecycleCameraController对象与当前的生命周期对象进行绑定。由当前生命周期拥有者LocalLifecycleOwner.current的生命周期lifecycle的状态将决定摄像机何时打开、启动、停止和关闭。
Composable
fun VideoPreview(cameraController:LifecycleCameraController,modifier: Modifier Modifier){val lifecycleOwner LocalLifecycleOwner.currentAndroidView(factory{context: Context -//预览视图PreviewView(context).apply{this.controller cameraControllercameraController.bindToLifecycle(lifecycleOwner)}},modifier modifier)
}3. 定义主界面设置摄像头前后镜头切换
OptIn(ExperimentalMaterial3Api::class)
Composable
fun MainScreen(cameraController: LifecycleCameraController){//设置前后摄像头的图标状态var cameraIcon by remember{mutableStateOf(Icons.Default.VideoCameraBack)}Scaffold {Box(modifier Modifier.fillMaxSize().padding(it)) {//视频预览的界面VideoPreview(cameraController cameraController, modifier Modifier.fillMaxSize())//左上角的摄像头前后镜图标IconButton(onClick {//照相机前后摄像头的切换if (cameraController.cameraSelector CameraSelector.DEFAULT_FRONT_CAMERA) {//设置后镜头cameraController.cameraSelector CameraSelector.DEFAULT_BACK_CAMERAcameraIcon Icons.Default.VideoCameraBack} else {//设置前镜头cameraController.cameraSelector CameraSelector.DEFAULT_FRONT_CAMERAcameraIconIcons.Default.VideoCameraFront}}, modifier Modifier.offset(16.dp, 16.dp)) {Icon(imageVector cameraIcon,tint Color.Green,contentDescription 摄像头)}}}
}运行结果如图3所示 图3
4.在主活动中增加录制视频的处理
1将录制的视频保存到文件中
下列代码将录制视频采用下列录制的方式 public Recording startRecording( NonNull FileOutputOptions outputOptions, //写入到文件的输出参数 NonNull AudioConfig audioConfig, //音频的配置 NonNull Executor executor,//将在其上运行事件侦听器的线程池 NonNull Consumer listener)//处理视频录制的事件监听器 这样的视频文件就会保存到当前应用包下的文件目录中具体代码如下所示
class MainActivity : ComponentActivity() {private var recording: Recording? nullcompanion object{val CAMERAX_PERMISSIONS arrayOf(android.Manifest.permission.CAMERA,//请求相机android.Manifest.permission.RECORD_AUDIO)//请求录制音频}SuppressLint(UnsafeOptInUsageError)override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)//检查权限若无就请求权限handlePermissions()setContent {val cameraController: LifecycleCameraController remember {LifecycleCameraController(applicationContext).apply {setEnabledUseCases(CameraController.VIDEO_CAPTURE)}}VideoCaptureAppTheme {MainScreen(cameraController,this::recordVideo)}}}/*** 检查权限* return Boolean*/private fun hasRequiredPermissions():Boolean CAMERAX_PERMISSIONS.all{ContextCompat.checkSelfPermission(applicationContext,it) PackageManager.PERMISSION_GRANTED}/*** Request permissions* 处理权限的操作*/private fun handlePermissions(){if(!hasRequiredPermissions()){//请求权限ActivityCompat.requestPermissions(this, CAMERAX_PERMISSIONS,0)}}/*** 录制视频* param cmaeraController LifecycleCameraController*/SuppressLint(MissingPermission, UnsafeOptInUsageError)private fun recordVideo(cameraController:LifecycleCameraController){if(recording!null){//停止录制视频recording?.stop()recording nullreturn}if(!hasRequiredPermissions())//没有访问权限returnval outputFile File(filesDir,video.mp4)//执行视频录制recording cameraController.startRecording(//输出文件配置FileOutputOptions.Builder(outputFile).build(),//启动语音AudioConfig.create(true),//在当前应用的上下文中创建事件监听器依附运行的线程池ContextCompat.getMainExecutor(applicationContext)){event:VideoRecordEvent-//监听器处理器when(event){is VideoRecordEvent.Finalize-{if(event.hasError()){recording?.close()recording nullToast.makeText(applicationContext,录制视频失败,Toast.LENGTH_LONG).show()}else{Toast.makeText(applicationContext,录制视频成功,Toast.LENGTH_LONG).show()}}}}}
}OptIn(ExperimentalMaterial3Api::class)
Composable
fun MainScreen(cameraController: LifecycleCameraController,onRecordAction:(cameraController:LifecycleCameraController)-Unit){//设置前后摄像头的图标状态var cameraIcon by remember{mutableStateOf(Icons.Default.VideoCameraBack)}var selected by remember{mutableStateOf(false)}Scaffold(bottomBar {BottomAppBar {NavigationBarItem(selected selected,onClick {onRecordAction(cameraController)},icon {Icon(imageVector Icons.Default.Videocam,contentDescription 视频录制)})}}) {Box(modifier Modifier.fillMaxSize().padding(it)) {VideoPreview(cameraController cameraController, modifier Modifier.fillMaxSize())IconButton(onClick {//照相机前后摄像头的切换if (cameraController.cameraSelector CameraSelector.DEFAULT_FRONT_CAMERA) {cameraController.cameraSelector CameraSelector.DEFAULT_BACK_CAMERAcameraIcon Icons.Default.VideoCameraBack} else {cameraController.cameraSelector CameraSelector.DEFAULT_FRONT_CAMERAcameraIconIcons.Default.VideoCameraFront}}, modifier Modifier.offset(16.dp, 16.dp)) {Icon(imageVector cameraIcon,tint Color.Green,contentDescription 摄像头)}}}
}运行结果如图4所示 图4 启动Device Explorer设备浏览器在data-data-对应应用的包名-files“目录下可以发现已经录制成功的视频文件video.mp4。 图5
2保存视频到媒体库
上述的代码需要检索并浏览录制的视频非常困难并不是一个很好的方法。比较好的处理方式是将录制的视频直接保存在媒体库中。通过将时间戳作为视频文件名根据时间便可以非常方便的在移动终端的媒体库中检索和浏览录制的视频。则就需要在录制视频中采用如下的方式 public Recording startRecording( NonNull MediaStoreOutputOptions outputOptions,//写入到媒体库的输出参数 NonNull AudioConfig audioConfig,//音频的配置 NonNull Executor executor,//将在其上运行事件侦听器的线程池 NonNull Consumer listener)//处理视频录制的事件监听器 将上述的MainActivity中关于视频录制的私有方法recordVideo重新定义具体代码如下
class MainActivity : ComponentActivity() {private var recording: Recording? nullcompanion object{val CAMERAX_PERMISSIONS arrayOf(android.Manifest.permission.CAMERA,//请求相机android.Manifest.permission.RECORD_AUDIO)//请求录制音频}SuppressLint(UnsafeOptInUsageError)override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)//检查权限若无就请求权限handlePermissions()setContent {val cameraController: LifecycleCameraController remember {LifecycleCameraController(applicationContext).apply {setEnabledUseCases(CameraController.VIDEO_CAPTURE)}}VideoCaptureAppTheme {MainScreen(cameraController,this::recordVideo)}}}/*** 检查权限* return Boolean*/private fun hasRequiredPermissions():Boolean CAMERAX_PERMISSIONS.all{ContextCompat.checkSelfPermission(applicationContext,it) PackageManager.PERMISSION_GRANTED}/*** Request permissions* 处理权限的操作*/private fun handlePermissions(){if(!hasRequiredPermissions()){//请求权限ActivityCompat.requestPermissions(this, CAMERAX_PERMISSIONS,0)}}/*** 录制视频到文件* param cmaeraController LifecycleCameraController*/SuppressLint(MissingPermission, UnsafeOptInUsageError)private fun recordVideo(cameraController:LifecycleCameraController){if(recording!null){//停止录制视频recording?.stop()recording nullreturn}if(!hasRequiredPermissions())//没有访问权限return//定义包含时间戳的视频文件名val name SimpleDateFormat(yyyy-MM-dd hh:mm:ss,Locale.CHINA).format(System.currentTimeMillis())//定义关于一条视频记录的相关配置val contentValue ContentValues().apply{put(MediaStore.MediaColumns.DISPLAY_NAME,name)put(MediaStore.MediaColumns.MIME_TYPE,video/mp4)if(Build.VERSION.SDK_INTBuild.VERSION_CODES.P){put(MediaStore.Video.Media.RELATIVE_PATH,Movies/CameraX-Video)}}//配置输出到媒体库的输出参数val mediaStoreOutputOptions MediaStoreOutputOptions.Builder(contentResolver,MediaStore.Video.Media.EXTERNAL_CONTENT_URI).setContentValues(contentValue).build()//执行视频录制recording cameraController.startRecording(//输出到媒体库的配置mediaStoreOutputOptions,//启动语音AudioConfig.create(true),//在当前应用的上下文中创建事件监听器依附运行的线程池ContextCompat.getMainExecutor(applicationContext)){event:VideoRecordEvent-//监听器处理器when(event){is VideoRecordEvent.Finalize-{if(event.hasError()){recording?.close()recording nullToast.makeText(applicationContext,录制视频失败,Toast.LENGTH_LONG).show()}else{Toast.makeText(applicationContext,录制视频成功,Toast.LENGTH_LONG).show()}}}}}
}运行录制视频后在手机模拟器的图片库中可以发现刚刚录制的视频运行结果如图6所示。 图6
五、设置WebCam为模拟器的摄像头
当然模拟器的前后镜头可以自行设置webCam0如图6所示。 图7 对于Camera Front和Camera Back可以任选其一设置为Webcam0不能二者同时进行设置为WebCam0。通过这样的设置可以在模拟器中启动WebCam录制实时的视频。运行效果类似图8所示 图8
六、参考文献
1.CameraX视频捕获架构
https://developer.android.google.cn/training/camerax/video-capture?hlzh-cn