Android中手机录屏及数据解析:
获取手机录屏数据:
01.手机权限获取
//动态请求权限的数组
//请求权限的数组,可以在数组中添加你需要动态获取的权限
private val PERMISSIONS_REQUIRED = arrayOf(
Manifest.permission.CAMERA,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE
)
//共享方法和常量
companion object {
//时间戳转换公式
private const val FILENAME = "yyyy-MM-dd-HH-mm-ss-SSS"
//照片的输出格式
private const val PHOTO_EXTENSION = ".jpg"
private const val TAG = "MyCameraXDemo"//标识
/** 用于检查应用程序所需的所有权限是否都被授予的方法 **/
fun hasPermissions(context: Context) = PERMISSIONS_REQUIRED.all {
ContextCompat.checkSelfPermission(context, it) == PackageManager.PERMISSION_GRANTED
}
}
//共享方法和常量
companion object {
//时间戳转换公式
private const val FILENAME = "yyyy-MM-dd-HH-mm-ss-SSS"
//照片的输出格式
private const val PHOTO_EXTENSION = ".jpg"
private const val TAG = "MyCameraXDemo"//标识
/** 用于检查应用程序所需的所有权限是否都被授予的方法 **/
fun hasPermissions(context: Context) = PERMISSIONS_REQUIRED.all {
ContextCompat.checkSelfPermission(context, it) == PackageManager.PERMISSION_GRANTED
}
}
//授权结果处理函数
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == PERMISSIONS_REQUEST_CODE) {
if (PackageManager.PERMISSION_GRANTED == grantResults.firstOrNull()) {
//用户点击权限给予按钮
// Toast.makeText(this, "获取到权限", Toast.LENGTH_LONG).show()
//启动相机
startCamera()
} else {
//用户点击拒绝按钮
Toast.makeText(this, "请赋予权限,否则无法正常使用本软件", Toast.LENGTH_LONG).show()
/* 可以跳转到权限设置界面,也可以关闭软件 */
}
}
}
01.CameraX获取YUV数据获取
//启动相机
private fun startCamera() {
//打开相机
viewFinder.post {
// 跟踪这个视图所附加的显示
displayId = viewFinder.display.displayId
//初始化CameraX,并准备绑定相机用例
setUpCamera()
}
}
/** 初始化CameraX,并准备绑定相机用例 */
private fun setUpCamera() {
//请求CameraProvider
val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
//检查 CameraProvider 可用性
cameraProviderFuture.addListener(Runnable {
//获取CameraProvider对象,并赋值我全局变量
cameraProvider = cameraProviderFuture.get()
// 创建和绑定相机用例
bindCameraUseCases()
}, ContextCompat.getMainExecutor(this))
}
// 创建和绑定相机用例(CameraX 的API的使用都在这个方法里)
private fun bindCameraUseCases() {
// 获取用于设置摄像头为全屏分辨率的屏幕指标
val metrics = DisplayMetrics().also { viewFinder.display.getRealMetrics(it) }
//获取预览框长宽比
val screenAspectRatio = Util().aspectRatio(metrics.widthPixels, metrics.heightPixels)
//获取屏幕的旋转方向
val rotation = viewFinder.display.rotation
//把全局CameraProvider赋值给局部对象
val cameraProvider = cameraProvider ?: throw IllegalStateException("相机初始化失败")
//创建Preview对象
preview = Preview.Builder()
.setTargetAspectRatio(screenAspectRatio)//设置预览的宽高比(或者分辨率)
.setTargetRotation(rotation)//设定初始旋转方向(横竖)
.build()
//指定相机是 前置 还是 后置
/*
* 前置相机:CameraSelector.LENS_FACING_FRONT
* 后置相机:CameraSelector.LENS_FACING_BACK
* */
val cameraSelector = CameraSelector.Builder()
.requireLensFacing(lensFacing)
.build()
/*
* 设置分析图片用例
*
* 作用:提供可供 CPU 访问的图片来执行图片处理、计算机视觉或机器学习推断
* */
imageAnalyzer = ImageAnalysis.Builder()
.setTargetAspectRatio(screenAspectRatio)//指定分辨率
.setTargetRotation(rotation)
/*
* 阻塞模式:ImageAnalysis.STRATEGY_BLOCK_PRODUCER (在此模式下,执行器会依序从相应相机接收帧;这意味着,如果 analyze() 方法所用的时间超过单帧在当前帧速率下的延迟时间,所接收的帧便可能不再是最新的帧,因为在该方法返回之前,新帧会被阻止进入流水线)
* 非阻塞模式: ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST (在此模式下,执行程序在调用 analyze() 方法时会从相机接收最新的可用帧。如果此方法所用的时间超过单帧在当前帧速率下的延迟时间,它可能会跳过某些帧,以便 analyze() 在下一次接收数据时获取相机流水线中的最新可用帧)
* */
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)//图片分析模式
.build()
.also {
it.setAnalyzer(cameraExecutor, LuminosityAnalyzer { luma ->
//分析图片用例返回的结果
// Log.d("分析图片用例返回的结果:", "$luma")
})
}
/*
* 设置图片拍摄用例
* ImageCapture的介绍:https://developer.android.google.cn/reference/androidx/camera/core/ImageCapture?hl=zh_cn#CAPTURE_MODE_MINIMIZE_LATENCY
* */
imageCapture = ImageCapture.Builder()
.setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)//设置拍照模式
.setTargetAspectRatio(screenAspectRatio)
.setTargetRotation(rotation)//设置旋转
.build()
//必须在重新绑定用例之前解除绑定
cameraProvider.unbindAll()
try {
//将所选相机和任意用例绑定到生命周期 将 Preview 连接到 PreviewView
var camera: Camera? = cameraProvider.bindToLifecycle(this, cameraSelector, preview, imageCapture, imageAnalyzer)
//将取景器的视图与预览用例进行绑定
preview?.setSurfaceProvider(viewFinder.surfaceProvider)
} catch (exc: Exception) {
Log.e("TAG", "相机启动失败", exc)
}
}
YUV数据的旋转:
学习产出: