android——录制屏幕

录制屏幕

1、界面

2、核心代码

import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.app.Service
import android.content.Context
import android.content.Intent
import android.graphics.BitmapFactory
import android.hardware.display.DisplayManager
import android.hardware.display.VirtualDisplay
import android.media.MediaRecorder
import android.media.projection.MediaProjection
import android.media.projection.MediaProjectionManager
import android.os.Build
import android.os.IBinder
import android.util.DisplayMetrics
import android.util.Log
import android.view.WindowManager
import androidx.core.app.NotificationCompat
import java.io.IOExceptionclass ScreenRecordService : Service() {private var mContext: Context? = nullprivate var projectionManager: MediaProjectionManager? = nullprivate var mMediaProjection: MediaProjection? = nulloverride fun onBind(intent: Intent): IBinder {TODO("Return the communication channel to the service.")}override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {mContext = thisvar resultCode = intent?.getIntExtra("resultCode", -1)var path = intent?.getStringExtra("path")var resultData: Intent? = intent?.getParcelableExtra("data")Log.e("TAG", "录制的路径为:" + path)startNotification();projectionManager = getSystemService(MEDIA_PROJECTION_SERVICE) as MediaProjectionManagermMediaProjection = resultCode?.let { resultData?.let { it1 -> projectionManager?.getMediaProjection(it, it1) } }path?.let { startRecording(it) }return super.onStartCommand(intent, flags, startId)}private var NOTIFICATION_CHANNEL_ID = "id";private var NOTIFICATION_CHANNEL_NAME = "channel";private var NOTIFICATION_CHANNEL_DESC = "desc";private fun startNotification() {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {var notificationIntent = Intent(mContext, ScreenRecordService::class.java)var pendingIntent: PendingIntent? = nullpendingIntent = if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_IMMUTABLE);} else {PendingIntent.getActivity(this, 0, notificationIntent,PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE);}var notificationBuilder = mContext?.let {NotificationCompat.Builder(it, NOTIFICATION_CHANNEL_ID).setLargeIcon(BitmapFactory.decodeResource(mContext!!.resources, R.drawable.ic_launcher_foreground)).setSmallIcon(R.drawable.ic_launcher_foreground).setContentTitle("start record").setContentText("=== start record ===").setContentIntent(pendingIntent)};var notification = notificationBuilder?.build();var channel = NotificationChannel(NOTIFICATION_CHANNEL_ID,NOTIFICATION_CHANNEL_NAME,NotificationManager.IMPORTANCE_DEFAULT);channel.description = NOTIFICATION_CHANNEL_DESC;var notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManagernotificationManager.createNotificationChannel(channel)startForeground(1, notification);}}private var isScreenRecoding = falseprivate var mMediaRecorder: MediaRecorder? = nullprivate var mVirtualDisplay: VirtualDisplay? = nullprivate fun startRecording(filePath: String) {if (!isScreenRecoding) {try {// 创建 MediaRecorder 并设置参数val metrics = DisplayMetrics()val windowManager: WindowManager = mContext?.getSystemService(WINDOW_SERVICE) as WindowManagerwindowManager.defaultDisplay.getMetrics(metrics)mMediaRecorder = MediaRecorder()mMediaRecorder?.setVideoSource(MediaRecorder.VideoSource.SURFACE)mMediaRecorder?.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)mMediaRecorder?.setOutputFile(filePath)mMediaRecorder?.setVideoSize(metrics.widthPixels, metrics.heightPixels)mMediaRecorder?.setVideoEncoder(MediaRecorder.VideoEncoder.H264)mMediaRecorder?.setVideoEncodingBitRate(1920 * 1080 * 3)mMediaRecorder?.setVideoFrameRate(30)// 准备 MediaRecordermMediaRecorder?.prepare()// 创建 VirtualDisplay 以获取屏幕内容mVirtualDisplay = mMediaProjection?.createVirtualDisplay("ScreenRecord",metrics.widthPixels, metrics.heightPixels, metrics.densityDpi,DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,mMediaRecorder?.surface, null, null)// 开始录制mMediaRecorder?.start()isScreenRecoding = trueLog.i("TAG", "开始录屏 $filePath")} catch (e: IOException) {Log.e("TAG", "录屏失败: " + e.message)e.printStackTrace()}}}public fun stopRecording() {if (isScreenRecoding) {try {// 停止录制mMediaRecorder?.stop()mMediaRecorder?.reset()mMediaRecorder?.release()mMediaRecorder = null// 停止 VirtualDisplaymVirtualDisplay?.release()// 停止 MediaProjectionmMediaProjection?.stop()Log.i("TAG", "结束录屏")} catch (e: Exception) {Log.e("TAG", "停止录屏失败: " + e.message)e.printStackTrace()}isScreenRecoding = false}}override fun onDestroy() {stopRecording()super.onDestroy()}
}
/*** 注意:* 1、需要手动给文件读写权限* 2、保存的视频文件在/storage/emulated/0/screen.mp4*/
class MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)enableEdgeToEdge()setContentView(R.layout.activity_main)ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)insets}}override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {super.onActivityResult(requestCode, resultCode, data)if (requestCode == 500) {val path = Environment.getExternalStorageDirectory().absolutePath// 录屏权限screenService = Intent(this, ScreenRecordService::class.java)screenService?.let {it.putExtra("resultCode", resultCode)it.putExtra("data", data)it.putExtra("path", "$path/screen.mp4")startForegroundService(it)}}}/** 开始录制 **/fun startRecord(view: View) {start()}/** 停止录制 **/fun stopRecord(view: View) {stop()}private var mProjectionManager: MediaProjectionManager? = nullprivate var screenService: Intent? = nullprivate fun start() {mProjectionManager = getSystemService(Context.MEDIA_PROJECTION_SERVICE) as MediaProjectionManager// 请求录屏权限mProjectionManager?.createScreenCaptureIntent()?.let { startActivityForResult(it, 500) };}private fun stop() {stopService(screenService)}
}
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"><uses-permission android:name="android.permission.FOREGROUND_SERVICE" /><uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION" /><uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /><applicationandroid:allowBackup="true"android:dataExtractionRules="@xml/data_extraction_rules"android:fullBackupContent="@xml/backup_rules"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/Theme.ScreenRecord"tools:targetApi="31"><activityandroid:name=".MainActivity"android:exported="true"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity><serviceandroid:name=".ScreenRecordService"android:enabled="true"android:exported="true"android:foregroundServiceType="mediaProjection" /></application></manifest>

3、下载地址

https://download.csdn.net/download/wy313622821/90115690

4、操作注意

点击开始录制后,切换到需要录制的界面,如果想要结束则回到当前应用点击停止录屏按钮

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/488349.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

自学高考的挑战与应对:心理调适、学习方法改进与考试技巧提升

一、自学参加高考的成功条件 &#xff08;一&#xff09;报名条件 基本要求 自学参加高考&#xff0c;首先需严格遵守国家的法律法规&#xff0c;这是参与高考的基本前提。具备高中同等学力是核心要素之一&#xff0c;意味着考生需通过自学掌握高中阶段的知识体系与学习能力…

SQL语句错误号:Incorrect integer value: ‘‘ for column ‘poi_id‘ at

SQL语句错误号&#xff1a;Incorrect integer value: for column poi_id at通用解决方案 在MySQL 5.7中&#xff0c;如果你遇到 Incorrect integer value: for column poi_id at row 1 错误&#xff0c;这通常意味着你尝试将一个空字符串插入到需要整数值的字段中。以下是几…

【密码学】SM4算法

一、 SM4算法简介 SM4算法是中国国家密码管理局于2012发布的一种分组密码算法&#xff0c;其官方名称为SMS4&#xff08;SMS4.0&#xff09;&#xff0c;相关标准为GM/T 0002-2012《SM4分组密码算法》。SM4算法的分组长度和密钥长度均为128比特,采用非平衡Feistel结构。采用32…

Qt Xlsx安装教程

Qt Xlsx安装教程 安装perl 如果没有安装perl&#xff0c;请参考perl Window安装教程 下载QtXlsxWriter源码 下载地址 ming32-make编译32 lib库 C:\Qt\Qt5.12.12\5.12.12\mingw73_32>d: D:\>cd D:\Code\QtXlsxWriter-master\QtXlsxWriter-master D:\Code\QtXlsxWrit…

1. 机器学习基本知识(3)——机器学习的主要挑战

1.5 机器学习的主要挑战 1.5.1 训练数据不足 对于复杂问题而言&#xff0c;数据比算法更重要但中小型数据集仍然很普遍&#xff0c;获得额外的训练数据并不总是一件轻而易举或物美价廉的事情&#xff0c;所以暂时不要抛弃算法。 1.5.2 训练数据不具有代表性 采样偏差&#…

通配符SSL证书申请

一、通配符SSL证书点击DV类型通配符SSL证书 二、点击立即生成证书&#xff0c;可以自己在线生成CSR提交&#xff0c;生成的时候私钥代码保存一下。 三、点击继续【建议选择DNS&#xff0c;DNS是指域名解析方式认证】 四、然后去域名注册商添加解析&#xff0c;解析如果可以设置…

个人ffmpeg笔记(一)

环境安装 QT环境安装 运行qt…run安装 下载地址&#xff1a;https://download.qt.io/archive/qt/ 下载地址&#xff1a;https://download.qt.io/archive/qt/5.12/5.12.10/ sudo apt install --reinstall libxcb-xinerama0 解决xcb问题 Ubuntu16.04打开Qt显示/home/user/.co…

JavaEE之多线程的风险以及如何避免

上文我们了解了单线程以及线程的一些基本常见方法&#xff0c;但是多线程在一些方面会存在安全问题&#xff0c;此文我们来为多线程的安全 保驾护航&#xff01;&#xff01; 详情请见下文 1. 多线程带来的风险——线程安全 1.1 观察线程不安全 /*** 使用两个线程&#xff0c…

LoViT: 用于手术阶段识别的长视频Transformer|文献速递-生成式模型与transformer在医学影像中的应用

Title 题目 LoViT: Long Video Transformer for surgical phase recognition LoViT: 用于手术阶段识别的长视频Transformer 01 文献速递介绍 快速发展的手术数据科学&#xff08;SDS&#xff09;领域旨在通过先进利用手术室&#xff08;OR&#xff09;内医疗设备采集的数据…

pika:适用于大数据量持久化的类redis组件|简介及安装(一)

文章目录 0. 引言1. pika简介2. pika安装3. pika设置开机自启4. pika主从搭建5. pika哨兵模式实现自动容灾总结 0. 引言 最近因为公司中用到pika组件&#xff0c;于是将研究过程和理解进行系统记录&#xff0c;以供后续参考。 1. pika简介 pika是360开发的一款国产类redis的…

LNMP和Discuz论坛

文章目录 LNMP和Discuz论坛1 LNMP搭建1.1 编译安装nginx服务1.1.1 编译安装1.1.2 添加到系统服务 1.2 编译安装MySQL服务1.2.1 准备工作1.2.2 编辑配置文件1.2.3 设置路径环境变量1.2.4 数据库初始化1.2.5 添加mysqld系统服务1.2.6 修改mysql的登录密码 1.3 编译安装PHP服务1.3…

Yocto 项目运行超出 BitBake 范围的内容

尽管 Yocto 项目依赖 BitBake 解析和调度元数据来完成构建&#xff0c;但在实际开发中&#xff0c;可能需要执行超出 BitBake 直接管理范围的任务。例如&#xff0c;调用外部脚本或工具完成一些特定的处理逻辑&#xff0c;如生成配置文件、执行硬件初始化脚本或调用第三方构建工…

SpringBoot+OSS文件(图片))上传

SpringBoot整合OSS实现文件上传 以前,文件上传到本地(服务器,磁盘),文件多,大,会影响服务器性能 如何解决? 使用文件服务器单独存储这些文件,例如商业版–>七牛云存储,阿里云OSS,腾讯云cos等等 也可以自己搭建文件服务器(FastDFS,minio) 0 过程中需要实名认证 … 1 开…

生产慎用之调试日志对空间矢量数据批量插入的性能影响-以MybatisPlus为例

目录 前言 一、一些缘由 1、性能分析 二、插入方式调整 1、批量插入的实现 2、MP的批量插入实现 3、日志的配置 三、默认处理方式 1、基础程序代码 2、执行情况 四、提升调试日志等级 1、在logback中进行设置 2、提升后的效果 五、总结 前言 在现代软件开发中&#xff0c;性能优…

SQL 在线格式化 - 加菲工具

SQL 在线格式化 打开网站 加菲工具 选择“SQL 在线格式化” 或者直接访问 https://www.orcc.online/tools/sql 输入sql&#xff0c;点击上方的格式化按钮即可 输入框得到格式化后的sql结果

汇编语言学习

文章目录 前言机器语言与机器指令汇编语言与汇编指令用汇编语言编写程序的工作过程注意事项 计算机组成指令和数据的表示计算机中的存储单元计算机中的总线三类总线X86 CPU性能一览 CPU对存储器的读写内存地址空间将各类存储器看作一个逻辑存储器 —— 统一编址内存地址空间的分…

MATLAB深度学习(七)——ResNet残差网络

一、ResNet网络 ResNet是深度残差网络的简称。其核心思想就是在&#xff0c;每两个网络层之间加入一个残差连接&#xff0c;缓解深层网络中的梯度消失问题 二、残差结构 在多层神经网络模型里&#xff0c;设想一个包含诺干层自网络&#xff0c;子网络的函数用H(x)来表示&#x…

【PHP】部署和发布PHP网站到IIS服务器

欢迎来到《小5讲堂》 这是《PHP》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解。 温馨提示&#xff1a;博主能力有限&#xff0c;理解水平有限&#xff0c;若有不对之处望指正&#xff01; 目录 前言安装PHP稳定版本线程安全版解压使用 PHP配置配置文件扩展文件路径…

SSM 校园一卡通密钥管理系统 PF 于校园图书借阅管理的安全保障

摘 要 传统办法管理信息首先需要花费的时间比较多&#xff0c;其次数据出错率比较高&#xff0c;而且对错误的数据进行更改也比较困难&#xff0c;最后&#xff0c;检索数据费事费力。因此&#xff0c;在计算机上安装校园一卡通密钥管理系统软件来发挥其高效地信息处理的作用&a…

TCP 2

文章目录 Tcp状态三次握手四次挥手理解TIME WAIT状态 如上就是TCP连接管理部分 流量控制滑动窗口快重传 延迟应答原理 捎带应答总结TCP拥塞控制拥塞控制的策略 -- 每台识别主机拥塞的机器都要做 面向字节流和粘包问题tcp连接异常进程终止机器重启机器掉电/网线断开 Tcp状态 建…