Android实现全局截图以及录屏

  • Post author:
  • Post category:其他


废话不多说 直接上代码(使用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 版权协议,转载请附上原文出处链接和本声明。