前言
我们前面基于摄像机的图像采集以及编解码已经完成了,那么接下来计划后面的三篇博文分别实现Android屏幕采集实现并进行H.264编解码、MIC音频采集并编码为AAC以及AAC解码播放,希冀可以通过这六篇博文能够对Android上面的音视频编解码有一个初步的学习和了解,由于博主也是近期刚从0开始学习这部分的知识,因此博文中有不恰当的描述,希望大家能够指正,对于有想法进行Android音视频开发的同学,希望这6篇博文能够帮助您启蒙。
那么本篇,我们就先来看看Android屏幕采集实现并进行H.264编解码。
屏幕采集简介
在Android 5.0及以上版本中,可以使用系统提供的MediaProjection API进行屏幕采集,而无需root权限 。MediaProjection 允许应用程序捕获屏幕内容并进行处理。
在实际实现过程还需要用到下面两个类:
MediaProjectionManager:是一个系统服务,看名字可以理解为对MediaProjection进行管理,所以在使用时需要通过MediaProjectionManager获取MediaProjection。
VirtualDisplay:大家可以理解为安卓上面的虚拟显示器,而最终的屏幕显示采集就是通过这个虚拟显示器实现的,可以理解为在录屏时安卓系统会将主屏画面拷贝一份到这个虚拟显示,而虚拟显示器会将图像数据最终输出到Surface,Surface还是之前说的大家理解为队列或者缓冲区都可以。
具体的屏幕采集实现流程如下:
屏幕采集实现
还是与之前一样我们需要对屏幕采集完整的流程进行封装,感觉有点封装上瘾了,哈哈。新建一个ScreenCapture类,并添加如下代码。
class ScreenCapture {
private val REQUEST_CODE: Int = 1000
internal val act: Activity?
internal var videoEncFormat:VideoEncFormat = VideoEncFormat()
internal var dpi:Int = 320
internal val callback:((ByteArray,Int)->Unit)?
internal var data: Intent? = null
internal var resultCode:Int = 0
internal val mediaProjectionManager: MediaProjectionManager?
private constructor(builder:Builder){
act = builder.act
videoEncFormat = builder.videoEncFormat
dpi = builder.dpi
callback = builder.callback
mediaProjectionManager = act?.getSystemService(Context.MEDIA_PROJECTION_SERVICE) as MediaProjectionManager
}
乍一看,是不是感觉全局变量有点多,不要怕,实际的比这个还要多一些,跟编码相关的一部分已经封装到了videoEncFormat中,这个就是我们上一篇中优化后的编码参数类。
ScreenCapture因为参数比较多,所以我使用了构造者模式,ScreenCapture不能直接创建必须通过构造器来创建。
然后屏幕录制时需要用到Activity,这里注意下是Activity,不是Context,因为屏幕录制权限申请需要通过startActivityForResult函数进行请求,权限申请结果会在onActivityResult中返回,所以这里的REQUEST_CODE就是Activity的请求码,data,resultCode则是onActivityResult中返回的Intent和结果码。
这里需要传入一个dpi,后面会设置到VirtualDisplay,可以认为就是虚拟显示器的dpi,我们任何屏幕都会有dpi,虚拟显示器也不例外。
这里的callback则是编码数据返回的回调接口。
全局变量作用介绍完了,那么下来我们看下这个构造器长什么样子。
companion object{
fun newBuilder():Builder{
return Builder()
}
}
class Builder{
var act: Activity? = null
var videoEncFormat:VideoEncFormat = VideoEncFormat()
var dpi:Int = 320
var callback:((ByteArray,Int)->Unit)? = null
fun with(act: Activity):Builder{
this.act =