博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android5.0免Root截屏,录屏
阅读量:5856 次
发布时间:2019-06-19

本文共 5647 字,大约阅读时间需要 18 分钟。

http://blog.csdn.net/wds1181977/article/details/52174840

MediaProjection介绍

MediaProjection可以用来捕捉屏幕,具体来说可以截取当前屏幕和录制屏幕视频。MediaProjection由MediaProjectionManager来管理和获取。

使用步骤

首先获取MediaProjectionManager,和其他的Manager一样通过 Context.getSystemService() 传入参数MEDIA_PROJECTION_SERVICE获得实例。

接着调用MediaProjectionManager.createScreenCaptureIntent()弹出dialog询问用户是否授权应用捕捉屏幕,同时覆写onActivityResult()获取授权结果。

如果授权成功,通过MediaProjectionManager.getMediaProjection(int resultCode, Intent resultData)获取MediaProjection实例,通过MediaProjection.createVirtualDisplay(String name, int width, int height, int dpi, int flags, Surface surface, VirtualDisplay.Callback callback, Handler handler)创建VirtualDisplay实例。实际上在上述方法中传入的surface参数,是真正用来截屏或者录屏的。

截屏

截屏这里用到ImageReader类,这个类的getSurface()方法获取到surface直接传入MediaProjection.createVirtualDisplay()方法中,此时就可以执行截取。通过ImageReader.acquireLatestImage()方法即可获取当前屏幕的Image,经过简单处理之后即可保存为Bitmap。

private void startCapture() {            mImageName = System.currentTimeMillis() + ".png";            Log.e(TAG, "image name is : " + mImageName);            Image image = mImageReader.acquireLatestImage();            int width = image.getWidth();            int height = image.getHeight();            final Image.Plane[] planes = image.getPlanes();            final ByteBuffer buffer = planes[0].getBuffer();            int pixelStride = planes[0].getPixelStride();            int rowStride = planes[0].getRowStride();            int rowPadding = rowStride - pixelStride * width;            Bitmap bitmap = Bitmap.createBitmap(width + rowPadding / pixelStride, height, Bitmap.Config.ARGB_8888);            bitmap.copyPixelsFromBuffer(buffer);            bitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height);            image.close();            if (bitmap != null) {                Log.e(TAG, "bitmap  create success ");                try {                    File fileFolder = new File(mImagePath);                    if (!fileFolder.exists())                        fileFolder.mkdirs();                    File file = new File(mImagePath, mImageName);                    if (!file.exists()) {                        Log.e(TAG, "file create success ");                        file.createNewFile();                    }                    FileOutputStream out = new FileOutputStream(file);                    bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);                    out.flush();                    out.close();                    Log.e(TAG, "file save success ");                    Toast.makeText(this.getApplicationContext(), "截图成功", Toast.LENGTH_SHORT).show();                } catch (IOException e) {                    Log.e(TAG, e.toString());                    e.printStackTrace();                }            }        }

录屏

录屏需要用到上篇博文中的MediaCadec,这个类将原始的屏幕数据编码,在通过MediaMuxer分装为mp4格式保存。MediaCodec.createInputSurface()获取一个surface对象讲起传入MediaProjection.createVirtualDisplay()即可获取屏幕原始多媒体数据,之后读取MediaCodec编码输出数据经过MediaMuxer封装处理为mp4即可播放,实现录屏。

private void recordVirtualDisplay() {//循环多去编解码器输出数据经过处理保存为mp4        while (!mIsQuit.get()) {            int index = mMediaCodec.dequeueOutputBuffer(mBufferInfo, 10000);            Log.i(TAG, "dequeue output buffer index=" + index);            if (index == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {//后续输出格式变化                resetOutputFormat();            } else if (index == MediaCodec.INFO_TRY_AGAIN_LATER) {//请求超时                Log.d(TAG, "retrieving buffers time out!");                try {                    // wait 10ms                    Thread.sleep(10);                } catch (InterruptedException e) {                }            } else if (index >= 0) {//有效输出                if (!mMuxerStarted) {                    throw new IllegalStateException("MediaMuxer dose not call addTrack(format) ");                }                encodeToVideoTrack(index);                mMediaCodec.releaseOutputBuffer(index, false);            }        }    }        private void encodeToVideoTrack(int index) {//输出数据为mp4文件        ByteBuffer encodedData = mMediaCodec.getOutputBuffer(index);        if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {//是特定格式信息等配置数据,不是媒体数据            // The codec config data was pulled out and fed to the muxer when we got            // the INFO_OUTPUT_FORMAT_CHANGED status.            // Ignore it.            Log.d(TAG, "ignoring BUFFER_FLAG_CODEC_CONFIG");            mBufferInfo.size = 0;        }        if (mBufferInfo.size == 0) {            Log.d(TAG, "info.size == 0, drop it.");            encodedData = null;        } else {            Log.d(TAG, "got buffer, info: size=" + mBufferInfo.size                    + ", presentationTimeUs=" + mBufferInfo.presentationTimeUs                    + ", offset=" + mBufferInfo.offset);        }        if (encodedData != null) {//存在编码数据            encodedData.position(mBufferInfo.offset);            encodedData.limit(mBufferInfo.offset + mBufferInfo.size);            mMuxer.writeSampleData(mVideoTrackIndex, encodedData, mBufferInfo);//写入            Log.i(TAG, "sent " + mBufferInfo.size + " bytes to muxer...");        }    }        private void resetOutputFormat() {        // should happen before receiving buffers, and should only happen once        if (mMuxerStarted) {            throw new IllegalStateException("output format already changed!");        }        MediaFormat newFormat = mMediaCodec.getOutputFormat();        Log.i(TAG, "output format changed.\n new format: " + newFormat.toString());        mVideoTrackIndex = mMuxer.addTrack(newFormat);        mMuxer.start();        mMuxerStarted = true;        Log.i(TAG, "started media muxer, videoIndex=" + mVideoTrackIndex);    }

附录参考

 

 
 
你可能感兴趣的文章
同步失败 8810 deny connection from
查看>>
在云服务器主机环境(不支持组播)基于单播模式的Tomcat Cluster集群配置
查看>>
nagios的web管理控制台-nagiosQL的安装和配置
查看>>
oracle数据库之sql语句使用
查看>>
ORA-01950: 对表空间 'USERS' 无权限
查看>>
Android笔记:Wake Lock
查看>>
js网页禁止复制-禁止另存为-禁止选择-禁止鼠标右键代码
查看>>
Java:简单的设置自己的Exception错误提示
查看>>
Java学习路线
查看>>
android 获取网络数据,回传到本地用TextView显示乱码问题解决方法
查看>>
我的友情链接
查看>>
centos7安装JDK1.8的两种方式
查看>>
myBatis之cache标签使用详解
查看>>
红黑树(Red-Black Trees)(2)
查看>>
如何在本地搭建Docker-Registry
查看>>
python实现队列
查看>>
ORACLE RAC运行在300G内存以上需要考虑的东西
查看>>
用PHP编写一个APP的API
查看>>
OAuth HTTP认证 bash版本
查看>>
Spring笔记——13.Spring的AOP
查看>>