废话不多说 直接上代码(使用kotlin编写大致与java差不多) 代码注释也挺详细的
利用mediaProjection 实现截屏与录屏
mediaProjection 是android 5.0 加入的一个 主要用户捕捉屏幕的东西
createVirtualDisplay(String name, int width, int height, int dpi, int flags, Surface surface, VirtualDisplay.Callback callback, Handler handler)
//创建一个VirtualDisplay捕获屏幕的内容。
//捕捉到的内容将写入到传入的surface中
//因此可将传入MediaRecorder以及ImageReader中的surface 并 通过他们取出surface进行截图与录制
class ScreenCapture constructor(private val width : Int ,private val height : Int ){
private var mImageReader : ImageReader = ImageReader.newInstance(width,height, PixelFormat.RGBA_8888,3)
private var mediaProjectionManager = App.app.mediaProjectionManager
//初始化截图功能
fun startCapture(resultCode : Int, data : Intent?) {
val mediaProjection = mediaProjectionManager.getMediaProjection(resultCode, data)
mediaProjection.createVirtualDisplay("capture",width,height,1,
DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC,
mImageReader.surface,null,null)
}
fun acquire() : Bitmap?{
var image: Image? = null
//当未开始录制的时候先调用此方法会报错
//java.lang.IllegalStateException: mImageReader.acquireLatestImage() must not be null
try {
image = mImageReader.acquireLatestImage()
//此高度和宽度似乎与ImageReader构造方法中的高和宽一致
val iWidth = image.width
val iHeight = image.height
//panles的数量与图片的格式有关
val plane = image.planes[0]
val bytebuffer = plane.buffer
//计算偏移量
val pixelStride = plane.pixelStride
val rowStride = plane.rowStride;
val rowPadding = rowStride - pixelStride * iWidth;
val bitmap = Bitmap.createBitmap(iWidth + rowPadding / pixelStride,
iHeight, Bitmap.Config.ARGB_8888);
bitmap.copyPixelsFromBuffer(bytebuffer)
//必须要有这一步,不如图片会有黑边
return Bitmap.createBitmap(bitmap,0,0,iWidth,iHeight)
}catch (e : Exception){
e.printStackTrace()
return null
}finally {
image?.close()
}
}
}
class MainActivity : PermissionCompatActivity(), MainContract.View {
//截屏图片大小设置
val width = 1440
val height = 2560
var capturor: ScreenCapture = ScreenCapture(width, height)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//启动MediaProjection并准备截图
startActivityForResult(mediaProjectionManager.createScreenCaptureIntent(), 1)
imageView.setOnClickListener {
imageView.setImageBitmap(capturor.acquire())
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
//截屏前的准备
capturor.startCapture(resultCode,data)
}
}
拼命截图放入同一个ImageView中的结果
屏幕录制需要的权限
Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.RECORD_AUDIO
class ScreenRecorder(private val width: Int, private val height: Int, val outputFile: String) {
private val mRecorder = MediaRecorder()
private val mediaProjectionManager = App.app.mediaProjectionManager
//初始化Recorder
init {
prepare()
}
private fun prepare() {
with(mRecorder) {
setAudioSource(MediaRecorder.AudioSource.MIC)
setVideoSource(MediaRecorder.VideoSource.SURFACE)
setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)
setVideoEncoder(MediaRecorder.VideoEncoder.H264)
setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB)
//帧率 帧数简单地说,帧数就是在1秒钟时间里传输的图片的帧数,
// 也可以理解为图形处理器每秒钟能够刷新几次,通常用fps(Frames Per Second)表示。
setVideoFrameRate(30)
//码率 码率:影响体积,与体积成正比:码率越大,体积越大;码率越小,体积越小。
//码率就是数据传输时单位时间传送的数据位数,一般我们用的单位是kbps即千位每秒。也就是取样率
setVideoEncodingBitRate(500 * 1000)
setOutputFile(outputFile)
//设置输出目录
val display = App.app.windowManager.defaultDisplay
val dm = DisplayMetrics()
display.getMetrics(dm)
setVideoSize(width, height)
prepare()
}
}
fun startRecord(resultCode: Int, data: Intent?) {
val mediaProjection = mediaProjectionManager.getMediaProjection(resultCode, data) ?: return
//如果无法获取mediaProjection 则返回
mediaProjection.createVirtualDisplay("test", width, height, 1,
DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, mRecorder.surface, null, null)
mRecorder.start()
}
fun stopRecord() {
Thread {
//避免录制时间过短而报错
Thread.sleep(1000)
mRecorder.stop()
}.start()
}
}
class MainActivity : PermissionCompatActivity(), MainContract.View {
val width = 1440
val height = 2560
val mRecorder = ScreenRecorder(width, height, outputFile = Environment.getExternalStorageDirectory().path + "/output.mp4")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//开始的同时开始录制
startActivityForResult(mediaProjectionManager.createScreenCaptureIntent(), 1)
imageView.setOnClickListener {
mRecorder.stopRecord()
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
//开始录制
mRecorder.startRecord(resultCode,data)
}
}
版权声明:本文为StackOverfloow原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。