当前位置: 首页 > news >正文

Android 实现屏幕录制

  1. 添加权限和服务声明

    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    <serviceandroid:name=".ScreenService"android:enabled="true"android:exported="true"android:foregroundServiceType="mediaProjection"></service>
    
  2. 创建屏幕录制的 Service

    import android.app.*
    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.CamcorderProfile
    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 ScreenService : 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")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, ScreenService::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);}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(ScreenUtil.TAG,"开始录屏 $filePath")} catch (e: IOException) {Log.e(ScreenUtil.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(ScreenUtil.TAG,"结束录屏")} catch (e: Exception) {Log.e(ScreenUtil.TAG, "停止录屏失败: " + e.message)e.printStackTrace()}isScreenRecoding = false}}override fun onDestroy() {stopRecording()super.onDestroy()}
    }
    
  3. 启动和停止录制

    private var mProjectionManager: MediaProjectionManager? = null
    var screenService:Intent?=null
    fun start(){mProjectionManager = getSystemService(Context.MEDIA_PROJECTION_SERVICE) as MediaProjectionManager// 请求录屏权限startActivityForResult(mProjectionManager?.createScreenCaptureIntent(), 500);
    }
    fun stop(){stopService(screenService)
    }
    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {super.onActivityResult(requestCode, resultCode, data)if (requestCode == 500){screenService = Intent(mConext, ScreenService::class.java)screenService?.let {it.putExtra("resultCode", resultCode);it.putExtra("data", data);it.putExtra("path", "screen.mp4");startForegroundService(it)}}
    }
    

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • GCKontrol-GCAir工具链在飞机功能系统设计中的应用
  • 安装 electron 报错解决
  • 你有GitHub Models,我有CSGHub和StarShip
  • 谷粒商城实战笔记-105~107-全文检索-ElasticSearch-入门
  • Mac OS平台,利用 gifify 制作gif教程
  • RK3568笔记五十:SPI通信-回环测试
  • vue3表格组件formatter
  • 视频超压缩保持质量 ffmpeg
  • 该设备几乎不消耗任何功率就能发射无线电波,且不违反物理定律
  • 掌握Python爬虫中的BeautifulSoup4:从环境搭建到实战演示
  • conda操作总结
  • 【数据湖与数据仓库】数据湖与数据仓库的区别与应用
  • flutter 使用正则表达式进行日期、时间格式化
  • ETL工程师角度下的SQL优化
  • 【C++11】解锁C++11新纪元:深入探索Lambda表达式的奥秘
  • css属性的继承、初识值、计算值、当前值、应用值
  • Docker: 容器互访的三种方式
  • FastReport在线报表设计器工作原理
  • idea + plantuml 画流程图
  • JAVA多线程机制解析-volatilesynchronized
  • miniui datagrid 的客户端分页解决方案 - CS结合
  • Python3爬取英雄联盟英雄皮肤大图
  • RxJS: 简单入门
  • Shadow DOM 内部构造及如何构建独立组件
  • Spring技术内幕笔记(2):Spring MVC 与 Web
  • ucore操作系统实验笔记 - 重新理解中断
  • Vue 2.3、2.4 知识点小结
  • Webpack入门之遇到的那些坑,系列示例Demo
  • 不上全站https的网站你们就等着被恶心死吧
  • 从0搭建SpringBoot的HelloWorld -- Java版本
  • 大整数乘法-表格法
  • 第13期 DApp 榜单 :来,吃我这波安利
  • 使用parted解决大于2T的磁盘分区
  • 3月27日云栖精选夜读 | 从 “城市大脑”实践,瞭望未来城市源起 ...
  • ​3ds Max插件CG MAGIC图形板块为您提升线条效率!
  • ‌‌雅诗兰黛、‌‌兰蔻等美妆大品牌的营销策略是什么?
  • #NOIP 2014# day.1 T3 飞扬的小鸟 bird
  • (C++20) consteval立即函数
  • (c语言版)滑动窗口 给定一个字符串,只包含字母和数字,按要求找出字符串中的最长(连续)子串的长度
  • (pojstep1.3.1)1017(构造法模拟)
  • (Redis使用系列) SpirngBoot中关于Redis的值的各种方式的存储与取出 三
  • (七)微服务分布式云架构spring cloud - common-service 项目构建过程
  • (四) 虚拟摄像头vivi体验
  • (原創) 如何安裝Linux版本的Quartus II? (SOC) (Quartus II) (Linux) (RedHat) (VirtualBox)
  • (自适应手机端)行业协会机构网站模板
  • .gitignore文件忽略的内容不生效问题解决
  • .Net(C#)常用转换byte转uint32、byte转float等
  • .net2005怎么读string形的xml,不是xml文件。
  • .net连接oracle数据库
  • /dev下添加设备节点的方法步骤(通过device_create)
  • /etc/apt/sources.list 和 /etc/apt/sources.list.d
  • []FET-430SIM508 研究日志 11.3.31
  • [000-01-030].Zookeeper学习大纲
  • [20181219]script使用小技巧.txt
  • [bzoj1912]异象石(set)